本文原作者为季逸超,译者为Lynn凌青。


中文译文原文:https://mp.weixin.qq.com/s/caMpAgYWoDzBlSxbItSWTQ


英文原文链接:

https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus


AI Agents 已经成为构建下一代智能系统的核心,而上下文管理(Context Engineering)则是 AI Agents 成败的关键之一。Manus 的创始人 Yichao 'Peak' Ji (季逸超)7月18日最新撰,毫无保留地分享了团队构建 Manus 过程中,通过实践得出的宝贵经验——如何有效进行上下文工程。


季逸超明确指出,上下文工程是一门实验科学,在实际开发中需要通过大量试错(他们戏称为“随机梯度下降”)来寻找局部最优解。本文详细探讨了 KV 缓存的优化策略、动作空间的动态管理方法、文件系统作为上下文的巧妙应用、如何利用待办事项操控模型注意力,以及保留错误信息如何促进智能体从失败中学习。同时,作者提醒开发者谨慎使用 Few-shot 技术,避免因上下文的单一化导致模型表现僵化。


无论你是从事 AI Agent 产品开发,还是关注 AI 前沿趋势的探索者,这篇文章都值得深入阅读与反复回味——它将帮助你更快、更清晰地构建起稳定、高效且适应性强的智能代理系统。


以下为原文:


在 Manus 项目的最初阶段,我和我的团队面临一个关键决策:我们是应该使用开源基础训练一个端到端的 agentic 模型,还是基于前沿模型的上下文学习能力构建一个 agent?


回到我在 NLP 领域的第一个十年,我们没有这种选择的奢侈。在 BERT 的遥远年代(是的,已经七年了),模型必须经过微调——并进行评估——才能迁移到新任务。这个过程每次迭代通常需要数周时间,尽管当时的模型相比今天的 LLMs 要小得多。对于快速发展的应用,尤其是在产品市场匹配(PMF)之前,这种缓慢的反馈循环是致命的。这是我上一家创业公司的一个惨痛教训,当时我从零开始训练模型用于开放信息抽取和语义搜索。随后出现了 GPT-3 和 Flan-T5,我自家的模型一夜之间变得无关紧要。具有讽刺意味的是,这些模型标志着上下文学习的开始——以及一条全新的前进道路。


这段来之不易的教训让选择变得清晰:Manus 将押注于上下文工程。这使我们能够在数小时内发布改进,而不是数周,同时保持我们的产品与底层模型正交:如果模型进步是涨潮,我们希望 Manus 成为船,而不是固定在海床上的柱子。


然而,上下文工程远非简单。这是一门实验科学——我们已经重建了四次代理框架,每次都是在发现了更好的上下文塑造方法之后。我们亲切地称这种手动的架构搜索、提示调整和经验猜测过程为“随机梯度下降”(Stochastic Graduate Descent)。它不优雅,但有效。


这篇文章分享了我们通过自己的“随机梯度下降”达到的局部最优解。如果你正在构建自己的 AI 代理,希望这些原则能帮助你更快收敛。

1

围绕 KV-Cache(KV 缓存)的设计


如果只能选择一个指标,我认为 KV 缓存命中率是生产阶段 AI 代理中最重要的指标。它直接影响延迟和成本。要理解原因,我们先来看一个典型代理的工作流程:


在接收到用户输入后,代理通过一系列工具调用来完成任务。在每次迭代中,模型根据当前上下文从预定义的动作空间中选择一个动作。然后在环境中执行该动作(例如,Manus 的虚拟机沙箱),以产生观察结果。动作和观察结果会被追加到上下文中,形成下一次迭代的输入。这个循环持续进行,直到任务完成。


正如你所想象的,上下文会随着每一步增长,而输出——通常是结构化的函数调用——则相对较短。这使得预填充和解码之间的比例在代理中相比聊天机器人显得极为不平衡。例如,在 Manus 中,平均输入与输出的 token 比例约为 100:1。


幸运的是,具有相同前缀的上下文可以利用 KV-cache,这大大减少了首次生成标记时间(TTFT)和推理成本——无论你是使用自托管模型还是调用推理 API。这里的节省可不是小数目:以 Claude Sonnet 为例,缓存的输入标记费用为 0.30 美元/千标记,而未缓存的则为 3 美元/千标记——相差 10 倍。


图片


