跳到正文
FunCoding
返回博客
上下文

上下文工程,管好模型每一步看到的东西

上下文窗口越来越大,塞得越满,模型反而越容易犯糊涂。上下文工程管的是智能体每一步能看到什么。本文结合 Chroma、Anthropic 和 Manus 公开的研究与经验,讲上下文为什么会越用越差,以及压缩、即时检索、外部记忆和子智能体隔离各适合什么情况。

阅读约需 8 分钟

#上下文#Agent 工程

本页目录

2025 年 7 月,向量数据库公司 Chroma 发了一份技术报告,测了 18 个模型,包括 GPT-4.1、Claude 4、Gemini 2.5 和 Qwen3。任务很简单,在一大段文字里找出一句指定的话,或者回答跟这句话有关的问题。结论是输入越长,表现越不稳定,所有实验里都能看到下滑,任务再简单也一样。

报告里有两个结果挺反直觉。往文本里加一句和答案相似、但不对的干扰句,正确率就会下降,加四句降得更多。另一个是把背景文字的句子随机打乱,模型反而答得比读通顺的原文更好。Chroma 给这个现象起了个名字,叫 context rot,上下文腐烂。

用编程智能体久了,多半见过它的样子。让智能体修一个 bug,前十分钟它表现很好。一个小时后它开始重复读同一个文件,忘了你最早说过不要改公共接口,还把已经否掉的方案又拿出来试一遍。这一个小时里,几十次文件读取、命令输出和报错日志都堆进了对话历史,你开头那几句约束早就埋在十几万个 token 中间。

上下文工程要解决的就是这个,让模型在每一步看到的内容尽量恰好够用。

窗口里装着什么

模型没有记忆,每次生成只能依靠这次调用传进去的 token,这些 token 就是上下文。编程智能体的上下文一般由下面几部分组成。

组成部分举例什么时候进入
系统提示词智能体产品自带的行为规范每次都有
工具定义读文件、跑命令、各个 MCP 工具的名称和参数每次都有
项目说明CLAUDE.md、AGENTS.md会话开始时
Skill 摘要每个 Skill 的名称和描述会话开始时
对话历史你说的话、它的回复一直累积
工具调用结果读到的文件、命令输出、搜索结果一直累积,通常占大头
按需加载的内容触发了的 Skill 全文、子目录的规则用到时

提示词工程关心的是其中一两行。上下文工程要管整张表,每一行占多少,什么时候进来,什么时候该出去。

Anthropic 在 2025 年 9 月的《Effective context engineering for AI agents》里,把上下文看成一笔有限的注意力预算。Transformer 里每个 token 都要和其他所有 token 建立关联,token 越多,关联越多,分到每条关联上的注意越稀。窗口装得下,不代表模型用得好。

第一种办法,把历史变短

对话快到上限时,把前面的历史总结成一份摘要,用摘要替换原文继续干活。Claude Code 的 /compact 做的就是这件事,接近上限时它也会自动压缩。

压缩难在取舍。摘要太狠,后面才发现重要的细节就丢了;太保守,又省不下多少空间。还没做完的任务、已经做出的决定和否掉的方案、用户给的约束,这些要留。处理完的工具输出、中间试错的过程,可以丢。文件内容也可以丢,留下路径,需要时重新读。

自动压缩只能猜什么重要,你自己更清楚。所以在一个阶段做完、开始下一阶段之前,主动压缩一次效果更好。Claude Code 的压缩命令可以带一句话说明保留什么,比如只保留认证模块重构的结论和剩下的待办。

更轻的一种做法是清理旧的工具结果。一个文件读过、改完了,完整内容就没必要一直留着。Anthropic 在 API 里提供了这个功能,叫上下文编辑。按他们 2025 年 9 月公布的内部评估,在一个 100 轮的网页搜索任务里,上下文编辑让 token 消耗降低了 84%,配合记忆工具,任务表现比基线高了 39%。

第二种办法,用到时再去读

很多早期的系统会先把可能相关的资料一次检索出来,塞进上下文,再让模型开始干活。问题是开始前很难判断哪些相关,要么漏了,要么塞了一堆没用的。

现在的编程智能体大多是用到时再读。上下文里只放线索,比如文件路径、函数名、文档链接,需要时由模型自己调用工具去取。Claude Code 不会在一开始把整个代码库读进来,它用 grep 和 glob 一步步定位,只读真正需要的几个文件。这和人类工程师差不多,代码库没人背得下来,大概知道在哪,要用时去查。

代价是工具调用变多,速度慢一些。好处是上下文一直比较干净,读到的也总是最新的文件,没有索引过期的问题。

这种方式对工具的设计有要求。读文件时最好能指定行范围,搜索结果要有数量上限,返回的格式要对模型友好。带行号的代码比纯文本好定位,精简过的 JSON 比原样转发的完整 API 响应好理解。一次查询返回五十个字段、两百条记录,模型只用得上其中三个字段的十条,这样的工具每调用一次,窗口就被灌一次水。

第三种办法,写到窗口外面

窗口里的东西会话一结束就没了,压缩时也会被总结掉。要长期保留的信息,应该写到窗口外面,需要时再读回来。

