首页 项目 博客 简历 联系 English
返回列表
2026年7月2日 约 4,485 字 预计 10 分钟读完

05:Context Management:Claude Code 如何决定这一轮看什么

上一篇讲 Memory System,重点是:哪些经验值得跨会话留下,下一次还能被 Claude Code 召回。

#Claude Code#Coding Agent#上下文工程#工程化#Agent Runtime

05:Context Management:Claude Code 如何决定这一轮看什么

上一篇讲 Memory System,重点是:哪些经验值得跨会话留下,下一次还能被 Claude Code 召回。

但记忆被保存下来,只解决了一半问题。真正到某一轮模型调用时,还要继续追问:

这些记忆、项目规则、工具结果、文件片段、历史消息,到底哪些会进入上下文?按什么顺序进入?太多时怎么处理?

这篇就看 Context Management。

这里说的上下文,范围比“聊天记录”大得多。它包括系统提示、工具描述、项目规则、memory、用户当前任务、历史消息、搜索结果、文件片段、命令输出、diff、todo、summary。Claude Code 每一轮都要把这些材料重新组织成模型能看的工作现场。

这篇的主线很简单:

  1. 哪些东西属于上下文。
  2. 这些东西大概按什么顺序进入。
  3. 上下文太多时,先压哪里,再压哪里。
  4. 平时使用 Claude Code 时,要不要主动处理上下文。

这篇文章要拆的主线:上下文到底是什么

很多时候,一说上下文管理,脑子里先冒出来的是 /compact。好像上下文管理就是窗口快满时做一次总结。

从几篇 Claude Code 源码分析资料看,compact 只是最后一层处理。更靠前的位置,还有很多细小但重要的动作:工具结果先裁剪,大文件只读必要片段,搜索结果先保留候选路径,稳定规则放在前面,动态事实放到后面,大范围探索交给隔离上下文[1],[2],[3]。

所以这篇先把问题收窄:

上下文管理,就是决定这一轮模型应该看见哪些材料,以及这些材料以什么形态出现。

这里的关键词是“这一轮”。

Claude Code 看起来像一直在连续思考,实际每次模型调用都要重新组织输入。系统提示、工具描述、项目规则、memory、历史消息和最新工具结果,会一起组成这一轮模型看到的现场。上一轮读过的文件、跑过的命令、得到的错误,也只有以某种形式进入这一轮上下文,才会影响下一步判断。

这就解释了上下文管理为什么重要。工具系统负责把事实拿回来,记忆系统负责把经验留下来,上下文管理负责决定:这些东西什么时候给模型看,给多少,放在哪里,太多时怎么压。

哪些东西属于上下文:聊天记录之外还有很多材料

Claude Code 的上下文可以先分成几类。它们的来源、稳定性和用途都不一样。

上下文材料提供什么信息稳定程度
基础行为规则Claude Code 的身份、协作方式、基础约束
工具描述有哪些工具、参数怎么写、结果怎么理解
项目规则项目命令、目录约定、代码风格、团队要求中高
memory用户偏好、项目经验、调试经验、长期交接中高
当前任务用户这一轮真正要完成什么
历史消息任务如何演变、用户补充过什么限制
工具结果搜索命中、文件片段、命令输出、测试结果
代码变更edit/write 后的 diff、已改文件、风险点
summarycompact、局部摘要、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 做代码任务时,上下文通常不会一开始就塞满整个仓库。更合理的过程是按任务逐步展开。

一轮任务可以这样看:

  1. 先看用户目标。
    这一轮到底是修 bug、改文章、重构、查原因,还是只做计划。

  2. 再看已有约束。
    包括项目规则、用户刚刚强调的限制、前文已经确定的改造方向。

  3. 用低成本方式缩小范围。
    先用目录、文件名、搜索命中、已有 todo 找候选位置。

  4. 读取少量关键片段。
    先读相关文件、相关函数、相关段落,再按需要展开更大的项目范围。

  5. 工具执行后整理证据。
    把搜索结果、命令输出、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 最核心的一节。

