Prompt Caching 真的省钱吗?同一份 12K 上下文算三家缓存账单
用 12,000 Token 固定前缀和 10 次请求,按 OpenAI、Claude 与 Gemini 官方缓存价格回放账单,拆解写入、命中、TTL、失效和盈亏平衡点。

如果一个 Agent 每轮都携带相同的系统提示、工具定义、仓库规则和长文档,重复输入会反复计费。Prompt Caching 的承诺很直接:相同前缀只处理一次,后续请求按缓存读取价结算。
但“缓存输入便宜 90%”不是完整账单。你还要回答:
- 首次写入是否加价?
- 最少多少 Token 才会缓存?
- TTL 是 5 分钟还是 1 小时?
- 改一个字符会不会让整段失效?
- 10 次请求以后,到底省了多少钱?
本文不伪造三组真实账号账单。实验环境没有三家可公开使用的生产密钥,因此采用官方价格 + 固定 Token 场景的可执行账单回放:输入规模和公式完全一致,脚本可以复算;缓存机制与价格截至 2026-07-19 逐项核对官方文档。它回答成本问题,但不冒充真实网络延迟 Benchmark。
先说结论
在本文的 10 次请求场景中:
| 方案 | 无缓存输入费用 | 使用缓存 | 节省 | 节省比例 |
|---|---|---|---|---|
OpenAI gpt-5.6-terra | $0.302000 | $0.066500 | $0.235500 | 77.98% |
| Claude Sonnet 4.6(5 分钟) | $0.362400 | $0.079800 | $0.282600 | 77.98% |
| Gemini 2.5 Flash(不计显式存储) | $0.036240 | $0.007080 | $0.029160 | 80.46% |
这不代表 Gemini“缓存能力更强”,也不代表它在所有任务上更便宜。三家基础模型、输出价格、质量、上下文限制和缓存接口都不同。表格只比较固定 Token 场景下的输入侧账单结构。
真正决定收益的是四件事:
- 可复用前缀有多长;
- 在 TTL 内复用多少次;
- 首次写入倍率;
- 请求是否保持精确或足够稳定的前缀。
实验怎么设计
固定参数:
固定前缀:12,000 input tokens
动态后缀:80 input tokens / request
请求次数:10
输出费用:不计入(各方案视为相同任务,本文只隔离输入缓存)
Gemini 显式缓存存储时间:默认按 0 小时计入主表
12K 前缀可以理解为:
- 系统提示与安全规则;
- 工具 Schema;
- 仓库约定;
- 一份长产品文档;
- 每轮变化的用户问题放在末尾。

我们回放三种请求:
- Cold / Write:第一次发送完整前缀,创建或填充缓存;
- Warm / Read:保持 12K 前缀不变,只替换末尾 80 Token 问题;
- Miss:改动前缀中间内容,验证为什么后续部分不能继续按命中计算。
主表使用一次写入 + 九次读取。失效请求用于解释风险,不计入主表,否则不同供应商的路由和隐式缓存行为会让比较失去可复算性。

