提示缓存机制,以及在DigitalOcean Serverless上的第一手测量(Anthropic风格的显式cache_control)。这些机制适用于所有提供商;DigitalOcean的数据来自有记录的基准测试,而非营销宣传。
提示缓存是大多数生产环境LLM团队已配置但并未真正受益的杠杆率最高的成本控制手段。来自ProjectDiscovery的一个有记录的生产案例既展示了失败模式,也展示了修复方法:一个安全智能代理每次请求都发送相同的4,000 token系统指令、工具定义和分析框架,随后附上要评估的特定威胁数据——但缓存命中率仍然只有7%。一次结构性调整,将单个动态标识符从提示词的中间移到末尾,将命中率提升到74%,并将月度推理账单削减了59%。
这种模式很常见:缓存原则上配置正确,但一个位置错误的动态字段会破坏整个前缀。本文介绍提示缓存的实际工作原理、大多数实现为何出错,以及从个位数命中率到生产环境可达的60–80%区间的具体步骤。
在LLM推理上下文中,“缓存”意味着三件不同的事情,混淆它们会导致优化努力用错地方:
1. KV缓存——自动,在单个请求内部。当模型生成响应时,它会为每个输入token计算键值注意力状态。如果没有KV缓存,每个解码步骤都会重新计算所有先前token的注意力。KV缓存存储这些状态,从而实现增量解码。它始终启用,无需配置,并加速单个请求内的生成。您无法控制它;您会自动受益。
2. 提示缓存(前缀缓存)——跨请求,由您控制。前缀缓存将KV缓存概念扩展到多个独立请求。当请求共享相同的前导token——相同的系统提示、相同的少样本示例、相同的参考文档——模型会复用第一个请求已计算的KV状态,而不是每次调用都重新计算。这正是本文其余部分讨论的缓存。稳定的前导token是可缓存前缀;每次请求的内容是动态尾部。
3. 语义缓存——应用层,独立系统。语义缓存存储完整的输入-输出对,并在新查询与先前查询语义相似时基于嵌入相似度检索它们。这不是模型级功能——而是您在应用层使用向量存储实现的一种模式。它与提示缓存互补,而不是替代。
您可以阅读更多关于提示缓存的内容。

三个不同层次上的三种不同缓存:KV(自动,请求内)、前缀(跨请求,由提示结构控制)和语义(应用层,用于重复查询)。
正是经济效益使前缀缓存成为主要的成本优化手段。
在Anthropic (Claude)上,缓存写入成本为基础输入费率的1.25倍(5分钟TTL)或基础输入费率的2倍(1小时TTL);缓存读取成本为基础输入费率的0.10倍——即90%的折扣。在Claude Sonnet 4.6按每百万输入token $3.00的价格下,您为5分钟窗口写入一个缓存条目需支付$3.75/M,每次读取支付$0.30/M。如果某个缓存前缀在过期前被读取10次,您需支付一次$3.75和10次读取费用$0.30 × 10 = $3.00——而不用缓存则需支付$3.00 × 11 = $33.00。对于适中的命中次数,该前缀成本降低了80%。
OpenAI 的缓存输入折扣在其产品线中并非固定数字——它会随模型代际而变化。历史上,GPT-4o 系列的打折幅度为 50%(五折);而在 OpenAI 的最新模型上,折扣已提升至约 90%(一折),与 Anthropic 收取的 0.10x 读取倍率相同。请检查你所调用具体模型的费率,而不是假设一个数字适用于 OpenAI 的所有模型。DigitalOcean 的配套文章《提示缓存何时真正划算》在 DigitalOcean 自己的定价页面上提供了 Anthropic、OpenAI 和开源模型的完整逐模型费率表,值得与本文一并阅读。
写入成本是需要理解的关键变量。缓存并不是免费的——你在填充缓存的首次请求上需要支付溢价,而且只有当后续请求足够频繁地命中缓存时,这笔账才算得过来。一般的盈亏平衡点是 h* = (w − 1) / (1 − r),其中 w 是写入倍率,r 是读取倍率。在 Anthropic 的 5 分钟档费率(w = 1.25,r = 0.10)下,得出 h* = 0.25 / 0.90 ≈ 0.28,向上取整为仅需 1 次缓存命中——在那一次命中之后,每一次后续命中都是纯粹的节省。你可以直接对照上面的演算数字来验证:在恰好 1 次命中(共 2 次请求)时,启用缓存的成本为 $3.75 + $0.30 = $4.05,而不启用缓存的成本为 $3.00 × 2 = $6.00——已经更便宜了。对于随每次请求发送的系统提示词,回本实际上是即时的。对于仅被引用几次的大型文档,请计算读取节省是否足以抵消写入成本。关于 DigitalOcean 支持的每一个费率档位的完整推导过程和演算示例,请参阅上面链接的配套文章。
前缀缓存何时有帮助——何时没有:
这正是上面 ProjectDiscovery 团队所犯的错误,也是绝大多数首次实现缓存的团队会犯的错误。
前缀缓存要求提示词从开头起逐位完全相同。缓存的键是从第一个 token 开始的确切 token 序列。任何变化——任何一个字符、任何一个随请求变化的字段——都会在那一处重置缓存边界。
假设有一个模板,第一部分是静态的(系统指令、工具定义),而中间某处有一个 session_id、一个 timestamp 或一个每次请求都会变化的用户配置字段。即使提示词的 90% 都是相同的,缓存也只能覆盖到第一个差异之前的 token。该点之后的所有内容在每次请求时都会从头重新计算。

