更新时间:2026 年 8 月 23 日
提示词缓存(Prompt Caching)是一种让大模型 API 在多次调用之间复用同一段静态前缀、只重算变化部分的机制,可以把该前缀的输入成本降低约 90%,把首 Token 延迟砍掉一半以上。2026 年,Anthropic、OpenAI、Google 三家都已经把缓存作为一等公民写进官方 API,但触发方式、最小 Token 门槛、TTL 与计费差异巨大。这篇文章用可运行代码、成本计算和命中率排查清单,把三家的缓存策略拆到能直接落地生产的粒度。说句实在话,我在给客户搭 RAG 客服系统的时候,靠这一层优化把月度账单直接砍掉 70%,方法很朴素,但坑真的不少。
- Anthropic 需要在请求体上显式加
cache_control 标记,支持 5 分钟和 1 小时两档 TTL,读取仅 0.1× 输入价,写入要付 1.25×(5m)或 2×(1h)溢价。
- OpenAI 是全自动缓存,无需改代码,前缀 ≥1024 Token 即可命中,GPT-5 系列上缓存输入约为标准输入的 10%。
- Google Gemini 提供隐式(免存储费)与显式(
cachedContents 资源)两种缓存,2.5 及以上模型统一约 90% 折扣。
- 把静态内容(工具定义、系统提示、RAG 文档、Few-shot 示例)放在最前,用户动态提问放尾部,这是三家都通吃的黄金结构。
- 只要前缀里出现
datetime.now()、乱序 JSON、变化的空白,缓存就会静默失效。先用返回体里的 cache_read_input_tokens / cached_tokens 字段核验命中率。
- 低频调用(每 5 分钟少于 2 次)请别开缓存,写入溢价会吃掉你所有的本金。
提示词缓存到底是什么?
提示词缓存本质上是一层"前缀记忆"。服务端把上一次请求编码好的 KV Cache 落到自家的高速存储里,下一次如果发来的请求前缀字节完全一致,就直接从缓存里读,不再重算注意力。这套机制在 2024 年被 Anthropic 首先做成公开 API,2025 年初 OpenAI 跟进推出自动缓存,Gemini 也在同年拆出 cachedContents 资源。到了 2026 年,三家都把它作为降本的核心武器,官方数据里输入 Token 的读取价一般只有原价的 10%–25%。
它解决的是一个非常具体的问题:你在同一段又长又不变的上下文之上,反复提出不同的小问题。典型场景有 RAG 里把同一份检索文档喂给多轮追问、Agent 循环里每步都要重发庞大的工具定义、长系统提示词加大量 Few-shot 示例的多客户会话。没有缓存时,一段 100K Token 的上下文每次都要付一次全价输入。有了缓存,第一次付一个略高的"写入"成本,之后每次只付 10% 的"读取"成本。
要注意的是,缓存并不改变模型输出,也不解决幻觉,它只是省钱和降延迟。它更不是上下文工程的替代品。上下文工程决定"塞什么进去",缓存决定"塞进去以后怎么省钱",二者是叠加关系。
三大厂商缓存机制速览对比
在写代码前,先用一张表把三家的差异吃透。下面这些参数是 2026 年 8 月的官方状态,写入价、读取价均以 API 直连计(Bedrock、Vertex 略有出入)。
| 维度 | Anthropic Claude | OpenAI | Google Gemini |
| 触发方式 | 显式,加 cache_control 块 | 全自动,无需 API 改动 | 隐式自动 + 显式 cachedContents |
| 最小前缀 Token | 512 / 1024 / 2048 / 4096(按模型分档) | 1024(按 128 Token 步进扩展) | 1024(Flash)/ 2048(Pro) |
| 可选 TTL | 5 分钟(默认)、1 小时 | 约 5–10 分钟空闲逐出;GPT-5.5 起可 24 小时 | 60 分钟默认,可显式配置 |
| 写入溢价 | 1.25×(5m)/ 2×(1h) | 无(自动,写入按标准价) | 标准价 + 存储费(仅显式) |
| 读取折扣 | 0.1×(约 90% 折扣) | GPT-5 系列 ~0.1×;旧模型 0.5× | 2.5+ ~0.1×,2.0 ~0.25× |
| 最大断点数 | 4 个显式断点 | 不适用(自动) | 不适用(整段作为一个资源) |
| 命中率字段 | usage.cache_read_input_tokens | usage.prompt_tokens_details.cached_tokens | usage_metadata.cached_content_token_count |
可以看出:Anthropic 给了最细粒度的控制权,代价是必须自己想清楚 TTL 和断点位置。OpenAI 用零改动换来了较少的可预测性;Gemini 在两种模式间做了折中,适合长期缓存同一份大文档。哪家最合适取决于流量形态和上下文形态,不是绝对哪家赢。
如何在 Claude API 中启用提示词缓存
Claude 需要你在请求体的 tools、system、messages 三个数组的任意 block 上加一个 cache_control 字段,标记"从这里往前的所有内容作为一段缓存"。渲染顺序是 tools → system → messages,所以往前的东西会一起被吃进同一段缓存。官方参考见 Anthropic Prompt Caching 文档。
基础用法:单个缓存断点
import anthropic
client = anthropic.Anthropic()
# 假设 policy.md 是一份 30KB 的合规手册,会被反复问到
with open("policy.md") as f:
policy_doc = f.read()
def ask(question: str):
return client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
system=[
{
"type": "text",
"text": "你是一位合规审计助手,只依据下面提供的政策原文回答问题。",
},
{
"type": "text",
"text": policy_doc,
# 关键:在最后一块静态内容上加断点
"cache_control": {"type": "ephemeral"},
},
],
messages=[{"role": "user", "content": question}],
)
first = ask("差旅报销的上限是多少?")
print(first.usage) # cache_creation_input_tokens 应该 > 0
second = ask("请把这条规则用一句话总结。")
print(second.usage) # cache_read_input_tokens 应该 > 0,写入应为 0
第一次调用会看到 cache_creation_input_tokens 非零(付 1.25× 溢价),第二次开始就是 cache_read_input_tokens(付 0.1× 折扣)。如果两个字段都不出现,说明前缀没到该模型的最小 Token 门槛,比如 Claude Opus 4.7 需要至少 2048 Token 才启用,短于此值将静默失败。我第一次上生产时就是栽在这里,日志里没有任何报错,但账单里的读取项永远是空的。
高级:多断点与 1 小时 TTL
Anthropic 最多允许 4 个 cache_control 断点,通常用来"分层缓存":工具定义(几乎永远不变)→ 系统提示(很少变)→ RAG 文档(会话内不变)→ 对话历史(每轮长一点)。用不同 TTL 时,规则是 长 TTL 必须出现在短 TTL 之前:
system=[
{"type": "text", "text": TOOLS_SPEC,
"cache_control": {"type": "ephemeral", "ttl": "1h"}}, # 长 TTL 先
{"type": "text", "text": policy_doc,
"cache_control": {"type": "ephemeral"}}, # 默认 5m
],
命中率验证
不要凭感觉判断缓存有没有生效。把每次调用的 usage 打出来:
u = response.usage
total_input = u.input_tokens + (u.cache_read_input_tokens or 0) + (u.cache_creation_input_tokens or 0)
hit_rate = (u.cache_read_input_tokens or 0) / total_input
print(f"命中率: {hit_rate:.1%} 写入: {u.cache_creation_input_tokens} 读取: {u.cache_read_input_tokens}")
OpenAI 的自动缓存怎么用
OpenAI 的哲学正相反:你什么都不用改。只要请求前缀达到 1024 Token,系统就自动为你建缓存,往后按 128 Token 的粒度延伸命中。折扣按模型分档:早期 GPT-4o 是 50%,GPT-5 系列(含 5.1、5.2、5.3-Codex、5.4、5.5)一律降到约 10%。官方细节见 OpenAI Prompt Caching 指南。
结构规范:把静态前缀放到最前面
自动缓存的代价是你必须严格按"静态在前、动态在后"来组装 prompt,否则前缀字节一变,命中率立刻掉零。下面是一个典型的正确姿势:
from openai import OpenAI
client = OpenAI()
STATIC_SYSTEM = """你是电商客服助手...(约 4KB 的角色说明、口径、Few-shot 示例)"""
CATALOG = open("catalog.json").read() # 约 60KB 商品目录
def answer(user_msg: str):
return client.chat.completions.create(
model="gpt-5.5",
messages=[
{"role": "system", "content": STATIC_SYSTEM}, # 静态
{"role": "system", "content": CATALOG}, # 静态
{"role": "user", "content": user_msg}, # 动态,放最后
],
)
r = answer("红色 XL 的连帽衫还有货吗?")
print(r.usage.prompt_tokens_details.cached_tokens) # 首次为 0
r = answer("换成蓝色 M 呢?")
print(r.usage.prompt_tokens_details.cached_tokens) # 应接近静态部分 Token 数
查看 cached_tokens
OpenAI 把命中信息放在 usage.prompt_tokens_details.cached_tokens。观察这个数字在多次调用间的走势,是你排查命中率问题唯一可靠的手段。GPT-5.5 起,如果账号关闭了 ZDR,默认缓存留存被延长到 24 小时,对每日固定跑批的工作流非常友好。
Gemini 隐式缓存和显式缓存有什么区别
Gemini 2.5/3.x 家族提供两条路径。隐式缓存类似 OpenAI,全自动、无存储费,2.5 Flash 门槛 1024 Token、2.5 Pro 门槛 2048 Token。显式缓存需要你先调 cachedContents.create 创建一个资源,之后每次请求引用这个资源 ID。显式模式多一笔按小时计的存储费,但换来了确定性的命中,适合"我知道这份 PDF 会被 500 人问一整天"这类场景。
from google import genai
client = genai.Client()
cache = client.caches.create(
model="gemini-2.5-pro",
config={
"contents": [{"role": "user", "parts": [{"file_data": {"file_uri": pdf_uri}}]}],
"system_instruction": "只根据这份年报回答问题。",
"ttl": "3600s",
},
)
resp = client.models.generate_content(
model="gemini-2.5-pro",
contents="第三季度的自由现金流是多少?",
config={"cached_content": cache.name},
)
print(resp.usage_metadata.cached_content_token_count)
官方对比与费率见 Gemini API Context Caching 文档。选择建议:单次或短会话用隐式,同一份大文档跨用户、跨会话反复读就用显式,把 TTL 设成你实际的活跃窗口。
提示词缓存能节省多少 API 成本
抽象的百分比不容易感知,用一个真实模型算一次。设想一个 RAG 客服系统:每次请求带 100K Token 的检索上下文,每小时被同一个用户会话调用 10 次,用 Claude Sonnet 5 处理。
真实场景计算示例
- 无缓存:100K × 10 次 × $2/百万 Token = $2.00 / 小时
- 5 分钟 TTL:假设每 5 分钟需要重写一次,1 小时约 12 次写入 + 剩余按读取算。写入 12 × 100K × $2.50 = $3.00,读取部分很少,反而更贵。不划算。
- 1 小时 TTL:1 次写入(100K × $4 = $0.40)+ 9 次读取(100K × 9 × $0.20 = $0.18)= $0.58 / 小时(省 71%)
这套算式抽象成一条经验:调用频率 ≥ 3 次/小时的场景,用 1h TTL 一定省;≥ 2 次/5 分钟才值得用 5m TTL。低频调用别开缓存,写入溢价会吃掉本金。同理,OpenAI GPT-5.5 上 500 次/天的固定工作流,24 小时缓存能把日成本压到无缓存的 15% 以下,这也是很多团队把批处理任务全迁 GPT-5.5 的原因。
为什么我的 prompt cache 命中率一直是 0
90% 的"缓存没生效"报障都能归到这九个原因,按优先级排查:
- 前缀太短。低于模型的最小门槛就完全不启用,也不会报错。先看
cache_creation_input_tokens 是否非零。
- 动态字符串混进静态段。请求 ID、当前时间、随机 UUID、用户 IP,任何一次调用变化的东西都不能放在缓存前缀里。
- 工具定义顺序变了。Anthropic 与 OpenAI 都按字节比对,Python
dict 转 JSON 的键顺序若不固定,就会打破缓存。用 json.dumps(obj, sort_keys=True)。
- 流式模式下切了
reasoning_effort 或 thinking 参数。这些也算前缀的一部分。
- TTL 已过期。Anthropic 5 分钟、OpenAI 5–10 分钟,空闲即逐出。低频任务改用 1h 或 Gemini 显式缓存。
- 并发路由到不同后端节点。OpenAI 的自动缓存按节点分区,突发流量下命中率会掉。用
user 字段做粘性可以缓解。
- 断点位置错了。Anthropic 的
cache_control 必须打在静态内容的最后一块,不是第一块。
- 模型换了。不同模型之间缓存不共享,A/B 测试同一段 prompt 会各自冷写。
- 请求体大小超过缓存池上限。Anthropic 单请求最多 20 个 block 参与缓存匹配,超出的块会被跳过。
缓存友好的提示词结构最佳实践
把这套"洋葱式"结构记进肌肉记忆,三家 API 都能吃到最大命中率:
- 工具/函数定义(最外层,一日不变,加 1h 断点)
- 系统提示词(角色、口径、安全规则)
- Few-shot 示例(如果做批处理,放这里)
- 静态检索文档 / 长知识库(会话级不变,加默认 5m 断点)
- 历史对话(可选加断点,滚动缓存)
- 当前用户提问(唯一动态,放最尾,绝不加断点)
另外还有三条硬性纪律:JSON 序列化永远 sort_keys=True;系统提示永远不注入时间,需要时间戳时放在用户消息尾部;工具列表永远按名字排序再序列化。这三条能防住 80% 的静默失效,代价几乎为零。
RAG、多轮对话与 Agent 场景实战
RAG 场景。缓存对 RAG 是"看命"的。如果每个查询检索到的都是不同的文档集,那你每次都在付写入溢价,反而更贵;但如果做的是"同一份文档、多轮追问"(法务合同分析、代码库审计、财报问答),命中率轻松破 80%。所以在向量数据库选型之外,还要提前规划:把检索命中的 chunk_ids 排序后拼接成前缀,同一批 chunk 才能共享缓存。
多轮对话场景。Anthropic 的推荐做法是每轮都在最后一条用户消息上加 cache_control。由于 4 个断点的限制,超过 4 轮就要把最老的断点丢弃、往前滚动。OpenAI 完全自动,你只要保证历史顺序稳定即可。
Agent 场景。Agent 循环里工具定义可能占到上下文的 30%,1h TTL 的缓存能把工具费用直接归零。这也是构建生产级智能体框架时首要的成本杠杆。用 MCP 挂了几十个工具的团队,如果没打开缓存,每步循环都在重烧一遍工具 spec,成本会成倍于实际推理。
常见问题
Claude 的 1 小时缓存和 5 分钟缓存,什么时候值得用 1 小时?
1 小时缓存的写入溢价是 2×,5 分钟只有 1.25×。经验公式:同一段前缀在 1 小时内会被读到 3 次以上,就切 1h,否则默认 5m。低于 2 次/5 分钟的场景根本不该开缓存。
OpenAI 的 cached_tokens 一直是 0,前缀明明超过 1024 了怎么办?
先检查前缀里有没有动态字符串(时间戳、请求 ID、未排序的 JSON)。再确认 messages 顺序在每次调用间完全一致,多加一条系统消息或换个位置都会失效。最后确认没在中间切换过 tools 或 response_format。
提示词缓存最少需要多少 Token 才会生效?
OpenAI 与 Gemini Flash 是 1024 Token,Gemini Pro 与部分 Claude 型号是 2048 Token。Claude Opus 4.7 需要 2048,Claude Opus 4.5/4.6 与 Haiku 4.5 需要 4096,Sonnet 5 是 1024。低于门槛不会报错也不会计费,只是不建缓存。
Gemini 隐式缓存和显式缓存哪个更省钱?
短会话、单用户用隐式更省,没有存储费。多用户复用同一份大文档,或者跨天调用,用显式更省,你只付一次写入 + 存储费,之后不管多少人读都是 10% 折扣。分水岭大约在"1 小时内被 20 次以上读取"。
开启提示词缓存会影响模型输出质量吗?
不会。三家的缓存都是对已编码好的 KV 状态做直接读取,模型的生成过程完全不变。你可以把它想成"重放"编码阶段的中间结果,输出的确定性、准确性、风格与不用缓存时完全一致。