Skip to content
Published at:

第 11 章:上下文管理

第 10 章我们拆解了 Claude Code 的 Agent Loop 和工具系统——你知道了 Claude 怎么工作。这一章我们要解决一个直接影响工作质量的核心问题:Claude 记得什么记得多少、以及忘了怎么办

上下文管理是区分"会用 Claude Code"和"用好 Claude Code"的分水岭。同样的指令,为什么有时 Claude 给出精准优雅的方案,有时却答非所问?同样的 Bug,为什么有时一次定位成功,有时绕了三圈还在原地打转?答案往往不在于你的指令质量,而在于上下文的状态

本章目标:理解上下文窗口的概念和构成,识别上下文膨胀的症状,掌握 /compact/clear 的使用时机与技巧,建立多会话管理的工作习惯。

11.1 什么是上下文窗口

类比:AI 的"工作记忆"

把 Claude 想象成一位坐在你旁边编程的同事。他面前的桌子上摊着几样东西:

  • 一本行为守则(系统提示词),告诉他什么能做、什么不能做
  • 一份项目说明书(CLAUDE.md),记录了项目结构、技术栈和约定
  • 你们的对话记录(聊天历史),从第一句话到现在
  • 他刚翻阅过的文件(Read 工具的输出)
  • 他执行命令后的终端输出(Bash 工具的结果)

这张桌子的面积是有限的——当东西太多时,他必须把一些纸张收起来,腾出空间放新的。这个"桌面面积"就是上下文窗口(Context Window)。

在技术层面,上下文窗口是模型在一次推理中能够"看见"的最大 token 数量。窗口内的所有内容构成了模型做决策的全部信息基础——窗口之外的世界对模型来说完全不可见。

什么是 Token

Token 是模型处理文本的最小单位。它不是字符,也不是单词,而是介于两者之间的"语义片段"。

英文的 Token 划分

"Claude Code is an AI coding tool."
 → ["Claude", " Code", " is", " an", " AI", " coding", " tool", "."]
 → 8 tokens

英文大致是 1 token ≈ 0.75 个单词,或者说 1 个单词 ≈ 1.3 个 token。

中文的 Token 划分

"Claude Code 是一个 AI 编程工具。"
 → ["Claude", " Code", " 是", "一个", " AI", " 编程", "工具", "。"]
 → 8 tokens

中文的一个汉字通常占 1-2 个 token(取决于编码方式和上下文),大致 1 个汉字 ≈ 1.5 token。换句话说,同样的语义内容,中文消耗的 token 通常是英文的 1.5-2 倍

这意味着:用中文与 Claude Code 对话时,你的上下文窗口会被更快地填满。这是一个容易被忽视但影响深远的差异。

各模型的上下文窗口

不同模型的"桌面面积"差异巨大:

模型上下文窗口等效页面数(估算)备注
Claude Opus 4.7200K tokens~600 页Anthropic 旗舰,推理最强
Claude Sonnet 4.6200K tokens~600 页平衡性能与速度
Claude Haiku 4.5200K tokens~600 页最快响应
DeepSeek V4 Flash1M tokens~3,000 页极低成本 + 超大窗口
DeepSeek V4 Pro1M tokens~3,000 页强推理 + 超大窗口

1M tokens 是什么概念?大约可以容纳《三体》三部曲的全部文本,还有余量。DeepSeek V4 的 1M 上下文窗口意味着——你几乎不会因为对话太长而遇到上下文溢出。

但别高兴太早。上下文窗口大 ≠ 模型能有效利用全部窗口。研究表明,模型对窗口中间位置的信息利用效率低于开头和结尾(即"Lost in the Middle"现象)。所以即使有 1M 窗口,你仍需要管理好上下文。

上下文预算的可视化

想象一个逐渐被填满的进度条。这是一个典型对话的上下文消耗过程:

上下文预算(200K tokens)

对话开始:
[System Prompt ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░] ~8K (4%)
加入 CLAUDE.md:
[System ████|CLAUDE.md ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░] ~12K (6%)

第 1 轮对话 + 读取 3 个文件:
[System ████|CLAUDE.md ██|对话 ██|文件 ███████░░░░░░░░░░░░] ~30K (15%)

第 5 轮对话 + 执行命令 + 输出:
[System ████|CLAUDE.md ██|对话 █████|文件 ███████|命令 ████░] ~65K (33%)

第 15 轮对话 + 多次工具调用:
[System ████|CLAUDE.md ██|对话 ██████████|文件 ████████|工具 ██████░░] ~120K (60%)

第 30 轮对话 + 复杂任务上下文:
[System ████|CLAUDE.md ██|对话 ██████████████|文件 ████████|工具 █████████░] ~170K (85%)

                                                自动压缩触发点(约 85-90%)

