Claude Code 会话管理与百万上下文窗口深度解析

从上下文窗口到会话管理,全面掌握 Claude Code 百万 Token 的正确使用方式

Posted by iceyao on Thursday, April 16, 2026

一、引言:百万上下文带来的新挑战

原文链接:Using Claude Code: session management and 1M context 作者:Thariq Shihipar(Anthropic 技术团队)

Claude Code 近期将上下文窗口升级到了 100 万 Token——这意味着模型在单次会话中可以"看到"远超传统编程助手的一次性上下文规模。按常见经验粗略换算,它大致可以容纳 数万行代码、长篇技术文档以及多轮工具调用结果;但真实可用空间仍会受到系统提示、工具输出和文件内容长度的共同影响。这是一个巨大的飞跃,但同时也引发了一系列新的工程问题:

  • 是否应该在一个超长会话中完成所有工作?
  • 会话变长后,模型的表现会如何变化?
  • /compact/clear/rewind 这些命令该在什么时候用?
  • 子代理(Subagent)到底解决了什么问题?

本文将从原理层面深入剖析这些问题,并提供可操作的最佳实践。

本文导读

  • 第二节 解析上下文窗口的内部结构与组成
  • 第三节 深入理解上下文腐化(Context Corruption)的机制与影响
  • 第四节 逐一拆解五种会话管理策略
  • 第五节 提供基于场景的决策模型
  • 第六节 总结实战最佳实践与进阶技巧

二、上下文窗口:你需要知道的一切

2.1 什么是上下文窗口?

上下文窗口(Context Window)是模型在生成下一个响应时能"看到"的全部信息。可以把它想象成模型的"工作记忆"——就像你在解决一个复杂问题时,桌面上能同时摊开的所有资料。

在 Claude Code 中,上下文窗口包含以下四类内容:

Claude Code 上下文窗口结构

2.2 上下文窗口的组成

组成部分 说明 典型占用
系统提示(System Prompt) 包含 CLAUDE.md 配置、工具定义、行为规则 数千~数万 Token
对话历史(Conversation History) 用户的每条消息和 Claude 的每次回复 随对话增长
工具调用及输出(Tool Calls & Outputs) read_filesearchbash 等工具的调用参数和返回结果 通常是最大消耗者
已读取的文件内容 通过工具读取的源代码、配置文件等 单个大文件可达数万 Token

让我们用一段伪代码来直观理解上下文窗口的构成:

# 概念模型:上下文窗口的组成
context_window = {
    "capacity": 1_000_000,  # 百万 Token 上限
    "components": [
        SystemPrompt(
            claude_md="项目配置与规则",
            tool_definitions=["read_file", "search", "bash", "..."],
            behavior_rules="安全规则、输出格式等"
        ),
        ConversationHistory([
            Turn(user="帮我重构 auth 模块", assistant="好的,让我先分析..."),
            Turn(user="改用 JWT 方案", assistant="了解,我来修改..."),
            # ... 每个 Turn 都占用 Token
        ]),
        ToolOutputs([
            ToolCall("read_file", "src/auth/middleware.ts", output="... 200行代码 ..."),
            ToolCall("bash", "npm test", output="... 测试输出 ..."),
            # ... 工具输出通常是最大的 Token 消耗者
        ])
    ]
}

# 关键洞察:上下文 ≠ 无限记忆
# 即使有百万 Token,也需要策略性地管理
used_tokens = sum(len(component) for component in context_window["components"])
remaining = context_window["capacity"] - used_tokens

2.3 百万 Token 到底有多大?

为了建立直观感受:

换算 大约等于
1M Token ~750,000 个英文单词
代码量 ~75,000 行代码(取决于语言)
书籍 约 3-4 本技术书的全文
对话轮次 取决于工具调用量,通常数十到数百轮

关键认知:百万 Token 虽然很大,但并不意味着你应该把它全部用完。上下文质量远比上下文数量重要。


三、上下文腐化:大上下文窗口的隐性风险

3.1 什么是上下文腐化?

上下文腐化(Context Corruption)是指随着上下文增长,模型性能逐渐下降的现象。这不是 Bug,而是 Transformer 架构的内在特性。

上下文腐化:随上下文增长的性能衰减

说明:这里展示的是一种趋势,而不是固定阈值。不同模型、任务类型、工具输出密度,都会影响上下文腐化出现的时机与程度。