从上下文工程的角度来看,提高 KV-cache 命中率涉及几个关键做法:


  1. 保持提示前缀稳定。由于 LLMs 的自回归特性,即使是单个标记的差异也会使该标记及其之后的缓存失效。一个常见错误是在系统提示开头包含时间戳——尤其是精确到秒的时间戳。虽然这样可以让模型告诉你当前时间,但也会大幅降低缓存命中率。

  2. 使上下文仅追加。避免修改之前的操作或观察。确保序列化是确定性的。许多编程语言和库在序列化 JSON 对象时不保证键的顺序稳定,这可能会悄无声息地破坏缓存。

  3. 在需要时明确标记缓存断点。一些模型提供商或推理框架不支持自动增量前缀缓存,而是需要在上下文中手动插入缓存断点。设置这些断点时,要考虑缓存可能过期,至少确保断点包含系统提示的结尾部分。

此外,如果你使用像 vLLM 这样的框架自托管模型,确保启用了前缀/提示缓存,并且使用诸如会话 ID 之类的技术来在分布式工作节点之间一致地路由请求。

2

屏蔽,而非移除


随着你的智能体具备更多能力,其动作空间自然变得更加复杂——简单来说,就是工具数量激增。最近 MCP 的流行更是火上浇油。如果你允许用户自定义工具,相信我:总会有人将数百个神秘工具接入你精心策划的动作空间。结果,模型更可能选择错误的动作或走上低效的路径。简而言之,你的重装智能体反而变得更笨了。


一种自然的反应是设计一个动态的动作空间——或许使用类似 RAG 的方法按需加载工具。我们在 Manus 中也尝试过这样做。但我们的实验表明一个明确的规则:除非绝对必要,避免在迭代过程中动态添加或移除工具。主要有两个原因:


  1. 在大多数 LLMs 中,工具定义在序列化后位于上下文的前部,通常在系统提示之前或之后。因此,任何更改都会使所有后续操作和观察的 KV 缓存失效。

  2. 当之前的操作和观察仍然引用当前上下文中不再定义的工具时,模型会感到困惑。若不进行约束解码,这通常会导致模式违规或虚构的操作。

为了解决这一问题,同时提升动作选择的效果,Manus 使用了一个上下文感知的状态机来管理工具的可用性。它不是移除工具,而是在解码过程中屏蔽某些标记的概率分布,以根据当前上下文防止(或强制)选择特定的动作。


图片


