LLM 101 FIELD NOTE

Agent Context Economics 101|05|The Price of a Miss:TTL、路由与模型切换的隐藏成本

缓存内容完全相同也可能 miss:TTL 会过期,模型会切换,路由会变化,worker 会淘汰状态。一次短请求可能因此重算整段长上下文。

测试跑了七分钟,缓存发生了什么

继续同一个 coding agent 任务:“定位失败测试、修改实现、运行完整测试并交付结果”。Agent 已经读过项目规则、工具定义、失败测试和实现文件,也完成了修改。此时一次模型请求开始:Provider 查找并读取可复用前缀,处理新增内容,再按产品规则写入延长后的前缀。模型随后调用 bash,本地完整测试运行了七分钟。测试结束后,Agent 才发出下一次模型请求,请模型解释结果并准备交付。

模型请求、七分钟测试与下一次请求之间的 TTL 时间线

这条时间线最容易出现一个误解:shell 一直在忙,不等于 Prompt Cache 一直活跃。bash、测试进程、编译器和文件系统都在 Agent 的工具执行侧运行;如果这七分钟里没有模型 API 请求,它们不会访问 Provider 的提示词缓存,也不会刷新缓存计时器。只有中间确实发生一次模型请求、该请求命中了相关前缀,而且对应 Provider 的文档语义规定命中会刷新生命周期时,才可能延长它。

因此,下一轮哪怕只追加“完整测试通过”几个字,也可能重新处理此前积累的长前缀。原因不是内容发生了变化,而是那份可复用计算未必还可用。相同内容只满足了 cache hit 的一个条件;TTL、模型、Provider、缓存所在位置、路由和淘汰状态仍要同时成立。

Cache TTL 是不活跃计时器

TTL(time to live)常被口语化成“缓存保存多久”,但只有在产品文档明确如此定义时,才应把它解释为自上次相关活动起算的不活跃计时器。不同缓存产品对何时创建条目、什么操作算命中、命中是否刷新、刷新哪一段、保证的是最短还是最长生命周期,都可能不同。不能看到字段名叫 ttl,就默认它们拥有同一套倒计时规则。

截至 2026-07-26Claude API Prompt Caching说明:默认缓存生命周期是 5 分钟,可选择 1 小时;命中并使用缓存内容会刷新其生命周期。对本例而言,连续七分钟没有任何模型请求,默认 5 分钟条目可能已经过期;1 小时条目则不会仅因为这七分钟空闲而到期。但这仍不是命中保证:请求还要保持精确前缀与模型配置,走到支持缓存的渠道,并找到仍可用的状态。

同一官方文档还区分首次写入、后续读取和刷新。测试工具本身既不是读取,也不是刷新。反过来,如果七分钟里 coding agent 因另一项真正需要推理的工作发出模型请求,并命中同一前缀,它可能按 Claude API 文档重置计时器。这里关键的不是“进程是否活着”,而是“Provider 是否处理了一次符合刷新条件的模型请求”。

因此,架构记录不应只有 cache_ttl=5m。至少还要记录条目对应的请求时间、上一次被报告读取的时间、两次模型请求之间的 idle gap、请求使用的 TTL 配置,以及 Provider 返回的 cache read / write usage。没有这些事实,团队无法分清“七分钟工具运行导致可能过期”和“七分钟内其实有一次命中刷新”。

模型、Provider 与状态位置

Prompt Cache 不是一份脱离模型存在的纯文本备份。可复用状态由特定模型处理前缀而建立;模型家族、具体版本、tokenizer、effort 或其他进入缓存身份的运行配置变化,都可能需要建立新的状态。coding agent 若定位问题时使用模型 A,完整测试后为了交付切到模型 B,即使历史文本完全一致,也不能要求 B 直接读取 A 的模型特定计算。

截至 2026-07-26Claude Code 的缓存说明也把模型切换视为缓存边界,并指出某些 effort、fast mode、compact 或升级变化会改变 cache key 或实际前缀。产品层的“同一会话”不会覆盖这些差异。模型切换可能为了质量、速度、配额或可用性而完全合理,但应把下一轮预期为新模型的 warmup,而不是把冷启动当成随机故障。

Provider 与状态位置同样重要。一次请求从第一方 API 改走 Bedrock,或切换账号、区域、deployment、数据驻留策略、代理网关,缓存隔离范围和物理可达位置都可能改变。即使上下游都支持名为 Prompt Caching 的能力,它们也不共享一份跨 Provider 的计算状态;第三方平台对模型、区域、最小可缓存前缀和 TTL 的支持还可能不同。

