Claude Code & Prefix Matching 前缀匹配缓存
0X00 Prefix Matching
作为 LLM 的用户,我们没必要深究 Prefix Matching(前缀匹配)的细节机制,但是有必要了解它大概是个怎么回事。下面这张图来自 Anthropic 官网,可以看到当我们不碰其他的什么东西,只是在 LLM 对话框里进行一轮轮的对话的话,那么由于我们是 System Prompt + User Prompt + LLM Response + User Prompt + LLM Response… 这样一路聊下去的,所以所以每次新的对话的前缀都会和缓存起来的内容匹配上,进而不需要再进行推理,只需要推理计算我们最近一次的 User Prompt 就行了。
为什么我们要尽量利用上缓存呢?理由和平时开发中的缓存是一样的,命中缓存不仅速度更快,还节约了计算资源。LLM 也是一样,命中了缓存就会节约大量的计算资源,并且在使用云端 LLM 服务时节约计算资源就是在节约钱。
以 Opus 模型为例,现在的价格大致如下:
- 输入 $5/M token
- 输出 $25/M token
- 命中缓存 $0.5/M token
假设一种场景,你每次输入 1k token,LLM 每次输出 1k token,就这样连续对话 30 轮。
下面是用 Opus 4.8 计算出拉的大致结果:
不使用缓存(每轮全部重算)
- 输入:900k × $5/M = $4.50
- 输出:30k × $25/M = $0.75
- 合计 = $5.25
使用缓存(旧前缀走 $0.5/M,新增走 $5/M)
- 新增输入:1k + 29×2k = 59k × $5/M = $0.295
- 命中缓存:1+3+…+57 = 29² = 841k × $0.5/M = $0.42
- 输出:30k × $25/M = $0.75
- 合计 ≈ $1.47
缓存省约 $3.78,降幅约 72%。节省全在输入侧,输出的 $0.75 省不掉;轮数越多、历史越长,缓存收益越大。
这里的计算主要是表现一个大致的差异,实际上 Anthropic 的缓存写入会比普通的输入更贵一些,再加上一些其他的稀碎规则,但总体还是维持在这个水平。
0X01 Cache Invalidation
那我们有限的 Token 用量应该如何尽量避免缓存失效呢?毕竟缓存失效之后带来的最直接的问题就是 Coding Plan 的消耗量突然爆炸。下面就来列举一些会导致缓存失效的场景,我们了解这些场景之后就能很大程度上避免这个问题了。
/model 和 /effort
这是最反直觉的情况之一,见过很多人都说“平时用 Sonnet 解决问题,遇到难搞的了再上 Opus”。但按照官方的说法,你切换到新的模型后就意味着不能使用上一个模型的 cache 了,所以这种用法最终消耗的 token 可能会比一直用 Opus 还要更多。
同上,这是另一个非常反直觉的情况,有些用法为了节省 token 或者为了更快,就一直使用 high 模式,遇到复杂问题再切 max。原理和上面一样,最终甚至会划掉更多的 token。
不过这里有个问题:先用小消耗,后切大消耗导致消耗更多的 token 的前提是最后会切到 Opus/max,如果一件事最后结束都没切到 Opus 或者 max 的话那自然就节省 token 了。
/compact
压缩上下文这个很好理解,因为把 800k 压缩成 50k 之后肯定跟之前不一样了,甚至大不相同,所以自然不会命中索引。我自己使用下来有个经验之谈,就是不要手动压缩上下文,等 Claude Code 自己压缩就行了,自己压缩通常没有什么显著的收益。并且现在 Context Window 已经拉到 1M 了,很多需求都能在 1M 之内搞定的。
MCP/skill/CLAUDE.md
这些东西会影响缓存的这件事虽然出乎意料,但一想就很合理,因为这些内容都是被注入到上下文里的,并且是注入在上下文的头部,所以当这些内容发生变化之后自然就会导致前缀匹配的缓存失效。
不过这里有个容易搞混的时序:session 进行到一半时你去改 CLAUDE.md 或增删 MCP,其实不会当场失效——改动也不会即时生效。真正的加载(以及随之而来的前缀失效)发生在下一次 /clear、/compact 或重启的时候。所以准确说,是”这些内容在重新加载时引起前缀失效”,而不是”一改就失效”。反过来讲,你在一个长 session 里顺手改了 CLAUDE.md,只要不重启,当前缓存其实还在用旧版本。
timeout
超时是缓存的典型过期理由了,如果你是通过 Anthropic 官方订阅使用的 Claude Code,那么你的缓存过期时间是 1h,也就意味着如果你有一个 800k 上下文的 session,中午吃饭睡觉回来再搞,就会一下子吃掉你一大截 token 用量 🙂
subagent
subagent 严格来说不能算缓存失效,而是你派出去的 subagent 压根就不会管你当前的上下文,它只带着自己接收到的 prompt 去干活,但这里还是可以提一下。
Other
没错,Claude Code 的版本信息还有 dir/platform/shell/os 这些信息也都在上下文的头部,但这些内容其实很少会变化,至少很少会在一个 session 中发生变化。
如果这篇文章对你有帮助,可以请我喝杯咖啡 ☕
评论