相同的内容,只是移动了一个字段。稳定布局:动态字段位于末尾,因此整个前缀保持可缓存。失效布局:字段位于前缀中间,其后的所有内容在每次请求时都会被重新计算。
这就是为什么该安全团队的命中率只有 7%:一个动态威胁标识符位于本应稳定的模板中间,导致系统提示词、分析指令和工具定义每次都被重新计算。将该标识符移到末尾——即所有稳定内容之后——恢复了完整的可缓存前缀,并在一次部署中将命中率从 7% 提高到 74%。
步骤 1:识别你的稳定前缀。梳理你的提示词结构,并对每个组件进行分类:
| 组件 | 稳定? | 示例 |
|---|---|---|
| 系统提示词 / 角色设定 | 是 | “你是一个乐于助人的助手……” |
| 工具 / 函数定义 | 是 | 完整的工具模式(schema) |
| 少样本示例 | 是 | 静态示例 |
| RAG 上下文模板 | 大多数情况下是 | 文档格式、章节标题 |
| 检索到的文档 | 视情况而定 | 相同文档 = 可缓存;随查询变化的文档 = 不可缓存 |
| 用户查询 | 否 | 每次请求都会变化 |
| 会话变量 | 否 | 用户 ID、会话 ID、时间戳 |
| 每次请求的元数据 | 否 | 请求特定的上下文 |
你的可缓存前缀是在大多数请求中保持不变的最长开头序列——通常是系统提示词、工具定义和固定的少样本示例,即 1,000–8,000 token 的稳定内容。
步骤 2:将所有动态内容移到末尾。重新组织结构,使稳定前缀位于最前面且不被中断,所有动态内容随后放在末尾。生产环境中的提示词会自然地积累动态字段——这里加一个会话 ID,那里插入一个用户偏好——而每一次插入都会悄然扼杀缓存。目标结构如下:
[System instructions — fully static]
[Tool definitions — fully static]
[Few-shot examples — fully static]
[Retrieved context — stable template, variable content]
[User query — dynamic]
[Session metadata — dynamic, at the very end]
具体来说,在DigitalOcean 无服务器提供的Anthropic风格cache_control API中,陷阱是位于标记前缀内的一个随请求而变化的值(如会话ID、时间戳),而修复方法是将其移出system,放入用户轮次中:
// The session id is DIFFERENT on every request — watch where it sits.
// BROKEN — id inside the cached system block:
{
"system": [{
"type": "text",
"text": "Session 4f9a-2c1e. You are a support agent. [ …600 lines of stable policy… ]",
"cache_control": {"type": "ephemeral"}
}],
"messages": [{"role": "user", "content": "How do I reset my password?"}]
}
// The next request carries "Session 7b3d-9f02…", so the system text is never
// byte-identical twice — the whole prefix is recomputed. Measured: 0% hit.
// FIXED — id moved to the user turn; system stays byte-identical:
{
"system": [{
"type": "text",
"text": "You are a support agent. [ …600 lines of stable policy… ]",
"cache_control": {"type": "ephemeral"}
}],
"messages": [{"role": "user", "content": "Session 4f9a-2c1e. How do I reset my password?"}]
}
// The changing id now rides after the breakpoint, so the 600-line prefix
// caches on every later request. Measured: ~99% hit.
第3步:将缓存命中率作为一等指标进行监控。 缓存命中率应与延迟和成本一起出现在你的LLM运维仪表板上。它是一个先行指标:命中率下降往往先于成本飙升,并且能在提示结构回归变成账单意外之前将其暴露出来。大多数提供商API会在响应元数据中返回缓存使用情况——记录它,并对其设置告警。
第4步:将缓存TTL与你的流量间隔相匹配。 Anthropic的TTL选项(5分钟或1小时)是操作约束,而不仅仅是定价层级。每10分钟发出一次请求的部署永远无法命中5分钟的层级——请根据预期的p50请求间隔(而不是突发峰值)来选择TTL。对于突发型工作负载(每小时处理数千个请求、随后归于平静的每日批处理),即使2倍写入成本,1小时TTL也更具优势:写入每小时仅支付一次,而读取节省会在突发期间累积。
提示缓存的成本节省已有充分记录。延迟影响则较少被讨论,但也同样显著。
Google的Vertex AI团队记录表明,智能路由——将具有共享前缀的请求发送到已经缓存了该前缀的同一推理服务器——使前缀缓存命中率翻倍,从35%提升至70%。Google报告称,这使上下文密集型编码代理工作负载的TTFT降低了35%(Qwen3-Coder),并使突发型聊天工作负载的P95尾部延迟改善了52%(DeepSeek V3.1)。这是两种不同的流量特征,瓶颈各异——上下文密集型工作负载受制于重计算开销,突发型工作负载受制于队列拥塞——而不是同一工作负载的两种度量方式。
其机制是:缓存命中消除了提示中稳定部分的前缀填充(prefill)计算。对于一个4,500个token中已有4,000个被缓存的提示,模型只需对500个新token执行预填充——预填充工作大约减少了89%。预填充是计算密集型的;跳过它不仅是成本节省,更是有意义的延迟收益。
为了用真实数据说话,而不是引用供应商的数字,我们直接对DigitalOcean Serverless Inference进行了基准测试(Claude Haiku 4.5,输入$1.00/M,输出$5.00/M,约6,000 token的共享前缀,每种布局运行3次,每次1,500个请求)。以下两个发现值得铭记:
首先,这里的缓存是显式的,而非自动的。 DigitalOcean serverless采用Anthropic风格模型:你需要使用一个临时的cache_control断点来标记稳定前缀。如果没有这个标记,无论提示结构多么清晰,命中率都是0%——并且存在一个最小可缓存长度(约2,300 token的前缀无法被缓存;约6,000 token的可以,这与上文提到的该模型4,096 token的最小值一致)。这是前面描述的5分钟/1小时TTL机制,而非vLLM的自动前缀缓存。
其次,当前缀被正确标记后,布局效果非常显著。 保持模型和token数量不变,仅将每次请求的动态字段从前缀内部移到尾部,测得的缓存命中率从0%提升到99.3%,估算的输入成本从每1,000个请求6.72美元降至0.57美元——大约减少了90%。这与90%折扣的缓存读取经济模型所预测的范围一致:当几乎所有输入都按0.1倍费率从缓存提供时,输入账单会下降大约一个数量级。(我们测得的降幅比仅根据命中率和折扣进行的最简单粗略估算高出几个百分点;如果你复现这一基准测试,请将精确百分比视为方向性参考,而不是用于预算规划的精确数字,并且要测量你自己的流量特征。)