当上下文使用率超过 85% 时,Claude Code 会触发自动压缩(auto-compact)。如果继续增长到接近 100%,模型的行为质量将显著下降——这就是下一节要讨论的问题。

11.2 上下文的构成

在任何一个时刻,Claude Code 的上下文窗口由以下几个部分组成。理解每一部分的性质和大小,是做好上下文管理的前提。

System Prompt(系统提示词)

大小:约 5-8K tokens(固定,不可修改)

系统提示词是 Claude Code 的"出厂设定"。它在每次对话启动时自动加载,包含:

  • 行为准则:安全性约束、编码风格偏好、响应格式要求
  • 工具定义:所有可用工具的 JSON Schema(名称、参数、返回值格式)
  • 平台信息:操作系统类型、Shell 环境、当前工作目录
  • Git 状态快照:当前分支、未提交变更、最近提交记录

你无法直接修改系统提示词,但它的内容会占用固定的上下文配额。这是你的"固定开销"——什么都不做就已经消耗了 ~6K tokens。

CLAUDE.md(项目上下文)

大小:0-5K tokens(可变,由你控制)

项目根目录的 CLAUDE.md 在每次对话启动时被自动读取。它的大小完全取决于你写了多少。一个精炼的 CLAUDE.md(200-500 字)仅占 ~1K tokens,而一个详尽的项目文档可能占 5-10K tokens。

在第 12 章中,我们将深入讨论如何编写高效的 CLAUDE.md——核心原则是:信息密度高,废话少

对话历史(Conversation History)

大小:从 0 开始,持续增长(无上限,直到触发压缩)

这是上下文窗口中增长最快、最不可控的部分。每一条消息、每一次工具调用、每一个工具返回结果,都会追加到对话历史中。

一个典型的消息-回复对消耗的 token 量:

用户消息(中文,50 字):                    ~100 tokens
Claude 的思考过程(Thinking):              ~200-500 tokens
Claude 的文本回复(中文,200 字):           ~400 tokens
工具调用请求(JSON):                       ~50-100 tokens
工具返回结果(如文件内容、命令输出):         ~500-5000 tokens
─────────────────────────────────────────────────
单轮对话总消耗:                             ~1,250-6,100 tokens

你每进行一轮对话,上下文就膨胀几千 token。30 轮对话后,光对话历史就轻松超过 100K tokens。

文件内容(File Contents)

大小:每次 Read 操作几百到几万 tokens(按需加载,累积消耗)

当 Claude 使用 Read 工具读取一个文件时,该文件的完整内容会进入上下文窗口。一个 500 行的 TypeScript 文件大约占 3-5K tokens。如果 Claude 在一轮对话中读取了 5 个文件,那就是 15-25K tokens。

需要注意的是:读取的文件内容会一直保留在上下文中,即使 Claude 已经完成了对那个文件的操作。除非被压缩清除,否则这些内容会持续占用窗口。

工具输出(Tool Outputs)

大小:因操作而异(从几十到几万 tokens)

Bash 命令的输出是最不可预测的部分。一个 npm install 的输出可能是几百行,一个 grep 搜索可能返回几十个匹配结果,一个 git diff 的输出可能涵盖几十个文件。

这些输出在帮助 Claude 做决策的同时,也在快速消耗上下文预算。

Memory(持久化记忆)

大小:通常 < 1K tokens(存储在磁盘,对话启动时加载)

Memory 系统在 .claude/projects/<path>/memory/ 下存储持久化信息。与对话历史不同,memory 是跨会话的——下次打开 Claude Code 时,它仍然记得你的偏好和之前的重要决定。

Memory 的内容通常包括:

  • 你的技术背景和编码偏好
  • 当前项目的工作目标和约定
  • 你之前纠正过的错误和确认的方向

上下文构成一览

┌──────────────────────────────────────────────────────────┐
│                    上下文窗口 (200K / 1M)                  │
├──────────────────────────────────────────────────────────┤
│  System Prompt (~6K)                           固定开销   │
│  ├─ 行为准则、工具定义、平台信息                           │
│  ├─ Git 状态快照                                         │
├──────────────────────────────────────────────────────────┤
│  CLAUDE.md (~1-5K)                            项目上下文   │
│  ├─ 项目架构、技术栈、常用命令                             │
│  ├─ 编码规范、约定                                       │
├──────────────────────────────────────────────────────────┤
│  Memory (~0.5K)                              持久化记忆    │
│  ├─ 用户偏好、已确认的约定                                │
├──────────────────────────────────────────────────────────┤
│  对话历史 (0 → 150K+)                     动态增长 ⚠️      │
│  ├─ 用户消息 + Claude 回复                                │
│  ├─ 思考过程(Thinking)                                  │
│  ├─ 工具调用请求 + 返回结果                               │
│  ├─ 读取的文件内容                                        │
│  ├─ Bash 命令输出                                         │
│  ├─ WebSearch / WebFetch 结果                             │
├──────────────────────────────────────────────────────────┤
│  剩余可用空间                              Claude 的工作区  │
│  └─ 用于新的推理、文件读取、命令执行                       │
└──────────────────────────────────────────────────────────┘

