AI代理的上下文工程:构建Manus的经验教训

作者: Yichao 'Peak' Ji | 日期: 2025/7/18 | 分类: 技术

核心决策:放弃从头训练模型,选择基于前沿模型进行“上下文工程”。

根本原因:上下文工程能以小时为单位快速迭代,并使产品与底层模型技术解耦,如同“水涨船高”中的船,而非固定的柱子。本文分享了在构建AI代理Manus过程中,通过大量实验(戏称为“随机研究生下降”)总结出的上下文工程核心原则。

1. 围绕KV缓存进行设计

+
核心理念:KV缓存命中率是生产级AI代理最重要的单一指标,直接决定延迟和成本。

问题所在

代理的输入(上下文)远大于输出(动作),平均Token比例可达100:1。低效的缓存利用会急剧增加成本和延迟。

具体实践

  • 保持提示前缀稳定:避免在系统提示开头加入时间戳等易变内容。
  • 确保上下文只追加:不修改历史记录,并使用确定性的序列化方式(如固定JSON键序)。
  • 明确标记缓存断点:在需要时手动插入缓存标记,至少包含系统提示。
  • 优化自托管模型:启用PagedAttention等技术,并确保请求路由一致。

2. 遮蔽,而非移除

+
核心理念:通过遮蔽(Masking)而非移除来动态管理工具集,避免破坏KV缓存和模型理解。

问题所在

工具数量爆炸会让代理“变笨”。但动态增删工具会使KV缓存失效,并让模型对引用了已消失工具的历史记录感到困惑。

具体实践

  • 使用Logits Masking:在解码时通过掩码阻止或强制模型选择某些动作,而不是从上下文中移除工具定义。
  • 利用响应预填充:使用`auto`、`required`、`specified`等模式,在不修改工具定义的前提下约束模型的选择。
  • 设计一致的动作名称前缀:如`browser_`、`shell_`,便于通过预填充函数名来约束模型只从特定工具组中选择。

3. 使用文件系统作为上下文

+
核心理念:将文件系统视为终极的、无限大小的上下文,使代理能按需读写,实现可恢复的信息压缩。

问题所在

即使是128K的上下文窗口,在处理网页、PDF等大型非结构化数据时也容易耗尽、性能下降且成本高昂。不可逆的压缩会丢失关键信息。

具体实践

  • 可恢复的压缩策略:从上下文中移除大块内容(如网页HTML),但保留其引用(如URL或文件路径)。当需要时,代理可以自行读取文件来恢复信息。
  • 将文件系统作为外部记忆:训练模型不仅将文件系统用作存储,还用作结构化的外部记忆,按需写入和读取。

4. 通过复述操控注意力

+
核心理念:通过让代理不断复述和更新其目标(如 `todo.md` 文件),将全局计划始终保持在模型的近期注意力范围内。

问题所在

在长达数十步的复杂任务中,代理容易“迷失在中间”,偏离最初的目标。

具体实践

  • 创建并迭代待办事项列表:代理在任务开始时创建`todo.md`,并在每一步后更新它,将完成项勾选掉。
  • 将复述内容置于上下文末尾:通过重写`todo.md`,这个包含全局计划的“复述”内容被推到上下文的末尾,有效对抗了模型的注意力衰减。

5. 保留错误的内容

+
核心理念:不要隐藏或擦除错误。将失败的尝试和错误信息保留在上下文中,是让模型学习和适应的最有效方法之一。

问题所在

开发者倾向于隐藏错误、重试或重置状态,但这剥夺了模型从失败中学习的机会。

具体实践

  • 完整记录失败:将失败的动作、返回的错误信息或堆栈跟踪完整地保留在上下文中。
  • 相信模型的适应能力:当模型看到“动作A -> 错误B”的序列后,它会隐式地更新其内部信念,降低重复犯错的概率。错误恢复是真正代理行为的标志。

6. 不要被少样本示例所困

+
核心理念:在代理上下文中引入受控的多样性,以防止模型因模仿历史行为而陷入次优的、重复的模式。

问题所在

LLM是优秀的模仿者。如果上下文中充满了大量相似的“动作-观察”对(少样本示例),模型会倾向于盲目重复该模式,即使当前情况已不适用。

具体实践

  • 引入结构化变化:在行动和观察的序列化中,引入少量、受控的随机性,如使用不同的模板、替代性措辞或微小的格式噪音。
  • 打破模式单一性:上下文越单一,代理就越脆弱。增加多样性可以调整模型的注意力,防止其过度泛化或陷入幻觉。

结论:上下文工程是构建强大、高效、可扩展AI代理的核心。你如何塑造上下文,最终决定了你的代理将如何行为。

原文

源链接