Claude Code 的 Prompt Caching:一年省下数千美金的秘密,从原理到实战

你有没有遇到过这种情况:用 Claude Code 写代码,每天烧掉几十美金,账单看得人血压飙升?同样的项目,同事月费几十你月费几百?明明听说有缓存功能,省钱效果却不明显?

问题大概率出在 Prompt Caching 的理解和配置上。最近我花了大量时间深入研究 Claude Code 的缓存机制,结合实战踩坑经验,写下了这篇深度解析。读完你会发现,之前账单里可能真有 80% 是冤枉钱。


一、先看一个场景:为什么你的账单这么高?

假设你用 Claude Code 修一个 bug。你输入了一行指令:「修复 handleLogin 函数的 null check 问题」。Claude Code 实际发送给服务器的内容远比你想象的多:

单次「修一个 bug」请求的 token 分布:
├─ system prompt(系统提示 + 24 个内置工具定义) ≈ 3,200 tokens
├─ CLAUDE.md(项目级指令)            ≈ 800 tokens
├─ 历史消息(5 轮对话累积)            ≈ 8,500 tokens
├─ 当前文件内容                        ≈ 2,000 tokens
└─ 用户新消息                          ≈ 50 tokens
─────────────────────────────────────────────
输入总计:14,550 tokens      输出:≈ 400 tokens
输入/输出 比:36:1

输入是输出的 36 倍。 你写的每一个 token 的指令,背后有三十几个 token 的上下文一起被发送、计费。这意味着你的账单几乎完全由输入 token 决定——而 Prompt Caching 能把这些输入 token 的成本打到一折。

理解了这个场景,你就能明白:Prompt Caching 不是锦上添花,它几乎是 Claude Code 经济高效运行的刚需。

二、原理拆解:前缀匹配,不是「内容去重」

很多教程把 Prompt Caching 描述成「系统检测到重复内容就给折扣」——这个理解是错的,而且这个误解本身会让你不知不觉击穿缓存。

2.1 真实机制:一字不差的前缀匹配

Anthropic 服务端会保存你最近发送的 prompt 前缀。下次请求时,只要前缀(从第一个 token 开始)与上次完全一致,就从缓存读取,跳过重新计算。

请求1: [System] [Tools] [CLAUDE.md] [对话历史 1-5] [新消息]
请求2: [System] [Tools] [CLAUDE.md] [对话历史 1-5] [另一条新消息]
                                     └── 这部分命中缓存 ──┘

2.2 关键约束:一处改动,后面全失效

前缀任何一处变化,后面所有内容的缓存全部失效——即使后面的内容和之前一模一样。

请求1: [System] [Tools] [CLAUDE.md v1] [对话 1-5] [新消息]
        缓存写入──→

请求2: [System] [Tools] [CLAUDE.md v1] [对话 1-5] [另一条新消息]
        命中!前面部分 0.1× 计费 ──→

请求3: [System] [Tools] [CLAUDE.md v2] [对话 1-6] [新消息]
                                ↑ CLAUDE.md 改了一行
        从 CLAUDE.md 开始,后面的对话 1-5(之前已缓存的)全部失效!
        全部按 1.0× 重新计算并写入新缓存

这种设计在工程上非常合理——对于 Transformer 架构的模型,每一层的计算都依赖前面所有 token 的注意力输出。一旦前缀中任何一个 token 变了,整个 KV cache 就必须重建。Anthropic 的缓存本质上就是在服务端保存了这些 KV cache,所以「从变化点开始全部失效」不是设计缺陷,而是底层计算模型的必然结果。

理解了这一点,很多「为什么我的缓存命中率这么低」的困惑就迎刃而解了。

三、Claude Code 的缓存层级与自动注入机制

3.1 自动配置的三层缓存

Claude Code 不需要你手动配置 API 调用来启用缓存——它已经在底层自动为你做了多层缓存标记。具体来说,它通过 cache_control 标记把请求内容分成三个缓存层级:

缓存层 │ 内容                              │ 大小         │ 复用频率
───────┼───────────────────────────────────┼──────────────┼─────────────
 L1    │ 系统提示词 + 24 个内置工具定义      │ ~3,000 token  │ 整个会话
 L2    │ CLAUDE.md(项目级指令)             │ 几百到几千    │ 整个会话
 L3    │ 对话历史(每轮追加)                │ 累积增长      │ 同一会话

三个层级中,L1(系统提示词)是全用户共享的——只要你和同事用同一个版本的 Claude Code,系统提示词完全一致,你们实际上在共享同一份缓存。L2(CLAUDE.md)是项目级的,只在你自己的项目会话内缓存。L3(对话历史)则随着对话推进逐轮累加。

3.2 cache_control 标记的实际位置

查看 Claude Code 实际发出的请求体(精简后),可以看到两个关键的 cache_control 标记:

{
  "model": "claude-opus-4-7",
  "system": [
    {
      "type": "text",
      "text": "You are Claude Code...",
      "cache_control": { "type": "ephemeral" }
    }
  ],
  "tools": [...],
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "<system-reminder>CLAUDE.md content...</system-reminder>",
          "cache_control": { "type": "ephemeral" }
        }
      ]
    },
    { "role": "assistant", "content": "..." },
    { "role": "user", "content": "新消息" }
  ]
}

注意两个关键细节:

细节一:CLAUDE.md 不在 system prompt 里。 它通过 <system-reminder> XML 标签注入到 messages 数组中。这个设计很精妙——让所有用户共享同一份 system prompt 缓存(同版本 Claude Code 的系统提示词完全一致),同时让每个项目的 CLAUDE.md 单独缓存,互不污染。

细节二:"type": "ephemeral" 这表示使用的是 5 分钟 TTL 缓存。Anthropic 也支持 1 小时 TTL,但写入成本更高。Claude Code 默认选择 5 分钟档位,因为对于连续编码工作流,这是性价比最优的选择。

3.3 5 分钟 vs 1 小时缓存档位

档位 写入价格(相对基础输入价) 读取价格 回本条件
5 分钟 1.25× 0.1× 1 次命中即回本
1 小时 0.1× 3 次命中回本

5 分钟档:写入溢价 0.25×,单次缓存命中节省 0.9×,一次命中就回本。适合高频连续工作场景——这正是 Claude Code 的典型使用模式。

1 小时档:写入溢价 1×,需要 3 次命中才能回本。适合间断使用或长任务场景,比如定时触发的自动化流水线。

四、五个最容易踩的坑

知道了原理,接下来看实战中最容易让缓存失效的场景。这些都是我和社区大量开发者用真金白银踩出来的坑。

坑 1:CLAUDE.md 中途修改

这是最常见、最隐蔽的缓存杀手。如果在一次会话中途修改 CLAUDE.md(比如调整了编码规范),从 CLAUDE.md 位置开始的所有缓存全部失效,即使之前对话历史已经缓存了十几轮。

你之前几十条消息的对话历史,本可以从缓存读取享受一折优惠,现在全部按全价重新计费。

避坑:CLAUDE.md 的修改只在新会话开始时生效。一次会话中保持其稳定,让修改在下一次会话中自然应用。

坑 2:动态时间戳

很多项目会在 CLAUDE.md 或系统提示词中插入当前时间、日期或版本号:

<!-- CLAUDE.md -->
# Project Rules (Updated: 2026-05-24 14:30:22)

每次请求时间戳都不同 → 前缀永远不匹配 → 缓存形同虚设,命中率直接归零

避坑:去掉所有动态内容,改用相对时间描述(如「参考项目根目录的 CHANGELOG.md 获取最新版本信息」),或者让动态内容出现在缓存断点之后。

坑 3:模型中途切换

缓存在服务端是与具体模型绑定的——Opus 4.7 的缓存和 Sonnet 4.6 的缓存不通用。如果你在会话中通过 /model 切换模型,前一模型的缓存全部不可用。

避坑:确定模型后一个会话内不再切换。如果需要不同模型处理不同任务,分两个会话操作。

坑 4:中断时间过长

5 分钟 TTL 到期后,缓存自动失效。如果你暂停对话超过 5 分钟(比如去开了个会),下次请求整个前缀需要重新计算写入。

避坑:长会话记得中间穿插请求保持缓存活跃;如果确实需要长时间离开,重建会话从头开始更划算。也可以使用 /compact 压缩历史,降低重建成本。

坑 5:大小写、空格和格式不一致

前文讲过,缓存基于精确前缀匹配。即使是一个额外的空格、一次大小写变化,都会触发缓存失效。

Request 1: "You are a helpful assistant."  → 缓存创建
Request 2: "You are a helpful assistant."  → 缓存命中 ✓
Request 3: "You are a helpful assistant "  → 缓存失效 ✗(多了个空格)
Request 4: "You are a Helpful assistant."  → 缓存失效 ✗(H 大写)

避坑:确保团队使用统一的模板,避免任何手动修改格式的行为。

五、成本计算:省了多少?

以 Claude Sonnet 4.6 为例(基础输入价 $3/MTok):

场景 计算 日成本 月成本
无缓存 5000 token × 1000次 × $3/MTok $15.00 $450
有缓存 1次写入 + 999次读取 $1.52 $45.6

一个月省下 $400+,节省幅度达到 90%。 这不是理论上的「最多 90%」,而是实操可稳定达到的水平。

在企业团队场景下,通过统一提示词模板、稳定模型配置与会话管理,缓存命中率可以稳定在 84%,平均整体支出可降低约 76%

