提示缓存怎么才命中
大模型账单里有一行最容易被看漏:缓存读取和缓存写入。开了提示缓存之后,同一段系统提示的第二次调用,输入成本可以降到十分之一左右;但如果你排版不对,它会一次都命中不了,账单上只多出一行"缓存写入",比不开还贵。
缓存不是"打开开关就省",它是一组关于内容排布的约束。这篇文章讲清楚机制、三家的差异,以及怎么算自己到底有没有省到。
1. 机制:从开头到断点的前缀哈希
所有厂商的实现都是同一个思路:把"从请求开头到某个断点"的内容做哈希,命中就复用之前算好的 KV,不再重新 prefill。
这带来两个直接推论:
只有前缀能缓存。 中间某段重复没用,必须从第一个 token 开始就一样。所以"把长文档放前面、问题放后面"是对的,"把问题放前面、文档放后面"就永远命中不了。
一处变了,后面全废。 前缀是连续的,断点之后的内容不参与哈希,但断点之前任何一个字符变了,整段缓存失效。这就是为什么在系统提示里塞一个时间戳,会让整个缓存体系归零。
2. 三家的机制不一样
Anthropic:显式断点。 在请求里手动标记缓存位置(最多四个),适合把提示切成几段、分别缓存。最小长度门槛要逐模型查表——512 到 4096 不等,和模型大小、新旧无单调关系(最新的两代旗舰是 512,Haiku 4.5 反而要 4096),低于门槛会静默不缓存、也不报错,只能从响应里的 cache_creation_input_tokens 和 cache_read_input_tokens 是否都为 0 来判断。TTL 默认 5 分钟,每次命中刷新;也可以选 1 小时,写入更贵。
OpenAI:分代际。 GPT-5.6 之前是自动的——不用标记,前缀超过约 1024 token 就按 128 token 的粒度尝试匹配,命中率不完全由你控制,请求会被路由到不同机器、缓存跟着机器走,所以"同样的请求打两次,一次命中一次没命中"是正常现象。GPT-5.6 及以后改成了显式断点 + prompt_cache_key:1024 仍是硬下限,缓存写入另收 1.25 倍,但命中与否基本可控。升级模型时先重读缓存文档,机制本身也在改。
Gemini:两套都有,但看代际。 隐式缓存自动生效,门槛随代际变(2.5 系约 2048,3.x / 4 代 4096);显式 context caching 可以自己创建缓存对象、指定 TTL,适合"一份长文档服务很多请求"的场景——但它在 Gemini 4 及之后的模型、以及 Interactions API 上已被移除,用之前先确认目标模型还支持不支持。
一句话记法:Anthropic 靠你标得准,OpenAI 新代际也要标、老代际靠前缀够稳,Gemini 看代际。优化手法不能直接互相搬。
3. 排布:把内容按"变的频率"排序
这是唯一一条你能完全控制、且收益最大的原则。
[最稳定] 系统指令 → 工具定义 → 固定示例 → 长参考资料 → 会话摘要 → 历史消息 → 本轮输入 [最易变]
对应的四条纪律:
别在系统提示里放动态内容。 时间戳、用户名、页面 ID、随机 session 标识——哪怕只是为了"让模型知道现在几点",也会让缓存全废。要放就放到用户消息里。
工具定义要版本化。 加一个参数、改一句 description,整段前缀就变了。线上边跑边调工具描述,等于持续给所有请求重新预热缓存。
长文档放前面。 一份 5 万 token 的手册放在系统提示后、问题前,能命中就是巨大收益;放在问题后面则完全无效(前缀已经不同了)。
多轮对话别整体重写。 每轮在末尾追加,前缀自然保持;如果每轮都重新生成一遍历史摘要(哪怕内容差不多),哈希也会变。
4. 什么会打掉缓存
除了改内容,还有几个不明显的:
- 加图片/附件。多模态内容参与前缀,加一张图会让该位置之后全部失效
- 切换模型或供应商。缓存不跨模型,也不跨供应商
- 路由打散。按请求随机分流到多个部署,每个部署各自冷启动(见《模型选型看哪几项》里的路由与缓存耦合)
- 并发冷启动。缓存写入后,要等第一个响应开始才对其他并发请求可见。高峰前同时打进十个请求,前几个会各写一遍
- 低于最小长度。短系统提示根本不进缓存,开了也没用
5. 怎么算有没有省到
别用"我感觉快了"。用响应里的三个字段算:
总输入 = input_tokens + cache_creation_input_tokens + cache_read_input_tokens
命中率 = cache_read_input_tokens / 总输入
两个常见误判:
只看 input_tokens。 开了缓存之后,这个字段只表示"最后一个断点之后、未缓存的部分",可能只有几十。用它算成本会严重低估(详见《Token 成本的三个杠杆》)。
只看命中率不看绝对值。 命中率 90%,但缓存的前缀只有 800 token、每次省下的钱不到一分,优化收益接近于零。要看"每次请求省下的 token 数 × 请求量"。
做一个简单的归因看板:按"系统提示版本 × 工具集版本 × 模型"分组,看各组的命中率。命中率突然掉下来的那一组,通常就是刚改过工具或提示词的那一组。
6. 三个误区
"开了缓存就能省钱"。 前缀短、变化频繁、请求稀疏(间隔超过 TTL)的场景,缓存写入比省下的还多。上线前先按真实流量估一遍。
"缓存能加速首字"。 能,但加速的是 prefill 那一段。如果瓶颈在排队或生成,TTFT 改善有限。真正的大头在长上下文场景。
"缓存能替代上下文工程"。 不能。缓存省的是"重复读同一段"的钱,不省"这段该不该进上下文"的钱。该压缩的历史还是要压缩,只是压缩点要和缓存断点对齐——先保稳定段,再压半稳定段。
最后一句:提示缓存是一项排布约束,不是配置项。把它当成"内容怎么放"的设计问题,才可能真的省到钱。