项目说明文件是最基本的一种。CLAUDE.md、AGENTS.md 每次会话自动加载,压缩后也会重新加载,适合放每次都要知道的事实。

长任务里还可以让智能体维护一份进度文件。Manus 的联合创始人季逸超在 2025 年 7 月写过他们的经验,一个典型的 Manus 任务要调用大约 50 次工具,智能体会建一个 todo.md,做完一项勾一项。这样做除了记进度,还有一个作用。每次重写清单,目标就被写到了上下文的末尾,模型最近注意到的位置。任务一长,模型容易跑偏,或者忽略中间的信息,这个办法能缓解一些。他们管这个叫复述。

文件系统本身也是一种外部记忆。Manus 那篇文章把它当成无限大、能持久保存的上下文来用,日志存成文件,用到时 grep 需要的几行。他们还强调压缩要能还原,网页内容可以从上下文里拿掉,只要 URL 还在;文档可以拿掉,只要沙箱里的路径还在。

外部记忆也会坏。一个只追加、从不整理的记忆文件,最后会和膨胀的上下文一样难用。

第四种办法,把脏活交给别的窗口

有些工作天生会产生大量上下文。在大代码库里找某个功能的实现可能要读几十个文件,调研一个技术问题可能要翻十几个网页。这些都在主会话里做,主窗口很快会被中间结果占满。

子智能体就是为这个准备的。主智能体把子任务交给一个有独立窗口的子智能体,它在自己的窗口里读文件、试错、探索,最后只交回一份几百字的结论。

主智能体,窗口保持干净
  │
  ├─→ 子智能体 A:找出所有调用 createUser 的地方
  │     在自己的窗口里搜索、读文件
  │     ←─ 返回:共 7 处,分别在……
  │
  └─→ 子智能体 B:查这个库 v3 的迁移指南
        在自己的窗口里搜索、读网页
        ←─ 返回:主要变化有三点……

这是用 token 换质量。子智能体花掉的总 token 更多,主智能体的上下文保持干净,判断更准。

它也有代价。子智能体看不到主会话的背景,交给它的任务描述得自己说得清楚;它带回的结论有错,主智能体也很难核实。所以适合交出去的是边界清楚、结果容易描述的活,比如搜索、调研、独立模块的评审。互相牵扯、需要大量共同背景的工作,留在主会话里做更稳。

几个用得上的习惯

一个任务开一个会话,这是最省事的一条。修完一个 bug 再开新会话做下一件,前一个任务的上下文对后一个只有干扰。

方向走错了,退回去往往比在对话里纠正有效。错误的尝试一直留在上下文里,会持续影响它。Claude Code 有 /rewind 和检查点,可以退回出错之前,带着新的说明重来。Manus 的经验在这一点上看起来相反,他们建议把失败的操作和报错留在上下文里,让模型看到这条路走不通,别再重复。两者其实适用的情况不同。智能体自己试错时,报错是有用的信息;整体方向被带偏时,留着那段历史只会让它继续偏。

大块输出要防着点。测试只看失败的用例,日志用 tail 或 grep,大文件指定行范围读。一次几万行的命令输出,就能吃掉窗口的一大块。

MCP Server 别连太多。每个 Server 都会把它的工具定义放进上下文,连十几个、上百个工具,光工具定义就占掉几万 token,模型还会在相似的工具之间选错。Claude Code 现在默认开启工具搜索,会话开始只加载工具名,用到时再取完整定义,可以缓解这个问题。

自己搭智能体的话,尽量让上下文开头那部分保持不变,只在末尾追加。Manus 那篇文章把缓存命中率说成生产环境里最重要的一个指标。他们的任务输入和输出的 token 比大约是 100 比 1,用 Claude Sonnet 时,命中缓存的输入每百万 token 0.3 美元,没命中是 3 美元,差了十倍。系统提示词开头放一个精确到秒的时间戳,缓存就全废了。需要临时禁用某个工具时,他们也不把它从列表里删掉,改成在解码时屏蔽,原因同样是保住缓存。

这一层管不了的事

上下文工程能决定模型这一步看到什么,管不了它能做什么。窗口里写着不要删除生产数据,和系统层面根本不给它删除权限,是两回事。关键信息只在某个同事脑子里,或者在一个没接入的系统里,检索策略再好也找不到。模型看到了全部正确的信息,写出来的代码仍然可能有 bug。

把知识放到智能体读得到的地方,用权限和沙箱约束它的行为,用自动检查验证结果,这些属于模型外面那套系统,见 Harness 工程。

参考资料

  • Agent 工程

    从提示词到 Loop,AI 编程的四层工程

    提示词工程、上下文工程、Harness 工程、Loop 工程,三年里先后流行起来。它们管的是同一件事的四层,外层包着内层,新词出现时旧的那层照样要做。本文顺着时间讲每一层为什么出现、各管什么、精力先放在哪。

    阅读约需 7 分钟

  • Harness

    Harness 工程,模型外面的那套系统

    同一个模型放进不同的智能体里,表现可以差很多,差别在模型外面那套系统。本文从 Mitchell Hashimoto 的「每个错误只犯一次」和 OpenAI、Anthropic 公开的经验讲起,介绍 harness 由哪些部分组成,以及用现成的编程智能体时能在哪里下功夫。

    阅读约需 7 分钟