11.3 上下文膨胀问题

问题的本质

上下文窗口就像你的电脑内存——足够大时一切流畅,接近满载时开始卡顿,溢出时直接崩溃。但上下文窗口的问题比内存更微妙:它不会直接报错,而是让 Claude 的行为质量悄悄下降

随着对话的进行,上下文窗口被不断填充。当剩余空间不足时,模型的信息处理能力开始衰减:

  1. 早期信息被"挤出"注意力范围:模型对窗口开头的信息关注度下降
  2. 中间信息被弱化:Lost in the Middle 效应——窗口中间位置的内容更容易被模型忽略
  3. 新信息缺乏"消化空间":模型没有足够上下文来充分理解新读入的代码
  4. 推理链变短:复杂的多步推理需要更多上下文来维持逻辑连贯性

上下文膨胀的症状

以下是需要警惕的信号——当你观察到以下任何一种情况时,说明上下文已经开始膨胀:

症状一:Claude "忘记"了早期的指令

你(第 1 轮): 这次重构遵循函数式风格,避免使用类
...(中间 20 轮对话)
你(第 22 轮): 这个新模块也用同样的风格写
Claude: 创建了一个 class BasedService { ... }

Claude 并非故意忽视你的要求,而是你在第一轮说的"函数式风格"已经被挤到了上下文窗口的远端,在模型做第 22 轮决策时无法有效参照。

症状二:Claude 开始重复自己或绕圈子

Claude(第 25 轮): 我建议将 validator.ts 拆分为三个模块...
你: 这个方案我们第 15 轮讨论过,当时决定不拆分,因为会影响 12 个调用方
Claude: 你说得对。那我改为...(提出另一个第 18 轮已经否决过的方案)

当 Claude 频繁提出你之前已经讨论并否决过的方案时,说明它已经"忘记"了对话中段的内容。

症状三:Claude 忽略你刚提到的关键细节

你: 注意,这个 API 的超时时间是 30 秒,不是默认的 10 秒
Claude: 好的。我会设置 10 秒超时...(忽略了你刚说的内容)

这看起来像 Claude 不听话,实际上是它在处理你的指令时,注意力被上下文中大量的其他信息分散了。

症状四:工具调用变得越来越不精准

# 对话早期:
Claude: Read src/services/auth.ts(精准,只读需要的一个文件)

# 对话晚期:
Claude: Read src/services/(模糊,试图读取整个目录)
Claude: Bash: grep -r "auth" .(过于宽泛的搜索)

当 Claude 的工具调用从"手术刀"变成"散弹枪",这是上下文过载的典型表现——它没有足够的上下文空间来做精准判断,于是退而求其次,用大范围的搜索来弥补。

何时需要警觉

以下阈值可以作为参考(以 200K 窗口为例):

消息轮数工具调用次数上下文使用率(估算)风险等级
< 10 轮< 20 次< 30%🟢 正常
10-20 轮20-40 次30-55%🟡 注意
20-35 轮40-70 次55-80%🟠 主动管理
35-50 轮70-100 次80-95%🔴 立即压缩
> 50 轮> 100 次> 95%⛔ 上下文过载

注意:这些数字是经验估算。实际消耗速度取决于你的文件大小、命令输出长度、以及 Claude 是否开启了思考模式。DeepSeek V4 的 1M 窗口可以让这些阈值乘以 5 倍,但 Lost in the Middle 效应仍然存在——窗口大了不代表你可以无限堆内容。

一个真实场景

对话开始: "帮我重构 src/services/orderService.ts"
第 1-3 轮: 读取 orderService.ts(2K tokens)和相关文件(8K tokens)
第 4-8 轮: 讨论重构方案,Claude 提出 3 个方案,你选了第 2 个
第 9-15 轮: Claude 逐步重构,每步读取关联文件验证兼容性
第 16-20 轮: 重构过程中发现了另一个模块的 Bug,你让 Claude 顺便修
第 21-25 轮: 修 Bug 涉及 4 个新文件(15K tokens)
第 26-30 轮: 回到重构,但 Claude 开始"忘记"你之前确认的方案细节
第 31 轮: Claude 修改了一个你第 8 轮明确说过不要动的文件
──────────────────────────────────────
此时上下文使用率可能已经超过 85%
→ 如果还不执行 /compact,后续的每次交互质量都会下降

