Chapter 06

把"重复的 prompt"缓存起来

每次把 50 页文档+同一段 system prompt 重新送给 Claude,你是在反复为同样的 input tokens 付全价。Prompt Caching 让这些"不变的部分"命中缓存——读只要 10% 原价。这是 Anthropic 独家的成本杀手锏。

Caching 解决什么问题

典型 RAG / 多轮对话场景:

没缓存:每次都付全额 input 价。开了缓存:前三项命中后只付 10% 价,第 4 项照常付全价。

价格模型

操作价格
普通 input1x(基准价)
Cache Write(创建缓存)1.25x — 一次性写入费
Cache Read(命中缓存)0.1x — 十分之一
1 小时 TTL Write2x — 想缓存久就加钱

只要同一缓存块被复用 3 次以上,整体成本就低于不缓存——所以命中率至关重要。

怎么打 cache_control

content block 上打标记,告诉 Anthropic "这里之前(包括这里)的内容可以缓存":

const msg = await client.messages.create({
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  system: [
    { type: "text", text: "你是金融数据分析师..." },
    {
      type: "text",
      text: longCompanyKnowledge,     // 10000 tokens
      cache_control: { type: "ephemeral" },   // ← 这里前面都缓存
    },
  ],
  messages: [
    { role: "user", content: "这份财报的关键风险是什么?" },
  ],
});

console.log(msg.usage);
// 第 1 次:{
//   input_tokens: 20,          // 没缓存的部分(user query)
//   cache_creation_input_tokens: 10050,   // 写缓存 @ 1.25x
//   cache_read_input_tokens: 0
// }

// 第 2 次(5 分钟内换个问题):{
//   input_tokens: 22,
//   cache_creation_input_tokens: 0,
//   cache_read_input_tokens: 10050   // 命中 @ 0.1x
// }

四个可缓存位置

system
system prompt 的 text block,最常用
tools
工具定义数组,打在最后一个工具上,前面所有工具全缓存
messages
对话中的某个 block,可用于锁定历史上下文
document / image
大型 PDF / 多张图,打 cache_control 后长上下文可复用

缓存 TTL

两档:

// 1 小时缓存(贵但稳)
cache_control: { type: "ephemeral", ttl: "1h" }

命中条件:精确字节匹配

最关键的规则
缓存命中靠 前缀精确匹配——从消息第一个 byte 开始,到 cache_control 打的点,必须完全相同。差一个空格就 miss。

这意味着:

多层 breakpoints

最多打 4 个 cache_control 断点,用于不同更新频率的内容:

// 层 1:极稳定(公司知识,每周更新)
{ type: "text", text: companyDocs, cache_control: { ttl: "1h" } },

// 层 2:稳定(用户画像,每天更新)
{ type: "text", text: userProfile, cache_control: { type: "ephemeral" } },

// 层 3:近期对话(每轮追加)
{ type: "text", text: recentContext, cache_control: { type: "ephemeral" } },

// 层 4:当前问题(不缓存)
{ type: "text", text: currentQuestion },

层次清晰,每层独立命中——即使某层变了,前面的还能复用。

实战:RAG 场景

async function ragQuery(userQuestion: string, retrievedDocs: string[]) {
  // 把 RAG 检索到的 N 段原文拼接
  const context = retrievedDocs.join("\n\n---\n\n");

  return client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    system: [
      { type: "text", text: "你是知识库助手。基于下面的资料回答,不要编造。" },
      {
        type: "text",
        text: `<documents>\n${context}\n</documents>`,
        cache_control: { type: "ephemeral" },
      },
    ],
    messages: [{ role: "user", content: userQuestion }],
  });
}

同一组检索结果连续问 5 个问题,输入 cost 降到原来的 ~28%(5 次里 1 次 1.25x 写 + 4 次 0.1x 读)。

实战:长会话 Agent

// 对话累积时,周期性打 cache_control 锁定历史
const history: MessageParam[] = [...];

// 每 10 轮在最后一条 assistant 消息上打点
if (history.length % 20 === 0) {
  const last = history[history.length - 1];
  if (Array.isArray(last.content)) {
    last.content[last.content.length - 1].cache_control = { type: "ephemeral" };
  }
}

实战:Tool-heavy Agent

tools: [
  { name: "search", description: "...", input_schema: {...} },
  { name: "fetch_url", description: "...", input_schema: {...} },
  { name: "query_db", description: "...", input_schema: {...} },
  {
    name: "email_send",
    description: "...",
    input_schema: {...},
    cache_control: { type: "ephemeral" },   // 最后一个工具打点,前面所有工具一起缓存
  },
],

10+ 工具的 agent 每次调用都带满工具定义,缓存命中后几乎不花 tool 定义的钱。

监控命中率

每次响应的 usage 都有三件套,积累起来:

function logCacheStats(usage: Anthropic.Usage) {
  const total = usage.input_tokens
             + (usage.cache_creation_input_tokens ?? 0)
             + (usage.cache_read_input_tokens ?? 0);
  const hitRate = (usage.cache_read_input_tokens ?? 0) / total;
  console.log(`hit rate: ${(hitRate * 100).toFixed(1)}%`);
}

生产系统应该把命中率作为 SLO 监控——命中率骤降通常意味着有人改了 system prompt。

MISS 调试清单

打了 cache_control 但 cache_read_input_tokens = 0?按顺序排查:

  1. 缓存已过期 —— 上次写入超过 5 分钟没读(或 1 小时 TTL 版本的 1 小时)
  2. 前缀差异 —— 某个字节不一样了(时间戳/随机值?)
  3. 缓存块太小 —— 最小 1024 tokens(Sonnet)或 2048(Haiku)才能缓存,小于不生效
  4. 模型变了 —— Sonnet 和 Haiku 的缓存不互通
  5. 参数变了 —— temperature / top_p 等只要变了,整条都 miss

最小缓存块

模型最小缓存 tokens
Opus 4.x1024
Sonnet 4.x1024
Haiku 4.x2048

短 prompt(几百 token)缓存不了——其实本来也省不下多少钱。

什么时候不该用

和 OpenAI 的 "Automatic" 缓存对比

AnthropicOpenAI
打点显式 cache_control自动(>1024 tokens 的前缀)
折扣0.1x 读0.5x 读
写入费1.25x(额外 25%)
TTL5 分钟 / 1 小时可选~10 分钟,不可控
控制精细,多断点粗放,黑盒

显式控制是 Anthropic 的优势——想缓存就缓存,折扣也更深。

本章小结