Claude Code 入门与原理
Claude Code 入门与原理
Prompt 缓存
4 分钟阅读
Claude Code 如何使用提示缓存
Claude Code 自动管理提示缓存。了解为什么切换模型会触发一次缓慢的未缓存轮次、
/compact的成本是多少、为什么 CLAUDE.md 的编辑在会话中不会生效,以及如何检查缓存命中率。
提示缓存让 Claude Code 更快、更省成本。没有缓存时,API 会在每一轮重新处理你的完整历史。有了缓存,它会复用已处理的内容,只对新变化的部分进行工作。
Claude Code 自动为你处理提示缓存,除非你禁用它。了解提示缓存的工作原理仍然很有用,因为某些操作会使缓存失效,导致下一次响应更慢、更昂贵,因为它需要重建缓存。本页涵盖了哪些操作会导致缓存失效、为什么某些设置需要重启才能生效,以及在使用量看起来很高时如何检查缓存性能。
缓存如何组织
每次你在 Claude Code 中发送消息时,都会发起一个新的 API 请求。模型在请求之间不会记住任何内容,因此 Claude Code 会重新发送完整的上下文:系统提示、项目上下文、所有先前的消息和工具结果,以及你的新消息。新内容追加在末尾,这意味着每次请求的大部分内容与上一次相同。提示缓存就是 API 避免重新处理未变化部分的方式。
API 通过将每次请求的开头(称为前缀)与最近处理的内容进行匹配来缓存。在正常轮次中,前缀是整个上一次请求,只有最新的交流是新的。匹配是精确的,因此前缀中任何位置的更改都会导致其后所有内容重新计算。没有按文件或按段落的缓存。有关底层机制,请参阅 API 参考中的提示缓存工作原理。
为了充分利用前缀匹配,Claude Code 将每次请求的内容按轮次间很少变化的部分优先排序:
| 层级 | 内容 | 何时变化 |
|---|---|---|
| 系统提示 | 核心指令、工具定义、输出样式 | 加载的工具定义集合发生变化,或 Claude Code 升级时 |
| 项目上下文 | CLAUDE.md、自动记忆、无范围规则 | 会话开始时,或执行 /clear 或 /compact 后 |
| 对话 | 你的消息、Claude 的回复、工具结果 | 每一轮 |
对话层的变化会保留系统提示和项目上下文的缓存。系统提示的变化会使所有内容失效,因为之后的所有内容现在位于不同的前缀之后。第三列给出的是常见触发因素而非详尽列表,下面的章节涵盖了完整集合,包括输出样式等在会话开始时固定的内容。
前缀匹配规则解释了本页上的大多数行为。例如,计划模式和技能加载将它们的指令作为对话消息追加,因此缓存的前缀保持完整。
有两个设置根本不属于提示文本,但都是缓存键的一部分:
- 模型:每个模型有自己的缓存。切换模型意味着即使内容完全相同,下一次请求也会读取整个对话历史而没有缓存命中。请参阅下面的切换模型。
- Effort level:每个 effort level 对同一模型有自己的缓存。在会话中更改它会重新计算整个请求,Claude Code 会在应用更改前要求你确认。请参阅下面的调整 effort level。
缓存存储在哪里
缓存发生在服务器端,位于服务你的模型的基础设施中。具体位置取决于你的认证方式:
- API 密钥、Claude 订阅或 Claude Platform on AWS:缓存位于 Anthropic 的基础设施中,通过 Claude API 访问
- Amazon Bedrock 或 Google Cloud 的 Agent Platform:缓存位于你的云服务提供商的服务基础设施中
- Microsoft Foundry:请求路由到 Anthropic 的基础设施
- 自定义
ANTHROPIC_BASE_URL或 LLM 网关:缓存位于你的请求被转发的任何地方,缓存是否有效取决于网关
有关每个提供商存储和处理的内容,请参阅数据使用。无论缓存位于何处,条目在一段时间不活动后过期,下面的缓存生命周期涵盖了 TTL 以及如何延长它。
使缓存失效的操作
这些操作会导致下一次请求部分或全部错过缓存。你会看到一次性的更慢、更昂贵的轮次,之后新的前缀会被缓存。其中大多数在了解其成本后可以避免在任务中执行。模型切换可能感觉免费,直到你注意到随之而来的更慢轮次。
切换模型
每个模型有自己的缓存。使用 /model 切换意味着下一次请求会读取整个对话历史而没有缓存命中,即使内容完全相同。
opusplan 模型设置在计划模式期间解析为 Opus,在执行期间解析为 Sonnet,因此每次计划模式切换都是模型切换并会启动新的缓存。
Fable 5 上的自动模型回退也是模型切换。当安全分类器标记请求时,Claude Code 会在默认的 Opus 模型上重新运行它,会话继续在那里进行。
调整 effort level
缓存按effort level以及模型进行键控,因此使用 /effort 切换意味着下一次请求会读取整个对话历史而没有缓存命中。一旦对话开始,Claude Code 会在应用会使缓存失效的 effort 更改前显示确认对话框。解析为与当前生效级别相同的更改(例如显式设置模型的默认值)会跳过对话框并保持缓存。
开启快速模式
启用快速模式会添加一个属于缓存键的请求头,因此下一次请求会读取整个对话历史而没有缓存命中。这些未缓存的输入 token 按快速模式费率计费,这就是为什么在会话开始时开启比在深入长会话后开启成本更低。从非 Opus 模型启用快速模式也会切换你的模型,这本身就会启动新的缓存。
成本每会话只应用一次。在第一个快速模式轮次之后,Claude Code 会持续发送该头,只变化请求的速度设置,而速度设置不是缓存键的一部分。关闭快速模式、自动回退到标准速度后的速率限制,以及稍后重新开启都保持缓存。/clear 和 /compact 会重置这一点,因为它们反正会在这些点重建缓存。
跨切换保持该头需要 Claude Code v2.1.86 或更高版本。在早期版本中,每次快速模式切换和速率限制回退都会使缓存失效。
连接或断开 MCP 服务器
工具定义位于系统提示层,因此当请求中的工具定义集合在轮次之间变化时,缓存会失效。切换advisor 工具是例外:它的定义位于缓存断点之后,因此启用或禁用 /advisor 保持缓存的前缀完整。MCP 服务器的变化是否这样做取决于其工具是被工具搜索延迟加载还是加载到前缀中:
- 延迟工具,支持模型上的默认设置:服务器连接、断开或其工具列表变化只追加新内容,不会干扰已缓存的内容。
- 加载到前缀中的工具:对它们的任何更改都会使缓存失效。这发生在工具搜索不可用或被禁用时,例如在 Haiku 模型上、在 Google Cloud 的 Agent Platform 上,或使用自定义
ANTHROPIC_BASE_URL网关时。对于标记为alwaysLoad的服务器或工具,以及通过基于阈值的加载保留在前面的定义,也会发生这种情况。
当工具加载到前缀中时,最常见的失效原因是服务器在会话中连接或断开,这可能在你未采取任何操作的情况下发生:stdio 服务器的进程退出、HTTP 会话过期,或服务器在瞬态故障后自动重新连接。已连接的服务器也可以推送动态工具更新来改变其工具列表。
编辑你的 MCP 配置本身不会改变缓存。新配置只在重启后生效,此时服务器连接或断开。
启用或禁用插件
插件捆绑了几种组件类型,更改的成本取决于插件提供的组件。技能、命令、代理、钩子、LSP 服务器、监视器和主题永远不会使缓存失效:它们添加到请求中的任何内容都追加在现有对话之后,因此下一次请求只需为新内容付费,但仍会读取之前所有内容的缓存。
例外是提供 MCP 服务器的插件。启用或禁用其中一个遵循与连接或断开 MCP 服务器相同的规则:当服务器的工具被延迟时缓存保留,当它们加载到前缀中时下一次请求会重新读取整个对话。
插件更改在你运行 /reload-plugins 或开始新会话时生效。成本(无论是追加的公告还是完整重新读取)显示在重新加载后的第一轮,而不是在你运行 /plugin install、/plugin enable 或 /plugin disable 时。从 v2.1.163 开始,当重新加载会触发完整重新读取时,/reload-plugins 会显示警告并且不会应用重新加载。传递 --force 以强制应用。
禁用你在会话早期启用的插件会恢复之前的请求形状。如果该前缀仍在其缓存生命周期内,下一次请求会读取旧的缓存条目而不是重建。
拒绝整个工具
添加裸工具名称如 Bash 或 WebFetch 作为拒绝规则会从 Claude 的上下文中完全移除该工具。内置工具定义加载到系统提示层,因此在会话中中期添加或移除其中一个规则会使缓存失效。无论通过 /permissions 添加还是通过直接编辑设置文件添加,更改都在下一轮生效。
只有匹配工具名称位置的拒绝规则才有这种效果:裸工具名称、等效的 Bash(*) 形式,或工具名称通配符如 "*"。仅匹配 MCP 工具的通配符(如 "mcp__*")以相同方式移除这些工具,但当匹配的工具被延迟时(默认情况)保持缓存完整,因为延迟定义从未在缓存的前缀中。作用域拒绝规则如 Bash(rm *),以及所有允许和询问规则,都不会改变 Claude 看到的工具。Claude Code 在 Claude 尝试调用时检查它们,保持前缀完整。
压缩对话
压缩会用摘要替换你的消息历史。根据设计,这会使对话层失效,因为下一次请求有一个新的、更短的历史,与旧历史不共享前缀。Claude Code 复用系统提示层并从磁盘重新加载项目上下文,只有当 CLAUDE.md 和自会话开始以来未变化时才会缓存命中。
为了生成摘要,Claude Code 会发送一个一次性请求,包含与你的对话相同的系统提示、工具和历史,以及一个作为最终用户消息追加的摘要指令。因为它共享你的前缀,该请求会读取现有缓存而不是重新处理完整历史。压缩的大部分时间用于生成摘要,而不是缓存未命中。随后的轮次只为更短的摘要重建对话缓存,因此压缩后的轮次不是慢的部分。
升级 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 密钥或第三方提供商
在 API 密钥、Amazon Bedrock、Google Cloud 的 Agent Platform、Microsoft Foundry 或 Claude Platform on AWS 上,你按 token 费率付费,因此 TTL 默认保持在更便宜的五分钟。要选择加入一小时 TTL,请设置 ENABLE_PROMPT_CACHING_1H=1。
在 Amazon Bedrock 上,提示缓存支持、最小可缓存前缀长度和一小时 TTL 的可用性都因模型而异。如果缓存 token 数始终为零,请检查 Amazon Bedrock 文档中的支持的模型、区域和限制。
覆盖 TTL
设置 FORCE_PROMPT_CACHING_5M=1 以强制使用五分钟 TTL,无论认证方式如何。这在调试缓存行为、比较两种 TTL 或覆盖托管设置中设置的 ENABLE_PROMPT_CACHING_1H 时很有用。
缓存范围
在 Claude Code 中,缓存实际上限定为一台机器和一个目录。系统提示嵌入了工作目录、平台、shell、操作系统版本和自动记忆路径,因此不同目录中的两个会话构建不同的前缀并错过彼此的缓存。这包括同一仓库的工作树,因为每个工作树有自己的工作目录。
你在同一目录中并行运行的会话构建匹配的前缀并读取彼此的缓存。顺序会话只在启动时的 git 状态快照匹配时共享前缀,因为系统提示也捕获分支和最近的提交。
底层 API 缓存更广泛。缓存在组织之间隔离,在某些提供商上,在组织内的工作空间之间也隔离。在这些边界内,任何两个具有相同模型和前缀的请求读取相同的缓存。对于运行自动化流程集群的 Agent SDK 调用者,请参阅改善跨用户和机器的提示缓存以抑制系统提示的每机器部分,并在机器之间共享缓存。
检查缓存性能
缓存性能显示为 API 在每次响应上报告的两个 token 计数。最实时的监控方式是使用读取 current_usage 对象的状态栏脚本:
| 字段 | 含义 |
|---|---|
cache_creation_input_tokens | 本轮写入缓存的 token,按缓存写入费率计费 |
cache_read_input_tokens | 本轮从缓存提供的 token,按标准输入费率的大约 10% 计费 |
高读取与创建比率意味着缓存工作良好。如果创建在连续轮次中保持高位,说明你的前缀中有某些内容在变化。使缓存失效的操作章节列出了常见原因。
要在组织范围内获得可见性,OpenTelemetry 导出器按用户和会话报告缓存读取和创建 token。请参阅监控使用了解指标和事件属性参考。
子代理与缓存
子代理启动自己的对话,有自己的系统提示和工具集,与父代理分开。它构建自己的缓存,第一次调用时没有缓存命中,并在自己的轮次中预热。子代理使用五分钟 TTL,即使在订阅上也是如此,因为自动一小时 TTL 只适用于主对话。
父代理的缓存不受影响。从父代理的角度看,子代理的调用和结果追加到对话中,保持父代理的前缀完整。
分叉则继承父代理的系统提示、工具和对话历史,因此它的第一次请求读取父代理的缓存。压缩对话中描述的压缩摘要调用使用相同的前缀共享方法。
禁用提示缓存
禁用缓存偶尔在调试特定模型或提供商的缓存行为时有用。要关闭它,将以下任一环境变量设置为 1:
| 变量 | 效果 |
|---|---|
DISABLE_PROMPT_CACHING | 对所有模型禁用 |
DISABLE_PROMPT_CACHING_HAIKU | 仅对 Haiku 禁用 |
DISABLE_PROMPT_CACHING_SONNET | 仅对 Sonnet 禁用 |
DISABLE_PROMPT_CACHING_OPUS | 仅对 Opus 禁用 |
DISABLE_PROMPT_CACHING_FABLE | 仅对 Fable 禁用 |
要在整个组织中设置缓存策略,将其中任何一个或 TTL 变量放在托管设置的 env 块中。对于正常使用,请保持缓存启用。
相关资源
- 构建 Claude Code 的经验教训:提示缓存是一切:计划模式、延迟工具加载和压缩的设计原理
- 探索上下文窗口:什么加载到上下文中以及何时加载
- 减少 token 使用:除缓存外管理上下文大小的策略
- 跟踪和减少成本:Agent SDK 调用者的缓存 token 跟踪和 TTL 配置
- 提示缓存:底层 API 机制、断点和定价