这个场景的教训是:当你在一个对话中"顺便"处理了另一个任务时,上下文膨胀的速度远超你的预期。这也是为什么本章后面要讲"一次一个主题"的原则。

11.4 /compact 压缩命令

/compact 是你对抗上下文膨胀的主要武器。它不解决问题——它解决问题带来的后果

/compact 做了什么

当你执行 /compact 时,Claude Code 会:

  1. 分析当前的完整对话历史
  2. 提取关键信息:重要的决策、确认的结论、你的显式偏好
  3. 压缩冗余内容:重复的工具输出、被纠正的错误尝试、中间步骤的详细过程
  4. 生成一份精炼的对话摘要,替换原有的对话历史
  5. 保留最近几轮对话(通常 3-5 轮),确保当前工作的连续性
压缩前(150K tokens):
┌────────────────────────────────────────────┐
│ [System Prompt] [CLAUDE.md]                │
│ [消息 1] [回复 1] [工具调用 1] [工具输出 1] │
│ [消息 2] [回复 2] [工具调用 2] [工具输出 2] │
│ ...(大量冗余的工具输出和纠正过程)          │
│ [消息 30] [回复 30] [工具调用 30]            │
│ [消息 31] [回复 31](最近 3 轮保留)          │
└────────────────────────────────────────────┘

压缩后(~35K tokens):
┌────────────────────────────────────────────┐
│ [System Prompt] [CLAUDE.md]                │
│ [压缩摘要]                                  │
│  ├─ 项目:重构 orderService 模块             │
│  ├─ 决定:采用方案 2(策略模式),不动 API 层 │
│  ├─ 用户偏好:函数式风格,避免 class          │
│  ├─ 已完成:orderService.ts 核心逻辑重构      │
│  ├─ 待处理:PaymentGateway 接口兼容性验证     │
│  └─ 注意事项:不要修改 src/api/ 下的文件      │
│ [消息 31] [回复 31](最近 3 轮保留)          │
└────────────────────────────────────────────┘

释放了约 115K tokens——足够再进行 15-20 轮高质量对话。

自动压缩 vs 手动压缩

Claude Code 有两种压缩触发方式:

自动压缩

当上下文使用率超过约 85-90% 时,Claude Code 会自动触发压缩。你会看到类似这样的提示:

Context usage is high. Compacting conversation to free up space...

自动压缩的优点是不需要你操心,缺点是你不知道它保留了哪些信息、丢弃了哪些信息。它可能丢掉你认为关键的一个细节,也可能保留了大量你已经不需要的冗余。

手动压缩

你主动输入 /compact/compact [保留指令]。手动压缩给你控制权,你可以精确指定保留范围。

建议的策略不要依赖自动压缩。自动压缩是安全网,不是工作流。你应该在以下时机主动手动压缩:

  • 完成一个主要阶段后(如重构方案确认完毕、准备开始执行)
  • 观察到上下文膨胀症状出现时
  • 对话超过 25 轮时(即使还没看到症状)
  • 切换子任务前(如从"分析问题"切换到"实现修复")

/compact 的指令语法

/compact 支持附加指令来指定保留策略:

基础用法

/compact

压缩对话,让 Claude 自行判断保留什么。

指定保留主题

/compact 只保留性能优化相关的对话内容,丢弃其他无关信息

指定保留的关键决策

/compact 保留以下信息:
1. 我们决定使用策略模式重构 orderService
2. API 接口不能修改,保持向后兼容
3. 测试用 Jest,覆盖率达到 80% 以上

指定丢弃的内容

/compact 丢弃所有关于错误尝试的讨论,只保留最终的实现方案

压缩后恢复策略

/compact 之后,Claude 通过一份摘要来"回忆"之前的对话。这份摘要的质量决定了压缩后 Claude 的表现。但摘要毕竟是摘要——它会丢失细节和细微的上下文。

压缩后你应该做的

  1. 快速浏览摘要:Claude 压缩后会展示保留的摘要。扫一眼,确认关键信息没有丢失
  2. 补充遗漏:如果发现重要信息被丢弃了,立即补充:
    压缩摘要中没有提到——我们之前还确认了错误处理使用 Result 模式,
    不要抛异常。请记住这一点。
  3. 重新锚定当前任务:简要重述你当前的进度和下一步方向:
    回到重构——orderService.ts 的核心逻辑已经改完,
    现在继续处理 PaymentGateway 接口的兼容性验证。
  4. 确认 Claude 理解了:在继续之前,让 Claude 用一两句话确认它理解当前状态:
    先确认下你理解现在的进度。