三家的缓存不是同一种产品
OpenAI:自动前缀缓存,新模型开始单独计算写入
OpenAI 对符合条件的请求自动启用 Prompt Caching。官方文档要求:
- 默认至少 1,024 Token;
- 只对精确前缀匹配产生缓存命中;
- 静态指令、示例、图片和工具定义放前面;
- 用户变量放末尾;
gpt-4o及更新模型支持缓存;- 使用
cached_tokens观察读取量; - GPT-5.6 及以后还通过
cache_write_tokens报告写入量,并支持显式断点; - GPT-5.6 及以后要获得更可靠的匹配,应设置稳定的
prompt_cache_key;官方建议单个键总流量约不超过 15 RPM,超过时按稳定规则分片。
一个重要的时效变化是:GPT-5.6 家族开始,缓存写入价为未缓存输入的 1.25 倍;读取价通常是输入价的 0.1 倍。旧模型通常没有额外写入费,不能把旧经验直接套到新模型。
本文选用官方价格页中的 gpt-5.6-terra:
未缓存输入:$2.50 / MTok
缓存写入: $3.125 / MTok
缓存读取: $0.25 / MTok
对 GPT-5.6 及以后,prompt_cache_options.ttl 当前使用 30m:它表示前缀至少可复用 30 分钟,不是 30 分钟后必然失效。更早模型的内存缓存通常在闲置 5–10 分钟后清除、最长约 1 小时;部分旧模型可选最长 24 小时扩展保留。因此 TTL 探针必须按模型分别解释,不能把“等待 31 分钟”当成确定性 miss。
Anthropic:明确的缓存断点、5 分钟与 1 小时写入价
Claude 使用 cache_control。当前文档提供两种方式:
- 顶层
cache_control自动选择最后一个可缓存块; - 在内容块上设置显式断点,精确控制前缀。
TTL 有两档:
- 5 分钟写入:基础输入价的 1.25 倍;
- 1 小时写入:基础输入价的 2 倍;
- 命中与刷新:基础输入价的 0.1 倍。
Claude Sonnet 4.6 的官方价格是:
普通输入:$3.00 / MTok
5m 写入: $3.75 / MTok
1h 写入: $6.00 / MTok
缓存读取:$0.30 / MTok
对 Sonnet 4.6,最小可缓存长度是 1,024 Token。低于门槛不会报错,只是不会缓存。需要检查:
{
"usage": {
"cache_creation_input_tokens": 12000,
"cache_read_input_tokens": 0
}
}
后续命中时,写入量应降低,cache_read_input_tokens 增加。并发请求要注意:缓存条目要到首个响应开始后才可用;不能把十个请求同时打出去,再假定后九个全部命中。
Gemini:Interactions API 只有隐式缓存,generateContent 仍可显式管理
Gemini 当前文档必须区分两条 API 路线:
- Interactions API:只支持隐式缓存,Gemini 2.5 及以后默认启用;
- generateContent API:仍支持显式创建缓存对象和 TTL。
Interactions API 的当前最小输入门槛包括:
| 模型 | 最少 Token |
|---|---|
| Gemini 3.5 Flash | 4,096 |
| Gemini 3.1 Pro Preview | 4,096 |
| Gemini 2.5 Flash | 2,048 |
| Gemini 2.5 Pro | 2,048 |
隐式缓存应把稳定内容放在最前,并在短时间内发送相似前缀。命中量通过 usage.total_cached_tokens 观察。旧 generateContent 响应常见字段则是 cachedContentTokenCount,接入网关时不要把两种字段当成同一个原始 Schema。
Gemini 2.5 Flash 的官方价格:
普通输入:$0.30 / MTok
缓存读取:$0.03 / MTok
显式存储:$1.00 / MTok / hour
Google 的价格表把“缓存读取”和“显式缓存存储”分开。若只测试隐式缓存,不应凭空加一小时存储费;若创建显式缓存对象,就必须把存储时长加入总账单。
账单如何复算
设:
- 固定前缀为 $P$;
- 动态后缀为 $S$;
- 请求数为 $N$;
- 普通输入单价为 $U$;
- 写入单价为 $W$;
- 读取单价为 $R$。
不用缓存:
$$ C_{plain} = N(P+S)U $$
一次写入、后续命中:
$$ C_{cache} = PW + (N-1)PR + NSU $$
如果有显式存储费,再加:
$$ C_{storage} = P \times H \times T $$
其中 $H$ 是保留小时数,$T$ 是每 Token 每小时存储单价。
OpenAI 回放
无缓存:10 × 12,080 × $2.50 / 1M = $0.302000
有缓存:
12,000 × $3.125 / 1M
+ 9 × 12,000 × $0.25 / 1M
+ 10 × 80 × $2.50 / 1M
= $0.066500
Claude 5 分钟回放
无缓存:10 × 12,080 × $3.00 / 1M = $0.362400
有缓存:
12,000 × $3.75 / 1M
+ 9 × 12,000 × $0.30 / 1M
+ 10 × 80 × $3.00 / 1M
= $0.079800
Gemini 隐式缓存回放
无缓存:10 × 12,080 × $0.30 / 1M = $0.036240
有缓存:
12,000 × $0.30 / 1M
+ 9 × 12,000 × $0.03 / 1M
+ 10 × 80 × $0.30 / 1M
= $0.007080
这里把第一次前缀按普通输入价计算,没有添加显式缓存存储费。若显式保存 12K Token 一小时,再增加:
12,000 × $1.00 / 1M × 1 hour = $0.012000
加上后 Gemini 此场景为 $0.019080,仍低于无缓存,但节省比例会从 80.46% 降低。

