05:Context Management:Claude Code 如何决定这一轮看什么
上一篇讲 Memory System,重点是:哪些经验值得跨会话留下,下一次还能被 Claude Code 召回。
05:Context Management:Claude Code 如何决定这一轮看什么
上一篇讲 Memory System,重点是:哪些经验值得跨会话留下,下一次还能被 Claude Code 召回。
但记忆被保存下来,只解决了一半问题。真正到某一轮模型调用时,还要继续追问:
这些记忆、项目规则、工具结果、文件片段、历史消息,到底哪些会进入上下文?按什么顺序进入?太多时怎么处理?
这篇就看 Context Management。
这里说的上下文,范围比“聊天记录”大得多。它包括系统提示、工具描述、项目规则、memory、用户当前任务、历史消息、搜索结果、文件片段、命令输出、diff、todo、summary。Claude Code 每一轮都要把这些材料重新组织成模型能看的工作现场。
这篇的主线很简单:
- 哪些东西属于上下文。
- 这些东西大概按什么顺序进入。
- 上下文太多时,先压哪里,再压哪里。
- 平时使用 Claude Code 时,要不要主动处理上下文。

这篇文章要拆的主线:上下文到底是什么
很多时候,一说上下文管理,脑子里先冒出来的是 /compact。好像上下文管理就是窗口快满时做一次总结。
从几篇 Claude Code 源码分析资料看,compact 只是最后一层处理。更靠前的位置,还有很多细小但重要的动作:工具结果先裁剪,大文件只读必要片段,搜索结果先保留候选路径,稳定规则放在前面,动态事实放到后面,大范围探索交给隔离上下文[1],[2],[3]。
所以这篇先把问题收窄:
上下文管理,就是决定这一轮模型应该看见哪些材料,以及这些材料以什么形态出现。
这里的关键词是“这一轮”。
Claude Code 看起来像一直在连续思考,实际每次模型调用都要重新组织输入。系统提示、工具描述、项目规则、memory、历史消息和最新工具结果,会一起组成这一轮模型看到的现场。上一轮读过的文件、跑过的命令、得到的错误,也只有以某种形式进入这一轮上下文,才会影响下一步判断。
这就解释了上下文管理为什么重要。工具系统负责把事实拿回来,记忆系统负责把经验留下来,上下文管理负责决定:这些东西什么时候给模型看,给多少,放在哪里,太多时怎么压。
哪些东西属于上下文:聊天记录之外还有很多材料
Claude Code 的上下文可以先分成几类。它们的来源、稳定性和用途都不一样。
| 上下文材料 | 提供什么信息 | 稳定程度 |
|---|---|---|
| 基础行为规则 | Claude Code 的身份、协作方式、基础约束 | 高 |
| 工具描述 | 有哪些工具、参数怎么写、结果怎么理解 | 高 |
| 项目规则 | 项目命令、目录约定、代码风格、团队要求 | 中高 |
| memory | 用户偏好、项目经验、调试经验、长期交接 | 中高 |
| 当前任务 | 用户这一轮真正要完成什么 | 中 |
| 历史消息 | 任务如何演变、用户补充过什么限制 | 中 |
| 工具结果 | 搜索命中、文件片段、命令输出、测试结果 | 低 |
| 代码变更 | edit/write 后的 diff、已改文件、风险点 | 低 |
| summary | compact、局部摘要、subagent 返回摘要 | 中 |
| 外部状态 | todo、notes、临时报告、任务状态文件 | 中 |
这张表里最容易被低估的是工具描述和工具结果。
工具描述本身会进入模型输入。模型能否正确调用工具,和工具描述、参数 schema、风险说明、输出格式有关。第 02 篇讲工具系统时已经说过,工具描述会把工具从函数列表变成模型和真实项目之间的行动协议。
工具结果也会快速吃掉上下文。一次搜索可能返回几十个命中;一次测试可能输出几千行日志;一次构建失败可能带出一串堆栈。它们都有价值,但价值集中在少数位置:路径、行号、错误类型、失败用例、关键堆栈、复现命令。
Memory 也在这里变成“上下文来源”。第 04 篇讲的是记忆如何写入和召回,这一篇只关心它进入模型时的形态:它可能是一个短索引,也可能是被按需读取的 topic file,还可能是 compact 后重新注入的项目规则。记忆保存得再好,进入上下文时仍然要接受预算和顺序管理。
这些内容按什么顺序进入:稳定的在前,动态的在后
上下文的顺序有工程含义。
大致可以理解成这样:
基础行为规则
-> 工具描述
-> 项目规则 / memory 索引
-> 当前任务
-> 历史消息
-> 工具结果 / 最新观察
-> summary / compact 后的任务状态
前面的内容负责稳定行为,后面的内容负责当前事实。
基础行为规则和工具描述通常更稳定。它们告诉模型自己在什么模式下工作、能用哪些工具、工具应该怎样调用。项目规则和 memory 也偏稳定,但会随着目录、任务和会话状态变化。用户当前任务、历史消息、工具结果、命令输出、diff 则更动态,通常出现在后面。
这和几篇资料里提到的 stable / dynamic boundary 对得上。稳定前缀越少变化,prompt caching 越容易发挥作用;动态尾部越干净,新增成本越可控[2][3]。
这里先把 prompt caching 放在上下文结构里看。对写 agent 的人来说,它传递出的设计原则更重要:
稳定内容尽量稳定,动态事实尽量追加,高噪声材料先整理再进入。
如果项目规则、工具描述、系统行为每一轮都大幅变化,模型看到的行为边界也会飘。反过来,如果把大日志、大文件、大搜索结果都直接放到尾部,模型虽然“看见”了很多东西,却更难抓住下一步最有用的证据。
所以,上下文顺序有点像给模型分层:前面告诉它“按什么规则行动”,后面告诉它“这一步发生了什么”。
每一轮怎样选择上下文:先看目标,再补证据
Claude Code 做代码任务时,上下文通常不会一开始就塞满整个仓库。更合理的过程是按任务逐步展开。
一轮任务可以这样看:
-
先看用户目标。
这一轮到底是修 bug、改文章、重构、查原因,还是只做计划。 -
再看已有约束。
包括项目规则、用户刚刚强调的限制、前文已经确定的改造方向。 -
用低成本方式缩小范围。
先用目录、文件名、搜索命中、已有 todo 找候选位置。 -
读取少量关键片段。
先读相关文件、相关函数、相关段落,再按需要展开更大的项目范围。 -
工具执行后整理证据。
把搜索结果、命令输出、diff、测试结果变成下一轮能用的事实。
这个顺序的好处是,模型每一步都有依据。
在大仓库里,这个选择更重要。更小的启动目录、局部规则、按需读取、生成文件排除,都在减少无关材料进入主上下文。资料里提到 Claude Code 会围绕 live repo context、专用 Grep/Glob/LSP、延迟工具加载等机制做上下文治理[2],[3]。正文不展开这些实现细节,只取它背后的工程思路:先确定边界,再展开细节。
工具结果进入上下文前要先变成证据
工具结果是上下文膨胀最快的来源。
第 02 篇讲过,工具系统让 agent 能读文件、搜代码、跑命令、改文件。到了上下文管理这里,要继续问:这些工具结果要原样给模型看吗?
多数时候,更好的做法是先把结果变成证据。
| 工具结果 | 适合进入主上下文的形态 |
|---|---|
| 搜索结果 | 候选路径、行号、匹配片段、命中数量 |
| 文件读取 | 有范围的片段、关键符号、必要上下文 |
| 命令输出 | 退出码、关键错误、关键 stdout/stderr、完整日志位置 |
| 测试结果 | 失败测试、断言信息、报错文件、复现命令 |
| diff | 修改文件、变更意图、风险点、是否触及无关内容 |
长日志和大文件尤其适合这样处理。
比如测试输出有 3000 行,主上下文里真正需要的可能只有:
- 哪个测试失败。
- 失败断言是什么。
- 报错文件和行号。
- 复现命令是什么。
- 完整日志存在哪里。
这样模型下一轮能继续判断,也不会被无关输出淹没。Kubesimplify 的分析里提到 large tool result persistence 这类思路:大结果可以持久化,模型只拿 preview 或摘要[2]。这点很适合放到自己写 agent 时借鉴。
这也是“先压工具结果,再压会话历史”的原因。工具结果在进入主上下文前先整理好,后面 compact 的压力会小很多。
上下文太多时怎么办:先压工具结果,再压会话历史
这是 Context Management 最核心的一节。
上下文太多时,处理顺序最好从轻到重。几篇源码分析资料里提到 snip、microcompact、context collapse、autocompact 等压缩策略[1],[3],[5]。这些术语作为资料锚点即可,正文可以翻译成四层动作:
1. 工具压缩:先把入口变窄
这是最便宜的一层。
搜索结果只留候选路径和片段;长文件只读必要范围;测试日志只留失败点;命令输出只保留退出码、关键错误和完整日志位置;diff 只保留变更摘要和风险。
这层压缩越早做,主上下文越干净。
2. 外部化:把长状态放到上下文外
有些信息后面还要用,但每轮都放进模型很浪费。
比如阶段结论、长日志、临时调研报告、todo、任务状态,可以放到外部文件或结构化状态里。主上下文只保留索引和下一步。需要时再重新读取。
这和第 04 篇 memory 的边界也有关:长期有效的经验可以沉淀为 memory;当前任务交接更适合放在 todo、notes 或 compact summary 里;下一篇 Planning & Task State 会继续讲显式任务状态。
3. 隔离:把高噪声探索留在主线外
大范围搜索、长文档阅读、日志分析,常常是“大量输入 + 少量结论”的任务。
这类任务适合放到子上下文或 subagent 里。主线只接收短摘要、证据路径、风险和建议下一步。第 11 篇会专门讲 subagent,这里只强调它在上下文管理里的价值:隔离噪声。
一个好的子任务返回结果,应该像这样:
- 结论是什么。
- 证据在哪些文件或日志里。
- 哪些方向已经排除。
- 有什么风险。
- 主线下一步该读哪里或改哪里。
只有结论、没有证据路径的摘要,会让主线很难继续验证。
4. 会话压缩:把聊天历史压成任务状态
最后才是会话级 compact。
它适合发生在两个时机:上下文接近上限,或者任务完成一个阶段,准备进入下一阶段。compact 的目标,是把原来的执行轨迹压成可继续工作的任务状态。
好的 compact summary 至少要保留这些字段:
| 摘要字段 | 为什么要保留 |
|---|---|
| 当前目标 | 防止任务方向漂移 |
| 硬约束 | 保留用户明确要求和禁止事项 |
| 关键文件 | 后续可以重读当前事实 |
| 已修改内容 | 知道代码或文章已经变到哪里 |
| 验证结果 | 继续判断是否完成 |
| 已排除方向 | 减少重复试错 |
| 风险和未验证事项 | 给下一轮留提醒 |
| 下一步 | 让任务能接着走 |
Sabrina 的分析提醒了 compact 的一个风险:压缩会把来源边界变模糊,原来分别来自用户、工具、模型推断、文件内容的信息,被压进同一段摘要后,后续模型可能难以区分[4]。
所以 compact 后最好做一次校准:重读关键文件,看当前 diff,必要时重跑关键命令。摘要是交接文档,文件系统和命令结果才是当前事实。

