验证Claude Prompt caching不能只看请求里有没有cache_control。一组完整证据至少包括:请求A写入缓存,请求B在有效期内复用相同前缀,并在usage里出现缓存读取Token。即使B有cache_read_input_tokens,也只能证明某段前缀被复用,不能证明整个Prompt都命中。若没有同时保存模型、渠道、断点位置和请求条件,单独一张usage截图无法复现结论。

动态边界:本文按 2026-08-11 查阅的 Anthropic Prompt caching 和 Messages 文档撰写。模型、渠道、最低长度、TTL 和价格都可能变化,发布或上线前要按当日文档重新核对。

三个usage字段分别说明什么

Anthropic Messages API当前使用以下字段记录输入Token:

字段 代表什么 排查时怎么看
cache_creation_input_tokens 本次写入缓存的输入Token 首次写入或创建新前缀时可能大于0
cache_read_input_tokens 本次从现有缓存读取的输入Token 后续请求是否复用前缀的直接证据
input_tokens 最后一个缓存断点之后的输入Token 不能单独当作本次全部输入

总输入量可按当前文档核对:

total_input_tokens = cache_read_input_tokens
                   + cache_creation_input_tokens
                   + input_tokens

典型基线是:A出现creation,B出现read。B也可能在读取旧前缀的同时写入新增前缀,因此不能看到creation就断言“没有命中”。如果creation和read都为0,先检查长度门槛、断点位置以及目标API是否支持缓存。

缓存比较的是哪一段

Prompt caching覆盖断点之前的完整前缀,顺序是tools → system → messages。显式断点所在块也包含在前缀内。

真正需要稳定的是这些语义结构和内容:

  • 工具定义、工具数组顺序与schema;
  • system各内容块及其顺序;
  • 断点之前的消息、角色和内容块顺序;
  • 图片、文档、thinking等被放入前缀的内容。

时间戳、随机ID、本轮检索结果或用户问题若放在断点之前,会形成新前缀。客户端重新排列数组、改写内容块或插入消息,也会影响匹配。

不要把“原始JSON文本必须字节级一致”写成官方规则。公开文档描述的是完整Prompt前缀,未公布服务端缓存键如何处理JSON对象键顺序。本地可以比较解析后的请求结构,但最终是否命中仍以API返回的usage为准。

自动缓存与显式断点怎么选

自动缓存:适合持续追加的对话

在请求顶层设置cache_control后,系统会把自动断点放到最后一个可缓存块,并随着对话增长向后移动。它适合历史消息主要在尾部追加、早期内容不被重写的多轮对话。

自动缓存也占用一个断点槽位。若最后一个块已经有相同TTL的显式断点,自动缓存不重复创建;TTL不同,或已有4个显式断点而没有剩余槽位时,当前API会返回400。

渠道边界要单独看。Anthropic 当前页面列出的例外是 legacy Amazon Bedrock(Opus 4.6 及更早集成)不支持顶层自动缓存;该集成上应改用显式断点。Bedrock 其他模型或集成以及其他云渠道、兼容网关,都要以各自当前请求格式为准,不要从这一例外外推。

显式断点:适合稳定资料加动态问题

cache_control放在最后一个稳定内容块上,动态查询留在断点之后:

{
  "model": "<按当前文档选择的模型>",
  "max_tokens": 256,
  "system": [
    {
      "type": "text",
      "text": "<稳定且达到当前模型门槛的资料>",
      "cache_control": { "type": "ephemeral" }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "<每次变化的问题>"
    }
  ]
}

示例不提供具体Token门槛,因为支持模型与最低长度会变化。请求低于门槛时,API可能正常响应但不创建缓存;上线前应查目标模型与渠道的当日说明。

一套可复现的A/B/C测试

步骤1:固定环境

记录模型ID、API或渠道、客户端版本、TTL和断点方式。固定tools、system、thinking配置与输出参数,关闭会在稳定前缀中注入时间或随机值的中间件。

步骤2:发送A,建立写入

用不含生产数据的测试样本发送请求A,保存测试编号、时间、模型、断点位置及完整usage。缓存条目在首个响应开始后才能被其他请求读取,所以不要让A与B同时起跑。

步骤3:发送B,验证读取

在目标渠道当前记载的 TTL 内发送B(文档默认通常为5分钟,但上线前仍要核对)。保持断点之前的前缀不变,只允许修改断点之后的动态查询。查看B的cache_read_input_tokens,同时记录creation和input。

步骤4:发送C,制造单变量差异

选择一种改动:移动断点、修改一处system内容、调整tools数组,或把时间戳移入稳定区。一次只改一项,再比较usage变化。A、B、C必须使用同一模型、同一渠道、同一客户端版本和同一TTL;tools、system、thinking、输出配置与断点前内容均保持不变。

步骤5:按证据强度下结论