所以一次可靠的命中判断至少包含四个身份:模型与运行配置、最终精确前缀、Provider / 账号 / 部署范围,以及能否找到仍驻留的缓存状态。仅比较 prompt 文本 digest,可以证明内容没有变,却不能证明其他三项相同。

路由、淘汰和网关

缓存总要驻留在某个 serving 系统里。概念上,一类系统通过 worker affinity 尽量把相似请求送回 warm worker;另一类系统维护分布式、按内容寻址的 prefix blocks,让多个 worker 能发现或搬运可复用状态。两者都要面对容量、负载均衡、隔离、重启和淘汰。它们是理解问题的概念选择,不是对某家托管 Provider 内部架构的断言。

vLLM Automatic Prefix Caching可以作为实现参考:它按父 block hash、当前 block 的精确 token 与隔离信息标识完整 block,并定义释放和 LRU 淘汰流程。这个例子说明“内容相同但 block 已淘汰”以及“内容相同但隔离范围不同”为何可能 miss;它不证明 OpenAI、Anthropic 或任一云平台采用相同 block 大小、哈希、worker 布局或淘汰算法。

prompt_cache_key、session ID 或其他 affinity hint 可以帮助路由器把共享前缀的请求聚到更可能命中的路径,但它们不能复活已经被淘汰的状态,也不能把不同模型或不同内容修复成相同前缀。截至 2026-07-26OpenAI Prompt Cachingprompt_cache_key 描述为影响缓存路由、改善共享长前缀请求命中率的线索,同时仍要求在断点处匹配精确前缀。

网关还可能因为负载、合规、故障转移、地区可用性或供应商成本在多个后端间路由。是否透传缓存字段、是否保持 deployment affinity、是否支持目标模型的 TTL 和 breakpoint,都是接入前应验证的系统行为。网关与 Provider 的商业激励会影响功能设计,但一次 miss 不是“故意破坏缓存”的证据。没有 usage 或诊断时,托管系统内部的 worker、block residency 与 eviction 通常不可观测;应把根因标为 unknown 或候选解释,而不是编造内幕。

一次 miss 的重算与重写成本

一次 miss 的直接价格可以用下面的增量近似来审查:

miss penalty ≈ reused-prefix tokens × (uncached input rate - cache-read rate)
             + rewritten tokens × cache-write premium

第一项比较的是:本来可以按缓存读取处理的长前缀,现在改按未缓存输入重新处理,多付了多少。第二项只计算重新建立缓存时的写入溢价;这里的 premium 指 Provider 采用此类计价时,cache write rate 超出普通未缓存输入价的增量,而不是完整写入价。若写入价已经作为完整输入价计入第一项,再把完整写入价加一次就会重复计算;若 Provider 没有单独写入溢价,这一项可以是零,或应按其实际 usage 口径改写。

以 Claude API 的文档口径为例,截至 2026-07-26Claude API Pricing给出的系数是:5 分钟 cache write 为基础输入价的 1.25×,1 小时 write 为 2×,cache read 为 0.1×。在上式中,对 5 分钟重写使用的 premium 是 0.25× 而不是再加 1.25×;对 1 小时重写则是 增量。上述倍数只适用于文档覆盖的 Claude API 模型、区域和平台条件,不是通用账单公式。

价格之外,还要单列 TTFT、排队与重试、速率限制占用、故障切换以及质量成本。长前缀冷 prefill 可能让用户更晚看到首 token;模型切换后重新理解项目可能改变判断;一次超时重试又可能制造第二次冷请求。这些运营代价不应硬塞进 token 单价公式,但必须进入完整任务的比较。

miss 有多贵,首先取决于首个未命中点之后的前缀长度;还取决于写入溢价、后续预计命中次数、工具运行与人工等待造成的 idle-gap 分布、模型切换频率和缓存淘汰概率。较贵的长 TTL 若能覆盖真实间隔并带来足够后续读取,可能回本;若任务只剩最后一轮,或马上切模型,重写高价缓存可能没有机会摊薄。这里关注的是 miss 的增量条件,不重复上一篇的完整单轮 token 账。

做 break-even 分析时,应按一次 cache epoch 统计:先付了多少增量写入成本,之后有几轮在有效期和同一模型下真正读取,又有几轮因空闲、切换或淘汰重新变冷。平均命中率会掩盖“长前缀恰好在最贵一轮 miss”的尾部风险,因此还要按前缀长度和任务阶段分组。

五分钟、一小时与三十分钟不能混为一谈

同样叫缓存有效期,三种产品语义也不能排成一条简单的“越长越贵”刻度。