平时要不要处理上下文:看任务长度和噪声程度
日常用 Claude Code 时,不需要每个小任务都手动管理上下文。
短任务通常顺其自然。比如改一个小 bug、调整一段文案、查一个函数调用,Claude Code 按轮次追加工具结果就够了。过早清理反而会打断连续性。
长任务就要主动一点。尤其出现这些信号时,可以考虑整理上下文:
-
上下文占用很高。
任务跑了很多轮,读了大量文件,测试和搜索输出堆了很多。 -
模型开始重复问已经说明过的事。
这说明关键约束可能被历史噪声冲淡了。 -
模型引用旧状态。
文件已经改过,但它还在按旧内容推理。 -
任务阶段发生变化。
探索结束准备实现,或者实现结束准备验证,这时适合总结一次。 -
用户目标变过多次。
早期要求和最新要求混在一起,容易让模型拿错优先级。 -
大输出进入太多。
日志、搜索结果、长文件片段已经占据大量上下文。
处理方式也分轻重。
轻一点的做法,是重申当前目标和硬约束,要求 Claude Code 用几句话总结当前状态。再重一点,可以让它整理 todo、列出已改文件和未验证事项。到了阶段切换或上下文压力很高时,再做 compact。
这背后的原则很朴素:
平时按需打扫;一旦任务变长、噪声变多、目标变过几次,就把工作台重新收拾一下。
对我写 Agent 的启发
如果自己写一个 coding agent,上下文管理应该是独立模块,而不是藏在 prompt 拼接函数里。
我会先定义一个 context budget:
| 区域 | 放什么 | 控制方式 |
|---|---|---|
| base context | 基础行为规则、工具说明 | 尽量短,稳定加载 |
| project context | 项目规则、memory 索引 | 启动加载,按需补细节 |
| task context | 当前目标、硬约束、todo | 每轮更新,保留最新版本 |
| evidence context | 文件片段、搜索结果、命令输出、diff | 工具返回时先裁剪 |
| summary context | compact summary、阶段结论 | 阶段切换或上下文压力高时生成 |
| external state | notes、日志文件、任务状态 | 可重读、可审计、可跨压缩延续 |
然后要设计 context router。每条信息进入上下文前,都问几个问题:
- 它来自哪里,是用户、工具、文件、模型总结,还是 memory?
- 它是否仍然新鲜?
- 下一步是否真的需要?
- 它应该放在稳定前缀,还是动态尾部?
- 能否用摘要替代?
- 完整内容在哪里能重新读取?
更重要的是压缩设计。
压缩要超出“让模型总结一下”。它应该有明确接口、触发条件和摘要结构。
工具压缩应该发生在入口处:
search返回候选路径、行号、匹配片段和命中数量。read_file默认支持范围读取,完整文件按需打开。run_command返回退出码、关键错误、关键输出和完整日志位置。edit返回修改文件、变更摘要、风险点和是否触及无关内容。
会话压缩应该有固定 schema:
当前目标:
硬约束:
关键文件:
已修改内容:
验证结果:
已排除方向:
风险和未验证事项:
下一步:
触发条件也要工程化:
- token 压力升高。
- 阶段切换。
- 连续大量工具输出。
- 同类搜索重复出现。
- 用户目标发生明显变化。
- 准备把任务交给子任务或恢复旧任务。
压缩后还要校准:重读关键文件,检查当前 diff,重跑关键命令。这样摘要负责交接,当前事实负责纠偏。
最后,我会保留一个很小但很重要的原则:
上下文管理的目标,是让 agent 每一轮都看见下一步真正需要的东西。
参考资料
Claude Code 源码与架构分析
-
[1] 《驾驭工程:从 Claude Code 源码到 AI 编码最佳实践》
本文主要参考它关于自动压缩、snip、microcompact、collapse、autocompact等分层压缩的分析。 -
[2] Kubesimplify - What Claude Code’s Leaked Source Teaches About AI Agents
本文主要参考它关于 prompt cache break detection、large tool result persistence、工具结果持久化和上下文成本的分析。 -
[3] Engineer’s Codex - Diving into Claude Code’s Source Code Leak
本文主要参考它关于 live repo context loading、stable/dynamic prompt boundary、专用搜索工具和 context compaction 的分析。 -
[4] Sabrina.dev - Comprehensive Analysis of Claude Code Source Leak
本文主要参考它关于上下文压缩、strip 逻辑和 compact 后来源边界风险的分析。 -
[5] Ken Huang - Claude Code Pattern 6: Context Management at Scale
本文主要参考它对 context collapse、snip compaction、micro-compaction、autocompact 的分类。 -
[6] Zane Chen - Learn From Claude Code: Context Compaction
本文主要参考它关于 compact 后如何保留继续工作信息的分析。
下一篇继续追的问题
这一篇讲的是:Claude Code 每一轮给模型看什么。
但模型看见上下文以后,还要把目标、计划、todo、阻塞点和完成条件组织起来。否则信息很多,推进过程仍然可能乱。
所以第 06 篇继续追:
Claude Code 如何把上下文里的信息整理成可执行、可追踪的任务状态?