[Bug]: `redis-semantic` cache never produces semantic hits, `_get_cache_key_filter_expression` uses full request hash as RediSearch pre-filt

用户在 LiteLLM 代理中配置了 cache_params.type: redis-semantic ,期望基于语义相似性(向量距离)命中缓存。但实际上,即使两个请求的语义高度相似(余弦距离约 0.008),缓存查找仍然返回 miss,请求被转发到模型并再次写入缓存。该问题在 LiteLLM 版

[Bug]: `redis-semantic` cache never produces semantic hits, `_get_cache_key_filter_expression` uses full request hash as RediSearch pre-filt

[Bug]: `redis-semantic` cache never produces semantic hits, `_get_cache_key_filter_expression` uses full request hash as RediSearch pre-filt

快速结论:该 Bug 发生在使用 LiteLLM 的 `redis-semantic` 缓存类型时,语义相似缓存查询永远返回 miss,原因是 `_get_cache_key_filter_expression` 将完整请求哈希作为 RediSearch 预过滤器,导致 KNN 向量搜索无法执行。优先排查 `redis_semantic_cache.py` 中 `_get_cache_key_filter_expression` 是否返回了正确的预过滤器表达式。

问题场景

用户在 LiteLLM 代理中配置了 cache_params.type: redis-semantic,期望基于语义相似性(向量距离)命中缓存。但实际上,即使两个请求的语义高度相似(余弦距离约 0.008),缓存查找仍然返回 miss,请求被转发到模型并再次写入缓存。该问题在 LiteLLM 版本 1.85.1 至 1.86.2 中复现,最早由 Redis 语义缓存隔离功能合并引入。

报错原文

Traceback (most recent call last):
No errors are raised. The failure is silent — the cache appears to function but never produces a semantic hit.
With --detailed_debug you can observe the embedding call succeeding and the Redis lookup returning empty on every request.

原因分析

根本原因在 litellm/caching/redis_semantic_cache.py 中:

  1. async_get_cache 调用 _get_cache_key_filter_expression(key),其中 key 是模型、消息、温度等参数的 SHA256 哈希。
  2. 该哈希被用作 RediSearch 的 Tag 预过滤器(pre-filter),要求检索的文档哈希必须完全匹配。
  3. RediSearch 索引在 KNN 向量搜索前先执行该预过滤器,对于任何非逐字节相同的请求,预过滤器返回空候选集,KNN 相似度计算和距离阈值判断永远不会执行。
  4. 即使预过滤器通过(极少见),_is_cache_hit 也会拒绝命中,因为存储的哈希与当前请求哈希不同。

可能原因:开发者意图通过哈希预过滤器实现缓存隔离(如按用户、应用隔离),但哈希粒度太细,导致语义缓存完全失效。

环境排查

  • LiteLLM 版本:1.85.1 至 1.86.2(该区间内均受影响)
  • Redis 版本:Redis Stack Server(需 RediSearch 模块)
  • 缓存类型:redis-semantic
  • Embedding 模型:ollama/mxbai-embed-large:335m(1024 维)
  • 部署方式:Docker / Docker Compose
  • Python 版本:3.13

解决步骤

  1. 确认 Bug 代码路径:检查 litellm/caching/redis_semantic_cache.py_get_cache_key_filter_expression 的实现,确认其返回包含完整请求哈希的 Tag 过滤器。
  2. 应用修复(已验证):移除请求哈希预过滤器。在 async_get_cachesync_get_cache 中,将预过滤器参数设为 None 或空表达式,让 KNN 搜索作用于整个索引:
    • 同步路径(约第 256 行):将 _get_cache_key_filter_expression(key) 改为 None
    • 异步路径(约第 370 行):同样改为 None

    这样 redisvl 会执行全索引 KNN 搜索,相似度和距离阈值生效。

  3. 注意保留写入逻辑set_cacheasync_set_cache 中写入文档时仍设置哈希标签(用于索引 schema),读取时不使用即可。
  4. 可优先尝试:如果需保留多租户隔离能力,可在 _get_cache_key_filter_expression 中使用 caller_idapi_key 代替完整请求哈希,但需同步修改 set_cache 调用方以传递身份信息。

验证方法

  1. 发送两个语义相似但措辞不同的请求(如 “What is the capital of France?” 和 “Which city is the capital of France?”),确认第二个请求命中缓存,不触发模型调用。
  2. 检查 Redis 中的缓存文档,确认 KNN 搜索返回正确结果,距离阈值 similarity_threshold(如 0.75)生效。
  3. 使用 --detailed_debug 日志确认 embedding 调用后 Redis 查找返回有效候选集。
  4. 运行回归测试:相同请求仍能命中缓存(同一哈希),完全不同的请求(距离 > 阈值)不命中。

参考来源

BerriAI/litellm #29086

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

celebrityanime
celebrityanime
文章: 8943

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注