上下文工程:AI Agent 真正的系统设计问题

上下文工程:AI Agent 真正的系统设计问题

_

过去两年很多团队都把精力放在 prompt engineering 上,但一旦 Agent 开始跨多轮、多工具、长时程工作,真正的瓶颈很快就会从“提示词怎么写”转移到另一个问题:哪些信息应该进入上下文,何时进入,保留多久,什么信息应该被压缩,什么状态根本不该暴露给模型。

这就是 context engineering

如果把大模型看成一个新的计算运行时,那么上下文窗口更像它的工作内存。模型每一步推理都依赖这块内存里当前可见的状态,而工程工作的目标,不是盲目把更多信息塞进去,而是让每一步恰好拥有最小但足够的高信号信息集。

从 prompt engineering 转向 context engineering:问题不只是怎么写提示词,而是怎样配置整段运行态上下文。

一、为什么 Agent 时代必须重视上下文工程

单轮问答时代,系统提示词往往就能覆盖大部分需求。可一旦进入 Agent 模式,系统立刻变得复杂:

  • 有系统提示词
  • 有工具描述
  • 有工具输出
  • 有消息历史
  • 有外部知识
  • 有运行时状态
  • 有长期记忆

这些内容都可能进入上下文窗口,而上下文窗口本身又是有限资源。更麻烦的是,资源变大不等于效果线性提升。上下文变长之后,模型通常会出现一系列问题:

  • 注意力被稀释
  • 无关信息干扰当前判断
  • 早期错误被写进历史并持续污染后续推理
  • 多个来源之间的规则互相冲突

Anthropic 提到过一个很关键的现象:context rot。随着 token 数继续增长,模型对上下文中具体信息的精准提取能力会下降。这不是个别模型的问题,而是当前大模型架构下都要面对的现实。

LangChain 那篇文章则把这些失效模式拆得更细,包括:

  • Context Poisoning
  • Context Distraction
  • Context Confusion
  • Context Clash

所以对 Agent 来说,上下文不是“越多越好”,而是注意力预算。多一个 token 并非总是多一分收益,它也可能是在消耗后续推理的清晰度。

二、上下文工程不只是管理 prompt,而是管理整段运行态

这也是为什么 context engineering 不该被理解成“prompt engineering 的同义词升级版”。

Prompt 只是上下文的一部分。到了 Agent 体系里,需要管理的是整个运行态:

  • 系统提示词
  • few-shot 示例
  • 工具及工具说明
  • 外部检索结果
  • 工具执行结果
  • 运行时 scratchpad
  • 长期记忆
  • 子代理返回摘要

换句话说,Agent 的表现不只取决于“你怎么对它说”,还取决于“你让它在当前时刻能看到什么、看不到什么、怎么获取更多信息,以及什么时候应该忘掉一部分信息”。

三、一个实用框架:写入、选择、压缩、隔离

LangChain 给了一个非常适合工程落地的框架,可以把上下文工程拆成四个动作:

  1. 写入上下文
  2. 选择上下文
  3. 压缩上下文
  4. 隔离上下文

这个框架比“优化 prompt”更有操作性,因为它直接对应了一个 Agent 系统里最常见的设计决策。

上下文工程的四个动作:写入、选择、压缩、隔离。

1. 写入:先决定哪些状态要被保存到窗口之外

很多信息没必要一直留在上下文窗口里,但又不能完全丢掉。这时就需要把它们写到窗口外的某个持久介质里。

典型做法包括:

  • scratchpad
  • todo 文件
  • NOTES.md
  • 线程级状态对象
  • 长期记忆库

这些信息的作用不是立刻喂给模型,而是作为后续可检索、可回读的工作记忆。

从记忆类型上看,可以至少分成三类:

  • procedural memory
    保存规则、操作方法、偏好约束。
  • semantic memory
    保存事实、关系和稳定知识。
  • episodic memory
    保存过去做过什么、哪些案例成功过、哪些路径踩过坑。

