先优化“稳定前缀”,再考虑参数。大多数请求先使用默认隐式缓存;当稳定资料后面紧跟动态内容、需要精确控制写入边界时,才在支持的模型上放置显式 prompt_cache_breakpoint。缓存命中不是承诺,必须记录读取、写入、普通输入 Token 和延迟,计算整个任务是否真的更省。
官方资料(2026-10-30 核对):Prompt caching guide · Responses create · Deployment checklist · API pricing
Prompt Caching 到底缓存什么?
模型处理输入时会计算用于后续注意力运算的 key/value 状态。Prompt Caching 保存可复用前缀的这些 KV 张量,让后续请求在前缀匹配时跳过一部分重复预填充计算。它不会把原始提示词当普通文本副本返回给应用,也不会保存并重放上一次答案。
| 机制 | 复用什么 | 解决什么 | 不能替代 |
|---|---|---|---|
| Prompt Caching | 相同输入前缀的 KV 状态 | 降低重复前缀的处理延迟与相应输入成本 | 结果缓存、上下文缩短 |
| Conversation State | 多轮 Items 或远端状态 ID | 决定下一轮从哪里获得历史上下文 | 缓存命中保证 |
| Compaction | 压缩后的上下文状态 | 控制长会话接近上下文窗口的问题 | 高命中缓存 |
| 应用结果缓存 | 你自己的完整业务响应 | 相同业务键可直接返回旧结果 | 需要新生成或个性化的请求 |
多轮状态怎样选见 Conversation State 教程;上下文持续增长则看 Responses Compaction。
命中的核心规则:从开头开始完全匹配
缓存匹配发生在请求前缀。OpenAI 会从可用 breakpoint 中寻找最长匹配前缀,因此“内容都一样但顺序不同”仍可能无法命中。完整渲染上下文还可能包含开发者消息、工具定义、对话历史、图片、文档和支持的音频。
推荐的排列顺序
- 工具与固定 Schema:保持函数名称、描述、参数 Schema 和工具顺序稳定。
- 稳定开发者指令:角色、规则、输出原则和长期参考资料。
- 稳定示例:few-shot 输入输出、政策或文档。
- 会话历史:追加新 turn,不要重写旧消息或把时间戳插进前缀。
- 动态后缀:本次用户问题、当前日期、请求 ID 和实时数据放在最后。
不要为了“看起来更随机”在工具数组、JSON Schema 属性或固定说明中频繁变更空格、顺序、版本号和时间戳。真正需要版本变化时,用明确版本管理并接受新版本首次请求需要重新写入缓存。
先用隐式缓存:大多数连续对话的起点
对支持 prompt_cache_options 的模型,可用 implicit 模式让 OpenAI 在符合条件的消息边界选择缓存点。GPT-5.6 及以后,官方当前说明最小可缓存前缀为 1,024 个可见输入 Token;更早模型的阈值会随模型和请求设置变化。
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "YOUR_SUPPORTED_MODEL",
prompt_cache_options: {
mode: "implicit",
ttl: "30m"
},
input: [
{
role: "developer",
content: [
{
type: "input_text",
text: STABLE_LONG_INSTRUCTIONS_AND_REFERENCE
}
]
},
{
role: "user",
content: "分析本次工单。"
}
]
});
console.log(response.usage?.input_tokens_details);后续请求必须保持前面部分完全一致,并在末尾追加新内容。如果第二次请求把旧 user message 改写为“旧内容 + 新内容”,原来的消息结束位置不再是同一个 breakpoint,可能失去命中;更稳妥的方式是保留旧消息,再新增一条消息。
什么时候需要显式 breakpoint?
GPT-5.6 及以后支持显式缓存。典型场景是:一大段稳定的规则或参考资料后面跟着每次都变化的问题,而默认隐式模式可能把动态内容一起写入。显式模式允许把缓存边界放在稳定内容末尾,让后面的动态后缀按普通输入处理。
const response = await client.responses.create({
model: "YOUR_SUPPORTED_MODEL",
prompt_cache_options: {
mode: "explicit",
ttl: "30m"
},
input: [
{
role: "developer",
content: [
{
type: "input_text",
text: STABLE_LONG_REFERENCE,
prompt_cache_breakpoint: {
mode: "explicit",
ttl: "12h"
}
}
]
},
{
role: "user",
content: [
{
type: "input_text",
text: SESSION_CONTEXT,
prompt_cache_breakpoint: {
mode: "explicit"
}
},
{
type: "input_text",
text: CURRENT_QUESTION
}
]
}
]
});顶层 instructions 不能直接携带显式 breakpoint;需要把可复用指令放进 developer message 的 input_text content block。每个请求当前最多创建四次缓存写入;只放“以后确实会复用”的边界,不要为每段文字都加标记。
30m 与 12h TTL 怎样选择?
对 GPT-5.6 及以后,Responses API 当前支持 30 分钟默认最短寿命和 12 小时最短寿命。30m 写入按普通输入费率的 1.25 倍计费,12h 写入按 2.5 倍;之后的缓存读取费率按模型定价。TTL 表示最短覆盖时间,不是强制删除期限,也不改变平台的最大数据保留政策。
| 选择 | 适合 | 当前写入费率 | 判断方法 |
|---|---|---|---|
| 30m | 几分钟内连续多轮 Agent、客服或代码任务 | 普通输入的 1.25× | 后续短时间至少会复用一次或多次 |
| 12h | 一天内跨会话重复使用的稳定规则或参考资料 | 普通输入的 2.5× | 较长间隔的读取次数足以覆盖更高写入成本 |
| 不写入 | 一次性、短前缀、变化频繁或无法复用的内容 | 普通输入费率 | 写入后很可能没有后续命中 |
Chat Completions 与更早模型的支持项和 TTL 字段不同;不要把 Responses 的 12h 示例直接复制到所有端点。迁移模型时重新核对官方 Prompt Caching 表与当前价格,不把本文费率写死到应用配置。
prompt_cache_key 应该怎么设计?
对于 GPT-5.6 之前的模型,稳定 prompt_cache_key 可帮助共享前缀的请求路由到相同缓存;它影响路由但不固定机器,也不保证命中。对 GPT-5.6 及以后,OpenAI 会自动处理缓存路由,key 不再是提升命中的必需参数,可以用来分开用户、客户或工作区的缓存核算。
- 使用稳定、确定性的内部 ID,例如
support:customer_123:v2。 - 不要放邮箱、手机号、姓名或原始用户输入。
- 同一客户的相关请求保持一致;版本变化时显式换版本。
- 不要让全部高流量用户共享一个 key;较早模型中,过热分组会被分散到更多机器。
- 按用户或客户分离 key,也有助于降低跨用户通过命中结果推测共享前缀的风险。
prompt_cache_key 用于缓存路由或核算,不是登录身份,也不能替代 Project、Organization 与权限隔离。
怎样读取 cached_tokens 和 cache_write_tokens?
单次响应的 usage.input_tokens_details 是判断缓存行为的直接证据。GPT-5.6 及以后还会把 30m 与 12h 写入 Token 分开:
const details = response.usage?.input_tokens_details;
console.log({
totalInput: response.usage?.input_tokens,
cachedRead: details?.cached_tokens ?? 0,
cacheWrite: details?.cache_write_tokens ?? 0,
write30m: details?.cache_write_tokens_details?.ttl_30m_tokens ?? 0,
write12h: details?.cache_write_tokens_details?.ttl_12h_tokens ?? 0
});普通输入 Token 可按“总输入 − 缓存读取 − 缓存写入”计算。成本要分别乘以当前模型的普通输入、缓存读取、30m 写入和 12h 写入价格;不要把 cache_write_tokens 与它的两个 TTL 子项重复相加。完整账单核对见 OpenAI API Usage。
怎样判断缓存是否真的降低总成本?
缓存第一轮可能比普通请求更贵,因为发生了写入。对于 GPT-5.6 及以后、读取费率为普通输入 0.1× 的大多数模型,官方示例中一个 30m 写入加一次完整读取为 1.35× 普通输入成本,而两次都不缓存为 2×;但真实任务还包含未缓存后缀、输出、工具调用、重试和未命中。
- 按相同任务集记录无缓存或旧架构基线。
- 记录每次普通输入、30m/12h 写入、缓存读取和输出 Token。
- 分别计算首次写入、后续读取和没有命中的请求。
- 比较 P50/P95 首 Token 延迟与总时长。
- 同时比较任务成功率、输出质量、重试和工具错误。
- 按客户、模型、任务类型和前缀版本分组,不只看全站平均命中率。
高缓存读取占比不等于任务总成本低:一个不断增长的长会话即使命中很多历史前缀,仍可能处理大量输入。必要时把 Prompt Caching 与 Compaction 分开评测。
为什么总是命不中?
| 现象 | 常见原因 | 处理 |
|---|---|---|
| cached_tokens 一直为 0 | 前缀未达到模型最小长度,或没有可用 breakpoint | 核对模型表和实际 Token;不要用字符数猜 |
| 工具调用页命中忽高忽低 | 工具定义、描述、Schema 或顺序变化 | 固定工具注册顺序和版本,只把动态工具放后面 |
| 相同文档仍未命中 | 前面插入日期、用户 ID、Request ID 或空格变化 | 把动态字段移到稳定前缀之后 |
| 从 implicit 切 explicit 后未复用 | 新请求没有与旧隐式写入端点一致的显式 breakpoint | 保持 implicit,或在两次请求的同一边界放显式标记 |
| 长时间后首次请求较慢 | 缓存过期或路由到没有该缓存的机器 | 把首次未命中纳入容量和延迟设计,不承诺必命中 |
| Compaction 后命中下降 | 压缩改变了上下文前缀 | 比较减少的总输入与命中损失,而不是单看命中率 |
数据、ZDR 与安全边界
Prompt Caching 可能把加密 KV 张量作为 application state 保存在 GPU 本地存储中。更早模型的 in_memory 与 24h 默认行为会受组织数据保留策略影响;GPT-5.6 及以后使用新的 TTL 与写入规则。不要把“KV 不是原始文本”理解成自动满足合规要求,也不要假设延长 TTL 一定兼容 ZDR。
- 在上线前核对当前模型、区域、组织控制和 Your data 表。
- 缓存 key 使用内部不透明 ID,不包含个人数据或 Secret。
- 不要记录完整提示词、API Key 或敏感文件来排查命中。
- 限制日志访问,并为 usage 明细设置合理保留期。
- 需要严格数据策略时,让安全或合规负责人确认可用模式和 TTL。
与 Conversation State、Compaction 怎样组合?
三者可以同时出现,但职责不同:
- Conversation State:决定历史 Items 如何保存和续接。
- Prompt Caching:在历史前缀相同且仍有效时复用预填充计算。
- Compaction:历史过长时改变上下文形状,降低窗口压力。
使用 previous_response_id 或 Conversation 不保证命中缓存;缓存依然依赖模型资格、前缀匹配、breakpoint、寿命和路由。Compaction 可能改变前缀,使压缩后的首个请求命中减少,但总输入下降仍可能更省。两项都应以完整任务成本和质量评测。
上线前检查清单
- 确认页面或任务确实存在重复的长前缀,不是一次性短请求。
- 稳定工具、Schema、开发者指令、示例和参考资料都放在动态内容之前。
- 核对当前模型的最小缓存长度、显式 breakpoint 和 TTL 支持。
- 默认从 implicit 开始;只有明确边界需求才使用 explicit-only。
- 显式 breakpoint 放在支持的 content block,不放在顶层 instructions。
- prompt_cache_key 不含个人数据,并按用户或客户需要分组。
- 记录 cached_tokens、cache_write_tokens、普通输入和输出 Token。
- 按当前模型价格计算写入与读取,不把缓存命中等同于免费。
- 比较 P50/P95、任务成功率、重试和完整任务总成本。
- 模拟缓存过期、首次未命中、模型迁移、工具版本变化和 Compaction 后请求。
- 数据保留、区域和 ZDR 由安全或合规负责人核对。
常见问题
OpenAI Prompt Caching 会直接返回上一次答案吗?
不会。缓存保存的是可复用前缀的 KV 中间状态,模型仍会为本次请求生成新的输出;相同输入也不保证每次得到完全相同的答案。
为什么请求内容相同却没有 cached_tokens?
常见原因包括可复用前缀未达到当前模型的最小长度、前缀中工具或 Schema 顺序变化、动态内容放在前面、缓存已过期、路由到没有该缓存的机器,或隐式与显式 breakpoint 没有对齐。
implicit 和 explicit Prompt Caching 怎么选?
大多数连续对话可先用 implicit,让 OpenAI 在符合条件的消息边界选择缓存点;如果稳定资料后面紧跟频繁变化内容,或需要避免给动态后缀付写入费,可在支持的模型上使用 explicit breakpoint。
prompt_cache_key 能保证命中缓存吗?
不能。对 GPT-5.6 之前的模型,稳定 key 可帮助相关请求路由到相同缓存;对 GPT-5.6 及以后,key 主要可用于不同用户或客户的缓存核算隔离。它不固定机器,也不保证命中。
30m 和 12h TTL 应该怎么选?
在支持 prompt_cache_options 的 Responses 模型上,30m 适合几分钟内频繁复用的会话;12h 适合跨较长间隔复用的稳定资料,但写入费率更高。应比较真实写入、读取次数、命中率和任务总成本,不能只看单次请求。
Prompt Caching 会减少上下文窗口占用吗?
不会。缓存减少的是重复前缀的预填充计算和相应输入费用,完整输入仍受模型上下文窗口限制。需要缩短长会话时,应另外设计 Compaction、截断或业务检查点。
怎样确认 Prompt Caching 真的省钱?
记录 usage.input_tokens_details 中的 cached_tokens、cache_write_tokens 及 TTL 写入明细,再结合当前模型的普通输入、缓存读取和缓存写入价格计算。还要比较 P50/P95 延迟与任务成功率,而不是只追求缓存命中百分比。
GPT Image 的缓存输入定价适用于 Responses image_generation 工具,不等于直接 Images Edit 请求可命中同一缓存;完整选型见 OpenAI Images API 教程。