🎁 新人 免费注册,送 10 次调用,最高 $1,免绑卡。
Prompt Cache 最低 token 数:文档比实测少算了 1.4~2.4 倍

Prompt Cache 最低 token 数:文档比实测少算了 1.4~2.4 倍

目录
  1. 文档标称值和实际生效值之间的差距
  2. 最小值不是唯一没写进文档的变量
  3. 你能控制的缓存是精确的
  4. 开放权重模型家族通常什么都不写
  5. 最新的模型正在改规则
  6. 该怎么做

有客户反馈,我们网关上的 prompt caching 没有在模型官方文档所承诺的 token 数上生效。我们复现了这个问题,然后换了第二条完全独立的服务链路——业界最大的 AI 网关之一——把每个模型重跑了一遍,同样的差距一个 token 不差地复现了出来。乐观的一方是文档本身,而不是某一个网关:文档公布的最低值只是一个「资格门槛」,并不是真正能命中缓存的长度。对于自动缓存的模型家族,两者相差 1.4 到 2.4 倍。OpenAI 首次命中的实际阈值实测在 1456 个 token 附近,文档写的是 1024;Gemini 2.5 Flash 首次从缓存读取在 5000 个 token 附近,文档写的是 2048;Claude 只在你显式打标记的地方做缓存,它按模型公布的最低值实测误差在几个百分点以内。

TL;DR

  • OpenAI 文档写的缓存最低值是 1024 个 token,但实际阈值约 1456 个 token,两条链路上都是如此。
  • Gemini 2.5 Flash 文档写 2048,实测首次读取在 5000 个 token 附近,高出约 2.4 倍。
  • Claude 的显式 cache_control 实测命中文档最低值,误差在几个百分点以内(Opus 实测 1073,文档 1024)。
  • GLM 5.2 和 DeepSeek V4 没有公布最低值,约 800 个 token 就能读到缓存;MiniMax M3 无论长度多少都只报大约 114 个缓存 token。
  • 自动缓存在首次读取前还需要 2 到 8 次调用来预热。

每一项测量我们都跑了两条服务链路,一条是我们自己的网关,另一条是业界最大的独立 AI 网关之一,只有两条链路结果一致时,我们才把它当作模型自身的行为。加第二条链路是为了归因:一个在毫无关联的厂商栈上也能复现的差异,那就是模型的问题,不是我们的问题。这个交叉验证在 OpenAI、Gemini 和 GLM 上跑得很干净,两条链路都缓存了,实际阈值也一致。但不是每个模型都适用:在第二条网关上,开放权重的模型大多由不实现厂商 prompt cache 的 GPU 主机来服务,网关自己的 endpoint 元数据也按 provider 逐一证实了这一点,而且不固定的路由会在这些主机之间漂移,导致缓存亲和性丢失。凡是第二条链路无法佐证的,下面的数字都来自能直接打到各厂商自家缓存 API 的那条链路。长度用的是每个模型自己的 token 数,根据返回的 usage 校准,不是字符数。每一组都用全新的前缀,记录的是首次产生缓存读取的那次调用序号,而不是单次的命中与否。

文档标称值和实际生效值之间的差距

文档里写的最小值告诉你一个 prompt 什么时候可以被缓存。而实际生效的阈值,是重复发送同一个 prompt 时它真正能命中读取的长度。对于自动缓存的这几个模型系列,这两个数并不一样。

系列缓存类型文档最小值实测首次命中差距
OpenAI GPT-5.5 / 5.4-mini自动1,024≈1,456+40%
Gemini 2.5 Flash自动2,048≈5,0002.4 倍
Gemini 3.5 Flash自动4,096≈5,200+27%
Claude Opus 4.8 / Sonnet 5显式标记1,0241,073一致
Claude Haiku 4.5显式标记4,0964,206一致

OpenAI 的数字在两条路径上都精确到 token:1,356 个 token 的 prompt 从不命中,1,456 个 token 的就命中了。Gemini 的差距最大。一次测到 3,300 个 token 封顶的扫描完全没有命中,看起来像是缓存被关掉了;把扫描范围扩展到 5,000 后,两条路径在同一长度上都干净地命中了。文档里的 2,048 只是缓存可用的下限,而不是它提供命中的下限。

整个研究里的规律是:你显式标记的缓存,规格是准的;自动发生的缓存,规格不准。

最小值不是唯一没写进文档的变量

跨过实际生效的阈值是必要条件,但不充分。自动缓存的这几个系列需要预热:首次命中出现在后面的某次调用,而不是第二次。

  • OpenAI:首次命中在第 2 到第 3 次调用。
  • Gemini:首次命中在第 4 到第 8 次调用。

这一点对成本建模很重要。一个 6,000 个 token 的 prompt 超过了 Gemini 所有的文档阈值和实际生效阈值,但如果某个工作负载只发两次就结束,两次都可能按全价计费,因为缓存还没预热。短流量或突发流量即便长度达标,也会按未缓存费率付费。我们只有在至少 12 次重复调用(每次之间留出沉降时间)之后才判定”不缓存”;更短的扫描在 Gemini 上得出了假阴性,更深的扫描推翻了它。

