Anthropic 的工程师们写了篇技术博客,标题是,《构建 Claude Code 的经验教训:Prompt Caching 就是一切》
有些工程经验,听起来像“性能优化”。
但你做过一次长对话 Agent,就会发现它不是优化。
它是生存条件。
Anthropic 的工程师写了一篇很不客气的技术博客,标题直白到像警告:
《构建 Claude Code 的经验教训:Prompt Caching 就是一切》。
它讲了 7 条经验(外加一个回到原理的总结)。
我读完的感受是:这不是在教你怎么省 token。
它是在告诉你——系统设计要先承认一个约束:前缀匹配。
承认之后,很多“看起来更优雅的直觉”,反而会变成事故。
1)缓存不是加速器,是地基
文章里有一个非常工程化的细节:Anthropic 把 Prompt Cache 命中率当作基础设施指标去监控,地位接近 uptime。
命中率掉了,就像线上服务掉了。
要 oncall。
这件事把问题的层级定死了:
- 你可以没有某个 fancy 的 planner
- 你可以没有某个漂亮的 UI
- 但你不能没有缓存
因为 Claude Code 这种产品的核心特征是:长对话。
同一个 session,几十轮很正常。
每一轮都要带着“之前所有上下文”一起发给模型。
如果每次都从头算,延迟和成本会把产品直接压扁。
所以“有没有缓存”,决定的不是体验好不好。
决定的是:它能不能跑。
2)把 prompt 排队:越不变的越靠前
Prompt Caching 的原理,在文中被压缩成一句话:前缀匹配。
于是 prompt 的结构,不再是写作问题。
它是数据结构问题。
文章给出一套很清晰的队形(我觉得值得直接背下来):
- 静态系统 prompt + 工具定义(全局共享)
- 项目级上下文(比如 CLAUDE.md 之类的项目说明)
- session 上下文
- 对话消息(逐轮增长)
一句话:越不容易变的东西,越往前放。
这里的坑也很“工程”:
- 你在静态 prompt 里塞了时间戳——缓存当场报废。
- 你的工具定义来自 dict / set,顺序不稳定——每次前缀都不一样。
- 你改了工具 schema 的一个字段——整条缓存链断。
这些都不是“体验差一点”。
是成本结构直接变形。
3)别动 prompt:让变化出现在消息层
如果信息确实会变怎么办?
文章的答案很硬:不要改 prompt,把变化塞进下一轮消息里。
他们提到用类似 <system-reminder> 这样的标签,把更新信息放进 user message 或 tool result。
这背后其实是一个分层:
- prompt 是不可变基础设施
- 消息是流动信息层
当你把“变”从基础设施里清出去,缓存才会稳定。
很多 Agent 产品之所以成本跑飞,不是因为模型太贵。
而是因为它们把“变化”随手塞进了系统 prompt。
4)别换模型:缓存链跟模型绑定
另一个反直觉点:对话中别频繁换模型。
你以为“简单问题用小模型,难问题用大模型”很省钱。
但文章提醒:缓存是跟模型绑定的。
换模型意味着:之前积攒的缓存作废,需要重建。
重建的成本,经常比“让大模型顺手回答一个简单问题”更高。
他们的策略是:主对话始终用同一个模型;需要便宜模型干活时,用子 Agent。
子 Agent 拿独立上下文、独立缓存,做完把结果带回来。
这是一种很朴素的组织结构:
- 主线程保连续性
- 子线程做分工
你不是在省模型钱。
你是在保住缓存链。
5)别碰工具:工具集要稳定
工具定义是前缀的一部分。
所以在 session 期间,不要加工具、不要减工具。
看起来“只保留必要工具”更干净。
但代价是缓存断裂,整个对话重建。
在 Agent 产品里,“干净”经常比“稳定”更贵。
6)Plan Mode 的关键不是少工具,而是多两个开关
Claude Code 有 Plan Mode:只做思考规划,不执行操作。
很多人会直觉地在 Plan Mode 移除执行工具,退出时再加回去。
文章说他们没这么做。
他们保留工具集不动,而是加两个特殊工具:EnterPlanMode / ExitPlanMode。
约束用 system message 说明就行。
工具集稳定,缓存就稳定。
我觉得这条经验很有启发:不要用“改结构”的方式表达状态切换。
用显式开关。
用协议。
7)延迟加载:用 stub 保持前缀不变
如果你接入几十个 MCP 工具,把完整 schema 都塞进 prompt,token 很贵。
但按需加减工具又会破坏缓存。
他们的折中方案是“延迟加载”:
- 起步只放轻量 stub(存根),标记
defer_loading: true - 模型需要时,通过 Tool Search 拉取完整 schema
这样前缀里永远是轻量目录,而不是一堆会变化的全文。
这其实是“目录 vs 全文”的经典做法。
你先有索引。
索引稳定。
全文按需取。
8)压缩也要走同一条缓存链:Cache-Safe Forking
长对话一定会遇到 context window 被填满。
你需要 compaction(压缩/摘要)。
很多系统会“另起一个调用”来压缩:换一套 system prompt、换一套工具定义。
文章指出这会导致两条缓存链完全不复用,白白多花钱。
他们的做法叫 Cache-Safe Forking:
- 压缩请求使用与主对话完全一致的 system prompt / user context / 工具定义
- 把主对话消息作为历史带上
- 只在最后追加一条“压缩指令”作为新的 user message
这样新增成本基本只来自最后那条指令。
压缩不是“另一个任务”。
压缩是主任务的一次分叉。
分叉也必须继承缓存。
最后:Prompt Caching 不是技巧,是约束
这篇文章最有价值的地方,不在某个细节技巧。
而在它把“缓存”从优化手段,抬升成架构约束:
- 别改 prompt
- 别换模型
- 别动工具
- 别另起炉灶
你先承认约束。
然后围绕约束设计系统。
做 Agent 产品的门槛,从来不是“你能不能让它跑起来”。
而是“你能不能让它长期稳定地、以可控成本跑起来”。
Prompt Caching 不是一切。
但当你真的开始交付一个会话型产品时,你会发现:它几乎决定了你能不能活下来。
参考
- https://mp.weixin.qq.com/s/2Qs5gRlhe7qSVYCd9r8t1g
- 原文(Anthropic 技术博客):https://claude.com/blog/lessons-from-building-claude-code-prompt-caching-is-everything
- Claude Code 文档:https://code.claude.com/docs/en/overview