每发一条消息,Claude Code 都会把整个会话从头到尾重发一遍。本课讲清这件事为什么可行:窗口的三层结构、接近上限时的自动压缩(compaction),以及让「重发」变便宜的前缀缓存机制——最后落到你随时能自查的 /context 和 /usage。
为什么这天学这个
D1 讲了 agentic loop,以及用 /context 能看到上下文里都装了什么。D2 接着回答三个问题:这个窗口有多大、装满了会发生什么、为什么每轮都重发全部内容却不至于又慢又贵。答案分别对应本课的三个机制:窗口上限、compaction 和 prompt caching。
这课是后面几课的地基:D6 会话管理里 /clear、/compact、/rewind 的取舍,全部建立在「什么会打掉缓存、什么能活过压缩」之上;实战 Tip D 簇(缓存失效、额度去哪了、长会话变笨)是本课机制的问题式速查。跳过这课,你会在「为什么切个模型突然变慢了」「为什么改了 CLAUDE.md 没反应」这类问题上反复踩坑。
概念讲清楚
三层结构,每轮全量重发
官方模型在两次请求之间不记得任何东西。所以你每发一条消息,Claude Code 都发起一次全新的 API 请求,重发完整上下文:系统提示、项目上下文、之前的每一条消息和工具结果,再加上你的新消息。新内容永远追加在末尾,因此每次请求的绝大部分和上一次是一模一样的。为了配合缓存,Claude Code 把请求内容按「变化频率」排序,越少变的越靠前:
| 层 | 内容 | 什么时候变 |
|---|---|---|
| 系统提示层 | 核心指令、工具定义、output style | 加载的工具集变化,或升级 Claude Code |
| 项目上下文层 | CLAUDE.md、auto memory、无 paths 的 rules | 会话开始,或 /clear、/compact 之后 |
| 对话层 | 你的消息、Claude 的回复、工具结果 | 每一轮 |
官方关于上限:官方交互演示以 200K token 为示意上限;Fable 5、Sonnet 5、Opus 4.6 及之后的模型和 Sonnet 4.6 支持 1M token 窗口(按套餐提供,一般需选 [1m] 模型变体,Sonnet 5 则直接以 1M 运行)。用 /context 随时查看当前会话各类内容的真实占用。
自动压缩:什么时候发生,什么能活下来
官方窗口装满不会终结会话:接近上限时 Claude Code 自动做 compaction——用一份结构化摘要替换掉整段对话历史。你也可以主动出手:/compact 聚焦某话题 手动压缩并指定保留重点;/autocompact 500k(或启动参数 --autocompact、环境变量 CLAUDE_CODE_AUTO_COMPACT_WINDOW)把触发线提前,可设 100K 到 1M。没有另行设置时,默认到模型上限才压;云端会话和部分以 200K 窗口运行的模型会提前触发。
官方压缩后各类内容的命运不同:系统提示与 output style 不变(它们不在消息历史里);项目根 CLAUDE.md、无 paths 的 rules 和 auto memory 从磁盘重新注入;带 paths: 的 rules 和子目录 CLAUDE.md 会丢失,直到 Claude 再次读到匹配文件;已调用的 skill 正文重新注入,但单个截断到 5,000 token、总计 25,000,最旧的先丢。本站观点所以「必须永远在场」的规则应放项目根 CLAUDE.md(D4 展开),别放路径规则里。
prompt caching:按前缀精确匹配
官方API 把每次请求的开头部分(前缀)与最近处理过的内容做精确匹配:命中的部分直接复用,按缓存读取价计费——约为标准输入价的 10%;只有末尾新增的部分按全价处理。匹配是逐字精确的,前缀里任何一处变化,其后的所有内容都要重算;不存在按文件或按片段的缓存。此外,模型和 effort 等级各有独立缓存(它们是缓存 key 的一部分),切换任何一个都等于从零重建。
本站观点换个讲法:把会话想成一摞不能抽页的稿纸,阅卷人读过的页数会记住,每次只续读新页;但只要中间某页改了一个字,他就得从那页开始把后面全部重读一遍——这就是「前缀」的含义,也解释了为什么改动越靠前代价越大。
官方缓存有有效期(TTL):每次命中都会重置计时,持续干活就一直是热的。订阅用户自动使用一小时 TTL(超限改用 usage credits 时降为五分钟);API key 或云厂商默认五分钟,可用 ENABLE_PROMPT_CACHING_1H=1 开启一小时。缓存在 Claude Code 里的作用域约等于「一台机器 + 一个目录」,同一仓库的不同 worktree 目录各建各的缓存。
什么会打掉缓存,什么不会
官方失效动作的共性是「改了前缀或缓存 key」,保住缓存的共性是「只往对话末尾追加」:
| 动作 | 缓存 | 说明 |
|---|---|---|
/model 切模型 | 全部失效 | 每个模型独立缓存;opusplan 进出 plan mode 也算切模型 |
/effort 调力度 | 全部失效 | 缓存按 effort 分 key,会话中改会弹确认 |
| 开启 fast mode | 全部失效 | 一次性成本,越早开越便宜;关掉再开不再触发 |
| MCP server 连接/断开 | 看情况 | 工具定义被延迟加载(默认)则保住;载入前缀则失效(D9) |
| deny 整个内置工具 | 全部失效 | 仅裸工具名(如 Bash);Bash(rm *) 这类范围规则不影响 |
/compact | 对话层失效 | 系统提示层复用;CLAUDE.md 没改过则项目层仍命中 |
| 升级 Claude Code | 全部失效 | 升级后 resume 长会话,第一轮可能是最贵的一次请求 |
| 编辑仓库文件 | 保住 | 只追加一条 <system-reminder>,不回改历史 |
| 会话中改 CLAUDE.md | 保住 | 但改动也不生效,要等 /clear、/compact 或重启 |
切权限模式、调 skill、/recap | 保住 | 都是往对话末尾追加内容 |
/rewind | 保住 | 截断回一个已缓存的前缀,比 compaction 便宜 |
| 派生 subagent | 保住 | 子代理自建缓存,父会话前缀不动(D10) |
误区澄清
- 「改了 CLAUDE.md 马上生效」——实际它在会话开始时读一次、存在内存里,会话中的编辑既不打缓存、也不生效。判断方法:
/clear、/compact或重启后再观察。官方 - 「切模型 / 切 effort 是免费的」——内容一个字没变也要整段重算,下一轮明显变慢变贵。判断方法:切换后看
/usage里 cache write 是否突增。官方 - 「缓存是按文件缓存的」——只有前缀整体匹配这一种机制,没有按文件、按片段的缓存;文件内容只在被读取时进入对话层。官方
机制怎么落到速度和账单上
官方三条最常见的「费用怎么来的」都能用本课机制解释:其一,长会话里问一句「这个函数叫什么」,消耗远大于这一句本身——因为每轮都携带全部历史,整卷按缓存价重读;其二,离开超过 TTL 后回来,第一条消息缓存全失,整卷按全价重算,所以「休息后的第一轮」明显慢;其三,/compact 本身要把待摘要的整段对话读一遍,趁缓存还热时做便宜得多,而想彻底换任务时 /clear 一分钱不花。/usage 会在 cache miss、长上下文等行为占近期用量 10% 以上时给出提示。
/compact 留到任务间隙的自然断点再用——会话中途改得越少,缓存命中率越高。官方当天能做完的实操
- 启动
claude,先不干活,直接运行/context。预期:对话层几乎为零,但系统提示、工具定义、CLAUDE.md、memory 已经占了不少——这就是 D1 说的「你还没说话,窗口已经不空了」。 - 把下面的 prompt 原样发给 Claude,让它读一个大文件,然后再运行
/context。预期:对话层(Messages)明显变大,涨幅主要来自文件内容。 - 运行
/usage,找到按模型分列的那一行。预期:cache read 远大于 input——说明大部分上下文在按约 1 折的缓存价重读。 - 故意打一次缓存:
/model换一个模型,随便问一句「继续」,再看/usage。预期:cache write 突增,因为整段会话在新模型下重写了缓存。(这一步真实消耗额度,在小会话里做。) - 运行
/compact 只保留与刚才那个文件相关的结论。预期:出现 Conversation compacted 提示;再看/context,对话层缩回一小段摘要。
帮我做一个上下文实验:
1. 挑本项目里较大的一个源码文件读一遍(自己挑,不用问我);
2. 用两三句话总结它;
3. 估计这次读取大约往上下文里增加了多少内容。
之后我会用 /context 和 /usage 核对,请把总结控制在五行以内。
过程中会反复用到的命令:
/context # 当前上下文各类内容的占用
/usage # 本会话 token 用量与 cache read / cache write
/model # 切换模型(本课用它演示缓存失效)
/compact 只保留与 X 相关的结论 # 带焦点的手动压缩
验收标准
- 能不看笔记说出上下文的三层结构,以及每层分别在什么时候变化。
- 能各举出三个「会打掉缓存」和「不会打掉缓存」的动作,并用「前缀 / 缓存 key」解释原因。
- 能解释为什么会话中修改项目根 CLAUDE.md 不生效、什么时候才生效。
- 实操跑通:能在
/usage里指认 cache read 与 cache write,并解释/model之后 cache write 为什么突增。 - 自测题:一个开了一整天的会话里,你只问了一句「这个函数叫什么」,为什么消耗远大于这句话本身?(参考答案:每轮请求都携带全部历史,整卷按缓存价重读;若离开时间超过缓存 TTL,还会整卷按全价重算。)