3.2 腐化的技术原理

从 Transformer 的注意力机制角度理解:

# 简化的注意力机制示意
def attention(query, keys, values):
    """
    当 keys 和 values(即上下文)变得很长时:
    1. 注意力分数被更多 token 稀释
    2. 模型需要在更多信息中找到相关内容
    3. 早期的、不相关的信息开始"干扰"当前任务
    """
    scores = dot_product(query, keys) / sqrt(d_k)
    weights = softmax(scores)  # 注意力权重分散到更多 token 上
    return weighted_sum(weights, values)

# 上下文腐化的直觉理解:
# - 上下文较短时:注意力更容易集中在关键信息上
# - 上下文持续拉长时:检索相关线索和排除噪声的成本会上升
# - 当无关历史与工具输出堆积过多时:模型更容易"走神"

3.3 腐化的实际表现

在日常使用中,上下文腐化通常表现为:

  1. 遗忘早期指令:在长会话后期,模型可能忘记你在开头设定的约束
  2. 重复错误:之前已经被否定的方案可能被再次提出
  3. 混淆文件内容:读取了太多文件后,可能混淆不同文件的内容
  4. 忽略关键细节:在大量调试信息中遗漏重要的错误线索

核心洞察:上下文腐化意味着模型在接近上下文满载时,处于其"最不智能"的状态——而这恰恰是自动压缩触发的时机。这就是为什么主动管理上下文如此重要。


四、五种会话管理策略深度解析

每当 Claude 完成一个任务后,你面临一个分支决策。以下是五种核心策略的深度解析:

会话管理决策树

4.1 继续对话(Continue)

操作:直接发送下一条消息。

适用场景:当前上下文中的信息对下一个任务仍然高度相关。

# 典型场景示例
# Turn 1: 实现了一个新的 API 端点
> 帮我实现 /api/users/profile 端点

# Claude 读取了路由配置、数据模型、中间件等文件,完成了实现

# Turn 2: 为刚实现的功能编写文档(继续对话是最优选择)
> 现在帮我为这个端点编写 API 文档

# 为什么继续比新建更好?
# - Claude 已经"记住"了端点的参数、返回格式、使用的中间件
# - 启动新会话意味着要重新读取所有这些文件
# - 继续对话节省了重新加载的 Token 成本和时间

核心原则:如果下一个任务需要用到当前会话中已加载的上下文,就不要浪费它。

4.2 回退(Rewind)

操作:双击 Esc 键或运行 /rewind 命令。

适用场景:Claude 走错了方向,但之前的文件读取和分析仍然有价值。

Rewind 工作流程

这是一个非常强大但容易被忽视的功能。来看一个具体例子:

# 场景:调试一个 API 响应格式问题

# Turn 1: Claude 读取了 5 个相关文件
> 调查为什么 /api/orders 返回的日期格式不对

# Turn 2: Claude 尝试了方案 A(修改序列化器)— 但不work
# 此时你发现问题其实在数据库层

# ❌ 错误做法:
> 那个方案不行,问题在数据库层,试试修改 migration

# 问题:Turn 2 中失败方案的所有代码变更和解释
#       仍然占用上下文空间,还可能误导后续推理

# ✅ 正确做法:
# 按 Esc Esc,回退到 Turn 1 之后
# 然后用你学到的知识重新提示:
> 问题不在序列化器层,是数据库 migration 中的日期列类型不对。
> foo 模块的序列化器没有问题不用改。直接修改 migration 文件。

# 效果:
# - Turn 1 中读取的 5 个文件仍然在上下文中 ✓
# - Turn 2 的失败尝试被完全移除 ✓
# - 新的 Turn 2 从干净状态开始,带着更精确的指令 ✓

进阶技巧——“时间旅行"模式

# 在回退前,让 Claude 总结它学到的东西
> 在我回退之前,总结一下你从这次尝试中学到了什么,
> 以及你建议下一步尝试什么方案

# Claude 会输出一份总结
# 然后你 Esc Esc 回退
# 再把这份总结作为新提示的一部分发送

# 这就像收到了一封"来自未来的 Claude"的信——
# 它尝试了某个方案、失败了,然后把经验教训传回给你

4.3 压缩(/compact)