一个更直观的场景:假设你的团队每天发出 500 次请求,每次 system prompt 5,000 token,用 Sonnet 4.6。不开缓存时每天光 system prompt 就消耗 2,500 万 token,约 75/天。开了缓存后,第一次写入0.019,剩下 499 次每次读取 0.0015,**system prompt 日成本从75 降到不到 $1**。

从速度维度看,Anthropic 官方测试显示,一个 100K token 的书籍示例中,启用缓存后响应时间从 11.5 秒降至 2.4 秒——这是几乎实时的体验差异。

六、如何最大化缓存收益

6.1 Claude Code 场景的最佳实践清单

策略 具体做法 关键原因
稳定 CLAUDE.md 一次会话中不修改,变更留到新会话 前缀匹配,改动导致全量重建
去除动态内容 不嵌入时间戳、日期、随机数 每次变化阻止缓存命中
锁定模型 会话内不切换模型 缓存与模型绑定
保持会话活跃 间隔不超过 5 分钟 TTL 到期自动失效
统一团队模板 团队共用同一份 CLAUDE.md 骨架 空格/大小写差异都会导致失效
慎用 /compact 只在历史过长时使用,而非频繁操作 compact 后的前缀必然变化

6.2 什么时候 Prompt Caching 收益最大?

  • 高重复率场景:编码助手、文档问答、RAG 系统,每次请求前缀高度重复
  • 大前缀场景:system prompt > 1,024 token 时才会触发缓存(这是 Anthropic 的最低缓存阈值)
  • 高频调用场景:每天数百到数千次请求,缓存写入的一次性开销被大量命中摊薄
  • 长会话场景:对话轮数越多,历史消息的缓存收益越大

6.3 什么时候收益有限?

  • 单次或低频调用:每次都是新会话,缓存来不及被第二次命中
  • 短 prompt 场景:system prompt 不到 1,024 token,缓存系统不会介入
  • 高度动态的 prompt:每次前缀都不同(如随机采样的 few-shot 示例),缓存命中率天然很低

七、对比其他主流 LLM:Claude 的缓存到底强在哪?

能力 Claude (Anthropic) GPT (OpenAI) Gemini (Google)
缓存粒度 自动 + 手动标记 全自动(5-10分钟) 手动创建上下文缓存
缓存 TTL 5分钟(自动)/ 1小时(手动标记) 5-10分钟(自动,不可控) 可配置,最长 24 小时
缓存命中判定 cache_read_input_tokens 字段明确区分 cached_tokens 字段 通过请求头 x-goog-cache-ttl
成本节省 90% 50% 75%(需显式启用)
最小缓存长度 1,024 token(标准)/ 256 token(快速) 1,024 token 不公开
显式控制 cache_control 断点精确控制 ❌ 全自动,开发者不可干预 ✅ 通过 TTL 参数控制
存储计费 ❌ 不单独计费 ❌ 不单独计费 ⚠️ 按小时收存储费

核心差异总结:

  • Claude:节省幅度最高(90%),但需要理解前缀匹配机制来避免失效。给开发者最大的控制权,但也需要开发者上心。5 分钟 TTL 短但高频场景下完全够用,1 小时 TTL 可手动扩展。

  • OpenAI:最省心,全自动无需配置。但节省幅度只有 50%,且缓存行为对开发者是完全黑盒——你不知道什么时候命中、什么时候失效,也无法手动优化。

  • Gemini:TTL 最长(可达 24 小时),适合低频但重复的定期任务。但它按小时收取存储费用,如果缓存了很多大上下文但不频繁访问,存储成本可能反噬节省效果。

如果你重度使用 Claude Code,Claude 的缓存方案显然是最优解——90% 的折扣幅度在账单上体现得非常直接,而且 Claude Code 已经自动帮你配置好了缓存层级,你只需要避开前文列出的几个坑。

八、总结与行动清单

Prompt Caching 对 Claude Code 来说不是「锦上添花的优化」,而是决定成本高低的核心基础设施。Claude Code 的请求结构(输入远大于输出)决定了你的账单几乎完全由输入 token 决定,而缓存恰好把输入 token 成本打到一折。只要你避开那几个失效陷阱,节省 80%-90% 的输入成本是稳定可达的。

立刻可以做的五件事:

  1. 检查 CLAUDE.md:去掉所有动态时间戳、版本号、随机内容
  2. 锁定模型:一个会话内不切换模型,不同任务分不同会话
  3. 固定模板:团队共享统一的 CLAUDE.md 骨架,避免个人随意修改格式
  4. 保持节奏:连续工作时确保间隔不超过 5 分钟;开会前考虑 /compact 或开启新会话
  5. 验证效果:关注 API 返回的 cache_read_input_tokenscache_creation_input_tokens 字段,监控真实缓存命中率

理解原理,避开陷阱,让缓存真正为你工作——你的下一张 Claude 账单,可能会让你大吃一惊。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容