Skip to content
Back/Harness Engineering

Prompt Caching 作为一等约束

View in Graph
Updated 2026-05-02
3 min read
569 words

Prompt Caching 作为一等约束

来源:grapeot,2026-04-04

核心判断

Prompt caching 在成熟 harness 中是 viability constraint(可行性条件),不是成本优化。

它同时决定:

  • 系统的成本基线(cache hit vs miss 有 10 倍成本差距)
  • 交互延迟(128K token prompt,cache hit 500ms vs miss 13秒)
  • 哪些系统架构能够存在(sub-agent 并行、speculation 模式)

为什么 Cache Discipline 反向塑造 Harness Design

缓存匹配基于严格的前缀比对,精确到 token 级别。哪怕改了一个空格,从改动位置往后的所有内容都无法命中。

这个约束渗透到多个子系统:

  • Compaction 顺序:从尾部删而非从头部删(OpenClaw PR #58036)
  • Tool definitions 排列:必须确定性排序,动态加载的抖动会导致 cache break
  • 图片裁剪时机:延迟裁剪优于激进裁剪
  • Sub-agent 参数传递:必须共享与父进程一致的 cache key

实践原则(来自 Manus 团队)

  1. Keep prefix stable
  2. Make context append-only
  3. Mask tools don't remove them(通过 logit masking 控制工具可用性,而非列表增删)

Sub-agent 的隐性成本

每个 sub-agent 启动时建立独立的 API 会话,主 agent 精心维护的缓存对 sub-agent 完全无效。短生命周期的 sub-agent 意味着一次缓存冷启动。

Auto-Caching API 机制

Claude Messages API 支持两种缓存模式:

Block-Level Caching(显式断点)

在任意消息块上放置 cache_control: {type: "ephemeral"},告诉 Claude 缓存该断点之前的所有内容块。缓存命中通过向后搜索最多 20 个块实现,内容必须完全匹配(一个字符差异即 miss)。

{
  "role": "user",
  "content": "C",
  "cache_control": {"type": "ephemeral"}
}

Request-Level Auto-Caching(推荐)

在请求顶层放置单个 cache_control 参数,自动将断点移动到最新可缓存块。随着对话增长,断点自动前移,无需手动管理:

{
  "cache_control": {"type": "ephemeral"},
  "messages": [
    {"role": "user", "content": "A"},
    {"role": "assistant", "content": "B"},
    {"role": "user", "content": "C"}
  ]
}

Cache-Friendly Prompt 设计

来自 Claude Code 团队(@trq212)的实践建议:

  • 避免编辑历史消息:修改历史会打破从该点往后的所有缓存
  • 追加优先于替换:新内容放在末尾,而非修改已有块
  • 保持系统提示词和工具定义稳定:这些是缓存前缀的核心部分
  • 结构化分隔:使用明确的角色标签和格式,让模型更容易识别重复模式

Claude Code 团队的规模化实践 (2026-04-30)

来源:Claude Blog — Prompt Caching is Everything

Claude Code 团队(Thariq Shihipar)公开了他们围绕 prompt caching 构建整个 harness 的经验。核心原则:cache hit rate 是 SEV 级别指标 —— 他们对此运行告警,过低时直接宣布严重事故。

四层缓存结构

Claude Code 的 system prompt 按稳定性分层排列:

  1. Static system prompt & Tools — 全局缓存(所有会话共享)
  2. CLAUDE.md — 项目级缓存(同一项目内所有会话共享)
  3. Session context — 会话级缓存
  4. Conversation messages — 动态增长,不缓存

这种排序最大化跨会话的缓存共享。但极其脆弱 —— 团队曾多次打破该顺序,原因包括:

  • 在静态 system prompt 中加入详细时间戳
  • 非确定性打乱 tool definition 顺序
  • 更新 tool 参数(如 Agent tool 可调用的子 agent 列表)

用 messages 传递更新,不要改 prompt

当 prompt 中的信息过时(如时间变化、用户修改文件),直觉是更新 system prompt,但这会导致 cache miss。

Claude Code 的做法:在下一轮的用户消息或 tool result 中加入 <system-reminder> 标签传递更新信息。这样既让模型获得新信息,又保持了缓存前缀的稳定性。

不要中途换模型

Prompt cache 是模型级别的 —— 不同模型不共享缓存。一个反直觉的例子:对话已到 100k tokens,想切换到 Haiku 回答一个简单问题,结果比继续用 Opus 更贵,因为需要为 Haiku 重建整个缓存。

正确做法:用 subagent 做模型切换。让 Opus 准备一份 "hand-off" 消息给另一个模型,由 subagent 在新模型上继续。Claude Code 的 Explore agents(使用 Haiku)就是这样工作的。

不要中途增删工具

这是最常见的缓存断裂原因。工具定义是缓存前缀的一部分,增删任何一个工具都会使整个对话的缓存失效。

Plan Mode 的缓存友好设计:直觉上,进入 plan mode 时应该只保留只读工具,但这会破坏缓存。Claude Code 的做法是始终保持全部工具在请求中,把 EnterPlanModeExitPlanMode 本身设计成工具。用户切换 Plan Mode 时,agent 收到 system message 说明当前处于 Plan Mode 及相应指令。工具定义从不改变。

附带好处:因为 EnterPlanMode 是一个工具,模型检测到难题时可以自主进入 plan mode,完全不需要缓存断裂。

defer_loading 替代移除工具:Claude Code 可能加载数十个 MCP 工具,全部包含在每个请求中很贵,但中途移除又会破坏缓存。解决方案是发送轻量级 stub(仅工具名 + defer_loading: true),模型通过 tool search 在需要时"发现"它们。完整 schema 只在模型选中后才加载。这样缓存前缀始终保持稳定。

缓存安全的 Compaction(Cache-safe Forking)

上下文窗口满时的 compaction(摘要压缩)极易出错。简单做法是另起一个 API call,用不同的 system prompt(如 "summarize this")且不带工具,但这就是成本陷阱:summarization call 的前缀与主对话不同(system prompt 和工具集都不同),从第一个 token 就分叉,没有任何缓存命中。对话越长、越需要 compaction,这个调用就越贵。

Claude Code 的解决方案:compaction 时使用与父对话完全相同的 system prompt、user context、system context 和 tool definitions。将父对话的消息历史 prepend 进去,然后把 compaction prompt 作为新的 user message append 到末尾。

从 API 视角看,这个请求与父对话的最后一次请求几乎完全相同 —— 相同前缀、相同工具、相同历史 —— 因此缓存前缀被复用。唯一新增的 token 是 compaction prompt 本身。

代价:需要预留 "compaction buffer",确保上下文窗口有足够空间容纳 compact message 和 summary output tokens。

Anthropic 已将这些经验直接 built into API,开发者无需自己实现。

度量先于优化

Claude Code 源码中的 promptCacheBreakDetection.ts 追踪缓存断裂的来源:system prompt 变了?工具列表顺序变了?历史消息被修改?

Manus 团队将 cache hit rate 称为生产 AI agent 最重要的单一指标

无法度量的东西无法改进。 Claude Code 团队进一步将其提升到 SEV 级别 —— cache hit rate 告警不足时直接宣布严重事故。

五条核心原则

  1. Prompt caching 是前缀匹配。 前缀中任何位置的改动都会使之后所有内容失效。围绕这个约束设计整个系统。
  2. 用 messages 替代 system prompt 改动。 进入 plan mode、更新日期等操作应插入 conversation messages,而非修改 system prompt。
  3. 不要在对话中途换工具或换模型。 用工具建模状态转换(如 plan mode),用 defer_loading 替代移除工具。
  4. 像监控 uptime 一样监控 cache hit rate。 几个百分点的 miss rate 会极大影响成本和延迟。
  5. Fork 操作必须共享父前缀。 side computation(compaction、summarization、skill execution)应使用与父对话一致的 cache-safe 参数。

Claude Code 从 day one 就围绕 prompt caching 构建;构建 agent 时建议你也这样做。

2026-04-27 价格信号

来源:AI 简报 2026-04-27

DeepSeek 宣布全系列 API 的 input cache hit 价格降到原来的 1/10。该价格变化强化了本页核心判断:prompt caching 不是附属优化,而是决定 agent 架构是否经济可行的约束。

对长上下文 agent 来说,稳定前缀、append-only context、确定性工具定义和 cache hit 度量会直接影响单位任务成本。缓存命中价格下降后,能够维持高 hit rate 的 harness 会获得更大经济优势。

关联

Sources

Synthesized from 4 sources
  • Prompt Caching 作为 Harness 工程的一等约束Supporting source listed by this page.Whole pagemediumbody
  • Prompt auto-caching with ClaudeSupporting source listed by this page.Whole pagemediumbody
  • AI 简报 2026-04-27Supporting source listed by this page.Whole pagemediumbody
  • Claude Blog — Prompt Caching is EverythingSupporting source listed by this page.Whole pagemediumbody

Evolution

1 event
  1. absorbed

    Derived from source material

    This page is currently synthesized from 4 sources.

    From Prompt Caching 作为 Harness 工程的一等约束, Prompt auto-caching with Claude, AI 简报 2026-04-27, Claude Blog — Prompt Caching is EverythingTo Prompt Caching 作为一等约束
    Sources: raw/to-learn/Prompt Caching 作为 Harness 工程的一等约束.md · raw/to-learn/Prompt auto-caching with Claude.md · raw/briefing/AI Briefing/2026-04-27-full.md · raw/social-triage/2026-05-02 Claude Blog - Prompt Caching is Everything.md

Linked from