教程Codex

OpenAI 提示词缓存怎么用:30 分钟有效期、缓存断点和未命中诊断

按 OpenAI 官方文章和文档整理 GPT-6 系列的新版提示词缓存:缓存读取最低是输入价的 5%,写入是 1.25 倍,有效期至少 30 分钟。讲清哪些改动会让缓存失效、显式断点怎么放、怎么用诊断工具查出未命中的原因。

发布 · 约 11 分钟读完 · 经人工审核()· 本站的内容怎么来的

本文根据公开分享整理,本站尚未实测。操作前请对照文末的原始来源。

本页目录(10 节)
  1. 缓存是怎么回事
  2. 价格:什么时候划算
  3. 有效期
  4. 哪些改动会让缓存失效
  5. 四个做法
  6. 隐式和显式:断点放在哪里
  7. 监控和诊断
  8. 从旧模型迁移时要留意
  9. 和 Claude 的提示词缓存对照
  10. 说明

这篇面向用 OpenAI API 做应用和智能体的开发者。OpenAI 在 9 月 22 日随 GPT-6 系列推出了新版的提示词缓存,同时给了监控面板和诊断工具。先说要点:

  • 缓存默认开启,不用改代码就有。请求之间相同的开头部分会被复用,这部分输入按缓存价计费。
  • 读取便宜,写入略贵。 GPT-5.6 及之后的模型,缓存读取是标准输入价的 0.1 倍,GPT-6.1 Sol 是 0.05 倍;缓存写入是 1.25 倍。
  • 有效期至少 30 分钟,每次写入或复用都会重新计时。
  • 前面任何一处变了,后面的缓存就用不上。 换模型、动工具、改推理强度、在开头放时间戳,都会让缓存失效。
  • 未命中可以查原因了。 新的诊断功能会告诉你是哪一类改动导致的。

关于折扣幅度有一处出入:9 月 22 日的文章写“最高 90%”,现在的官方文档写“最高 95%”。95% 对应的是 9 月 29 日发布的 GPT-6.1 Sol,其他模型是 90%。

缓存是怎么回事

模型处理输入时要算出一批中间状态。缓存保存的是提示词开头不变的那一段(前缀)对应的状态。后面的请求如果开头完全一样,并且找到了匹配的缓存,就不用把这段重新算一遍,只处理新增的部分。

被缓存的是模型看到的完整上下文:OpenAI 提供的指令、开发者消息、工具定义、对话历史(文字、图片、文档和支持的音频)。

三个基本规则:

规则 说明
整段前缀必须一致 断点之前有任何内容或相关设置变了,从变的地方往后都匹配不上
有最小长度 GPT-5.6 及之后的模型是 1,024 个 token(OpenAI 隐藏的系统内容不算在内)
不跨组织 缓存不在不同组织之间共享,也不能跨数据处理区域复用

官方还回答了三个常见问题:缓存不影响模型怎么生成输出,相同的请求不保证得到相同的回答;不能手动清除缓存;缓存的输入 token 仍然计入每分钟 token 数的速率限制。

价格:什么时候划算

GPT-5.6 及之后的模型,输入 token 按三种费率之一计费(写入费不是额外叠加的):

类型 相对标准输入价
未缓存的输入 1 倍
缓存写入 1.25 倍
缓存读取 0.1 倍(GPT-6.1 Sol 是 0.05 倍)

官方给的算例,按 0.1 倍的读取价:

情况 不用缓存 用缓存
同一段前缀用 2 次 2 倍 1.35 倍(写 1 次、读 1 次)
同一段前缀用 10 次 10 倍 2.15 倍(写 1 次、读 9 次)

也就是说,只要一段前缀会被复用哪怕一次,缓存就是划算的。反过来,写进去却没人再读的内容是亏的,多付了 0.25 倍。这就是后面“显式断点”要解决的问题。

GPT-5.5 及更早的模型规则不同:没有单独的缓存写入费,读取价因模型而异,也不支持显式断点。

有效期