DigitalOcean serverless实测(Claude Haiku 4.5,约6,000 token前缀,每种布局1,500个请求):使用cache_control标记前缀并将动态字段移至尾部,使命中率从0%提升至99.3%,并将输入成本降低了约90%(每1,000个请求从6.72美元降至0.57美元)。
数据中一个诚实的提醒:在共享serverless环境中,可复现的收益是成本,而非吞吐量。在多次运行中,TTFT和吞吐量随队列状况波动,而成本降低保持稳定。客户端观察到的缓存吞吐量提升——“释放更多GPU周期用于解码”的说法——出现在专用端点上,因为你拥有GPU。DigitalOcean面向GPU Droplets的推理优化镜像正是针对这种情况,将自动前缀缓存分层到vLLM服务栈中;在专用Droplet上测量其吞吐量差异是顺理成章的后续基准测试。若要获得一个完全可复现的、针对自托管GPU Droplet的引擎级基准测试框架(包括原始命中率和TTFT日志),请参阅配套文章提示缓存何时才能真正实现收支平衡。
对于查询重复度高的场景——客户支持、FAQ机器人、知识库搜索——语义缓存通过消除常见查询的完整推理来补充前缀缓存。其模式如下:
经济性非常显著:一次缓存命中的边际成本几乎为零(一次嵌入调用 + 一次向量查找)。对于支持机器人来说,如果40%的问题都是“如何重置密码”的变体,语义缓存可以消除近一半的推理调用。
何时使用以及需要管理什么:
如果正确实施,所有三层共同从缓存中提供60–80%的推理成本和延迟。只有前缀缓存依赖于提示结构,这就是为什么大多数收益——以及大多数错误——都集中在这里。
KV缓存是自动的,并且作用于单个请求——它允许模型增量生成令牌,而无需在每一步解码时从头重新计算整个序列的注意力。提示(前缀)缓存是该思想的跨请求扩展:当后续请求与先前请求共享相同的前导令牌时,平台重用已计算的KV状态,而不是重新处理。你不需要配置KV缓存;你确实需要配置前缀缓存,通过构建提示使稳定内容放在前面。
最普遍的原因是一个动态字段——时间戳、会话ID或每请求标识符——位于可缓存前缀结束前的某个位置。缓存从第一个令牌开始精确匹配逐字节相同的内容,因此缓存边界之前任何位置的一个字符变化都会使其后的所有内容失效。将所有每请求内容移到提示的末尾,在标记的缓存边界之后。
不会。缓存只影响输入前缀在内部的处理方式——无论平台是重用先前计算的注意力状态还是重新计算它们。无论哪种方式,响应都以相同方式生成,提供商表示输出不受是否发生缓存命中的影响。
这取决于提供商,在Anthropic上,还取决于具体的模型代次——没有单一通用数字。较旧的Claude 3.x模型可以缓存短至1,024–2,048个令牌的前缀;较新的模型如Claude Haiku 4.5需要至少4,096个令牌。低于该下限,提示将根本无法缓存,无论重复多少次或如何放置cache_control标记。在假设来自不同模型或旧Claude代次的数字仍然适用之前,请检查你的特定模型的当前最小值。
在Anthropic标准的5分钟层级费率(1.25×写入,0.10×读取)下,盈亏平衡点约为1次缓存命中——在那一次命中之后,每次额外命中都是纯节省。通用公式是h* = (w − 1) / (1 − r),其中w和r是相对于标准输入价格的提供商的写入和读取倍数;代入你自己的提供商费率即可得到你自己的盈亏平衡点。
并非统一如此。Anthropic 的读取折扣在 Claude 系列中一致为 90% 折扣(0.10 倍),而写入加成则根据 TTL 在 1.25 倍到 2 倍之间。OpenAI 的缓存读取折扣因模型代次而异——历史上 GPT-4o 系列享有 50% 折扣,较新模型则接近 90% 折扣。请检查您具体模型的当前费率,而不是假设一个数字适用于 OpenAI 的整个目录。
可以,而且它们解决不同的问题,因此它们是叠加而非竞争关系。前缀缓存降低了每次请求时重新处理共享提示结构的成本。当传入查询与已回答的查询在语义上足够相似时,语义缓存会完全跳过推理。例如,支持机器人可以对每个请求的系统提示和工具定义使用前缀缓存,同时对与先前查询近乎重复的查询子集使用语义缓存来完全绕过推理。
这是最具杠杆效应的单一修复手段,能解决大多数情况,包括本文开篇的 ProjectDiscovery 示例。不过,如果您的提示前缀低于提供商的最小可缓存长度,如果您的流量过于稀疏而无法在 TTL 窗口内产生重复命中,或者如果“稳定”内容实际上并非因为其他原因而在请求间完全一致(例如模板包含一个您未注意到的细微变化字段),那么它也无济于事。重新排序解决的是布局问题,而不是流量形态或前缀长度问题。
提示缓存是降低 LLM 成本和延迟的强大工具。这是一种简单的技术,只需极少的努力即可实现,但它能对您的利润产生显著影响。
遵循本文概述的步骤,您可以实现提示缓存,并开始在 LLM 工作负载中看到成本节约和延迟改善。
您可以参考来自本生产环境中的推理系列的以下教程来入门:
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。