缓存计数也会对齐到固定的块,这在你核对账单时值得知道:OpenAI 是 128 个 token 一块,DeepSeek 是 64 个 token 一块。一个 5,014 个 token 的 prompt 读到 4,073 个缓存 token,是部分前缀命中按块边界取整的结果,不是 bug。

你能控制的缓存是精确的

Claude 只缓存你用 cache_control 标记的片段,而这种控制配套的规格是准确的。我们测试的每一项 Anthropic 声明都成立:

  • 各模型的最小值,精确到 token。 Opus 4.8 和 Sonnet 5 在 1,073 个 token 时首次命中,文档标称 1,024;Haiku 4.5 在 4,206 时命中,文档标称 4,096。这点小超出是块取整,不是漂移。
  • 读取费率为输入的 0.1 倍。 我们从每个模型自己的冷启动行推导出输入价格,再从一条命中行解出缓存费率。Opus 4.8 和 Haiku 4.5 算出来都是 0.10,与文档标称的倍率一致。
  • 五分钟刷新,每次读取免费。 种下一段前缀,分别在第 2、4、6 分钟重新读取,每次都命中。在每个五分钟窗口内的一次读取会让条目保持存活,不产生额外写入。
  • 级联失效。 用一段稳定的 system 前缀外加定义一个 tool,只改这个 tool 的描述,就会强制重写它下方的整个 system 缓存。改动一个 tool 定义会使 system 缓存和 message 缓存全部失效,与文档描述的层级一致。

这里牵出了一处文档与文档的冲突。某个第三方表格把 Claude Opus 的最小值列为 4,096 个 token;实测在 1,073 时命中,Anthropic 自己给的 1,024 才是正确数值。

开放权重模型家族通常什么都不写

上面提到的那些模型家族至少还公布了一个可以拿来验证对错的数字。开放权重模型和中国实验室的模型大多根本不公布最小值,只能靠实测。我们的各家缓存对比讲了命中之后各家公布的缓存费率如何对应;这里只关心一个问题:多长的输入才会出现第一次读取。

模型家族文档最小值实测首次命中粒度
GLM 5.2 (Z.ai)约 800 起读取,两条路径都是64-token 块
DeepSeek V4走厂商 API 时约 800 起读取64-token 块
MiniMax M3512任意长度都报告固定约 114 缓存非标准

GLM 5.2(Z.ai)不公布最小长度,两条路径上都是约 800 token 开始缓存,粒度为 64-token 块,门槛比上面任何一个有文档的家族都低。DeepSeek V4 同样不公布最小值,也是从约 800 token 起读取、粒度同为 64-token 块,但只在走它自家的缓存 API 时成立。DeepSeek 的文档把缓存描述为 best-effort、不保证命中率,中间商暴露出来的正是这一点:另一家网关通过一组 GPU 主机来提供 DeepSeek 服务,其中只有 DeepSeek 自己的 endpoint 实现了缓存,因此没有固定路由到该 endpoint 的请求根本读不到任何缓存。

MiniMax M3 是那种报告数字本身就会误导人的情况。它文档写着 512-token 最小值,但从 200 到 5000 token 的每一种长度上,它从第一次调用起就报告约 114 个缓存 token 的固定值。这个数字既不随 prompt 长度变化,在不做任何缓存的路径上也照样出现,所以它只是模型自己的记账,而不是真正复用了什么的信号。这和更新的 OpenAI 模型从另一个方向给出的教训一样:usage 里的 token 字段和真实缓存可能对不上,所以当省下的成本真的重要时,要拿 usage.cost 来核对,而不是 token 数量。

最新的模型正在改规则

在你假设旧行为还能继续套用之前,有两处文档层面的变化值得留意。在 GPT-5.6 家族上,OpenAI 的指南写明缓存写入的费用是未缓存输入费率的 1.25 倍,而早先的家族写入是免费的。同一份指南把隐式缓存描述为在最新一条消息上放置一个断点,这和跨多轮对话对稳定的 system 块做前缀缓存是不同的形态。如果你想在这些模型上跨不同的用户轮次复用一个稳定前缀,就用显式断点标记它,别指望隐式路径。写入倍率和最小值要按每个模型逐一确认,因为现在两者都随家族而变,单页文档会把这些差异抹平。

该怎么做

  • 测出你自己的有效阈值。 用你自己的 token 数扫一遍 prompt 长度,记录下第一个能触发 cache read 的长度。别假设文档里写的最小值就是命中开始的地方。
  • 给预热留出预算。 对于自动缓存的 provider,在成本模型里把新前缀上的前 2 到 8 次调用当成未命中来算。
  • provider 提供显式标记时优先用它。 Claude 的 cache_control 给出了一份准确、可验证的规格:已知的最小值、已知的读取费率、已知的 TTL、已知的失效规则。这种可预测性,比一个你根本没法依赖的更低的文档下限更有价值。
  • 换到新模型系列时重新做基准。 在这次研究期间,光是同一家厂商的产品线内部,最小值、写入定价和断点行为就都变过。

关于这些阈值背后的读取费率、TTL 和键控规则,我们的 prompt caching 指南 里有各家 provider 的具体机制。

一句话总结:文档里的最小值是资格门槛,不是命中阈值;对于自动缓存,两者相差 1.4 到 2.4 倍。用你自己的 token、拿你自己的流量,去验证那个真正决定你账单的数字。

← 返回博客