一文搞懂 Context Engineering:为什么 AI 聊得越久,越容易跑偏?
一文搞懂 Context Engineering:为什么 AI 聊得越久,越容易跑偏?
一、问题从哪里来?
假设你正在使用一个 AI 编程助手开发项目。
你告诉它项目使用 Python、FastAPI 和 MySQL。接下来,它帮你阅读代码、修改文件、运行测试、修复 Bug。
一开始,它表现得很好。但随着任务推进,你可能发现:
- 它忘记了之前确定的技术方案。
- 它反复尝试已经失败的方法。
- 它开始忽略你的要求,甚至修改不相关的代码。
奇怪的是,模型并没有变,为什么表现却越来越差?
问题可能出在上下文(Context)上。
在复杂的 Agent 任务中,模型不仅要处理用户指令,还要处理对话历史、工具返回结果、错误日志等大量信息。
这些信息不断累积,可能让真正重要的内容淹没在噪声中。
如何解决这个问题?这就需要上下文工程(Context Engineering)。
二、什么是上下文工程?
先理解两个容易混淆的概念。
提示词工程(Prompt Engineering) 关注的是如何把问题描述清楚,让模型更容易给出正确答案。
上下文工程(Context Engineering) 关注的则是:模型在每次推理时,究竟应该看到哪些信息?
可以用一个简单的比喻理解:
假设 LLM 是一名员工。
提示词工程负责告诉他任务是什么;上下文工程则负责准备任务资料,决定哪些文件应该放在他的办公桌上,哪些文件应该归档,哪些过时的信息应该清理。
因此,上下文工程的核心目标是:
在正确的时间,将正确的信息,以合适的形式提供给模型。
这里还有一个重要概念:上下文窗口(Context Window)。
上下文窗口决定了模型一次推理能够处理多少 Token。但窗口越大,并不意味着模型一定表现越好。
当上下文变得冗长、混乱时,模型可能难以准确定位关键信息。这类长上下文带来的性能退化现象,通常被称为 Context Rot(上下文腐烂)。
它并不是说上下文越长,性能就一定越差,而是提醒我们:信息的质量和组织方式,与信息的数量同样重要。
三、Agent 的上下文包含什么?
一个典型的 Agent,其上下文通常包含四类信息。
| 类型 | 作用 | 示例 |
|---|---|---|
| 指令上下文 | 告诉模型应该做什么 | System Prompt、行为规则 |
| 知识上下文 | 提供任务所需的知识 | 检索文档、项目资料 |
| 工具上下文 | 告诉模型如何使用工具 | 工具定义、调用结果 |
| 历史上下文 | 记录之前发生了什么 | 对话历史、执行记录 |
例如,一个编程 Agent 在修复 Bug 时,可能同时需要知道用户的修复要求、项目代码、可用的终端工具,以及此前测试失败的原因。
但问题在于:这些信息并不需要始终全部存在于上下文中。
于是,我们需要一套机制来管理它们。
四、上下文工程的四大核心策略
目前,Agent 系统中有四种非常重要的上下文管理思路。
1. Offloading:上下文卸载
核心思想:用外部存储代替长期占用上下文窗口。
假设 Agent 读取了一份很长的技术文档。
它没有必要始终把完整文档放在上下文中。更合理的方式是将文档保存在文件系统中,只留下路径和必要的摘要。
当需要查询具体内容时,再重新读取。
这就像电脑内存不够时,不会要求所有文件都常驻内存,而是把文件放在硬盘中,按需加载。
2. Retrieval:上下文检索
核心思想:需要什么,就检索什么。
例如,用户让编程 Agent 修改登录功能。
Agent 没必要阅读整个代码仓库,而是可以先搜索 login、auth 等关键词,再读取相关代码文件。
这就是按需检索(Just-in-time Retrieval)。
它与 RAG 有相似之处,但在 Agent 系统中,检索往往是执行过程的一部分:Agent 可以根据中间结果,主动决定下一步需要什么信息。
3. Isolation:上下文隔离
核心思想:不同任务使用不同的上下文,避免相互干扰。
假设一个系统中有三个 Agent:
- 搜索 Agent:负责收集资料。
- 编码 Agent:负责修改代码。
- 测试 Agent:负责运行测试。
它们不需要共享所有执行历史。
搜索 Agent 可以只向编码 Agent 传递相关资料;编码 Agent 只需要向测试 Agent 提供修改内容和测试要求。
通过这种方式,每个 Agent 都能专注于自己的任务,减少无关信息带来的干扰。
4. Compaction:上下文压缩
核心思想:当上下文过长时,保留关键信息,清理冗余内容。
例如,Agent 已经执行了几十轮操作。
此时,可以把之前的执行过程整理成一份简短的摘要:
- 当前任务目标是什么?
- 已经完成了哪些工作?
- 哪些方案尝试失败了?
- 还有哪些问题没有解决?
然后使用这份摘要继续执行任务,而不必始终携带完整历史。
需要注意:压缩不只是缩短文本,更重要的是保留未来执行任务仍然需要的信息。
五、上下文管理不当,会出现什么问题?
除了上下文过长,信息本身的质量也可能影响 Agent。
常见的失效模式有四种:
| 失效模式 | 具体表现 |
|---|---|
| Context Poisoning(中毒) | 错误信息进入上下文,导致后续持续做出错误判断 |
| Context Distraction(分心) | 历史信息过多,干扰当前任务 |
| Context Confusion(混淆) | 无关信息或过多工具使模型难以做出正确选择 |
| Context ***(冲突) | 不同阶段的信息相互矛盾,导致决策混乱 |
例如,Agent 曾经错误地判断一个文件不存在。如果这个错误结论被反复写入摘要,后续 Agent 就可能一直基于错误前提进行推理。
因此,上下文工程不仅要控制信息数量,还要关注信息的正确性、相关性与时效性。
六、上下文与记忆有什么区别?
学习 Agent 时,经常会遇到另一个概念:Agent Memory(记忆系统)。
它和上下文工程有什么关系?
可以用计算机中的内存与硬盘来类比。
| 对比 | Context | Memory |
|---|---|---|
| 类比 | 工作内存 | 持久化存储 |
| 主要作用 | 为当前推理提供信息 | 保存需要长期使用的信息 |
| 容量 | 受到上下文窗口限制 | 取决于外部存储系统 |
| 使用方式 | 直接提供给模型 | 通常需要检索后加载 |
| 生命周期 | 随推理请求构建 | 可以跨会话保留 |
举个例子:
你曾经告诉 Agent,项目统一使用 TypeScript。
Memory 可以长期保存这个技术偏好。
当你下次要求 Agent 编写代码时,上下文工程负责判断是否需要读取这条记忆,并将其加入当前上下文。
因此,可以这样理解:
Memory 负责保存信息,Context Engineering 负责决定当前应该使用哪些信息。
两者相互配合,但并不是同一个概念。
七、工程实践:如何设计一个更可靠的 Agent?
理解这些概念后,我们再回到最开始的编程 Agent。
假设用户要求:
“修复项目中的登录 Bug,并确保所有测试通过。”
一个具备上下文管理能力的 Agent,可以这样工作:
第一步:加载必要信息。
读取用户要求、项目规范,以及与登录功能相关的代码,而不是直接加载整个仓库。
第二步:执行任务并记录状态。
修改代码、运行测试,将关键错误信息和已完成的步骤记录下来。
第三步:按需检索。
遇到新的问题时,再读取对应文件或查询相关文档。
第四步:压缩历史。
当执行历史过长时,清理无用的工具输出,保留关键决策、未解决的问题和失败原因。
第五步:继续执行。
利用整理后的上下文进行下一轮推理,直到完成任务。
在实际工程中,还有两个值得注意的细节。
首先,不要盲目删除错误记录。必要的失败信息有助于 Agent 避免重复犯错,但已经处理完毕的冗余日志可以清理。
其次,尽量保持稳定的提示词前缀。在支持前缀缓存的模型服务中,这有利于复用已有计算结果,降低延迟和成本。不过,具体收益取决于模型服务的缓存机制。
八、总结与思考
回顾全文,上下文工程其实围绕着一个问题展开:
如何让模型在每次推理时,都能获得足够准确、相关且精简的信息?
我们可以把四大策略总结为:
- Offloading(卸载):暂时用不到的信息,放在外部。
- Retrieval(检索):需要信息时,再主动获取。
- Isolation(隔离):不同任务,只关注各自需要的信息。
- Compaction(压缩):历史太长时,提炼真正重要的内容。
值得注意的是,上下文工程并不是越复杂越好。
对于简单的问答应用,完整保留对话历史可能已经足够;但对于需要持续执行数十甚至上百步操作的 Agent,合理的上下文管理可能直接影响任务成功率、响应速度和运行成本。
从更大的视角看,这也是 AI Agent 工程与普通 LLM 应用之间的重要区别:
我们不仅需要一个能够推理的模型,还需要一套能够持续为模型提供有效信息的系统。
模型负责思考,上下文工程则努力确保模型始终拥有做出正确判断所需的信息。
浙公网安备 33010602011771号