对 Claude API,截至 2026-07-26,默认的 five-minute TTL 与可选的 one-hour TTL 是两种明确的缓存写入选择;命中会按文档刷新生命周期。七分钟纯工具空闲可能越过前者,却没有越过后者。选择 1 小时会提高首次写入系数,是否值得取决于真实请求间隔和后续命中,而不是“长任务一律开最长”。

对 Claude Code,同日的官方说明显示,客户端会按认证与配置选择 TTL:Claude subscription 通常自动请求 1 小时;超过套餐限制并改用按量 usage credits 时,会降为 5 分钟。API key、Amazon Bedrock、Google Cloud Agent Platform、Microsoft Foundry 或 Claude Platform on AWS 默认使用较便宜的 5 分钟;在支持的渠道可用 ENABLE_PROMPT_CACHING_1H=1 选择 1 小时,FORCE_PROMPT_CACHING_5M=1 则强制 5 分钟。第三方平台的模型、区域、前缀门槛与 1 小时支持各不相同,必须以目标渠道为准。

对 OpenAI,截至 2026-07-26官方文档在 GPT‑5.6 及后续模型家族中提供 prompt_cache_options.ttl: "30m":它表达缓存 breakpoint 至少可复用 30m 的最短生命周期,并配合较新的 cache write usage、写入计价和 breakpoint 语义;它不是“30 分钟不活跃后必定删除”的通用倒计时。更早的受支持模型使用 prompt_cache_retention 与不同默认规则,区分 in-memory 和 extended retention;不能把 GPT‑5.6+ 的 30m 套到旧模型,也不能用旧模型的最长保留策略解释新字段。

因此,配置审查必须写完整的四元组:Provider + model family + API/product + retention/TTL option。只在文档或配置里抄一个 5m1h30m,不足以预测下一轮是否命中。

任务开始前应该决定什么

在让 coding agent 开始读取文件之前,先确定下面这些事项,通常比 miss 之后再猜更便宜:

  • **模型与 effort:**定位、修改、测试和交付是否坚持同一模型配置;若必须切换,在哪个阶段切,下一轮是否预期冷启动。
  • **TTL、认证与配置:**实际通过 subscription、usage credits、API key 还是第三方 Provider;最终请求的是哪档 TTL,环境变量与托管策略谁优先。
  • **长工具间隔:**完整测试、构建、审批或人工等待通常多久;七分钟只是本例,应该用真实 idle-gap 分布选择策略。
  • **预热、刷新与 heartbeat 的经济性:**在 Provider 明确规定命中会刷新 TTL 时,主动 pre-warming 或 refresh 可以是合理策略;例如 Claude API Prompt Caching记录了相应刷新语义。break-even 条件是“预计的 cache-read 成本,加上请求与任何输出成本”低于“所避免的 miss / 重写成本,加上按业务价值折算的 TTFT 影响”。决策要同时比较下一次使用的预计时间与概率、可复用前缀长度、TTL、读写费率、延迟 SLO、配额和目标 Provider 规则。盲目 heartbeat 流量仍会浪费成本与 quota,也不具有跨 Provider 的普遍收益;它必须是显式测量的策略,而不是默认经验。
  • **cache key 与路由:**相同前缀如何稳定映射到 prompt_cache_key 或网关 affinity;高并发、租户隔离和 key 分片怎样处理。
  • **网关能力:**目标模型、breakpoint、TTL、cache key 与 usage 字段是否透传;故障转移是否会切换 Provider、区域或 deployment。
  • **可观测字段:**保存 Provider、模型、effort、TTL、请求时间、idle gap、前缀 keyed digest、cache read / write tokens、TTFT、网关 route 与 fallback 原因;敏感 prompt 不写入普通日志。
  • **fallback 与模型切换:**限流、故障或质量升级发生时,哪些缓存必然不能沿用;用户是否能接受一次额外 warmup。
  • **预热预期:**新模型、新工具 epoch、新区域或新缓存 key 的第一轮由谁承担 cache write 与 TTFT;预计有多少后续命中,若没有足够读取,就不要把预热当成免费优化。

这份清单不会消除所有 miss。它的作用是把 miss 分成三类:内容或配置主动建立的新 epoch、生命周期和容量造成的预期冷却,以及路由或平台能力不明造成的待诊断事件。三类分别规划,才不会把正常模型切换当故障,也不会把真实缓存回归归咎于“TTL 大概到了”。


上一篇:Sessions Are Trees:会话、分支与缓存并不是一回事

下一篇:Append, Prune, or Compact:上下文不是越短越便宜

参考资料