系列最后一篇聊钱。如果你用 API 运行过代理,可能注意过账单上的异常:输入 token 费用远高于输出。回想第 1 篇的结构,这很自然。每一轮都要重新发送从系统提示词到完整对话历史的全部内容,所以一个 50 轮的代理会话,相当于同一份系统提示词被收费 50 次。
提示词缓存(prompt caching)就是用来削减这种重复成本的机制。使用得当,输入成本可降到十分之一,响应也会更快,但有一个条件:必须按照缓存喜欢的方式构建上下文。本篇将介绍其原理,以及那些不经意间让缓存全部失效的错误。
相同的前缀无需重新计算
第 1 篇已经介绍了一半原理。模型处理输入时,会为每个 token 生成注意力中间结果,并作为 KV 缓存累积在 GPU 内存中。提示词缓存会在请求结束后保留这份 KV 缓存;如果下一个请求以相同内容开头,就能完整复用该部分的计算结果。
看看它有多适合代理对话。第 10 轮输入是“系统提示词 + 第 19 轮 + 新消息”,第 11 轮输入是“系统提示词 + 第 110 轮 + 新消息”。前半部分完全相同。有缓存时,服务器只需取出已经计算到第 10 轮的结果,再计算新追加的尾部。
计费也遵循这一结构。以 Anthropic API 为例,从缓存读取的输入 token 只收标准价格的 10%。新写入缓存的 token 会加收 25%,但对于写入一次、读取多次的代理模式,很快就能抵消。在数百轮的会话中,有无缓存可能造成数倍成本差异;由于缓存区段被跳过,首 token 延迟也会明显降低。
只有一个条件:前缀不能改变一个字符
没有免费的午餐。复用缓存的条件是前缀匹配。缓存只适用于从输入开头连续相同的部分;从第一个不同的位置开始,后面的内容都要重新计算。
第 1 篇也解释了原因。在注意力机制中,每个 token 的 KV 值都依赖它前面的所有 token。只要前面的 token 有一个发生变化,后面所有 token 的计算结果都会改变,因此无法使用缓存。这就是上下文前部修改成本更高的原因。
缓存友好型上下文的原则可以概括为一句话:稳定的放前面,可变的放后面,历史记录不要修改,只追加内容(append-only)。
让缓存全部失效的无心错误
原则很简单,但违反它的方式却很隐蔽。
第一种是系统提示词中的可变值。如果把当前时间精确到秒写入系统提示词,上下文开头每次请求都会变化,缓存命中率就会变成 0%。如果必须加入,至少粗略到日期,或放在上下文后部。会话 ID 和随机值也是同样的陷阱。
第二种是修改工具定义。工具模式通常位于上下文顶部,因此在会话中途添加或删除工具,会使后面的全部缓存失效。第 4 篇建议整理 MCP 服务器;从缓存角度还要补充一句:在会话开始前整理,中途不要改动。
第三种是编辑历史记录中间部分。修改上一轮内容或删除旧轮次来节省上下文,会破坏前缀,缓存也会从该位置开始消失。为了省下几千个 token,反而支付整个会话的重新计算成本,往往得不偿失。如果必须删除历史记录,不如先建立分界,再整体清空。
最后,从缓存角度重新看第 3 篇的 /compact。压缩会用新的摘要替换全部历史,因此缓存会完全重置。当然,后续轮次可以在更短的历史上建立新缓存,长期来看可能更划算;但要意识到,“compact 不是免费的清理,而是需要支付缓存重建成本的事件”。这也是频繁 compact 在成本上常常不如每个分界使用 /clear 的原因。
系列总结:处理上下文的七种感觉
逐行回顾贯穿 7 篇的原则。
- 上下文窗口是有限的,其限制来自注意力计算和 KV 缓存的物理条件。
- 能放进去不代表能用好。长度本身就会降低质量。
- 每个工作边界默认使用 /clear;只有需要延续上下文时,才使用带指令的 /compact。
- 系统提示词、CLAUDE.md 和工具定义都是固定成本。只简短保留永远成立的内容。
- 将过程繁重但结论简单的任务隔离到子代理的上下文中。
- 需要跨越会话保留的知识要外化到文件中:计划文件、记忆,规模较大时使用 RAG。
- 上下文必须按 append-only 追加,缓存才会发挥作用:稳定的在前,可变的在后。
归纳成一句话:上下文不是模型的能力,而是由用户设计的预算。即使进入 100 万 token 时代,这种意识仍然有效。窗口越大,选择放入什么内容的眼光越会造成性能差异。

![[AI 上下文 #7] 用提示词缓存降低 API 成本 封面图](/assets/images/posts/80775323-baa4-47ad-bc90-fa3cce66546c/1.jpg)