这类写入动作的价值非常大。因为 Agent 在长任务里最容易丢的是“已经做过什么、为什么这么做、接下来该接哪一步”。如果没有外部化状态,长链路任务很快就会漂。

2. 选择:不是所有已保存的信息都该重新读回来

会写还不够,更难的是会选。

选择上下文,本质上就是决定下一轮推理应该把哪些窗口外信息重新拉进来。

这件事最容易出错的地方有两个:

  • 选少了,模型缺关键上下文
  • 选多了,模型又重新被噪声淹没

Anthropic 在这方面强调的是 just-in-time 检索思路。与其预先把所有相关资料一次性塞进窗口,不如只保留轻量引用,例如:

  • 文件路径
  • URL
  • 查询语句
  • 目录索引

等到任务真正需要时,再通过工具按需读取。

这种做法在代码智能体里尤其有效。比如让模型先看到:

  • CLAUDE.md
  • 目录结构
  • 文件命名
  • 时间戳
  • 测试路径

然后通过 grepglobheadtail 或数据库查询去逐步探索,而不是把整个仓库或整张表直接送进上下文。

这类“引用先行、内容后取”的策略,本质上是在把静态检索改造成动态探索。速度会慢一点,但上下文质量通常更高。

3. 压缩:上下文迟早会满,关键是怎么压

只要 Agent 连续工作得够久,压缩就是必选项。

最常见的压缩方法有两类:

  • 总结
  • 修剪

总结是让模型把当前轨迹浓缩成较短的新上下文;修剪则更偏规则化过滤,比如:

  • 去掉过旧消息
  • 清除冗余工具输出
  • 删除不再相关的长日志
  • 保留决策,丢弃执行噪声

Anthropic 在这里给的建议很实用:压缩的目标不是“摘要写得漂亮”,而是高保真保留后续仍然可能影响决策的信息。例如:

  • 架构决策
  • 未解决的问题
  • 已知失败路径
  • 关键实现细节
  • 最近访问文件

而像深历史里的原始工具返回值,很多时候可以直接清掉。因为这些内容的原始字节量很大,但对后续推理的边际收益很低。

LangChain 也提到,压缩不一定只能发生在“窗口快满的时候”。它还可以被设计在一些固定边界上,例如:

  • 搜索工具返回之后先做结果压缩
  • 子代理完成任务后只回摘要
  • 某个工作阶段结束时做阶段总结

压缩上下文并不只是整段对话做 summary,也可以在工具调用和阶段交接处有选择地做摘要。

4. 隔离:有些上下文不该给当前模型看

隔离是很多团队最容易忽略、但收益极高的一步。

一个常见误区是:既然某些信息将来可能有用,那就先都放在 messages 里。问题在于,暴露给模型的每一份状态,都会参与下一轮注意力竞争。

更稳的方式是把状态拆开:

  • 一部分进 messages
  • 一部分留在运行时 state
  • 一部分留在沙箱环境
  • 一部分交给子代理独立处理

例如:

  • 大图像、音频、JSON、大搜索结果保留在环境变量或沙箱对象里
  • 工具调用明细写入运行时状态对象
  • 子代理在自己的上下文里展开搜索,主代理只拿摘要

这背后的核心思想是:不是所有状态都应该成为模型的直接思考材料。

多代理就是一种典型隔离方式。每个子代理有自己的工具集、自己的上下文窗口、自己的任务边界。这样主代理不需要被搜索过程、试错过程和海量中间结果污染,只需要接收结构化结论。

当然,隔离不是没有代价。多代理通常会带来更高 token 成本和更复杂的协调问题。是否值得做,取决于任务是否真的存在明显的可分解边界。

四、系统提示词仍然重要,但重点变了

上下文工程并不意味着系统提示词不重要,而是意味着系统提示词不再是唯一杠杆。

Anthropic 对系统提示词的建议可以总结成一句话:把提示词写在正确的高度。

