Claude Code 的提示缓存是怎么命中的:缓存边界在哪一段
会话进行到一半,你用 /model 换了个模型,接下来那一轮明显比前面几轮慢。内容没变、目录没变,什么都没动,就是慢。
Claude Code 官方文档的《How Claude Code uses prompt caching》这一页正好拿这个现象开头。它讲的不是缓存有多好,而是缓存的边界画在哪一段、哪些动作会把这条边界推翻。这篇沿这一页的路径走一遍,顺手标出关键字段名,方便你自己回文档核。
一次请求是怎么拼起来的
文档写明:模型在两次请求之间不记得任何东西,所以每次你发消息,Claude Code 都会把完整上下文重发一遍——system prompt、项目上下文、之前所有消息与工具结果,再加上你这条新消息。新内容追加在末尾,于是每次请求的绝大部分和上一次逐字相同。
缓存就做在这个「绝大部分相同」上。文档的说法是:API 拿请求开头的一段(称为 prefix)去匹配它最近处理过的内容,匹配是精确的,prefix 里任何一处改动都会让它后面的全部内容重新计算。
有一句值得单独拎出来,因为它推翻了不少人的直觉:文档写明不存在按文件或按段落的缓存(There is no per-file or per-segment caching)。缓存不是「哪几个文件缓存了、哪几个没有」这种颗粒度,它只有一条前缀线:线以前整段复用,线上任何位置动一下,线以后全部重来。理解这一条,后面的行为大半能自己推出来。
三层结构:谁在前,谁在后
为让前缀匹配尽量长,Claude Code 把「两轮之间很少变」的内容排在前面。文档给了一张三层表:
| 层 | 内容 | 什么时候会变 |
|---|---|---|
| System prompt | 核心指令、工具定义、output style | 加载的工具定义集合变化,或 Claude Code 升级 |
| Project context | CLAUDE.md、auto memory、无作用域的 rules | 会话开始时,或 /clear、/compact 之后 |
| Conversation | 你的消息、Claude 的回复、工具结果 | 每一轮 |
读法是从下往上:改动落在越靠下的层代价越小。会话层每轮都变,但它在最后,前两层照样命中;system prompt 一变,它后面的所有内容都换了前缀。文档特意说明第三列只是常见触发条件,不是穷举。
另有两样东西根本不在提示文本里,所以没进这张表,但文档写明它们同样是缓存键的一部分:模型(每个模型各有缓存,换模型意味着内容一字不差也要整段重算)和 effort level(同一模型下每档 effort 各有缓存)。会话开始后改 effort,Claude Code 会先弹确认,文档写明原因就是这次改动会让缓存失效;如果你设的值解析下来和当前生效的是同一档(比如把模型默认值显式再设一遍),确认框跳过,缓存也保住。
开头那个「换了模型就变慢」,到这里就有出处了。
哪些动作会作废前缀
文档列了一份清单,逐条看有几处容易踩:
模型切换除了手动 /model,还有两个未必意识到的入口:opusplan 这个模型设置在 plan mode 下解析为 Opus、执行时解析为 Sonnet,所以每次进出 plan mode 都是一次模型切换;自动模型回退(安全分类器命中且该类别配了回退模型时重跑请求)同样算切换,文档写明这一行为出现在它当时列出的那两个模型上,具体是哪些模型随版本变动,以官方文档最新内容为准。
fast mode 启用会加一个请求头,这个头属于缓存键,所以开启后下一次请求整段重读。但这个代价每次会话只付一次——之后 Claude Code 会一直带着这个头,只改请求里的速度设置,而速度设置不在缓存键里。所以关掉 fast mode、限流后自动回落到标准速度、之后再打开,都不动缓存。另外从非 Opus 模型启用 fast mode 会顺带切换模型,那是另一次失效。
MCP server 连接与断开:工具定义在 system prompt 层,请求里的工具定义集合一变就失效。但要不要失效取决于这些工具是不是被 tool search 延后加载的——deferred(文档写明这是受支持模型上的默认行为)时,server 连上、断开、改工具列表都只是往末尾追加;加载进 prefix 时任何改动都作废,文档列出的情况包括 tool search 不可用或被禁用、被标了 alwaysLoad 的 server 或工具,以及被基于阈值的加载策略留在前面的定义。
麻烦在于工具进了 prefix 之后,最常见的失效原因是「你什么都没干」:stdio server 进程退了、HTTP 会话过期了、server 在瞬时故障后自动重连了,或者一个已连接的 server 推了一次动态工具更新。文档还澄清一个常见误会:改 MCP 配置文件本身不影响缓存,新配置要重启后才生效,那时才发生连接或断开。一处例外是切换 advisor 工具(/advisor),文档写明它的定义位于 cache breakpoint 之后。
插件启用与禁用:文档把 plugin 的组件拆开讲,skills、commands、agents、hooks、LSP servers、monitors、themes 这些从不作废缓存,它们加的东西都追加在已有会话之后;唯一例外是提供 MCP servers 的插件,规则同上一条。代价出现在「改动生效后的第一轮」,不是你敲 /plugin enable 的那一刻。如果一次 /reload-plugins 会触发整段重读,文档写明该命令先警告且不执行,要加 --force 才应用。
deny 掉整个工具:把裸工具名(如 Bash、WebFetch)加成 deny 规则会把该工具从上下文里整个拿掉,内置工具定义在 system prompt 层,所以中途加减这类规则会作废缓存。文档把「哪些写法算」说得很细:只有匹配在工具名位置上的才算——裸工具名、等价的 Bash(*),或像 "*" 这样的工具名通配;"mcp__*" 这种只匹配 MCP 工具的通配在 deferred(默认)时不动缓存,因为那些定义本来就不在前缀里;带参数的 Bash(rm *) 与所有 allow、ask 规则不改变 Claude 看到的工具集合。
compaction:/compact 用摘要替换消息历史,按设计就会作废会话层。文档补了一句很实用的:生成摘要时 Claude Code 另发一个请求,system prompt、工具、历史都和你的会话相同,只在末尾追加一条摘要指令,所以缓存还热的时候这个请求读的是你的前缀;隔太久之后再 /compact 就没有缓存可读,摘要请求要把完整历史当未缓存输入重新处理——这是恢复老会话时 /compact 代价最大的原因。两种情况下压缩之后那一轮反倒不慢,因为它只需为那份短得多的摘要重建会话层。
升级 Claude Code:新版本通常改 system prompt 或工具定义,升级后第一次请求从顶上重建。文档写明自动更新在后台下载、在下次启动时应用,不会在会话中途生效,想控制时机可设 DISABLE_AUTOUPDATER=1;另有一条注记说升级后再 resume 旧会话,整段历史都在新的 system prompt 后面。
哪些动作保住前缀
这一组文档的解释统一是「要么追加在末尾,要么根本没碰请求」。
改仓库里的文件不作废缓存:文件内容只在 Claude 读它时才进上下文,改一个它先前读过的文件不会回头改写历史里那次读取,Claude Code 会追加一条 <system-reminder> 说明文件变了。
中途改 CLAUDE.md 不作废缓存,但改动同样不生效——这两句是一体的。文档写明项目根与用户级的 CLAUDE.md 在会话开始时读一次并驻留内存,新内容要等下一次 /clear、/compact 或重启。子目录里的嵌套 CLAUDE.md 和带 paths: frontmatter 的 rules 不同,它们在 Claude 第一次读到匹配文件时才加载,加载前编辑有效,加载后就成了会话历史的一部分。output style 同理:它属于 system prompt,会话开始读一次,中途改既不失效也不生效。「为什么某个设置要重启才生效」,答案常常就在这一段。
permission mode 的切换不改 system prompt 也不改工具定义,是缓存安全的,唯一例外还是 opusplan。skills 与 commands 在调用处以用户消息注入。/recap 与 /compact 的差别也在这里:前者把摘要作为命令输出追加,不替换历史。/rewind 则截断回更早一轮,剩下的历史正是当时那份缓存的来源。
作用范围:一台机器、一个目录
文档写明:在 Claude Code 里缓存实际被限定在一台机器加一个目录,因为 system prompt 里嵌了工作目录、平台、shell、操作系统版本和 auto memory 路径。由此有几个直接后果:不同目录的会话构建出不同前缀,互相命不中,同一仓库的不同 worktree 也算不同目录;同一目录下并行的多个会话前缀相同,可以互相读缓存;先后跑的会话只有启动时那份 git 状态快照一致时才共享前缀,因为 system prompt 还捕获了分支和最近的提交。
把「system prompt 嵌了平台与操作系统版本」和「缓存按工作目录区分」放在一起,Windows 上一个常见情况就清楚了:原生终端里打开某个仓库,和 WSL 里打开同一个仓库,属于两个前缀,不会互相命中。这是把文档两处并列得出的,文档本身没有专门讨论 Windows。
缓存存在哪里取决于你怎么认证:API key、Claude 订阅这类在 Anthropic 的基础设施,Amazon Bedrock 或 Google Cloud 的 Agent Platform 在对应云厂商那边,Microsoft Foundry 取决于该部署的托管选项;而自定义 ANTHROPIC_BASE_URL 或 LLM gateway 的情况下,缓存在你请求被转发到的地方,能不能生效取决于那个 gateway。文档还写了一个具体的降级行为:gateway 若拒绝了某个块上的 cache breakpoint,Claude Code 会去掉它重试,并在该会话剩余时间里让那个块保持未缓存。
存活期与怎么看效果
缓存前缀会在一段不活动后过期,每次命中都会重置计时器。文档写明 API 提供两档 TTL,短档与长档分别对应环境变量名里的 5M 与 1H;Claude Code 按你的认证方式替你选一档,也允许覆盖:ENABLE_PROMPT_CACHING_1H=1 选长档,FORCE_PROMPT_CACHING_5M=1 则不论认证方式一律强制短档(文档说这在调试缓存行为或覆盖 managed settings 里已设的值时有用)。这些是文档写明的变量名,随版本可能变动。
想看缓存有没有在工作,文档指向 API 每次响应里报的两个 token 计数,最直接的办法是写一个 statusline 脚本读 current_usage 对象:cache_creation_input_tokens 是本轮写入缓存的量,cache_read_input_tokens 是本轮从缓存读取的量。判断很朴素:creation 一轮接一轮居高不下,说明前缀里有东西在变,回上面那份清单去找。组织范围的可见性由 OpenTelemetry 导出器提供,它按用户和会话报告这两类 token。
要整个关掉,DISABLE_PROMPT_CACHING 对所有模型生效,另有按模型系列区分的几个(Haiku、Sonnet、Opus、Fable 各一个,命名是在前者后面接模型名)。文档明确说常规使用请保持缓存开启,关掉只在调试特定模型或供应商的缓存行为时偶尔有用。
这些都是环境变量。Linux/macOS 上是常规 shell 环境变量的设法,Windows 上 PowerShell 与 CMD 的写法各不相同,官方文档这一页没有分平台给出设置示例;要在团队里统一,文档给出的可移植做法是把它们或那两个 TTL 变量放进 managed settings 的 env 块,而不是各人各设一遍。
subagent 与 fork 不是一回事
文档写明 subagent 会开一段属于自己的会话,有自己的 system prompt 和工具集,它的第一个请求读不到父会话的缓存(两边前缀不同),而是自己攒一份;并且即使在订阅上 subagent 也用短档 TTL,因为自动选长档只适用于主会话。从父这边看,subagent 的调用与结果是追加进来的,父的前缀完好。
fork 相反:它逐字继承父的 system prompt、工具与会话历史,第一个请求就能读到父的缓存。文档还提到在同前缀 agent 的 workflow 扇出场景里,Claude Code 会短暂按住除第一个之外的其余 agent,好让它们的首个请求能读到第一个刚缓存下来的前缀。
读完这一页,判断「我这个动作会不会毁掉缓存」其实只剩一个问题:它改的是 prefix 里的东西,还是往末尾追加。前者整段重来,后者只付新内容。至于模型和 effort 这两个不在提示文本里的东西,记住它们也在缓存键上,就不会再对着一次「什么都没改却变慢」的回合发愣了。
本文依据 Claude Code 官方文档(code.claude.com/docs)于 2026-08-17 的公开内容整理。
该产品闭源,本文只复述官方文档写明的机制,不推断其内部实现;
我们没有对文中涉及的功能做过实测,因此不涉及界面外观、操作手感与运行速度的任何描述。
该产品迭代频繁,文中涉及的命令、配置项与默认值随版本变动,请以官方文档最新内容为准。
本文不涉及价格、额度与限流的具体数值,相关信息请以官方定价与用量说明页为准。
文中提及权限规则与环境变量仅为说明其对缓存前缀的影响,安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。