这个恢复过程只需要 1-2 轮对话,但它能确保压缩后的对话质量不会断崖式下跌。

/compact 的局限性

/compact 不是银弹,它有明确的局限:

  1. 丢失细微的上下文:你随口提的一句"那个变量名我觉得还是叫 userContext 比较清楚"——这种非结构化的偏好很可能会在压缩中被丢弃
  2. 无法保留"否定性信息":如果之前 Claude 提出了 A 方案被你否定,压缩后的摘要可能只写了"采用 B 方案",而丢失了"不要用 A 方案"这个信息。在后续对话中,Claude 可能再次提出类似的 A 方案
  3. 中间推理链断裂:如果一个 Bug 是经过 10 步推理定位到的,压缩只会保留"定位结果:Bug 在 auth.ts 第 42 行",而不会保留完整的诊断推理链。如果修复后出现了新问题,Claude 需要重新推理
  4. 无法区分"重要"和"看起来重要":自动压缩的提取算法基于内容的重复频率和位置,而不是真正的语义重要性

缓解策略:对于复杂任务,在关键节点主动向 Claude 确认:"总结一下目前达成的共识和已完成的步骤"。这句话会以 Claude 的回复形式明确记录在对话中,压缩时被保留的概率远高于你的单方面指令。

11.5 /clear 清空对话

如果说 /compact 是整理桌面,/clear 就是端走整张桌子,换一张新的。

/clear 与 /compact 的本质区别

维度/compact/clear
保留什么压缩后的摘要 + 最近几轮对话System Prompt + CLAUDE.md + Memory
丢弃什么冗余的工具输出、中间过程一切对话历史,包括压缩摘要
Claude 的状态"记得"关键信息彻底失忆,从头开始
适用场景同一任务太长,需要释放空间话题完全切换,需要全新开始
风险可能丢失细微信息丢失所有当前任务的进度
恢复成本低(1-2 轮对话恢复)高(需要完整重述背景)

什么时候用 /clear

/clear 是重型武器,只在以下情况使用:

场景一:话题完全切换

之前:调试 Webpack 配置问题,涉及 10 个配置文件的读写
现在:想用 Claude 设计一个全新的 API 路由结构

→ /clear 后重新开始。
两个任务完全无关,之前的上下文都是噪音。

场景二:上下文污染严重

之前的对话中,Claude 多次误解你的意思,形成了错误的认知惯性。
你纠正了好几次,但它仍然在之前的错误理解上打转。

→ /clear,用一个干净的上下文重新给出精确的指令。
有时"重启"比"修复"更高效。

场景三:需要一个全新的视角

你已经和 Claude 在同一个方案上讨论了很久,
感觉思路被局限在某个方向。你想看看 Claude 能否提出完全不同的方案。

→ /clear,用一个开放式的 Prompt 重新开始。
旧的讨论方向不会束缚 Claude 的思路。

场景四:上下文已被系统压缩过多次

如果一次对话已经被自动压缩过 2-3 次,对话历史已经变成了
"摘要的摘要的摘要",信息丰富度已经很低。

→ /clear 重新开始,重新建立上下文,质量更高。

执行 /clear 之前

/clear 不可撤销。在执行之前,做好以下准备:

  1. 保存关键结论到其他地方

    • 已经确认的技术方案 → 写进 CLAUDE.md 或项目文档
    • 已经完成的代码 → 确保已经 commit
    • 重要的决策和理由 → 记录在 commit message 或 issue 中
  2. 让 Claude 输出一份最终总结

    在清空之前,帮我总结一下本次对话中达成的所有重要决策和已完成的工作。
    我会把这份总结保存下来。

    这份总结是你重新开始时向 Claude 提供背景的素材。

  3. 确认当前所有改动已保存

    确认一下,本次对话中做的所有代码改动都已经写入了文件。

    确保没有只在 Claude 的"记忆"中存在、尚未实际写入磁盘的修改。

/clear 之后的快速重启

/clear 后,Claude 不知道你是谁、在做什么、之前讨论了什么。你需要高效地重新建立上下文:

(/clear 后)

我们之前在做 orderService 的重构,以下是关键背景:

1. 目标:将订单查询逻辑从混杂的 if-else 改为策略模式
2. 约束:不能修改 src/api/orderApi.ts 的接口签名
3. 已完成:核心的策略接口和三个具体策略已实现
4. 当前问题:PaymentGateway 接口的兼容性验证还没做

