Appearance
Claude Code 自动管理提示缓存,但模型切换、MCP 服务器重连、执行 `/compact` 等操作会强制重建缓存,导致下一次响应变慢且成本增加。可通过 statusline 脚本实时监控 `cache_read` 与 `cache_creation` 指标,或设置 `ENABLE_PROMPT_CACHING_1H=1` 启用更长缓存 TTL。
运行
Claude Code 提示缓存配置与缓存失效排查
提示缓存让 Claude Code 更快,同时降低成本。不启用缓存的话,API 每次交互都要重新处理完整的历史记录。启用缓存后,它会复用已经处理过的内容,只对新变化部分进行增量计算。
Claude Code 默认自动管理提示缓存,除非你手动禁用。了解缓存机制还是很有必要,因为某些操作会使缓存失效,导致下一次响应变慢、成本变高——系统需要重建缓存。本站点覆盖哪些操作会触发重建、为什么某些设置要等到重启才生效,以及当用量异常偏高时如何检查缓存性能。
缓存的组织方式
每次向 Claude Code 发送消息,都会发起一个新的 API 请求。模型不会记住请求间的任何状态,所以 Claude Code 需要重新发送完整上下文:系统提示词、项目上下文、每一轮的消息与工具结果,以及你的新消息。新内容总是追加在末尾,这意味着多数请求的绝大部分内容和前一次是相同的。提示缓存的作用就是让 API 跳过那些没变化的部分。
API 通过匹配每个请求的开头(称为前缀)与近期处理过的内容来实现缓存。正常交互中,前缀就是整个前一次请求,只有最新一轮的交换是新增的。匹配是精确匹配,所以前缀中任何位置的改动,都会导致该改动之后的所有内容被重新计算。没有按文件或按段落的局部缓存。底层机制详见 API 参考文档的提示缓存工作原理。
为了充分利用前缀匹配,Claude Code 会对每个请求进行排序,让轮次间很少变化的内容放在前面:
| 层级 | 内容 | 什么时候会变化 |
|---|---|---|
| 系统提示词 | 核心指令、工具定义、输出风格 | MCP 服务器连接或断开,或者 Claude Code 升级 |
| 项目上下文 | CLAUDE.md、自动记忆(auto memory)、非作用域规则 | 会话启动,或者执行 /clear 或 /compact 之后 |
| 对话内容 | 你的消息、Claude 的响应、工具结果 | 每轮交互都会变化 |
对话内容层级的变化不会影响系统提示词和项目上下文的缓存。系统提示词的改动会使整个缓存失效,因为所有后续内容现在都位于不同的前缀之后。第三列列出的是常见的触发条件,并非详尽列表;后面的章节会覆盖完整集合,包括会话开始时就固定的输出风格等内容。
前缀匹配规则能解释本站点大多数行为。例如,计划模式和技能加载会将它们的指令作为对话消息追加,因此已缓存的前缀保持不变。
有两项设置完全不属于提示文本,因此不在层级表格中。它们对缓存的影响不同:
在会话开始时选择好模型并连接好 MCP 服务器,然后在任务自然停顿处执行
/compact。你在任务过程中做的改动越少,缓存命中率就越高。
缓存存放位置
缓存发生在服务端,在提供模型服务的底层基础设施中。具体位置取决于你的认证方式:
- API Key、Claude 订阅或 Claude Platform on AWS:缓存在 Anthropic 的基础设施中,通过 Claude API 访问。
- Bedrock 或 Vertex AI:缓存在你云服务商的推理基础设施中。
- Foundry:请求路由到 Anthropic 的基础设施。
- 自定义
ANTHROPIC_BASE_URL或 LLM 网关:缓存在请求被转发到的位置,缓存是否生效取决于网关。
关于各提供商存储和处理的内容,参见数据使用。无论缓存存放在哪,条目在不活动后会过期。下面的缓存生命周期部分介绍了 TTL 以及如何延长它。
哪些操作会使缓存失效
以下操作会导致下一次请求部分或全部缓存失效。你会遇到一次变慢、变贵的交互,之后新的前缀会被缓存起来。大多数操作在了解其成本后,可以在任务中避免。模型切换或 MCP 重连可能看似没有消耗,但随后变慢的交互会让你察觉到。
切换模型
每个模型拥有独立的缓存。使用 /model 切换模型意味着下一次请求需要从头读取整个对话历史,即使内容完全相同,也无法命中缓存。
opusplan 模型设置 在计划模式下使用 Opus,执行时使用 Sonnet,因此每次进入或退出计划模式都会触发模型切换,并重建缓存。
连接或断开 MCP 服务器
工具定义位于系统提示词层级中,因此当 Claude 可用的 MCP 工具集合在轮次间发生变化时,缓存会失效。最常见的原因是 MCP 服务器 在会话中途连接或断开,这可能是你无意中触发的:一个 stdio 服务器的进程退出、HTTP 会话过期,或者一个服务器在瞬时故障后自动重连。已连接的服务器也可能通过动态工具更新改变其工具列表。
编辑 MCP 配置本身不会改变缓存。新配置只在重启后才生效,重启时服务器才会连接或断开。
MCP 工具搜索 通过延迟加载完整的工具定义来减少每个工具对前缀的贡献量,但工具名称的集合仍需保持稳定,缓存才能继续有效。
拒绝整个工具
将裸工具名(如 Bash 或 WebFetch)添加到拒绝规则中,会将该工具从 Claude 的上下文中完全移除。工具定义位于系统提示词层级,因此在会话中途添加或删除一条这样的规则,会以与 MCP 服务器连接或断开相同的方式使缓存失效。无论你是通过 /permissions 还是直接编辑设置文件 来修改,改动都会在下一次交互时生效。
只有裸工具名,或等效的 Bash(*) 形式,才会产生这个效果。带作用域的拒绝规则(如 Bash(rm *))以及所有允许规则和询问规则,不会改变 Claude 看到的工具集。Claude Code 仅在 Claude 尝试调用时进行检查,因此前缀保持不变。
压缩对话
压缩 会用摘要替换你的消息历史。这种操作会故意使对话层级缓存失效,因为下一次请求会有一个全新且更短的历史,不会与旧历史共享前缀。Claude Code 会复用系统提示词层级,并从磁盘重新加载项目上下文,而这只有当 CLAUDE.md 和记忆在会话启动后未发生变化时,才能命中缓存。
为了生成摘要,Claude Code 会发送一次性的请求,使用与你当前对话相同的系统提示词、工具和历史,并在末尾追加一条包含摘要指令的最新用户消息。由于它共享了你的前缀,这个请求会读取现有的缓存,而不是重新处理全部历史。压缩的大部分时间花在生成摘要上,而不是缓存未命中上。之后的交互只会为简短得多的摘要重建对话缓存,因此压缩后的那次交互并不慢。
当你丢弃不再需要的内容时,压缩对你是有利的。要控制其开销的发生时机,可以在工作的自然停顿点(例如任务切换时)手动执行
/compact,而不是等待自动压缩在任务中间触发。如果你想完全废弃某条路径,使用/rewind回到更早的轮次。回退会截断到已经缓存的前缀,而不是像压缩那样构建一个全新的前缀。
升级 Claude Code
新的 Claude Code 版本通常会更新系统提示词或工具定义,因此升级后的第一个请求会从头重建缓存。自动更新 在后台下载新版本,并在下次启动时应用,绝不会在会话中途应用。因此,你会将这次缓存未命中视为重启后的第一次交互较慢,而不是会话中的意外。设置 DISABLE_AUTOUPDATER=1 来控制升级时机。
恢复会话 在升级后需要完全重新处理整个对话历史,没有任何缓存命中,因为历史现在位于不同的系统提示词之后。开销与恢复的对话长度成正比,因此长会话恢复后的第一次交互可能是你发送的最昂贵的一次请求。
哪些操作不会影响缓存
以下操作要么将内容追加到对话末尾,要么根本不触及请求。其中一些操作,例如编辑 CLAUDE.md 或更改输出风格,也是为什么某些设置更改需要重启才能生效的原因。
编辑仓库中的文件
文件内容只有在 Claude 读取时才会进入上下文,而读取操作会追加到对话中。编辑 Claude 之前读过的文件不会追溯性地更改历史记录中较早的读取内容。相反,Claude Code 会追加一条 <system-reminder>,提示文件已更改,如果必要,Claude 会重新读取它。
在会话中途编辑 CLAUDE.md
项目根目录和用户级别的 CLAUDE.md 文件在会话启动时被读取一次并保存在内存中。在会话中途编辑它们不会使缓存失效,但编辑内容也不会生效。Claude 会继续使用会话启动时加载的版本。新内容会在下一次执行 /clear、/compact 或重启后加载。
子目录中的嵌套 CLAUDE.md 文件 和 带有 paths: 前置元数据的规则 会在 Claude 首次读取匹配文件时加载。在加载之前编辑它们会生效。加载之后,内容就成为对话历史的一部分,因此中途编辑不会追溯性地改变它。
更改输出风格
输出风格 是系统提示词的一部分,Claude Code 在会话启动时读取一次。通过 /config 或 outputStyle 设置在中途更改,不会使缓存失效,但更改也不会生效。Claude 会继续使用会话启动时加载的风格。新风格会在下一次执行 /clear 或重启后加载。
更改权限模式
在权限模式 之间切换,例如从默认模式切换到接受编辑模式,不会改变系统提示词或工具定义,因此模式切换是安全的。例外情况是带有 opusplan 模型设置的计划模式,它会在你进入或离开计划模式时在 Opus 和 Sonnet 之间切换模型,这使得模式切换变成了模型切换。
调用技能和命令
技能 和命令 会将它们的指令作为用户消息注入到调用点。对话中更早的内容不会发生变化。
运行 /recap
/recap 会生成一个摘要显示在你的终端中。与 /compact 不同,它只是将摘要作为命令输出追加,而不是替换你的消息历史,所以缓存的前缀保持完整。
回退对话
/rewind 会将对话截断到更早的一轮。剩余的历史与当时缓存构建所用的内容相同,系统提示词和项目上下文层级保持不变,因此下一次交互会命中更早的缓存条目。此后的每一轮都通过那个前缀读取,这会保持条目温暖,即使原始轮次发生在比 TTL 更久之前。
随对话一起恢复文件检查点对缓存没有额外影响。文件内容只有在 Claude 读取时才会进入上下文,这与编辑仓库中的文件 同理。
缓存生命周期
缓存的前缀条目在不活动一段时间后过期。每次命中缓存的请求都会重置计时器,因此只要你继续工作,缓存就会保持温暖。在间隔足够长的时间后,下一次请求会重新计算完整输入并重建缓存,这就是为什么离开一段时间后第一次交互会明显变慢。
生存时间(TTL)控制缓存能够承受多久的空档。API 提供两种选择:五分钟 TTL 和一小时 TTL,后者能让缓存通过更长的休息间隙,但缓存写入费率更高。Claude Code 会根据你的认证方式自动选择 TTL,你也可以通过环境变量覆盖它。
使用 Claude 订阅
使用 Claude 订阅时,Claude Code 会自动请求一小时 TTL。用量包含在你的计划内,而不是按 token 计费,因此更长的 TTL 不会产生额外费用,只会影响缓存保持温暖的时间。
如果你超出了计划用量限制,Claude Code 开始消耗用量积分,这部分用量是计费的,因此 Claude Code 会自动将 TTL 降回五分钟。
使用 API Key 或第三方提供商
使用 API Key、Bedrock、Vertex、Foundry 或 Claude Platform on AWS 时,你按 token 费率付费,因此 TTL 默认保持在更便宜的五分钟。要选择一小时 TTL,设置 ENABLE_PROMPT_CACHING_1H=1。
在 Bedrock 上,提示缓存支持、最小可缓存前缀长度以及一小时 TTL 的可用性都因模型而异。如果缓存 token 计数始终为零,请查阅 Bedrock 文档中的支持模型、区域与限制。
覆盖 TTL
设置 FORCE_PROMPT_CACHING_5M=1 来强制使用五分钟 TTL,无论认证方式如何。这在调试缓存行为、比较两种 TTL,或覆盖托管设置 中已设置的 ENABLE_PROMPT_CACHING_1H 时很有用。
缓存作用域
在 Claude Code 中,缓存的作用域实际上限定在一台机器和一个目录。系统提示词中嵌入了工作目录、平台、Shell、操作系统版本和自动记忆路径,因此两个在不同目录中的会话会构建不同的前缀,互相错过对方的缓存。这包括同一仓库的不同工作树,因为每个工作树都有自己的工作目录。
你在同一目录中并行运行的会话会构建匹配的前缀,并能读取彼此缓存。顺序运行的会话仅在启动时的 git 状态快照匹配时(因为系统提示词也捕获了分支和最近的提交信息)才能共享前缀。
底层的 API 缓存作用域更广。缓存按组织隔离,在某些提供商上,按组织内的工作空间隔离。在这些范围内,任何两个使用相同模型和前缀的请求都读取同一个缓存。对于运行着自动化流程集群的 Agent SDK 调用方,请参阅跨用户和机器改进提示缓存 来抑制系统提示词中与机器相关的部分,从而实现跨机器共享缓存。
检查缓存性能
缓存性能通过 API 在每次响应中报告的两个 token 计数来体现。最直接的实时查看方式是通过 statusline 脚本 读取 current_usage 对象:
| 字段 | 含义 |
|---|---|
cache_creation_input_tokens | 本轮写入缓存的 token 数,按缓存写入费率计费 |
cache_read_input_tokens | 本轮从缓存读取的 token 数,费率约为标准输入费率的 10% |
读取与创建的比率高表示缓存工作良好。如果创建计数在一轮又一轮中持续偏高,说明你的前缀中有什么在变化。哪些操作会使缓存失效 章节列出了常见原因。
要获得组织级别的可见性,OpenTelemetry 导出器会报告每个用户和会话的缓存读取和创建 token。指标和事件属性参考见监控用量。
子代理与缓存
子代理 启动自己的对话,拥有自己的系统提示词和工具集,与父代理分开。它构建自己的缓存,从第一次调用无缓存命中开始,并在自己的轮次中逐渐预热。子代理使用五分钟 TTL,即使在订阅模式下也是如此,因为自动的一小时 TTL 仅适用于主对话。
父代理的缓存不受影响。从父代理的角度看,子代理的调用和结果只是追加到对话中,父代理的前缀保持不变。
相反,分支(fork) 会完全继承父代理的系统提示词、工具和对话历史,因此它的第一次请求会命中父代理的缓存。压缩对话 中描述的压缩摘要调用使用了相同的前缀共享方法。
禁用提示缓存
在某些场景下,调试特定模型或提供商的缓存行为时禁用缓存可能有用。要关闭缓存,将以下环境变量之一设置为 1:
| 变量 | 效果 |
|---|---|
DISABLE_PROMPT_CACHING | 对所有模型禁用 |
DISABLE_PROMPT_CACHING_HAIKU | 仅对 Haiku 禁用 |
DISABLE_PROMPT_CACHING_SONNET | 仅对 Sonnet 禁用 |
DISABLE_PROMPT_CACHING_OPUS | 仅对 Opus 禁用 |
要在组织范围内设置缓存策略,可以将以上任一变量或 TTL 变量 放入托管设置 的 env 块中。日常使用请保持缓存启用。
相关资源
- 构建 Claude Code 的经验教训:提示缓存至关重要:计划模式、延迟工具加载和压缩的设计原理
- 探索上下文窗口:哪些内容会被加载到上下文中以及何时加载
- 减少 token 使用量:除缓存之外,管理上下文大小的其他策略
- 跟踪和降低成本:Agent SDK 调用方的缓存 token 跟踪与 TTL 配置
- 提示缓存:底层的 API 机制、断点和定价
常见问题
为什么 Claude Code 切换模型后第一次对话特别慢?
每个模型有独立的缓存。使用 /model 切换模型后,虽然对话内容完全一样,但是缓存键(包括模型名称)变了,所有内容需要重新计算并写入新缓存。如果启用了 opusplan 模型设置,每次进出计划模式也会触发同样的缓存重建。
如何判断 Claude Code 的提示缓存是否正常工作?
设置一个 statusline 脚本,读取 current_usage 中的 cache_read_input_tokens 和 cache_creation_input_tokens。如果 cache_read_input_tokens 持续远高于 cache_creation_input_tokens,说明缓存命中率高。如果 cache_creation_input_tokens 每轮都居高不下,说明前缀有变化,排查哪些操作会使缓存失效中提到的原因。
使用 API Key 时缓存很快失效,可以延长 TTL 吗?
可以。API Key 默认使用五分钟 TTL。设置环境变量 ENABLE_PROMPT_CACHING_1H=1 可以启用一小时 TTL,适合需要短暂中断后继续工作的场景。一小时 TTL 的缓存写入费率更高,但在 API Key 计费模式下按 token 计费。如果是 Claude 订阅用户,自动使用一小时 TTL,无需额外配置。