每次 AI agent 进一步,它都会把整个对话历史重新发给 LLM。系统指令、工具定义、项目上下文——全部重新读一遍,重新处理一遍,按全价重新计费一遍。
对于 long-running agentic workflows,这通常是整个 AI 基础设施里最贵的账单项目。
Avi Chawla 在 X 上发布了这篇 prompt caching 的完整技术解析,用 Claude Code 作为真实案例(92% 缓存命中率,81% 成本降低),是当天 LLM 工程领域最受关注的分享。
为什么需要缓存:Prefill 和 Decode
LLM 推理请求有两个本质不同的阶段:
Prefill 阶段:处理整个输入 prompt,在全部 token 上运行密集矩阵乘法,构建模型的内部表征。这是 compute-bound 的,贵。
Decode 阶段:逐个生成 token,新 token 被加入序列后预测下一个。这阶段主要是 memory-bound,因为主要读取历史状态而非做重计算。
Prefill 阶段,transformer 为每个 token 计算三个向量:Query、Key、Value。注意力机制用这三个向量决定每个 token 与其他所有 token 的关系。对于任意给定 token,它的 Key 和 Value 向量只取决于它之前的 token,一旦计算出来就永不改变。
没有 KV Cache 的话,这些 Key/Value 张量在每次请求后被丢弃,下一个请求从头重新计算。对于 20,000 token 的 prefix,这意味着 20,000 token 的注意力计算做了完全不必要的重复。
KV Cache 解决了这个问题:把这些张量持久化到推理服务器的内存中,用 token 序列的密码学哈希作为索引。当新请求带着相同 prefix 到达时,哈希匹配,从内存加载张量,prefill 计算完全跳过。
计算复杂度从 O(n²) per generated token 降到 O(n)。
价格结构
Cache 读取 = 0.1x 基础输入价格,即 90% 折扣。 Cache 写入 = 1.25x,即 25% 溢价(存储 KV 张量的成本)。 扩展一小时缓存 = 2.0x。
Claude Code 的 92% 命中率
Claude Code 整个设计围绕一个目标:保持 cache 热。
一次真实 30 分钟 coding session 的计费视角:
- 第 0 分钟:Claude Code 加载系统 prompt、工具定义和项目 CLAUDE.md,超过 20,000 token,全部是新的,是整个 session 最贵的时刻。但只付这一次。
- 第 1-5 分钟:开始给指令,Explore Subagent 在 codebase 里导航、打开文件、跑 grep。所有这些追加到动态 suffix。但 20,000 token 的静态 prefix 现在以 3.00/MTok 从缓存读取。
- 第 6-15 分钟:Plan Subagent 收到摘要简报而非原始结果(传原始输出会让动态 suffix 不必要地膨胀)。每轮都从缓存读取 static prefix,命中率突破 90%,每次访问重置 TTL 保持缓存热。
- 第 28 分钟:跑
/cost。无缓存:200 万 token × Sonnet 4.5 费率 = 1.15**,单任务成本降低 81%。
最反直觉的事实
"1 + 2 = 3" 能命中缓存。"2 + 1" 是 cache miss。
基础设施对从开头起的完整 token 序列做哈希。如果序列里有任何变化——哪怕只是两个元素换了顺序——哈希就变化,整个 prefix 在全价重新计算。
三个会让缓存瞬间失效的操作
1. 在 session 中途修改工具:工具定义是缓存 prefix 的一部分,增加或删除工具会使下游所有内容失效。
2. 在 session 中途换模型:缓存是模型特定的,切换到更便宜的模型需要从头重建整个缓存。
3. 修改 prefix 来更新状态:Claude Code 的解法是在下一条用户消息里追加 reminder tag,而不是编辑系统 prompt——这样 prefix 完全不动。
Prompt 结构规范
1. 系统指令和行为规则在最上。Session 中途不要改。
2. 所有工具定义预先加载。Session 中途不要增删。
3. 检索的 context 和参考文档接下来放。Session 期间保持稳定。
4. 对话历史和工具输出在最下。这是你的动态 suffix。
监控三个字段
cache_creation_input_tokens:写入缓存的 token 数cache_read_input_tokens:从缓存读取的 token 数input_tokens:未缓存处理的 token 数
缓存效率 = cache_read_input_tokens / (cache_read_input_tokens + cache_creation_input_tokens)。像追踪 uptime 一样追踪这个数字。
Prompt caching isn't a feature you toggle on. It's an architectural discipline you design around.