操作:运行 /compact/compact <hint>

机制:Claude 将当前对话历史总结成一段更简短的描述,然后用这个总结替换原始历史,在新的"压缩后"上下文中继续工作。

# 基本用法
/compact

# 带引导的用法(推荐)
/compact 重点保留 auth 重构相关的上下文,测试调试的部分可以丢弃

# 更具体的引导
/compact focus on the database schema changes and API contract, 
drop the CSS debugging and test fixture setup details

压缩的本质是有损的——就像 JPEG 压缩图片会丢失细节一样,对话压缩也会丢失信息。但关键区别在于:你可以通过 hint 控制"丢什么、留什么”

/compact 压缩机制

4.4 清除(/clear)

操作:运行 /clear,然后手动输入新的上下文。

机制:完全清空对话历史,从零开始新的会话。

/compact vs /clear 对比

# 典型用法
/clear

# 然后手动提供精炼的上下文:
> 我正在重构 auth 中间件。
> 约束条件:必须保持向后兼容,不能修改公开的 API 接口。
> 关键文件:src/middleware/auth.ts 和 src/models/user.ts
> 已排除的方案:直接替换 session 为 JWT(会破坏现有客户端)
> 当前进展:已完成 token 验证逻辑,接下来需要处理 refresh token 流程。

/compact vs /clear 的选择指南

维度 /compact /clear
工作量 低(自动) 高(手动编写)
上下文质量 Claude 决定重点 你决定重点
适用场景 同一任务继续深入 切换到新任务方向
腐化风险 中(可能保留无关信息) 低(你控制一切)
信息保留 可能更全面 可能遗漏重要细节

4.5 子代理(Subagent)

操作:提示 Claude 生成子代理,或者 Claude 在需要时自动调用。

机制:子代理获得一个全新的独立上下文窗口,完成工作后只将最终结论返回给父级会话。

子代理架构

关键心理测试

“我是需要这个工具调用的完整输出,还是只需要最终结论?”

如果答案是"只需要结论",那就应该使用子代理。

# 场景 1:验证工作结果
> 生成一个子代理,根据以下规范文件验证我们刚完成的 auth 重构是否符合要求

# 子代理会:读取规范文件 → 读取实现代码 → 逐条验证 → 返回验证报告
# 所有中间的文件读取和分析过程不会污染父级上下文

# 场景 2:学习另一个代码库的实现方式
> 生成一个子代理,研究 stripe-node SDK 的错误处理模式,
> 总结它的 retry 机制和 error 类型层级,
> 然后我们在自己的项目中实现类似的方案

# 场景 3:编写文档
> 根据我最近的 git changes,生成一个子代理来编写这个功能的用户文档

# 场景 4:大规模代码库搜索
> 生成一个子代理,搜索整个代码库中所有使用 deprecated API 的地方,
> 列出需要迁移的文件和具体行号

子代理的本质优势:它是一种上下文隔离机制。大量中间工作产出(文件读取、搜索结果、分析过程)被封装在子代理的上下文中,只有精炼后的结论回流到主会话。


五、场景化决策模型

5.1 综合决策表

场景 推荐策略 原因
相同任务,上下文仍然相关 继续(Continue) 上下文中的信息是关键资产,不要浪费重建成本
Claude 走错了方向 回退(Rewind) 保留有用的文件读取,删除失败尝试,用新知识重新引导
任务中途,会话充满过时的调试信息 /compact <hint> 低工作量;可引导 Claude 保留关键信息
开始全新任务 /clear 零腐化;你完全控制传递什么内容到新会话
下一步会产生大量中间输出 Subagent 中间噪声留在子级;只有结论返回

5.2 决策流程图(代码版)

def choose_session_strategy(current_state):
    """
    根据当前状态选择最优的会话管理策略
    """
    if current_state.is_new_unrelated_task:
        return "/clear"  # 新任务,干净起步
    
    if current_state.claude_went_wrong_direction:
        if current_state.has_useful_file_reads:
            return "rewind"  # 保留文件读取,删除错误尝试
        else:
            return "/clear"  # 没什么值得保留的
    
    if current_state.context_is_stale:
        if current_state.continuing_same_task:
            return "/compact"  # 压缩后继续
        else:
            return "/clear"  # 换方向了
    
    if current_state.next_step_produces_lots_of_intermediate_output:
        return "subagent"  # 隔离中间输出
    
    if current_state.context_still_relevant:
        return "continue"  # 上下文仍有价值,继续
    
    # 默认:如果不确定,倾向于 /compact
    return "/compact"

