PromptCache:LLM 语义缓存网关的架构与实现

💡 原文中文,约4300字,阅读约需11分钟。
📝

内容提要

PromptCache是一个用Go编写的LLM语义缓存网关,通过向量相似度双阈值判定(高阈值直接命中、低阈值未命中、灰区用廉价模型仲裁)缓存重复请求,支持OpenAI兼容接口、多提供商热切换和持久化存储。它降低token成本和延迟,但存在语义误判、忽略上下文、多租户隔离不足及暴力扫描性能瓶颈等风险。

🎯

关键要点

  • PromptCache是一个用Go编写的LLM语义缓存网关,通过向量相似度双阈值判定(高阈值直接命中、低阈值未命中、灰区用廉价模型仲裁)缓存重复请求,支持OpenAI兼容接口、多提供商热切换和持久化存储。它降低token成本和延迟,但存在语义误判、忽略上下文、多租户隔离不足及暴力扫描性能瓶颈等风险。

  • PromptCache定位为自托管语义缓存网关,单Go二进制,横在应用和LLM提供商之间,对外暴露OpenAI兼容的/v1/chat/completions,SDK改base_url即可接入,业务代码零改动。

  • 核心机制是双阈值判定:top-1余弦相似度≥high(默认0.70)直接命中;<low(默认0.30)判未命中;灰区用最便宜模型做语义仲裁,拿廉价调用换掉昂贵生成,降低误命中率。

  • 模块实现包括:gin HTTP入口与中间件(Recovery、RequestID、Logger、Metrics、RequestSizeLimit),语义引擎聚合embedding、检索、仲裁、转发,向量索引为暴力扫描(1536维余弦441ns/次),存储用BadgerDB(键布局:响应、prompt、embedding),支持TTL、容量淘汰、批量预热。

  • 提供商适配OpenAI、Mistral、Anthropic/Claude(Claude用Voyage AI做embedding),统一接口,出口HTTP重试客户端(429/5xx指数退避,最多3次),流式支持(未命中转发并缓冲,命中合成SSE)。

  • 管理面包括/metrics、/v1/stats、/v1/config、/v1/cache、/v1/cache/warm,Bearer token认证(crypto/subtle常量时间比较),API_AUTH_TOKEN不设则裸奔。

  • 风险与边界:语义相似≠语义等价,高阈值需调高或避免缓存;判定只看最后一条user消息,忽略system prompt、多轮历史、model、temperature,易串答案;多租户隔离依赖调用方自觉,命名空间退化为线性扫描;延迟有下限(embedding调用),命中率低反而变慢;暴力扫描O(n·d)有性能瓶颈;存在簿记缺陷(访问序列表删除后下标缓存不回写,可能错删)。

🔎

延伸解读

双阈值仲裁:成本与准确率的折中

PromptCache 用高、低两个阈值划分命中、未命中与灰区,灰区再调用最便宜的模型做语义仲裁。这种设计在避免高阈值漏掉同义改写的同时,用廉价调用替代昂贵生成,降低了误命中率。但仲裁本身也引入额外延迟和成本,且仲裁模型的能力有限,对复杂语义判断未必可靠。部署时需根据业务对准确率的敏感度,权衡是否启用灰区仲裁。

缓存键的简化:上下文缺失的隐患

系统仅以最后一条 user 消息作为缓存键,忽略 system prompt、多轮历史、model 和 temperature 等参数。这意味着不同上下文或模型配置的请求可能共享缓存,导致答案串用。例如,gpt-4o 的请求可能命中 gpt-4o-mini 的缓存。文章明确指出,这要求部署场景基本是单应用、单模型、单轮问答,否则需自行扩展缓存键,如将 model 名纳入键值。

性能瓶颈与簿记缺陷

向量索引采用暴力扫描,复杂度 O(n·d),10 万条 1536 维向量每次查询约需 1.5 亿次乘加,可能造成几十毫秒的 CPU 尖峰。此外,源码存在簿记缺陷:访问序列表删除后下标缓存未回写,可能导致错删。这些细节提示,项目适合中小规模缓存,生产部署前需评估容量上限并修复已知缺陷。

延伸问答

PromptCache是什么?它主要解决什么问题?

PromptCache是一个用Go编写的自托管LLM语义缓存网关,位于应用和LLM提供商之间,对外暴露OpenAI兼容的/v1/chat/completions接口。它通过将prompt转换为向量并检索语义相似的缓存响应,避免重复请求上游LLM,从而降低token成本和延迟。

PromptCache的双阈值判定机制是如何工作的?

PromptCache使用双阈值判定:top-1余弦相似度≥high(默认0.70)直接命中;<low(默认0.30)判未命中;落在两者之间的灰区,用最便宜的模型(如gpt-4o-mini)进行语义仲裁,只回答YES或NO,以降低误命中率。

如何接入PromptCache?需要修改业务代码吗?

接入PromptCache只需将OpenAI SDK的base_url改为http://localhost:8080/v1,并设置api_key,业务代码无需改动。部署时设置环境变量如EMBEDDING_PROVIDER、OPENAI_API_KEY和API_AUTH_TOKEN,然后启动服务即可。

PromptCache支持哪些LLM提供商?如何切换?

PromptCache支持OpenAI、Mistral和Anthropic/Claude(Claude使用Voyage AI做embedding)。提供商可以在运行时通过POST /v1/config/provider接口热切换,无需重启服务。

PromptCache的缓存存储和淘汰策略是怎样的?

PromptCache使用BadgerDB嵌入式存储,每条缓存记录拆分为响应、prompt和embedding三个键。支持TTL(默认24小时)、容量淘汰(默认10万条,按访问序淘汰最久未用的)、单条删除、整体清空和批量预热。

PromptCache存在哪些主要风险和限制?

主要风险包括:语义相似不等于语义等价,高阈值需调高或避免缓存;判定只看最后一条user消息,忽略system prompt、多轮历史、model等,易串答案;多租户隔离依赖调用方自觉,命名空间退化为线性扫描;延迟有下限(embedding调用),命中率低反而变慢;暴力扫描O(n·d)有性能瓶颈;存在簿记缺陷(访问序列表删除后下标缓存不回写,可能错删)。

🏷️

标签

➡️

继续阅读