请先读取 src/services/orderService.ts 和相关文件,理解当前状态。

这段"重启提示"包含了目标、约束、进度、下一步——信息密度极高,在一段话中重建了之前的核心上下文。

11.6 会话管理

除了在对话内部管理上下文,Claude Code 还提供了会话级别的管理能力——保存、恢复、查看历史会话。

为什么要管理会话

一个对话(Session)是一个独立的上下文空间。不同对话之间的上下文完全隔离。这意味着:

  • 在对话 A 中讨论的内容不会影响对话 B
  • 对话 A 的上下文膨胀不会拖累对话 B
  • 你可以为不同的任务维护不同的对话,各自保持"干净"的上下文

会话的创建与命名

创建新会话

在 VSCode 侧边栏面板中,点击右上角的 加号(+) 图标即可创建新会话。也可以通过快捷键 Cmd+N(需在设置中启用 enableNewConversationShortcut)。

命名会话

Claude Code 默认以时间戳自动命名会话(如 "Session 2026-05-30 14:23")。你应该立即重命名为有意义的名字。

好的命名:

  • 重构 orderService 策略模式
  • 调试支付回调签名验证
  • 编写用户模块单元测试
  • 审查 PR #342

不好的命名:

  • Session 1
  • 测试
  • 问题
  • 未命名

命名是你未来在历史会话列表中快速定位的唯一线索。一个月后面对 50 个历史会话时,好的命名能帮你 3 秒找到需要的会话,不好的命名意味着你需要逐个打开查看内容。

查看和恢复历史会话

点击侧边栏面板的历史时钟图标,可以看到所有历史会话的列表。列表显示每个会话的:

  • 名称
  • 最后活跃时间
  • 消息数量

点击任意历史会话即可恢复——你可以继续之前的对话,上下文(包括压缩后的摘要)完整保留。

历史会话的上下文是持久化的。即使你关闭了 VSCode、重启了电脑,一个月后打开历史会话,Claude 仍然"记得"那个对话中发生过什么。

会话的归档

当你不再需要某个会话时,可以将其归档(Archive)。归档后的会话从主列表中隐藏,但不会被删除——你仍然可以在归档列表中找到并恢复。

何时归档

  • 任务已经完成,代码已合并
  • 项目已经结束或不再维护
  • 会话已经很久没有活动(> 2 周)

归档不是删除——它是"整理"。保持主列表的整洁,让你能快速找到当前活跃的会话。

11.7 多会话并存策略

这是本章最重要的实践技巧之一。它不是 Claude Code 的某个具体功能,而是一种工作习惯

核心理念:一个会话 = 一个任务

不要在同一个会话中混合处理多个不相关的任务。每个会话应该有单一的、明确的主题边界

反模式

会话 "工作":
  - 修复登录 Bug
  - 优化首页加载性能
  - 更新 README
  - 审查同事的 PR
  - 设计新的 API 路由

这个会话的上下文是五个完全无关主题的大杂烩。Claude 在帮你优化首页性能时,登录 Bug 的调试历史还占着上下文窗口的大量空间。这些信息对当前任务不但没用,还会干扰 Claude 的判断。

推荐模式

会话 1: "修复登录 Token 刷新 Bug"
会话 2: "优化首页 LCP 性能"
会话 3: "更新项目 README 和 API 文档"
会话 4: "审查 PR #342 - 支付模块"
会话 5: "设计 v2 API 路由结构"

每个会话的上下文都是纯净的、与当前任务高度相关的。Claude 在"优化首页性能"的会话中,看到的全部内容都与性能优化相关。

多会话的日常工作流

以下是一个典型一天中的多会话使用方式:

早上 9:00 — 打开会话 "修复登录 Token 刷新 Bug"
  │  继续昨天的工作,上下文完整保留
  │  10:30 修复完成,提交 PR

上午 10:35 — 收到同事请求,帮忙审查 PR #342
  │  切换到会话 "审查 PR #342 - 支付模块"
  │  上下文中没有登录 Bug 的任何信息,干净高效
  │  11:20 审查完成,输出 Review 意见

上午 11:25 — 回到会话 "修复登录 Token 刷新 Bug"
  │  PR Review 反馈回来了,需要微调
  │  上下文中仍然是登录模块的所有讨论,不需要任何恢复

下午 14:00 — 新任务:优化首页性能
  │  创建新会话 "优化首页 LCP 性能"
  │  Claude 读取首页相关文件,进行性能分析
  │  16:00 优化方案确定,开始实施

注意这个流的关键优势:每次切换会话,你切换到的会话中的上下文是完整且纯净的。你不需要每次切换任务时执行 /compact/clear——会话本身帮你隔离了上下文。

