• 请不要在回答技术问题时复制粘贴 AI 生成的内容
submit2mxh
V2EX  ›  程序员

Claude Code 的 Prompt Cache 到底怎么工作? 5 个让缓存失效的坑

  •  
  •   submit2mxh · 4h 20m ago · 350 views

    用 Claude Code 一段时间后我发现,同样的工作量,token 账单能差好几倍——差别几乎全在 Prompt Cache 有没有用对。官方文档把"有这个功能"讲了,但"怎么才不会踩坑"基本没说。这篇把我踩过的坑和读源码/官方博客理解的机制整理一下。

    纯技术,不涉及任何平台推荐,就事论事。


    一、为什么 Claude Code 对缓存特别敏感

    普通 API 调用输入输出大致 1:1 ,prompt 短,缓存收益有限。

    Claude Code 反过来——单次请求的输入 token 远大于输出。一次"改个 bug"的对话,输出可能就 200 token ,但输入要带:

    • 系统提示词(约 3000 token ,含全部工具定义)
    • CLAUDE.md (项目指令,几百到几千 token )
    • 历史对话(几千到几万 token )
    • 当前文件内容

    典型一次请求:输入 15K ,输出 500 ,输入是输出的 30 倍。 这种结构下,输入 token 的单价几乎决定总账单。而 Prompt Cache 对命中部分给的是 90% 折扣(只收 10%),不是小优化,是数量级差异。


    二、工作原理:前缀匹配,不是"重复内容打折"

    很多人以为是"系统检测到重复内容就打折",这是错的。

    真实机制:服务端保存你最近发送的 prompt 前缀。下次请求只要前缀完全一致(一字不差),就从缓存读取、跳过重算。

    关键点:前缀任何一处变化,后面所有内容的缓存全部失效。

    请求 1:[系统提示][工具定义][CLAUDE.md][对话 1-5][新消息]
    请求 2:[系统提示][工具定义][CLAUDE.md][对话 1-6][新消息]
           前面完全相同 → 命中,只有"对话 6+新消息"按全价
    

    但如果你在请求 2 里给 CLAUDE.md 偷偷加了一行,从 CLAUDE.md 往后全部失效,包括之前已经缓存的对话历史。

    一个反直觉的设计细节

    CLAUDE.md 不是拼在 system prompt 里发送的,而是通过 <system-reminder> 标签注入到 messages 数组。为什么?因为同版本 Claude Code 的 system prompt 在所有用户之间字字相同,服务端可以做全局共享缓存;如果把每个人不同的 CLAUDE.md 拼进 system prompt ,这个共享缓存就没了。拆开放,既保住全局共享,又让你的 CLAUDE.md 独立缓存。


    三、5min vs 1h 两档,怎么选

    档位 写入价格 读取价格 回本条件
    5 分钟 1.25× 基础输入价 0.1× 1 次命中即回本
    1 小时 2× 基础输入价 0.1× 2 次命中回本
    • 高频连续工作(<5min 一次请求)→ 5min 档
    • 任务间隔长、跨会议/午餐 → 1h 档

    Claude Code 内部对 system prompt + 工具定义默认 5min (高频复用),用户上下文按 session 长度自动选档。


    四、5 个让缓存失效的坑(最实用的部分)

    坑 1:中途修改 CLAUDE.md

    最常见。几轮对话后随手给 CLAUDE.md 加条规则——从 CLAUDE.md 往后全部失效,之前几轮的输入全按全价重算。 对策:session 开始前配好,开始后只读不改,要改先 /new

    坑 2:prompt 里塞动态内容

    "当前时间 2026-07-21 15:23:45 ,请…"
    

    时间戳、随机 ID 、UUID 只要进了前缀,缓存命中率直接归零(每次都不一样)。 对策:动态信息放最后一条用户消息里,别混进 system 或前置。

    坑 3:中途切模型

    不同模型缓存隔离。opus 切 sonnet ,之前的缓存直接作废。 对策:同任务保持模型一致,要切先 /new

    坑 4:/compact 的隐藏成本

    /compact 的总结请求用的是专门的总结 system prompt 、且不带工具定义,前缀从第一个 token 就和日常缓存不同,整个对话历史按全价计费一次对策:别攒到几十轮才 compact ;做完一个子任务就 compact 一次(被全价的内容少);只想清空的话 /new 更划算。

    坑 5:/resume 破坏缓存

    --resume / /resume 在多个版本存在缓存失效——恢复后前几轮全价,可能 10–20 倍成本暴增。原因是序列化/反序列化后 messages 结构有微小差异,服务端当成新前缀。 对策:长任务尽量一个连续 session 做完;不得不断,宁可新 session 简短复述,也别 resume 。


    五、怎么确认缓存真的命中了

    看响应里的 usage 字段:

    {
      "usage": {
        "input_tokens": 245,
        "cache_creation_input_tokens": 3120,
        "cache_read_input_tokens": 8450,
        "output_tokens": 412
      }
    }
    
    • cache_creation_input_tokens:本次写入缓存( 1.25× 或 2×)
    • cache_read_input_tokens:本次命中( 0.1×)
    • 连续 session 第 N 轮( N>1 ),cache_read 应远大于 input_tokens
    • 如果 cache_read 一直是 0 ,前缀肯定哪里被破坏了,照上面 5 个坑排查

    六、三条核心原则

    1. 保持前缀稳定——别中途改 CLAUDE.md 、加时间戳、切模型
    2. 同任务一气呵成——长 session 比频繁 resume 划算
    3. /compact 早用别攒——越晚 compact 被全价的内容越多

    CLAUDE.md 我个人保持在 50 行以内,当"索引"用(列关键文件路径、命令、约定),详细文档放 docs/ 让 Claude Code 自己 Read——既省 token 又不容易失效。

    以上是我自己的实践,有不同经验欢迎评论区交流。

    基于 Claude Code 1.x 与 Anthropic 官方文档,如有错误欢迎指正。

    2 replies    2026-07-22 21:40:03 +08:00
    r6cb
        1
    r6cb  
       3h 54m ago
    用 ai 灌水真的有意义?“别攒到几十轮才 compact ;做完一个子任务就 compact 一次” 一次处理十个和分成十次处理每次一个有区别?其他的都无力吐槽了
    mmdnk
        2
    mmdnk  
       2h 20m ago
    AI 文章就别发了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2585 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 57ms · UTC 16:00 · PVG 00:00 · LAX 09:00 · JFK 12:00
    ♥ Do have faith in what you're doing.