第几次复用才开始赚钱
忽略很短的动态后缀,盈亏平衡条件是:
$$ W + (N-1)R < NU $$
得到:
$$ N > \frac{W-R}{U-R} $$
| 写入策略 | 写入倍率 | 读取倍率 | 第几次起总成本低于全量输入 |
|---|---|---|---|
| OpenAI GPT-5.6 / Claude 5m | 1.25× | 0.1× | 第 2 次 |
| Claude 1h | 2× | 0.1× | 第 3 次 |
| Gemini 隐式(首次按普通输入) | 1× | 0.1× | 第 2 次 |
所以“只调用一次也开缓存”通常没有成本收益;1 小时缓存如果只使用两次,甚至可能更贵。TTL 应由实际重用间隔决定,而不是越长越好。
为什么你以为命中了,账单却没下降
1. 你改了前缀,不是只改末尾
缓存依赖前缀。时间戳、随机 ID、用户姓名或动态权限若放在开头,会让后续静态文档也无法复用。
正确顺序:
稳定系统规则
→ 稳定工具定义
→ 稳定参考文档
→ 用户/会话变量
→ 当前问题
2. 请求低于最小 Token
短 Prompt 加了缓存标记也可能安静地不缓存。必须检查 usage,而不是只看 HTTP 200。
3. 并发预热方式错了
首个请求尚未开始返回时,缓存可能还不可用。并行突发的十个冷请求不能直接等同于“一次写入、九次读取”。
4. 工具、图片或 Schema 发生变化
OpenAI 明确要求图片和工具也保持一致。对 Agent 来说,动态重排工具、每轮重新生成 JSON Schema,都可能破坏前缀。
5. 网关把相同前缀分发到不利于命中的渠道
这也是 MCP 与 A2A 协作架构 之外的另一层工程问题:协议能工作,不代表成本路径正确。多渠道网关若不了解缓存亲和性,普通负载均衡可能降低命中率。
网关必须记录哪些字段
只记 prompt_tokens 不够。至少要归一化:
| 统一指标 | OpenAI | Claude | Gemini |
|---|---|---|---|
| 普通输入 | prompt_tokens 的未缓存部分 | input_tokens | promptTokenCount 等 |
| 缓存读取 | cached_tokens | cache_read_input_tokens | total_cached_tokens 或 cachedContentTokenCount |
| 缓存写入 | cache_write_tokens | cache_creation_input_tokens | 依隐式/显式 API 处理 |
| TTL 档位 | retention / model config | 5m / 1h | 缓存对象 TTL |
| 命中率 | 读取量与请求数 | 读取量与请求数 | 读取量与请求数 |
Nbility 后端已经区分这些语义:
- OpenAI
cached_tokens、cache_write_tokens; - Claude
cache_creation_input_tokens、cache_read_input_tokens; - Claude 5 分钟和 1 小时写入量;
- Gemini
cachedContentTokenCount; - 总体及 OpenAI/Claude 分项缓存命中率、读取量和写入量。
计费时还会把缓存读取、缓存创建和普通输入分开应用倍率,并防止上游重叠字段把普通输入扣成负数。这比把所有输入 Token 乘一个单价更接近真实账单。
可执行账单回放脚本
保存为 cost_replay.py:
from dataclasses import dataclass
PREFIX = 12_000
SUFFIX = 80
REQUESTS = 10
@dataclass(frozen=True)
class Plan:
name: str
uncached: float
write: float
read: float
plans = [
Plan("OpenAI gpt-5.6-terra", 2.50, 3.125, 0.25),
Plan("Claude Sonnet 4.6", 3.00, 3.75, 0.30),
Plan("Gemini 2.5 Flash", 0.30, 0.30, 0.03),
]
for p in plans:
plain = REQUESTS * (PREFIX + SUFFIX) * p.uncached / 1_000_000
cached = (
PREFIX * p.write
+ (REQUESTS - 1) * PREFIX * p.read
+ REQUESTS * SUFFIX * p.uncached
) / 1_000_000
print(p.name, round(plain, 6), round(cached, 6))
文章发布前已实际执行这份公式,得到文中主表。将 PREFIX、SUFFIX、REQUESTS 和官方价格换成自己的 usage 与模型价格,就能重建业务账单。
实际上线时怎么测
不要一次跑完三家然后比较总耗时。正确步骤是每家独立执行:
- 固定模型版本、区域、工具和生成参数;
- 记录请求 JSON 的稳定前缀哈希;
- 发送冷请求,等待响应开始;
- 连续发送 9 个只改变末尾问题的请求;
- 保存原始 usage、HTTP 总耗时和 TTFT;
- 修改前缀中部一处,再发送失效请求;
- 按供应商原生字段重建输入账单;
- 重复多轮并报告中位数和分位数。
本文没有三家生产密钥,因此不报告 TTFT 数字。缓存能降低处理工作量,但网络、排队、模型负载和区域都会影响延迟;用价格表推导 TTFT 会制造假数据。
什么时候不该用缓存
- Prompt 本来就很短;
- 相同前缀在 TTL 内只出现一次;
- 每个用户的前缀都高度个性化;
- 工具列表和权限每轮变化;
- 1 小时显式存储成本高于复用收益;
- 数据敏感性或保留政策不允许使用对应模式。
Prompt Caching 不是“打开后自动省 90%”,而是一个对请求布局、调度亲和、usage 归一化和计费模型都有要求的系统功能。
给生产团队的检查清单
- 静态内容在前,动态内容在后
- 前缀长度超过所用模型门槛
- 首个请求响应开始后再依赖并发命中
- 记录读取、写入和普通输入三类 Token
- 区分 5 分钟、1 小时和隐式缓存
- 监控请求命中率与 Token 命中率
- 计算包含存储费的真实盈亏平衡点
- 模型或工具 Schema 变更后重新预热
- 网关路由避免无意义地破坏缓存亲和性
- 价格页变化时重新执行账单脚本
结论
在 12K 固定前缀、10 次请求的账单回放中,三种方案的输入成本都下降了约 78%–80%。但收益来自“稳定前缀被连续复用”,不是缓存这个名字本身。
最实用的判断方法只有两个:
- 从原始 usage 重建读取、写入、普通输入和存储费用;
- 让实际请求次数、TTL 和前缀失效率进入公式。
如果你需要通过一个入口管理 OpenAI、Claude、Gemini 的模型与账单,可以在 Nbility 中统一配置渠道并查看用量;需要小额测试额度时,可在工单中心说明实验模型与场景。