在实际操作中,大多数模型提供商和推理框架都支持某种形式的响应预填充,这使您可以在不修改工具定义的情况下限制动作空间。函数调用通常有三种模式(我们将以 NousResearch 的 Hermes 格式为例):


  • 自动 – 模型可以选择是否调用函数。通过仅预填回复前缀来实现:<|im_start|>assistant

  • 必需 – 模型必须调用一个函数,但选择不受限制。通过预填充至工具调用标记实现:<|im_start|>assistant<tool_call>

  • 指定 – 模型必须调用特定子集中的函数。通过预填充直到函数名称的开头来实现:<|im_start|>assistant<tool_call>{“name”: “browser_

利用这一点,我们通过直接屏蔽标记的 logits 来限制动作选择。例如,当用户提供新的输入时,Manus 必须立即回复,而不是执行某个动作。我们还特意设计了带有一致前缀的动作名称——例如,所有与浏览器相关的工具都以 browser_开头,命令行工具则以 shell_开头。这使我们能够轻松地确保代理在特定状态下只从某一组工具中选择,而无需使用有状态的 logits 处理器。


这些设计有助于确保 Manus 代理循环保持稳定——即使在模型驱动架构下也是如此。

3

将文件系统用作上下文


现代前沿的 LLMs 现在提供 128K 令牌或更多的上下文窗口。但在现实世界的智能代理场景中,这通常还不够,有时甚至成为负担。有三个常见的痛点:


  1. 观察内容可能非常庞大,尤其是当代理与网页或 PDF 等非结构化数据交互时。很容易超出上下文限制。

  2. 即使窗口技术上支持,模型性能在超过某个上下文长度后往往会下降。

  3. 长输入代价高昂,即使使用前缀缓存。你仍然需要为传输和预填充每个令牌付费。

为了解决这个问题,许多智能体系统采用了上下文截断或压缩策略。但过度激进的压缩不可避免地会导致信息丢失。这个问题是根本性的:智能体本质上必须基于所有先前的状态来预测下一步动作——而你无法可靠地预测哪条观察信息在十步之后可能变得关键。从逻辑角度来看,任何不可逆的压缩都存在风险。


这就是为什么我们将文件系统视为 Manus 中的终极上下文:它大小无限,具有持久性,并且可以由代理自身直接操作。模型学会按需写入和读取文件——不仅将文件系统用作存储,更作为结构化的外部化记忆。


图片


我们的压缩策略始终设计为可恢复的。例如,只要保留了 URL,网页内容就可以从上下文中删除;只要沙箱中仍有文档路径,文档内容也可以省略。这使得 Manus 能够缩短上下文长度而不会永久丢失信息。


在开发这个功能的过程中,我开始设想让状态空间模型(SSM)在智能代理环境中有效运行需要什么条件。与 Transformer 不同,SSM 缺乏完整的注意力机制,难以处理长距离的向后依赖。但如果它们能够掌握基于文件的记忆——将长期状态外部化,而不是保存在上下文中——那么它们的速度和效率可能会开启一类全新的智能代理。具备代理能力的 SSM 或许才是真正继承神经图灵机的下一代技术。

4

通过复述操控注意力


如果你使用过 Manus,你可能注意到一件有趣的事:在处理复杂任务时,它倾向于创建一个 todo.md 文件,并随着任务的进展逐步更新,勾选已完成的事项。


这不仅仅是可爱的行为——这是一种有意操控注意力的机制。


图片


Manus 中的一个典型任务平均需要大约 50 次工具调用。这是一个较长的循环——由于 Manus 依赖 LLMs 进行决策,因此在长上下文或复杂任务中,容易偏离主题或忘记之前的目标。


通过不断重写待办事项列表,Manus 将其目标反复输入到上下文的末尾。这将全局计划推入模型的近期注意范围,避免了“中途丢失”问题并减少了目标不一致的情况。实际上,它利用自然语言来引导自身关注任务目标——无需特殊的架构改动。

5

保留错误


智能体会犯错。这不是漏洞——这是现实。语言模型会产生幻觉,环境会返回错误,外部工具会出现异常,意想不到的边缘情况随时都会出现。在多步骤任务中,失败不是例外;它是循环的一部分。


然而,一个常见的冲动是隐藏这些错误:清理痕迹,重试操作,或者重置模型状态,寄希望于神奇的“温度”参数。这看起来更安全、更可控。但这付出了代价:抹去失败就抹去了证据。而没有证据,模型就无法适应。


图片


根据我们的经验,改善智能体行为的最有效方法之一看似非常简单:在上下文中保留错误的尝试。当模型看到一个失败的动作——以及随之产生的观察结果或堆栈跟踪时——它会隐式地更新其内部信念。这会使其先验偏离类似的动作,从而减少重复同样错误的可能性。


事实上,我们认为错误恢复是体现真正智能体行为的最明显标志之一。然而,在大多数学术研究和公开基准测试中,这一点仍然被忽视,这些研究和测试通常侧重于理想条件下的任务成功率。

6

别被few‑shot(少样本提示)坑了


少样本提示是提升 LLM 输出效果的常用技术。但在智能体系统中,它可能以微妙的方式适得其反。


语言模型是出色的模仿者;它们会模仿上下文中的行为模式。如果你的上下文中充满了类似的过去动作-观察对,模型往往会遵循这种模式,即使这已不再是最优选择。


在涉及重复决策或动作的任务中,这可能是危险的。例如,当使用 Manus 帮助审查一批 20 份简历时,代理经常陷入一种节奏——仅仅因为上下文中出现了类似的内容,就重复类似的动作。这会导致偏离、过度泛化,甚至有时产生幻觉。


图片


解决方法是增加多样性。Manus 在动作和观察中引入少量结构化的变化——不同的序列化模板、替代表达、顺序或格式上的细微噪声。这种受控的随机性有助于打破模式,调整模型的注意力。


换句话说,不要让少量示例把自己陷入僵局。上下文越统一,代理就越脆弱。

7

结论


上下文工程仍然是一门新兴的科学——但对于智能体系统来说,它已经至关重要。模型可能变得更强大、更快速且更廉价,但无论多强的原始能力,都无法替代记忆、环境和反馈的需求。你如何塑造上下文,最终决定了你的智能体的行为:运行速度、恢复能力以及扩展范围。


在 Manus,我们通过反复重写、走过死胡同以及在数百万用户中的实际测试,学到了这些经验。我们在这里分享的内容并非普适真理——但这些是对我们有效的模式。如果它们能帮助你避免哪怕一次痛苦的反复迭代,那么这篇文章就达到了它的目的。


智能代理的未来,将在一次又一次的上下文管理中被逐步搭建,请精心设计它们。


  ✦   END  ✦  

 



点击下方名片 即刻关注我们