常见的两个极端都不理想:

  • 太低:把脆弱的流程逻辑硬编码进 prompt
  • 太高:只写抽象原则,缺少可执行信号

比较稳的做法是:

  • 用分段结构组织提示词
  • 语言直接、短句、少歧义
  • 明确工具使用边界
  • 用少量高质量示例代替大量边缘规则

系统提示词需要写在“足够具体但不过度硬编码”的高度。

这和上下文工程并不冲突。提示词负责设定大方向,而写入、选择、压缩、隔离负责管理运行时状态。

五、工具设计本身也是上下文工程的一部分

工具经常被当成执行层问题,但实际上它也是上下文工程的一部分。

原因很简单:工具不仅定义“能做什么”,还定义“会带回什么上下文”。

如果工具返回:

  • 巨大的原始 JSON
  • 含糊不清的错误信息
  • 多个功能重叠的接口

那模型就会在选择和理解工具时被迫消耗更多注意力。

比较好的工具设计应该满足几件事:

  • 单一职责
  • 参数含义清晰
  • 返回值尽量面向下一步决策
  • 错误结构化
  • 少返回无关噪声

LangChain 还提到一个很有用的方向:如果工具很多,可以先对工具描述做检索,只把当前任务最相关的少量工具暴露出来,而不是一开始就把全部工具列表给模型。

六、长期记忆不是“越会记越好”,而是“越会取越好”

上下文工程里另一个经常被高估的点,是长期记忆。

很多人会把长期记忆理解成“尽量多存”。但真正难的是检索质量。

如果记忆系统会在不合时宜的时候把旧信息拉回来,用户会明显感觉上下文窗口“不再属于自己”。这不仅影响体验,也会直接干扰推理。

所以长期记忆系统至少要回答三个问题:

  1. 存什么
  2. 什么时候存
  3. 什么时候取

从工程角度看,比起“无差别自动记忆”,更稳的路径通常是:

  • 先把高价值规则和少量稳定事实结构化保存
  • 再补充案例、轨迹和用户偏好
  • 最后才考虑更大规模的语义记忆集合

也就是说,记忆系统应该先追求高信噪比,再追求覆盖率。

七、真正落地时,先做最小闭环

这两篇文章有一个共同点:都不建议一上来做过度复杂的体系。

比较合理的落地顺序通常是:

  1. 先把系统提示词写到合适高度
  2. 给 Agent 一套最小可用工具
  3. 把关键状态外写到文件或状态对象
  4. 做最基础的上下文选择逻辑
  5. 再补压缩和清理
  6. 最后才考虑多代理和复杂记忆

这里最关键的不是“功能完整”,而是“每个环节都有可观察性”。

如果没有 tracing、token 统计和评测,团队很难知道:

  • 上下文到底在哪一步膨胀了
  • 哪些文件经常被误检索
  • 哪类工具输出最污染窗口
  • 压缩之后到底是变好了还是变差了

这也是 LangChain 为什么反复强调 observability 和 evals。上下文工程不是靠感觉调出来的,它本质上是一个需要持续测量、验证和迭代的系统工程问题。

结语

对 Agent 来说,上下文窗口不是被动容器,而是主动设计对象。

当系统开始进入多轮推理、工具循环、长期任务和跨会话状态之后,真正决定效果的往往不是模型本身,而是你是否认真设计了以下四件事:

  • 什么信息写到窗口外
  • 什么信息在当前时刻被选进来
  • 什么信息应该被压缩或修剪
  • 什么状态应该被隔离而不是暴露给模型

Prompt engineering 解决的是“怎么告诉模型要做什么”,而 context engineering 解决的是“怎样让模型在每一步都看到最该看到的信息”。对正在构建 Agent 的团队来说,后者已经越来越接近核心工程工作本身。

参考来源:
https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
https://www.langchain.com/blog/context-engineering-for-agents

Agent Skills:把经验封装成可按需加载的能力模块 2026-04-28
AI Agent 工作流设计模式全览:从 ReAct 到 Planning 与 Reflection 2026-04-28

评论区