GPT-5.6 及之后的模型,缓存在最近一次写入或复用之后至少 30 分钟内可以复用,OpenAI 可能保留得更久。控制它的参数是 prompt_cache_options.ttl,目前唯一支持的值 30m 也是默认值。复用会刷新有效期,不会再收一次写入费。

哪些改动会让缓存失效

官方文档列出了影响前缀的设置:

设置 为什么会影响
model 不同的模型权重和缓存行为不同
tools 工具的名字、描述、schema、顺序变了
parallel_tool_calls 会改变关于一轮里调用多个工具的指令
text.format(结构化输出) 加入了输出格式的指令和 schema
reasoning.effort 会改变模型侧的推理指令
text.verbosity 会改变关于回答详略的指令
context_management(压缩) 用压缩后的内容替换了前面的对话

再加上内容本身的变化:改了、调换了或删了前面的消息,或者指令开头有时间戳、请求 ID 这类每次都不同的东西。

四个做法

1. 稳定的放前面,会变的放后面,只追加不改写

  • 固定的开发者指令和共享的参考资料放最前面。
  • 时间戳、用户相关的内容等放到末尾,或者放进后面的对话消息里。
  • 新消息往后追加,不要改写前面的轮次。摘要、压缩、截断上下文都会改变前缀。

官方文档提醒,多轮应用里,复用不断增长的对话历史省下的 token,可能比只缓存开头的指令更多。所以要保留前面的消息和工具结果。

压缩是个需要算账的地方:压缩后第一个请求的缓存复用会变少,但输入 token 总数也少了。官方的建议是比较压缩前后的总输入成本,命中率下降不等于更贵。

2. 调推理强度时用 configuration_update

直接改请求顶层的 reasoning.effort 会改写隐藏的系统指令,缓存就断了。在 GPT-6 及之后支持的模型上,做法是顶层的值保持不变,往 input 数组里追加一项:

{
  "type": "configuration_update",
  "reasoning": { "effort": "high" }
}

最新的一条配置更新决定后续回复的推理强度。这样难的任务可以调高,常规的后续任务可以调低,前面的缓存都还在。

3. 工具列表保持不变,改“哪些能调”

应用在不同的请求里需要的工具不一样时,不要增删工具定义,而是:

需求 做法
这次请求不用工具 把 tool_choice 设为 "none",不要移除工具定义
只允许其中几个 用 allowed_tools 限制可调用的工具,tools 列表不动
工具太多,一开始不想全带上 用工具搜索并设 defer_loading: true,找到的工具追加在上下文末尾
对话中途要加工具 用开发者角色的 additional_tools 输入项追加

同样的思路也适用于指令:要给新的指令,用一条新的开发者消息追加在靠后的位置来覆盖旧的,不要回头改前面的。

4. 需要快速响应时预热

对 GPT-5.6 及之后的模型,可以在用户提问之前先把已知的上下文准备好,缩短第一个 token 出来的时间。比如交互式应用在启动时预热共享的指令、工具定义或参考资料。

把 prompt_cache_options.prewarm 设为 true,这个请求只准备缓存、不生成输出:

{
  "model": "gpt-6.1-sol",
  "input": [
    {
      "role": "developer",
      "content": "Your app's shared instructions and reference material..."
    }
  ],
  "prompt_cache_options": {
    "prewarm": true
  }
}

之后的正式请求用同样的开头,不带 prewarm。预热时写入缓存的 token 按标准的缓存写入价计费。

隐式和显式:断点放在哪里

“缓存断点”标记一段可以保存和复用的前缀的结尾。GPT-5.6 及之后的模型有两种放法。

隐式(默认):OpenAI 自动把断点放在最新一条符合条件的消息末尾。适合不断往后追加的多轮对话。

显式:你自己选断点。把 prompt_cache_options.mode 设为 explicit,并在要作为断点的内容块上加 prompt_cache_breakpoint。官方的例子:

{
  "model": "gpt-6.1-sol",
  "reasoning": { "effort": "low", "context": "all_turns" },
  "text": { "verbosity": "medium" },
  "prompt_cache_options": { "mode": "explicit" },
  "input": [
    {
      "role": "developer",
      "content": [
        {
          "type": "input_text",
          "text": "Stable instructions and shared reference material...",
          "prompt_cache_breakpoint": { "mode": "explicit" }
        }
      ]
    },
    {
      "role": "developer",
      "content": "Dynamic developer instructions, such as user-specific content and timestamps..."
    },
    {
      "role": "user",
      "content": "The user's current question..."
    }
  ]
}

显式模式的几条规则:

  • 最后一个断点之后的内容按未缓存的输入价计费,不收写入费。所以可以避免把不太会被复用的、变化的内容写进缓存。
  • 只开显式模式却一个断点都不放,这个请求就完全不用缓存。
  • 每个请求最多产生四次缓存写入。可以放多个断点,分别保住变化快慢不同的几段前缀。
  • 顶层的 instructions 不能放断点。要标记可复用的开发者指令,把它放进开发者消息里的 input_text 块。
  • 也可以在隐式模式下加显式断点,这时隐式断点占掉四个写入名额里的一个。

什么时候必须用显式断点

官方文档的“容易踩的坑”里有两个,都是隐式模式下开头相同却没命中:

一、固定指令加每次不同的提问。 每个请求都是“一段固定的开发者消息 + 一条不同的用户消息”。隐式断点在最新消息的末尾,第一个请求写入的是包含用户消息的整段。下一个请求的用户消息变了,匹配不上那段更长的前缀,而固定内容后面又没有单独的断点。办法是在固定内容末尾放一个显式断点。从旧模型迁移到 GPT-5.6 及之后时特别容易遇到,因为隐式缓存的行为变了。

二、往同一条消息里续写。 请求 1 的最后一条用户消息是“内容 A”,请求 2 把这条消息扩成“内容 A + 内容 B”。原来的断点现在落在了消息中间,匹配不上。办法是保留原消息、另外追加一条新消息;做不到的话,把可复用的文字放在单独的内容块里,两个请求都在它后面放显式断点。

监控和诊断

看整体:缓存面板和用量字段

平台的用量页面里有提示词缓存面板,显示输入中有多少来自缓存、命中率随时间的变化,以及已缓存和未缓存 token 的构成。适合用来发现命中率下降,或者评估一次改动的影响。

自己统计的话,看每个响应的这两个字段:

  • usage.input_tokens_details.cached_tokens:从缓存读取的 token 数;
  • usage.input_tokens_details.cache_write_tokens:写入缓存的 token 数。

命中率的算法是缓存 token 总数除以输入 token 总数,可以按用户、工作区或天来汇总。

查单个请求:诊断功能

诊断功能在 Responses API 里提供,支持 GPT-5.6 及之后的模型。它把当前请求和之前的一个响应作比较,说明本该复用的前缀为什么没复用。用法是三步:

  1. 选一个基准响应:同一组织下最近完成的、你认为当前请求应该复用其前缀的响应,比如上一轮对话。
  2. 把 prompt_cache_options.comparison_response_id 设为那个响应的 id。
  3. 读当前响应里的 prompt_cache_diagnostics。

官方的示例:两个请求只差一个工具的名字。

from pathlib import Path

from openai import OpenAI

client = OpenAI()
policy = Path("support-policy.txt").read_text()  # At least 1,024 tokens.

first = client.responses.create(
    model="gpt-6-astra",
    instructions=policy,
    input="Reply with exactly OK.",
    tools=[{"type": "function", "name": "get_time"}],
)

second = client.responses.create(
    model="gpt-6-astra",
    instructions=policy,
    input="Reply with exactly OK.",
    tools=[{"type": "function", "name": "get_date"}],
    prompt_cache_options={"comparison_response_id": first.id},
)

diagnostics = second.prompt_cache_diagnostics
if diagnostics is not None and diagnostics.type == "cache_miss":
    print(diagnostics.reason)
    print(diagnostics.comparison_reusable_tokens)
    print(diagnostics.cache_missed_tokens)