上下文太多时,处理顺序最好从轻到重。几篇源码分析资料里提到 snipmicrocompactcontext collapseautocompact 等压缩策略[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 按轮次追加工具结果就够了。过早清理反而会打断连续性。

长任务就要主动一点。尤其出现这些信号时,可以考虑整理上下文:

  1. 上下文占用很高。
    任务跑了很多轮,读了大量文件,测试和搜索输出堆了很多。

  2. 模型开始重复问已经说明过的事。
    这说明关键约束可能被历史噪声冲淡了。

  3. 模型引用旧状态。
    文件已经改过,但它还在按旧内容推理。

  4. 任务阶段发生变化。
    探索结束准备实现,或者实现结束准备验证,这时适合总结一次。

  5. 用户目标变过多次。
    早期要求和最新要求混在一起,容易让模型拿错优先级。

  6. 大输出进入太多。
    日志、搜索结果、长文件片段已经占据大量上下文。

处理方式也分轻重。

轻一点的做法,是重申当前目标和硬约束,要求 Claude Code 用几句话总结当前状态。再重一点,可以让它整理 todo、列出已改文件和未验证事项。到了阶段切换或上下文压力很高时,再做 compact。

这背后的原则很朴素:

平时按需打扫;一旦任务变长、噪声变多、目标变过几次,就把工作台重新收拾一下。

对我写 Agent 的启发

如果自己写一个 coding agent,上下文管理应该是独立模块,而不是藏在 prompt 拼接函数里。

我会先定义一个 context budget:

区域放什么控制方式
base context基础行为规则、工具说明尽量短,稳定加载
project context项目规则、memory 索引启动加载,按需补细节
task context当前目标、硬约束、todo每轮更新,保留最新版本
evidence context文件片段、搜索结果、命令输出、diff工具返回时先裁剪
summary contextcompact summary、阶段结论阶段切换或上下文压力高时生成
external statenotes、日志文件、任务状态可重读、可审计、可跨压缩延续

然后要设计 context router。每条信息进入上下文前,都问几个问题:

  1. 它来自哪里,是用户、工具、文件、模型总结,还是 memory?
  2. 它是否仍然新鲜?
  3. 下一步是否真的需要?
  4. 它应该放在稳定前缀,还是动态尾部?
  5. 能否用摘要替代?
  6. 完整内容在哪里能重新读取?

更重要的是压缩设计。

压缩要超出“让模型总结一下”。它应该有明确接口、触发条件和摘要结构。

工具压缩应该发生在入口处:

  • search 返回候选路径、行号、匹配片段和命中数量。
  • read_file 默认支持范围读取,完整文件按需打开。
  • run_command 返回退出码、关键错误、关键输出和完整日志位置。
  • edit 返回修改文件、变更摘要、风险点和是否触及无关内容。

会话压缩应该有固定 schema:

当前目标:
硬约束:
关键文件:
已修改内容:
验证结果:
已排除方向:
风险和未验证事项:
下一步:

触发条件也要工程化:

  • token 压力升高。
  • 阶段切换。
  • 连续大量工具输出。
  • 同类搜索重复出现。
  • 用户目标发生明显变化。
  • 准备把任务交给子任务或恢复旧任务。

压缩后还要校准:重读关键文件,检查当前 diff,重跑关键命令。这样摘要负责交接,当前事实负责纠偏。

最后,我会保留一个很小但很重要的原则:

上下文管理的目标,是让 agent 每一轮都看见下一步真正需要的东西。

参考资料

Claude Code 源码与架构分析

下一篇继续追的问题

这一篇讲的是:Claude Code 每一轮给模型看什么。

但模型看见上下文以后,还要把目标、计划、todo、阻塞点和完成条件组织起来。否则信息很多,推进过程仍然可能乱。

所以第 06 篇继续追:

Claude Code 如何把上下文里的信息整理成可执行、可追踪的任务状态?