Manus 中的上下文工程 | Lance
作者:Lance Martin | 日期:2025年10月15日
为什么需要上下文工程
本周早些时候,我与 Manus 的联合创始人兼首席战略官 Yichao “Peak” Ji 举办了一场网络研讨会。你可以在这里观看视频,在这里查看我的幻灯片,在这里查看 Peak 的幻灯片。以下是我的笔记。
Anthropic 将 agent 定义为这样一种系统:由大语言模型(LLM)来主导自身的流程和工具使用方式,并保持对任务完成方式的控制。简而言之,就是一个在循环中调用工具的 LLM。
Manus 是最受欢迎的通用型消费级 agent 之一。一个典型的 Manus 任务会使用 50 次工具调用。如果没有上下文工程,这些工具调用结果会不断累积在 LLM 的上下文窗口中。随着上下文窗口不断变大,许多人已经观察到 LLM 的性能会下降。
例如,Chroma 对“上下文腐化(context rot)”做过一项非常好的研究,Anthropic 也解释了不断增长的上下文是如何消耗 LLM 的注意力预算的。因此,在构建 agent 时,仔细管理进入 LLM 上下文窗口的内容至关重要。Karpathy 对此有一个非常清晰的表述:
上下文工程是一门精细的艺术与科学,其目标是在 agent 轨迹中的下一步,向上下文窗口中填入恰到好处的信息。
上下文工程的方法
每一个 Manus 会话都会使用一个专用的、基于云的虚拟机,从而为 agent 提供一台虚拟计算机,具备文件系统、用于导航的工具,以及在该沙箱环境中执行命令(例如内置工具和标准 shell 命令)的能力。
在这个沙箱中,Manus 使用了三种主要的上下文工程策略,这些策略与 Anthropic 在这里所介绍的方法,以及我在许多项目中看到的实践是一致的:
-
• 减少上下文 -
• 卸载上下文 -
• 隔离上下文
上下文减少
Manus 中的工具调用有“完整”和“紧凑”两种表示形式。完整版本包含工具调用返回的原始内容(例如完整的搜索结果),这些内容会被存储在沙箱中(例如文件系统)。紧凑版本则只保存对完整结果的引用(例如一个文件路径)。
Manus 会对较旧的(“过时的”)工具结果应用压缩。这意味着用紧凑版本替换完整的工具结果。这样一来,如果之后确实需要,agent 仍然可以获取完整结果,但通过移除 agent 已经用来做出决策的“过时”结果,可以节省 token。
较新的工具结果则会以完整形式保留,用于指导 agent 的下一步决策。这似乎是一种非常通用且有效的上下文减少策略,我注意到它与 Anthropic 的“上下文编辑(context editing)”功能非常相似:
当接近 token 限制时,上下文编辑会自动清除上下文窗口中的过时工具调用及其结果。随着 agent 执行任务并不断累积工具结果,上下文编辑会移除过时内容,同时保留对话流程,从而有效延长 agent 在无需人工干预的情况下可运行的时间。
当压缩带来的收益开始递减时(如下图所示),Manus 会对整个轨迹应用摘要。摘要是基于完整的工具结果生成的,并且 Manus 使用一个 schema 来定义摘要字段。这为任何 agent 轨迹创建了一个一致的摘要对象。
上下文隔离
Manus 对多 agent 采取了一种务实的做法,避免将其拟人化为分工明确的角色。人类之所以按照角色(设计师、工程师、项目经理)来组织工作,是因为人类的认知能力有限,而 LLM 并不一定存在同样的限制。
基于这一点,Manus 中子 agent 的主要目标是隔离上下文。例如,如果有一个任务需要完成,Manus 会将该任务分配给一个拥有自己上下文窗口的子 agent。
Manus 使用多 agent 架构,其中包括一个负责分配任务的规划器(planner),一个负责回顾对话并决定哪些内容应该保存到文件系统中的知识管理器(knowledge manager),以及一个执行由规划器分配任务的执行子 agent。
Manus 最初使用一个 todo.md 文件进行任务规划,但发现大约三分之一的操作都花在了更新 todo 列表上,浪费了宝贵的 token。于是他们转而使用一个专门的规划器 agent,由它调用执行子 agent 来完成任务。
在最近的一期播客中,Anthropic 从事多 agent 研究的 Erik Schluntz 提到,他们同样会使用一个规划器来分配任务,并使用函数调用作为启动子 agent 的通信协议。Erik 以及 Cognition 的 Walden Yan 提出的一个核心挑战是:规划器与子 agent 之间如何共享上下文。
Manus 通过两种方式来解决这一问题。对于简单任务(例如规划器只需要子 agent 的输出结果的离散任务),规划器会直接创建指令,并通过函数调用将其传递给子 agent。这种方式类似于 Claude Code 的 task 工具。
对于更复杂的任务(例如子 agent 需要写入规划器也会使用的文件),规划器会将其完整上下文共享给子 agent。子 agent 仍然拥有自己的行动空间(工具)和指令,但同时也会接收与规划器相同的完整上下文。
在这两种情况下,规划器都会定义子 agent 的输出 schema。子 agent 拥有一个提交结果的工具,用于在返回给规划器之前填充该 schema,而 Manus 使用受约束解码来确保输出符合所定义的 schema。
上下文卸载
工具定义
我们通常希望 agent 能够执行范围非常广泛的操作。当然,我们可以将大量工具绑定到 LLM 上,并提供如何使用这些工具的详细说明。但是,工具描述会消耗宝贵的 token,而且大量(往往存在重叠或歧义的)工具可能会导致模型产生混淆。
我看到的一种趋势是,agent 只使用一小组通用工具,让 agent 能够访问一台计算机。例如,只使用一个 Bash 工具和少量用于访问文件系统的工具,agent 就可以执行非常广泛的操作。
Manus 将这一点视为一个分层的行动空间,包括函数/工具调用层和虚拟计算机沙箱层。Peak 提到,Manus 使用的原子函数数量很少(少于 20 个),其中包括 Bash 工具、用于管理文件系统的工具,以及代码执行工具。
Manus 并没有让函数调用层变得臃肿,而是将大部分操作卸载到沙箱层。Manus 可以直接在沙箱中使用 Bash 工具执行许多实用程序,而 MCP 工具则通过 CLI 的形式暴露出来,agent 同样可以使用 Bash 工具来执行它们。
Claude 的 skills 功能使用了类似的思路:技能是存储在文件系统中的,而不是作为绑定工具存在,因此 Claude 只需要少量简单的函数调用(Bash、文件系统)就可以逐步发现并使用这些技能。
渐进式披露是使 Agent Skills 灵活且可扩展的核心设计原则。就像一本组织良好的手册,先是目录,然后是具体章节,最后是详细附录一样,skills 让 Claude 只在需要时加载信息……拥有文件系统和代码执行工具的 agent,在处理特定任务时,不需要将整个技能内容全部读入上下文窗口。
工具结果
由于 Manus 可以访问文件系统,它也可以卸载上下文(例如工具结果)。如前所述,这对于上下文减少至关重要;工具结果会被卸载到文件系统中,以便生成紧凑版本,从而用于从 agent 的上下文窗口中裁剪过时的 token。与 Claude Code 类似,Manus 使用基本的实用程序(例如 glob 和 grep)来搜索文件系统,而无需使用索引(例如向量存储)。
模型选择
Manus 并没有固定使用某一个模型,而是采用任务级路由:例如,使用 Claude 进行编码,使用 Gemini 处理多模态任务,或使用 OpenAI 进行数学和推理任务。总体而言,Manus 的模型选择策略主要由成本驱动,其中 KV cache 的效率起着核心作用。
Manus 使用缓存(例如缓存系统指令、较旧的工具结果等)来降低跨多个 agent 轮次的成本和延迟。Peak 提到,使用开源模型实现分布式 KV cache 基础设施非常具有挑战性,但前沿模型提供商对此提供了良好的支持。这种缓存支持在某些 agent 使用场景下,实际上可以让前沿模型更便宜。
牢记“苦涩的教训”来构建系统
我们在讨论的最后谈到了“苦涩的教训(The Bitter Lesson)”。我一直对它在 AI 工程中的影响很感兴趣。Claude Code 的创建者 Boris Cherny 提到,“苦涩的教训”影响了他保持 Claude Code 不带过多主观设计的决策,从而使其更容易适应模型能力的提升。
基于不断改进的模型进行构建,意味着要接受持续变化。Peak 提到,自 3 月份发布以来,Manus 已经重构了五次。
此外,Peak 警告说,agent 的“支架(harness)”可能会随着模型能力的提升而限制性能;这正是“苦涩的教训”所指出的挑战。我们在某一时间点加入结构以提升性能,但随着计算能力(模型)的增长,这些结构反而可能限制性能。
为了防止这种情况,Peak 建议在不同模型强度下运行 agent 评估。如果在更强模型下性能没有提升,那么你的支架可能正在束缚 agent。这可以用来测试你的支架是否具备“面向未来”的能力。
OpenAI / MSL 的 Hyung Won Chung 在其相关演讲中进一步强调了:随着模型能力的提升,需要持续重新评估结构(例如你的支架和假设)。
在给定的计算和数据水平下加入所需的结构。之后再移除它们,因为这些捷径会成为进一步改进的瓶颈。
结论
为 agent 提供一台计算机(例如文件系统、终端和实用程序)是一种我们在包括 Manus 在内的许多 agent 中看到的常见模式。它使得多种上下文工程策略成为可能:
1. 卸载上下文
-
• 将工具结果存储在外部: 把完整的工具结果保存到文件系统中(而不是上下文中),并通过 glob、grep 等工具按需访问 -
• 将操作推送到沙箱: 使用一小组函数调用(Bash、文件系统访问),在沙箱中执行大量实用程序,而不是将每一个实用程序都绑定为工具
2. 减少上下文
-
• 压缩过时结果: 随着上下文变满,用引用(例如文件路径)替换较旧的工具结果;保留最近的完整结果以指导下一步决策 -
• 在必要时进行摘要: 当压缩的收益递减时,对完整轨迹应用基于 schema 的摘要
3. 隔离上下文
-
• 对离散任务使用子 agent: 将任务分配给拥有独立上下文窗口的子 agent,其主要目的在于隔离上下文(而不是按角色分工) -
• 有意识地共享上下文: 对于简单任务,仅传递指令;对于子 agent 需要更多上下文的复杂任务,则传递完整上下文(例如轨迹和共享文件系统)
最后一个需要考虑的问题是,确保你的支架不会随着模型能力提升而限制性能(即“被苦涩的教训洗礼”)。通过在不同模型强度下进行测试,验证这一点。
简单、不带过多主观设计的系统往往更能适应模型能力的提升。
最后,不要害怕随着模型的改进而重建你的 agent(Manus 自 3 月以来已经重构了 5 次)。
https://rlancemartin.github.io/2025/10/15/manus/
如果觉得内容不错,欢迎你点一下「在看」,或是将文章分享给其他有需要的人^^
相关好文推荐:
引入嵌套学习(Nested Learning):一种用于持续学习的全新机器学习范式
理解 LSTM 网络 | Ilya Sutskever’s Top 30 Reading List
循环神经网络不合理的有效性 | Ilya Sutskever’s Top 30 Reading List
复杂动力学第一定律 | Ilya Sutskever’s Top 30 Reading List
赋权于民:大语言模型如何逆转技术扩散的范式 | karpathy
“通用智能根本不存在”?Yann LeCun 与 Demis Hassabis 正面开撕

0条留言