结果类似这样:

{
  "prompt_cache_diagnostics": {
    "type": "cache_miss",
    "reason": "tools_changed",
    "comparison_reusable_tokens": 5629,
    "cache_missed_tokens": 5629
  }
}

设置 comparison_response_id 只是请求诊断,不会加载之前的对话,也不改变缓存的行为。多轮对话里,把每个完成的响应的 id 存下来,下一次请求时传进去即可。

原因对照表

reason 字段的取值和对应的处理,按官方文档整理:

reason 什么变了 怎么办
model_changed 换了模型,可能是路由、A/B 测试或回退造成的 检查有没有意外的切换
tools_changed 工具被增删、调换顺序,或描述、schema 变了 保持工具定义和顺序,用 tool_choice 或 allowed_tools 控制
reasoning_effort_changed 推理强度变了 用 configuration_update
input_changed 前面的输入变了,比如指令里有时间戳或请求 ID,或者消息被改、被删 把变化的内容挪到断点之后,只追加
context_compacted 压缩替换了前面的对话 保持稳定的指令不变;比较总输入成本
text_format_changed 输出格式或 schema 变了 结构没变时保持一致
verbosity_changed 回答详略的设置变了 保持一致
service_tier_changed 处理请求的服务档位变了 保持一致;注意返回的 service_tier 可能和请求的不同
prompt_cache_key_changed 传入的 key 变了 不需要按客户分开统计缓存时,不传这个参数

用的时候注意几点:

  • 诊断只报告第一个识别出的原因。修掉之后要再比较一次,看还有没有别的。
  • 诊断记录过一段时间就过期,过期后会返回 comparison_response_not_found。
  • cache_hit 的意思是这次比较没发现未命中,新增的输入仍然要处理。实际复用了多少,看 cached_tokens。
  • 诊断本身不额外收费,不单独占速率限制,也不会让请求失败。为了做对比而多发的请求照常计费。
  • 有些变化是有意的,比如换模型或压缩对话,可以选择保留。

改完之后的确认步骤:再发一个有代表性的请求和基准比较,然后在若干个请求上对比 cached_tokens、cache_write_tokens 和总成本。

从旧模型迁移时要留意

行为 GPT-5.6 及之后 更早的模型
隐式断点的位置 最新一条符合条件的消息末尾 按固定的 token 间隔
显式断点 支持 不支持
最小可缓存长度 1,024 个可见输入 token 随请求设置变化
缓存写入费 1.25 倍 不另外收
prompt_cache_key 可选,只用于分开统计 用稳定的 key 来改善路由
有效期 至少 30 分钟 因模型和设置而异

两点提醒:在一个模型上够长的前缀,换一个模型可能就不够了,换模型后要重新确认;旧模型上靠 prompt_cache_key 优化路由的做法,在新模型上不再需要,OpenAI 会自动处理路由。

和 Claude 的提示词缓存对照

两家的缓存都是按前缀匹配,所以经验是相通的:不变的放前面,更新信息时追加消息而不是改提示词,会话中途不要增减工具。Claude Code 团队的做法见本站的 提示词缓存为什么这么重要。

OpenAI 这边多出来的是几个专门的开关:换推理强度有 configuration_update,限制工具有 allowed_tools,未命中有诊断字段可以直接看原因。

说明

  • 本文按官方文章和文档整理,本站没有实际调用这些接口测试。
  • 文中的费率是相对标准输入价的倍数,具体的美元价格见官方价格页;三个 GPT-6 模型的价格也可以看本站的 Codex 该选哪个模型。
  • 9 月 22 日的文章里引用了 GitHub Copilot、Strawberry Browser 等公司的使用效果,那是客户自己的说法,本文没有采用。

来源

通过 API 中转站使用这些模型?到 Veridrop 免费检测中转站给你的是不是它声称的模型,或者看看中转站排行榜前 100 名。

相关文章