cache_control 工作机制

AUTOMATIC
请求顶层挂 cache_control: {...}
服务器自动打最后一个 block · 最多 1 个
EXPLICIT
✓ Claude Code 用的就是这种
block 上挂 cache_control: {...}
位置自己挑 · 最多 4 个
{
"cache_control": null, ← 顶层为 null = 不是 Automatic
"tools": [ 29 items ],
"system": [
{ ... }, // system[0]
{ ..., cache_control }, ← breakpoint 1 · 静止
{ ..., cache_control }, ← breakpoint 2 · 静止
],
"messages": [ ..., (末尾)
{ ..., cache_control } ← breakpoint 3 · 移动
]
}
全在 block 上 = Explicit  用了 3 个 / 上限 4 个 · 留 1 个空位
第 1、2 个 breakpoint 永远钉在 system 末尾,三轮一动不动 → 静止
第 3 个 breakpoint 每轮跟着最新 user 消息往后跑移动
Claude Code 的 Explicit = 2 静止 + 1 移动。
hash( tools + system[0] + system[1] )
第 1 条
hash( tools + system[0] + system[1] + system[2] )
第 2 条
hash( tools + system[0] + system[1] + system[2] + user "hello" )
第 3 条
每条缓存的 hash 算的是 从开头到这个 breakpoint 所有内容,覆盖范围一条比一条长。
29 个 tools 没标 cache_control 也被缓存 — 它蹭了 system[1] 那条的车一起打包写进去。
原理 2:在 breakpoint 位置查不到,往前一个 block 再查,找的是"之前写过的缓存"
每轮第 3 个 breakpoint 往后挪一两块,lookback 翻几格就能找到上一轮在前一个 user 消息上的写入。
原理 3:lookback 最多往回 20 个 block,找不到就放弃
日常聊天滚雪球能滚得很稳,因为单轮就几个 block。但只要某一轮内部产生的 block 撑爆 20 格窗口,下一轮 cache 就直接掉。