同一套系统提示词、同一份知识库、同一组工具,前几天还能稳定复用缓存,今天 cached_tokens 却突然掉了下来。输入 token 和延迟跟着上升,同样的任务也开始多花钱。此时最该检查的,往往是请求前缀里发生了哪些细小变化。
OpenAI 在 2026 年 9 月 8 日把 Prompt Cache Diagnostics 开放到 Responses API,用来比较当前响应和之前响应的缓存复用情况,并指出未命中的原因。这项更新让原本只能靠猜的缓存问题有了更直接的定位手段。本文也会沿着这条思路,讲清怎样确认异常、查找变化,再验证修正是否有效。

图 1:OpenAI API Changelog 发布 Prompt Cache Diagnostics,来源:https://developers.openai.com/api/docs/changelog#date-2026-09-08-1
为什么一次调用和一个总分都不够
Prompt Cache 判断能否复用,看的是请求开头那段已经渲染好的前缀。两次请求主题相同还不够。系统指令、developer message、工具定义、历史消息、文档和图片,只要在缓存断点之前出现变化,变化位置后面的内容就可能无法继续匹配。工具顺序换了、输出格式变了、模型或推理参数变了,也会影响结果。
所以,一次请求只能说明当时发生了什么;总 token 或总费用只能说明花了多少。要查清原因,至少需要一条缓存复用正常的历史响应和一条复用下降的当前响应,并且两者的任务、模型和请求范围要能对得上。
官方给出的操作并不复杂:选一条近期完成且缓存正常的响应作为基线,让当前请求带上它的 response ID,然后从当前响应中读取诊断结果。comparison_response_id 只用于比较,不会把旧对话重新加载进来,也不会改变这次请求原有的缓存行为。

图 2|Prompt Cache Diagnostics 的功能说明与三步诊断流程,来源:https://developers.openai.com/api/docs/guides/prompt-caching/diagnostics
第一项检查:先看 token 和费用
先从响应记录确认异常是否真实。重点看 input_tokens、cached_tokens、cache_write_tokens、首 token 延迟、总耗时和实际费用。缓存读取下降、缓存写入上升,或者输入量突然增加,才说明复用结构确实发生了变化。不要拿一次偶然请求下结论,最好按同一任务连续记录几次。
下面这份OkenAI平台的 Token 缓存测评报告把缓存写入、缓存读取、标准输入、模型输出、费用和响应时间放在同一张结果里。看这类报告时,重点不是总分或标签,而是这些字段能否把每轮请求的消耗与复用情况对应起来。

图 3|GPT-6 Astra Token 缓存测评报告示例,来源:OkenAI
第二项检查:选一条真正可比的基线
基线响应应来自同一组织、同一模型和同一业务流程,而且此前确实出现过缓存复用。建议一起记录 response ID、模型、组织或处理区域、请求时间、输入 token、缓存 token、延迟和费用。
如果当前请求换过模型、工具或任务内容,就不能直接拿它和旧结果比较。先用新的请求结构建立一条基线,再观察后续变化。否则,缓存问题和业务变更会混在一起,后面所有判断都会失去参照。
第三项检查:把差异归入四个方向
先看前缀内容和顺序。developer message、工具 schema、历史消息、文档或图片在断点之前被插入、改写或重新排序,都会让后面的前缀失配。
再看断点和消息边界。稳定内容后没有合适的缓存端点,或者把旧消息从“内容 A”改成“内容 A 加内容 B”,原来的端点就可能落到消息内部,无法继续复用。
请求配置也要单独核对。模型、工具名称和 schema、工具顺序、并行工具调用、输出格式、reasoning.effort、text.verbosity 等设置都可能改变模型实际看到的前缀。
最后是生命周期和作用域。缓存可能已经过期,请求也可能跨越组织、处理区域,或被路由到没有对应缓存的机器。业务文字没有改,不代表缓存一定还在。
OpenAI 的官方示例把原因展示得很直观:两次请求保持模型、指令和输入不变,只把工具名从 get_time 改成 get_date。第二次诊断结果返回 cache_miss,原因是 tools_changed,同时给出保持工具定义和顺序不变的建议。

图 4|Prompt Cache Diagnostics 官方示例:请求、诊断结果与修复建议,来源:https://developers.openai.com/api/docs/guides/prompt-caching/diagnostics
官方示例的核心调用关系可以简化为:
first = client.responses.create(...)
second = client.responses.create(
...,
prompt_cache_options={"comparison_response_id": first.id},
)
diagnostics = second.prompt_cache_diagnostics
print(diagnostics.type, diagnostics.reason)
print(diagnostics.comparison_reusable_tokens)
print(diagnostics.cache_missed_tokens)
没有这类诊断接口时,也可以用同一思路做结构化 diff:固定任务,保留基线,一次只改一个变量,再重复请求记录结果。
第四项检查:修正后重新看结果
修正通常从请求结构入手。稳定说明、工具 schema 和公共资料放在前面,动态问题放在后面;工具定义和顺序保持稳定;需要复用的固定区段后设置断点;多轮对话追加新消息,不回头改写旧消息。
复测不能只盯着命中率。要同时比较 cached_tokens、cache_write_tokens、总输入 token、首 token 延迟、总耗时、实际费用和任务结果。命中率上升,但为了写入一大段之后不会再用到的内容付出更多成本,不能算真正完成优化;工具调用和最终输出也必须保持正确。
缓存突然失效时,反复重试通常解决不了问题。先用 token 和费用记录确认异常,再选出可比的基线,从前缀、断点、配置、生命周期四个方向逐项定位,修正后用同一任务复测,这套顺序更可靠。即使所用 API 没有 Prompt Cache Diagnostics,也可以沿着相同思路把范围一点点缩小。
想进一步核对缓存写入、读取、费用和延迟,可以继续查看 token 与缓存测评结果。

431

被折叠的 条评论
为什么被折叠?



