同样的模型、同样的工具,有的 Agent 好用,有的一塌糊涂,差别往往不在提示词写得多漂亮,而在于每一步给模型看了什么。这就是上下文工程(Context Engineering)。
一、从提示工程到上下文工程
早期大家关注提示工程:怎么写一段好的提示词。到了 Agent 时代,问题变了。一个任务跑十几轮,上下文里除了你写的提示词,还有工具定义、历史对话、几十次工具结果、检索到的资料。你写的那段提示词只占很小一部分。
上下文工程关注的是:在每一次模型调用时,让上下文里恰好包含完成当前步骤所需的信息,不多也不少。
二、上下文里都有什么
| 组成部分 | 特点 | 常见问题 |
|---|---|---|
| System Prompt | 固定,每次都有 | 写得过长、规则互相矛盾 |
| 工具定义 | 固定,工具越多越长 | 工具太多,占空间且易选错 |
| 历史消息 | 随对话增长 | 早期内容和当前任务无关 |
| 工具结果 | 增长最快 | 一次返回大量原始数据 |
| 外部资料 | 检索或预加载 | 塞了太多不相关的内容 |
在大多数 Agent 中,工具结果是上下文膨胀的头号来源。一次查询返回几千行日志,上下文就被占掉一大块,而且后面每一轮都要为它重复付费。
三、上下文太长会怎样
第 02 篇提到过,上下文越长越贵越慢。更隐蔽的问题是质量下降:
- 注意力稀释:关键信息淹没在大量无关内容中,模型容易忽略。
- 忘记早期指令:System Prompt 里的规则被几十轮工具结果「挤」到很远的位置,执行效果变差。
- 被过时信息误导:前几步得出的错误推断还留在上下文里,影响后面的判断。
所以上下文并不是越满越好。窗口能装一百万 token,不代表应该装一百万 token。
四、管理上下文的常用手段
1. 在源头控制:精简工具结果
最有效的办法是让工具本身返回精简的结果(第 05 篇讲过):先汇总、再截断、只返回需要的字段。数据处理交给代码,模型只看结论性的数据。
2. 按需加载,而不是预先全部塞入
与其一开始就把所有可能用到的资料都放进上下文,不如给模型一个「目录」,让它需要时再去取。比如:
- 先给文件列表,让模型决定读哪个文件;
- 先给数据摘要,让模型决定要不要查明细;
- 先给技能的名称和描述,用到时再加载完整说明(这就是第 14 篇 Skills 的思路)。
3. 清理过时的工具结果
工具结果被模型「消化」之后,原始内容往往就没用了。可以把较早的工具结果替换成一句简短说明,比如「已查询 10:00-11:00 订单数据,结论:下降 70%」。
4. 压缩与摘要
当上下文接近上限时,让模型把到目前为止的进展总结成一段摘要:任务目标、已完成的步骤、关键发现、下一步计划。然后用摘要替换掉大部分历史,继续工作。
压缩时要注意保留:用户的原始要求、已经做出的决定、尚未解决的问题。这些一旦丢失,Agent 就会重复劳动或跑偏。
5. 把信息存到上下文之外
让 Agent 把中间结果写到文件或数据库里,需要时再读回来。上下文只保留「去哪里找」,而不是信息本身。这和第 08 篇的记忆机制相关。
6. 用子 Agent 隔离上下文
把一个会产生大量中间数据的子任务交给子 Agent,子 Agent 只把结论返回给主 Agent。主上下文保持干净。第 11 篇会展开。
五、提示缓存:让固定部分更便宜
System Prompt、工具定义这些内容每次调用都一样。很多模型 API 支持提示缓存:上下文开头不变的部分可以被缓存,后续调用命中缓存时,这部分的费用和延迟都会大幅降低。
要用好缓存,关键是把上下文按「从稳定到易变」排列:
- System Prompt 和工具定义放最前面,尽量不改动;
- 历史消息在中间,只追加不修改;
- 最新的内容放最后。
如果频繁修改开头的内容,比如在 System Prompt 里放当前时间,缓存就会一直失效。具体的缓存规则和价格以各家 API 文档为准。
本篇小结
- 上下文工程:让每次调用恰好包含当前步骤需要的信息。
- 工具结果是上下文膨胀的主要来源。
- 上下文过长会导致注意力稀释、遗忘指令、被过时信息误导。
- 手段:精简工具结果、按需加载、清理过时结果、压缩摘要、外部存储、子 Agent 隔离。
- 提示缓存:上下文按从稳定到易变排列,降低成本和延迟。
思考与练习
- 一个查询日志的工具返回了 2000 行,你会怎么处理再交给模型?
- 设计一个压缩摘要的提示词:当上下文过长时,让模型总结进展。摘要必须包含哪些内容?
上一篇:AI Agent原理篇06:结构化输出与解析容错
下一篇:AI Agent原理篇08:记忆机制:短期记忆、长期记忆与检索
返回系列总目录