观察结果 可以支持 不能直接推出
A写入,B读取 B复用了已写入的某段前缀 线上所有请求都会命中
B同时读取和写入 读取了旧前缀,并可能缓存新增部分 B完全没有变化
A、B都只有写入 两次未复用同一条目或原条目不可用 一定是某个字段导致
creation和read都为0 可能低于门槛、配置未生效或渠道不支持 平台缓存服务故障
C的读取量下降 单变量改动影响可复用范围 它是生产命中率低的唯一原因

20-block回溯如何影响长对话

当前文档说明,每个断点最多向前检查20个块,并把当前断点算作第一个位置。写入只发生在设置断点的位置;回溯只能寻找以前已经写入的条目,不会替你在任意早期位置补写缓存。

如果对话一次新增很多内容块,当前断点可能在20个位置内找不到早先条目。可以把断点放在稳定前缀末尾,或者事先设置额外断点。当前最多可用4个断点,不能等到回溯窗口已经越过旧条目后再指望新断点找回它。

如何安全比较两次请求

不要直接把生产Prompt写进排查日志,也不要简单哈希密钥、姓名等低熵敏感值。更安全的做法是使用无客户数据的固定测试夹具,在本地比较解析后的结构:

  1. 对比模型、TTL和断点位置;
  2. 对比tools数量、名称顺序和schema版本;
  3. 对比system块数量、类型和允许留存的测试文本;
  4. 对比断点前的消息角色与内容块顺序;
  5. 最终回到usage确认服务端是否读取缓存。

本地结构摘要只能帮助判断两次测试输入是否按预期构造,不能证明服务端一定命中。TTL、长度门槛、回溯窗口和渠道实现仍可能改变结果。

TTL和并发的两个坑

默认ephemeral缓存有效期为5分钟,命中会刷新有效期。当前还支持1小时TTL,但写入价格不同。混用TTL时,不要把“1小时条目必须先于5分钟条目”当成通用规则;应按目标模型和渠道的当前 API 规则测试两种顺序,记录状态码、错误体和usage。是否采用1小时TTL应根据真实调用间隔、当前文档和发布当天价格计算,不应只追求更高命中率。

并发测试也要控制时序。缓存写入在首个响应开始后才可供读取;多个相同前缀请求同时发出时,后续请求未必已经看到第一条缓存。应让A开始返回,再发送B。

建议记录的测试结果

可以把每次结果保存为一行JSONL,只留下无敏感信息的测试元数据,并按需要记录请求ID、错误类型摘要、价格文档版本和失败重试次数:

{
  "case": "baseline-b",
  "time": "<带时区时间>",
  "model": "<模型ID>",
  "cache_mode": "explicit",
  "breakpoint_label": "stable-system-end",
  "cache_creation_input_tokens": 0,
  "cache_read_input_tokens": 0,
  "input_tokens": 0,
  "output_tokens": 0,
  "request_id": "<服务返回的请求ID>",
  "error_type": null,
  "retry_count": 0,
  "pricing_doc_date": "<价格文档查阅日期>"
}

这些数字只是字段占位,不是测试结果。测试文件不要包含API Key、客户Prompt、内部工具定义、完整请求体或真实调用标识。

验收清单

  • 已记录模型、API或渠道、TTL和测试时间
  • 已按当前文档核对缓存方式与长度门槛
  • 已标注目标渠道、模型和文档查阅日期
  • 已明确使用自动缓存还是显式断点
  • 断点前的tools、system和messages可复现
  • 请求A开始响应后才发送请求B
  • 同时保存creation、read和input三个字段
  • 单变量测试没有同时改动多个前缀部分
  • 本地结构对比只使用无生产数据的测试夹具
  • 结论只覆盖本次模型、渠道和请求结构

常见问题

第二次请求有read,是否代表整个Prompt都命中?

不是。read只表示其中一段输入来自缓存。结合断点位置、creation和input,才能判断本次读取及新增范围。

自动缓存和显式断点可以同时使用吗?

可以,但自动断点也占用4个可用槽位之一。还要处理最后一个显式断点与自动缓存的TTL关系;不匹配可能返回400。

本地结构摘要相同,为什么read仍然为0?

摘要只能说明你选择记录的结构相同。目标模型可能未达到最低长度,缓存可能过期,回溯窗口可能未找到旧条目,渠道也可能有不同支持边界。以usage和目标平台文档为准。

缓存命中后,回答内容会完全相同吗?

不会因此保证一致。缓存复用的是输入前缀处理结果,不是固定最终生成;采样设置和生成过程仍会影响输出。

参考资料

  • Anthropic Prompt caching(查阅于 2026-08-11):https://platform.claude.com/docs/en/build-with-claude/prompt-caching
  • Anthropic Messages API(查阅于 2026-08-11):https://platform.claude.com/docs/en/api/messages
  • Anthropic release notes(查阅于 2026-08-11):https://platform.claude.com/docs/en/release-notes/overview
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