会话切换的最佳实践

  1. 为每个独立任务创建独立会话。任务完成后再归档
  2. 不要在会话 A 中"顺便"处理会话 B 的任务。即使是"帮我快速看一下这个"——先切换到正确的会话或创建新会话
  3. 利用 Claude Code 的多会话能力。VSCode 扩展支持同时打开多个会话(每个在独立的标签页中),你可以在它们之间快速切换
  4. 命名要具体到能唯一识别任务。"重构用户模块"比"重构"好一百倍
  5. 定期整理会话列表。每周花 2 分钟,归档已完成的会话,重命名那些当初随手起名的会话

多会话与 Git 分支的配合

多会话策略与 Git 分支工作流天然契合:

分支: feature/login-token-fix    →  会话: "修复登录 Token 刷新 Bug"
分支: perf/homepage-lcp          →  会话: "优化首页 LCP 性能"
分支: docs/api-v2                →  会话: "设计 v2 API 路由结构"

一个分支对应一个会话。切换分支时切换会话,上下文始终与当前代码状态保持同步。

11.8 上下文管理最佳实践

以下是经过大量实战验证的上下文管理方法。它们不是互相独立的技巧,而是一个有机的整体——同时实践效果最好。

1. 一次一个主题

不要在同一个会话中混合处理多个不相关的任务。

这是上下文管理的第一原则。违反这一条,后续所有的管理技巧都只能亡羊补牢。

如果你正在会话中处理任务 A,临时被要求处理任务 B,正确的做法是:

  • 创建一个新会话来处理任务 B
  • 完成任务 B 后回到原会话继续任务 A

而不是在图省事在同一个会话中说:"先不管 A 了,帮我看看 B 这个 Bug。"

2. 定期手动 compact

不要等待自动压缩。在以下节点主动执行 /compact

  • 完成一个主要方案设计后
  • 完成一个子任务后(如"所有测试写完了")
  • 对话超过 25 轮时
  • 观察到任何上下文膨胀症状时

养成在每个里程碑后 "/compact + 快速确认摘要" 的习惯。

3. 压缩前先确认

在执行 /compact 之前,花 30 秒想一下:

  • 这个对话中哪些信息是必须保留的?
  • 有没有我之前纠正过的方向,不希望 Claude 再犯的?

如果有关键信息需要保留,用 /compact 保留... 的语法明确指定。

4. /clear 后重述关键信息

/clear 之后,Claude 对你的项目和你当前的任务一无所知。你需要用一段精炼的"重启提示"重建上下文:

简明扼要地告诉 Claude:
1. 项目的性质和技术栈
2. 当前任务的目标和约束
3. 已经完成了什么
4. 下一步要做什么

这个习惯能将 /clear 后的恢复时间从 5-6 轮缩短到 1-2 轮。

5. 长任务分拆为子任务

一个需要 100 轮对话才能完成的任务,拆成 4 个子任务,每个子任务在一个独立会话中完成:

原任务: 重构整个订单系统

分拆后:
子任务 1(会话 A): 重构数据模型层 → 15 轮,完成后 /compact
子任务 2(会话 B): 重构业务逻辑层 → 25 轮,完成后 /compact
子任务 3(会话 C): 重构 API 接口层 → 20 轮,完成后 /compact
子任务 4(会话 D): 集成测试与兼容性验证 → 20 轮,完成后 /compact

总轮数相同(80 轮),但每个会话的上下文都在 25 轮以内,质量远高于一个 80 轮不压缩的会话。

需要注意的是,子任务之间的信息传递需要通过代码状态(已 commit 的代码)和CLAUDE.md(记录架构决策),而不是依赖 Claude 的记忆。

6. 利用 Memory 系统

Memory 是你跨会话传递持久化信息的渠道。当你希望 Claude 在未来的所有会话中都记住某个信息时,明确告诉它记录下来:

记住:这个项目使用 Result 模式处理错误,不要使用 try-catch 抛异常。

或者:

记住我的偏好:React 组件使用函数式声明,不用 class component。

这些信息会存储在 .claude/projects/<path>/memory/ 下,在每次新会话启动时自动加载。

但注意:Memory 应该用于稳定、长期的信息,而不是临时性的任务描述。"我们正在重构订单模块"这种临时状态不应该进 Memory——它只对当前任务有效。

7. 监控上下文用量

使用 /context 命令查看当前的上下文使用情况:

/context

Claude Code 会显示当前上下文窗口的使用量、各组成部分的占比。定期检查这个数据,你能建立对上下文消耗速度的直观感觉。

