提示词缓存:把重复前缀的钱省下来

cache read 与 cache write 是独立的计费桶,各有各的单价。所以省下的是真的,写进去时付的那笔也是真的。

四个桶,而不是一个输入总数

每次计费请求都会拆成四个互不重叠的桶:新增输入、输出、cache read、cache creation。每桶按自己的每百万 token 单价算,再对总额乘该模型的倍率——命中缓存的前缀确实不再按新增输入的价格收钱。

拿 claude-sonnet-5 举例:官方价输入每百万 3 美元、输出 15 美元,cache read 0.30 美元,cache creation 3.75 美元。读缓存是新增输入的十分之一,写缓存反而比直接发这段文本还贵约四分之一。该模型倍率 0.1,四个桶同比例缩放。

最容易被忽略的正是「写」那一笔。前缀必须先花钱写进缓存,之后才谈得上便宜地读回来,所以只用一次的前缀做缓存,比不做更亏——回本点大致落在第二次读取。

在长 system prompt 上打一个缓存断点。连跑两次,第二次的返回里会出现 cache_read_input_tokens。
curl https://token-share.app/v1/messages \
  -H "x-api-key: $TOKEN_SHARE_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 512,
    "system": [
      {
        "type": "text",
        "text": "You are reviewing a codebase. Style guide follows. ...(a long, stable prefix)...",
        "cache_control": {"type": "ephemeral"}
      }
    ],
    "messages": [{"role": "user", "content": "Review the diff I paste next."}]
  }' | python3 -c 'import json,sys; print(json.load(sys.stdin)["usage"])'

断点应该打在哪

缓存复用是按前缀匹配的,所以要缓存的那段必须在最前面,而且两次调用之间要逐字节一致。把时间戳、request id、按用户定制的问候语放在稳定文本之上,下面的内容全都会挪位,于是每次调用都是一次「你已经付过写入费」的 miss。

在 /v1/messages 上,用 cache_control 标在你想覆盖的最后一个 block 上——通常是 system prompt,或者一大段文档 block。这个字段是随请求原样转发的,不会被改写,所以上游认的就是你发的。

组织 prompt 时让稳定的部分真的稳定:系统指令和参考资料放前面,每轮会变的内容放后面。技巧本身就这一条;cache_control 只是标出稳定部分到哪儿结束。

不是每个模型都单独给 cache write 定价

Claude 系列和较新的 GPT-5.6 系列同时声明了 cache read 与 cache creation 两个单价。另有几个——gpt-5.5、gpt-5.4、gpt-5.4-mini、Grok 全系、Gemini 全系——只声明了 cache read,没有 cache creation,这些模型的写入会回退按该模型的完整输入价计费。

这改变的是算式,不是做法。以 gemini-3-flash 为例,官方输入每百万 0.50 美元,cache read 是 0.05 美元,正好十分之一;而写入按 0.50 美元算,和直接把文本发过去一样。相对那些给写入加价的模型,这里的写入反而更便宜,但无论哪种,你买的都是读取那一档折扣。

另外,各家上游报「缓存输入」的口径不一样:有的把缓存 token 算进 input 总数里,有的单列在旁边。网关会先把它们归一成四个互不重叠的桶再计价,所以你被收多少钱不取决于 provider 用了哪种约定。想知道确切数字,就拿你打算用的那个模型跑一次真实请求,读返回里的 usage——只有它反映你自己的 prompt。

常见问题

怎么判断缓存到底命中没有?
看响应里的 usage 对象。命中时 cache read 的计数非零;把缓存写进去的那次则是 cache creation 有值。如果每次调用看到的都是 creation,说明两次的前缀并非逐字节一致——它上面有东西在变。
每次请求都把整个仓库贴进去,缓存救得了吗?
只有当这些内容每次都完全一致、且调用频次足够摊薄写入成本时才有用。缓存降的是「重复前缀」的价格,它不会让大上下文变便宜,对每次都在变的内容也毫无帮助。如果那段仓库文本在一个长会话里始终不变,省下的是真金白银;如果你每轮贴的是新的 diff,那就没有。
OpenAI 形态的路径和 stable 通道上,缓存能用吗?
缓存指令在这几条路径上都会带过去,命中的缓存输入也一律按自己的桶计费,与你走哪条路无关。每个 id 在目录里都有自己的缓存单价,stable-* 也不例外,所以要按你实际要用的那个 id 算成本,别把一个模型的比例套到另一个身上。