draft · 仅 crs13 预览环境显示,正式站不会发布

03 5 分钟和 1 小时,TTL 要按使用节奏选

Claude prompt caching 默认是 5 分钟 TTL,也可以选择 1 小时 TTL。

这两个选项的差别不只是缓存时间长短,还直接影响写入成本。

按 Anthropic 文档里的计费规则:

也就是说,写入缓存本身并不免费。1 小时 TTL 写入更贵,只有后续确实能多次读回来,才有意义。

配置上,5 分钟 TTL 是默认值。只写 type 时,就是 5 分钟缓存:

{
  "cache_control": {
    "type": "ephemeral"
  }
}

1 小时 TTL 需要额外写 ttl 字段:

{
  "cache_control": {
    "type": "ephemeral",
    "ttl": "1h"
  }
}

这个字段很重要。很多时候,讨论 5 分钟和 1 小时缓存,不能只讨论概念,还要看请求里到底有没有 ttl: "1h"。没有这个字段,走的就是默认 5 分钟路径。

不过 Claude Code CLI 用户还要多看一层:CLI 可能在不同 block 上写入不同 TTL。

Claude Code changelog 里,2.1.108 增加了两个环境变量:

本机 Claude Code 2.1.160 的代码里,cache_control 的生成逻辑也能看到这一点:基础函数会返回 type: "ephemeral",并在调用方传入 ttl 时附加 ttl 字段。另一个内部判断会先看 FORCE_PROMPT_CACHING_5M,再看 ENABLE_PROMPT_CACHING_1H,然后才进入 CLI 自己的 query source / 账号状态 / 内部配置判断。

因此,最新 Claude Code 里的 TTL 不能简单理解成“整个会话统一 5m”或“整个会话统一 1h”。更准确的说法是:Claude Code 会按自己的缓存策略给不同缓存块生成 cache_control,其中一部分可能是默认 5m,一部分可能带 ttl: "1h"

看账单时也要对应看 usage 里的拆分字段:

这两个字段比单纯看 cache_creation_input_tokens 更有用。前者说明写入了多少 5 分钟缓存,后者说明写入了多少 1 小时缓存。

5 分钟 TTL 适合高频连续会话。

比如 Claude Code 连续修 bug、跑测试、读文件、再改代码。用户和 Agent 都在几分钟内连续互动,前面的 system、tools、项目规则、历史上下文会被反复使用。只要缓存持续命中,5 分钟已经足够覆盖大部分连续工作流。

而且 5 分钟缓存命中后会刷新。只要会话没有长时间中断,它不一定会很快失效。

1 小时 TTL 更适合中间会有明显停顿的场景。

比如:

这些场景里,5 分钟可能过期,1 小时 TTL 才能保住前缀复用。

但 1 小时 TTL 不适合无脑打开。

如果一段内容只会用一次,1 小时写入成本就是纯额外成本。

如果前缀本身每轮都在变,1 小时 TTL 也救不了命中率。

如果应用只是短时间内连续调用,5 分钟 TTL 往往更划算。

Claude 还支持混用不同 TTL,但顺序有要求:长 TTL 内容要放在短 TTL 内容前面。

原因也和前缀有关。长时间稳定的内容应该更靠前,例如工具定义、系统规则、项目规范;短时间稳定或变化频率更高的内容放在后面,例如最近对话、临时任务状态、当前用户问题。

一个比较合理的结构是:

[工具定义 / 系统规则 / 项目规范]  →  1h cache
[近期对话 / 本轮任务上下文]        →  5m cache
[当前用户输入]                    →  no cache

这只是一个参考结构,方向很清楚:越稳定、越常复用的内容,越值得放到更长 TTL;越临时、越动态的内容,越应该靠后。

对 Agent 框架来说,TTL 选择其实是在回答一个工程问题:这段上下文接下来会不会被多次用到,以及会在多长时间内被用到。

如果答案是“连续几分钟内反复用”,5 分钟通常够。

如果答案是“中间可能停二三十分钟,但还会回来继续”,1 小时才有价值。

如果答案是“这段内容每轮都变”,先别急着调 TTL,应该先处理上下文结构。

所以,TTL 不能只看时长。真正要看的,是写入成本、复用次数和会话节奏。