一旦你建立了这种感觉,你就不再需要频繁查看——你会本能地在"感觉上下文快要溢出了"的时候执行 /compact

8. 先读再问

在提出一个复杂问题之前,先让 Claude 读取相关文件,而不是依赖它"可能记得"之前读过的内容。

# 不好:
Claude,我们之前讨论的那个 validator.ts 文件,你帮我加个 XX 验证。

# 好:
先读取 src/utils/validator.ts,然后帮我加一个 XX 验证函数。

"先读再问"确保 Claude 对文件内容的理解是基于最新内容,而不是基于可能已经被压缩或丢失的旧上下文。这个习惯在长对话中尤其重要——你无法确定 validator.ts 的内容是否仍然在上下文窗口中。

9. 善用 CLAUDE.md

CLAUDE.md 是每次对话自动加载的,不占用对话历史的上下文配额(它是在对话开始前就被加载的,占用的是固定的初始开销)。因此,适合放在 CLAUDE.md 中的信息不要放在对话指令中反复重复

# 不要每次都说的信息 → 放进 CLAUDE.md
- 项目的技术栈和架构
- 编码规范和约定
- 常用命令

# 只在当前对话中说的信息 → 放在对话指令中
- 当前任务的具体目标
- 临时的约束条件
- 特定于当前任务的偏好

第 12 章将深入讨论 CLAUDE.md 的编写策略。

实践清单

你可以把以下清单作为日常上下文管理的检查项:

□ 当前会话只处理一个主题吗?
□ 对话超过 25 轮了吗?(如果是,考虑 /compact)
□ 观察到任何上下文膨胀症状了吗?
  □ Claude 忘记了早期指令?
  □ Claude 在重复或绕圈子?
  □ Claude 忽略了最近的细节?
  □ 工具调用变得越来越不精准?
□ 如果准备执行 /clear,关键结论已保存到其他地方了吗?
□ 历史会话有清晰的名字吗?
□ 已完成的会话归档了吗?
□ Memory 中存储的信息都是长期有效的吗?

11.9 本章小结

上下文管理不是 Claude Code 的一项"高级功能"——它是有效使用 Claude Code 的基础素养。同样的 Claude Code,在懂得管理上下文的开发者手中和在不懂得管理的开发者手中,产出的质量可以是天壤之别。

核心要点

  1. 上下文窗口是有限资源。每一条消息、每一次文件读取、每一个命令输出都在消耗它。你需要像管理内存一样管理上下文
  2. Token 消耗比你想的快。英文一个单词约 1.3 token,中文一个汉字约 1.5 token。中文用户需要更加注意上下文消耗
  3. 上下文膨胀的症状很微妙。Claude 不会直接说"我上下文不够了"——它表现为忘记早期指令、重复自己、忽略细节、工具调用变模糊
  4. /compact 是日常工具,/clear 是重置按钮。前者用于释放空间同时保留关键信息,后者用于彻底的上下文切换。它们的适用场景完全不同
  5. 多会话是上下文隔离的最强工具。一个会话一个任务——不是建议,是原则。违反这一条,后续所有的管理都只是修修补补
  6. 压缩后必须恢复。/compact 之后花 1-2 轮对话确认摘要完整、补充遗漏、重新锚定任务方向——这个步骤不可省略
  7. 上下文管理是从"会用"到"用好"的关键跨越。基础篇教的是"怎么让 Claude 做事",本章教的是"怎么让 Claude 持续做好事"

与前后章节的关系

  • 第 10 章讲 Agent Loop——Claude 怎么工作。本章讲上下文——Claude 记得什么。理解 Agent Loop 能帮你预测 Claude 的行为,理解上下文能帮你预测 Claude 的行为质量
  • 第 12 章讲 CLAUDE.md——它是上下文窗口中由你完全控制的部分。读完本章,你应该已经理解 CLAUDE.md 在上下文中扮演的角色,第 12 章将教你如何最大化它的价值
  • 第 31 章(效率优化策略)将回到上下文管理的话题,从方法论层面讨论上下文预算的规划和分配

一个思维转变

很多开发者把 Claude Code 当作一个"万能答题机"——问什么答什么,答不好就再问一次。这种心态下,上下文管理变成了被动应付:溢出了就压缩,忘了就再提醒。

真正高效的用法是:把 Claude Code 当作一个会疲劳的同事。你会在同事刚上班、头脑清醒时让他处理最重要的事,会用简洁的方式沟通关键信息,会在午餐后提醒他上午讨论的重要结论。对 Claude Code 也是一样——你需要站在它的角度,思考它"能看到什么"、"记得什么"、"需要知道什么"。

这就是上下文管理的本质:不是管理 token 的数字,而是管理信息的可用性