5.3 典型工作流示例

示例:全栈功能开发

全栈功能开发典型工作流


六、实战最佳实践总结

6.1 四条黄金法则

# 法则 解释
1 新任务 = 新会话 不要在一个巨大的会话中混合不相关的任务
2 回退 > 纠正 与其说"那不对,试试这个",不如回退后用更精确的指令重新开始
3 主动压缩 > 被动压缩 在你还清楚下一步方向时压缩,而不是等到自动触发
4 只需结论 → 子代理 大量中间输出会污染上下文,用子代理隔离它

6.2 避免糟糕的自动压缩

自动压缩触发的时机恰恰是模型表现最差的时候(上下文接近满载,腐化最严重)。以下策略可以避免这个问题:

# ❌ 等到自动压缩被触发(模型此时最不智能)
# 会话越来越长... 突然自动压缩触发
# 压缩结果可能很糟糕,因为模型无法预测你的下一步

# ✅ 主动在"关键转折点"压缩
# 完成一个子任务后:
/compact 保留数据库 schema 变更和 API 接口定义,
调试 CSS 的部分和 test fixture 的设置细节可以丢弃,
接下来我要做前端组件

# ✅ 或者在任务切换前清除
/clear
# 然后提供精炼的上下文简报

6.3 /usage 命令:了解你的消耗

Claude Code 新增的 /usage 命令可以帮助你了解当前的 Token 使用情况:

# 查看当前会话的使用情况
/usage

# 你可以据此判断:
# - 当前会话是否已经堆积了太多文件读取和工具输出
# - 下一步是否还会引入大量新上下文
# - 此时是继续、压缩、清空,还是交给子代理更合适

6.4 上下文管理命令速查表

命令 快捷键 功能 使用时机
/usage - 查看 Token 使用情况 随时检查
/rewind Esc Esc 回退到之前的消息 Claude 走错方向
/compact - 压缩当前会话 上下文过时或过满
/compact <hint> - 带引导的压缩 精确控制保留内容
/clear - 清除并开始新会话 切换到全新任务

七、结语:像管理内存一样管理上下文

如果把 Claude Code 的上下文窗口类比为计算机内存,那么:

  • 继续对话 = 继续使用当前内存中的数据
  • Rewind = 回滚到之前的内存快照
  • Compact = 垃圾回收(GC),自动释放不需要的内存
  • Clear = 手动清空内存并重新初始化
  • Subagent = 在独立的进程空间中运行任务,只通过 IPC 传回结果
# 类比:上下文管理 ≈ 内存管理
class ContextManager:
    """管理 Claude Code 会话的上下文,就像管理内存一样"""
    
    capacity = 1_000_000  # 百万 Token
    
    def continue_session(self):
        """最高效——直接复用现有上下文"""
        pass  # 不做任何清理,继续使用
    
    def rewind(self, checkpoint):
        """回滚到检查点——保留有用数据,丢弃错误尝试"""
        self.state = self.snapshots[checkpoint]
    
    def compact(self, hint=None):
        """垃圾回收——压缩但有损"""
        summary = self.summarize(self.history, focus=hint)
        self.history = summary  # 用总结替换历史
    
    def clear(self, briefing):
        """硬重置——零腐化但需要手动重建"""
        self.history = []
        self.add(briefing)  # 用你的简报作为新起点
    
    def spawn_subagent(self, task):
        """独立进程——中间状态不影响主上下文"""
        child = ContextManager()  # 全新上下文
        result = child.execute(task)
        return result.summary  # 只返回结论

百万上下文窗口是一个强大的工具,但强大不等于可以无脑使用。掌握会话管理策略的开发者,能够让 Claude Code 始终保持在最佳性能状态,而不是在上下文腐化中逐渐失控。

记住:最好的上下文管理是主动的——不要等到模型表现下降才想起来清理。就像写高性能程序一样,最好的内存管理不是依赖 GC,而是在架构层面就避免内存泄漏

「真诚赞赏,手留余香」

爱折腾的工程师

真诚赞赏,手留余香

使用微信扫描二维码完成支付