Skip to main content

Manus 架构还原

前置02 Kimi CLI。有一份能读的实现当参照,才看得出 Manus 哪里不一样。

Manus 上线那阵子,最让人好奇的是它凭什么能连续跑几十分钟不跑偏。但它不开源 —— 你能拿到的只有官方博客里的设计说法,和社区流出的一批提示词文件。

这两种材料的可信度完全不同:博客说的是「我们想这么做」,泄露物证明的是「它手上确实有这些零件」。所以这一篇是拼图,每块材料先标清来源和硬度,仅靠泄露物支持的结论一律标注,不当成事实断言。

一、材料硬度

先把手上有什么摊开:

材料内容来源可信度
Context Engineering for AI Agents六条上下文工程原则manus.im 官方博客✅ 官方一手
Wide Research 产品页多 Agent 架构说明manus.im 官方✅ 官方一手
tools.json 18.5KB29 个工具的完整 JSON Schema社区泄露仓库⚠️ 非官方
Agent loop.txt 2.1KB六步循环社区泄露仓库⚠️ 非官方
Modules.txt 12KB20 个 XML 标签的完整系统提示词社区泄露仓库⚠️ 非官方

泄露物出自 x1xhlol/system-prompts-and-models-of-ai-tools(142,905★)里的 Manus Agent Tools & Prompt/ 目录。

官方博客给出设计意图,泄露物给出零件形态。两者互相印证的部分可信度最高;仅泄露物支持的结论标 ⚠️,不作为事实断言。

泄露物获取方式:

curl -sL "https://raw.githubusercontent.com/x1xhlol/system-prompts-and-models-of-ai-tools/main/Manus%20Agent%20Tools%20%26%20Prompt/tools.json" -o manus-tools.json

二、Manus 是什么

闭源的通用 Agent 产品(Monica 出品):给用户一台联网的 Ubuntu 沙箱,Agent 在里面用浏览器、shell、文件系统完成任务,产出可部署的网页或文件。典型任务形态是「调研 100 个品牌做成对比表」——数百次工具调用、跨越数十分钟到数小时

这个形态和 Kimi CLI 的代码任务 有本质差异,也决定了它的全部设计取向:

Kimi CLI(代码)Manus(通用长任务)
典型时长分钟级数十分钟–数小时
工具调用量几十次官方均值 ~50,重任务数百次
主要瓶颈上下文被探索垃圾填满成本 + 遗忘 + 装不下
环境本地工作目录云端 Ubuntu 22.04 沙箱

理解 Manus 全部设计的单一关键数字,来自官方博客:

平均输入输出 token 比约 100:1。

模型每产出 1 token,需先消费 100 token 输入。Agent 成本几乎完全在输入侧——优化输出长度无意义,输入侧的 KV-cache 命中率近似等于成本本身。

官方称 Agent 框架重写过四遍才收敛到现行方案,核心结论:

不与上下文窗口对抗,把上下文当作需主动经营的资源。

具体为六条原则(第五节)+ 一层多 Agent(第七节)。

三、先把 Manus 的零件认全

在讲怎么解决之前,先看 Manus 手里有什么牌。

3.1 29 个工具:一台电脑的完整切面

泄露的 tools.json(⚠️ 非官方)里正好 29 个工具,按前缀分七组:

先看最反常的一点:浏览器占了 12 个,接近一半。

而且它不是「给我这个网页的文字」这种粗工具,是 clickinputscrollpress_keyselect_option 这种把人的每个动作都单独拆出来的细工具。

回到第二节的「想法二」:粗工具好写,但模型控制不了细节。Manus 选了细工具,代价是调用次数暴涨(这又加剧了第一堵墙),收益是模型真的能操作任何网页——要登录就填表单,要加载更多就点按钮,遇到反爬就换个方式。

这是「给用户一台电脑」这个产品定位的直接后果。 你的产品如果只需要读几个固定的 API,千万别学这个。

三个容易忽略但很有意思的工具:

browser_console_exec —— 直接在页面里跑 JavaScript 并读控制台输出。这一个工具就绕开了所有 DOM 解析的麻烦:与其教模型怎么从复杂 HTML 里找价格,不如让它写一行 document.querySelectorAll('.price')

shell_write_to_process / shell_wait / shell_kill_process —— 有这三个,说明 shell 不是「跑一条命令拿输出」,而是一个长期活着的会话。Agent 可以启动一个进程、往它的标准输入里写东西、等它、再杀掉。这是「真的在用一台电脑」和「调用一个函数」的分水岭。

idle —— 「什么都不做,进入待机」被做成了一个显式工具。

最后这个值得单独说。做 Agent 时有个很实际的问题:你怎么知道模型认为自己干完了? 常见做法是解析它的文字输出,看有没有「完成」之类的词——非常不可靠。让它显式调用一个 idle 工具,判定就变成了确定性的。能用工具调用表达的状态,就别用文字解析。

3.2 事件流:Manus 的核心数据结构

泄露的 Modules.txt(⚠️ 非官方)里,Manus 把自己的上下文定义成一个事件流,有七种事件:

事件流严格按时间顺序追加,七种事件类型分成两拨:

#事件类型内容谁产生的
Message用户说的话Agent 自己
ActionAgent 调了什么工具Agent 自己
Observation工具返回了什么Agent 自己
Plan当前计划Planner 模块推进来
Knowledge最佳实践Knowledge 模块推进来
DatasourceAPI 文档Datasource 模块推进来
其他系统事件系统

分界线在④。 ①②③是 Agent 自己产生的(用户说话、调工具、拿结果),④⑤⑥不是 —— 它们是系统从外面「推」进事件流的。

这是 Manus 架构里最容易被忽略的一点:Manus 不只是一个 Agent 循环,它旁边还挂着三个独立模块,往这个 Agent 的上下文里注入东西。 第七节会详细讲。

四、六条上下文工程原则

4.0 主循环:单工具调用约束

先看基础循环。泄露的 Agent loop.txt(⚠️ 非官方)里是六步:

  1. Analyze Events:从事件流理解现状
  2. Select Tools:基于现状、计划、知识、可用数据 API,选下一个工具
  3. Wait for Execution:沙箱执行,把新的 Observation 追加进事件流
  4. Iterate每次迭代只选一个工具调用,耐心重复
  5. Submit Results:通过消息工具把结果发给用户
  6. Enter Standby:全部完成后进入待机

第 4 步「每次只调一个工具」是个重要的架构决定,而且跟别家相反。

对照 Kimi CLI 的 explore 子 Agent,它的提示词明确鼓励「尽可能并行发起多个工具调用来提速」。两家取向完全相反。

Manus 为什么选串行? 因为它要保证事件流是严格线性、只追加的

这一点直接支撑了后面所有的上下文工程。并行工具调用会让事件的顺序变成偏序——A 和 B 同时发出,谁先返回不确定,那么上下文的前缀就不稳定。而下一节你会看到,前缀稳定是省钱的全部前提

代价是慢。 这也是为什么 Manus 后来必须搞 Wide Research(第八节)——单个 Agent 串行跑不快,那就同时开一百个 Agent。

4.1 围绕 KV-cache 设计(成本)

这是 Manus 官方博客的第一条原则,也是最重要的一条。

先讲清楚 KV-cache 是什么,为什么它决定成本。

模型处理一段文字时,会为每个 token 算出一组中间结果(key 和 value)。关键在于:这些中间结果只取决于它前面的内容。所以如果两次请求的开头一模一样,那部分的计算结果可以直接复用,不用重算。

厂商把这个能力开放出来,就是「提示词缓存」。价格差距很夸张:

价格(Claude Sonnet)倍数
缓存命中的输入 token$0.30 / MTok
未命中的输入 token$3.00 / MTok10×

配合第一节那个 100:1 的输入输出比,结论很直接:

KV-cache 命中率几乎就等于你的成本本身。

情形 A · 前缀逐字节稳定第 N 轮请求系统提示词工具定义 ×29历史事件 1…N(只追加)新事件 N+1命中缓存 $0.30 / MTok重算代价:只为最后一小段付全价情形 B · 系统提示词内含每轮变化的内容第 N 轮请求系统提示词含 14:23:07工具定义 ×29历史事件 1…N新事件 N+1变化点之后全部作废 $3.00 / MTok (10×)一个 token 的差异即导致其后所有内容重算;配合 100:1 的输入输出比,命中率近似等于成本本身缓存命中缓存作废,按 10 倍价重算本轮新增,必然重算
推论有三:① 提示词前缀必须逐字节稳定(别放时间戳、随机 ID、进度百分比);② 历史只能追加不能修改,「删旧内容省空间」这条路被封死;③ 工具列表不能动态增删——因此才有下一节的「遮蔽而非删除」。

怎么才能命中?前缀必须一模一样。 注意是「前缀」——从第一个 token 开始逐个比对,一旦有一个 token 不同,从那里往后的缓存全部作废

最经典的自杀方式就是在系统提示词里放当前时间。 看起来无害,实际上让缓存 100% 不命中。

这条原则推导出三个具体做法(后面 Step 3、Step 5 都是它的推论):

  1. 提示词前缀必须逐字节稳定
  2. 历史只能追加,不能修改——这就否定了「删掉旧内容来省空间」的做法
  3. 工具列表不能动态增删

第 3 条最反直觉,单独讲。

4.2 遮蔽而非删除(工具集)

任务不同阶段需要的工具不一样。调研阶段要浏览器,出报告阶段要文件工具。很自然的想法是:按阶段动态换工具列表,减少干扰。

Manus 明确说这是错的,理由有两条:

理由一(成本):工具定义在提示词的最前面,属于前缀。改了工具列表,后面全部缓存作废——就是上一节说的那件事。

理由二(正确性):这个更隐蔽。假设第 20 步用了 browser_click,第 50 步你把浏览器工具组删了。那么历史里第 20 步那条记录引用了一个「现在不存在」的工具。模型看到这个会困惑,有些模型的 API 甚至会直接报 schema 错误。

正确做法是「遮蔽」:工具定义永远留在上下文里不动,只在模型生成的时候,把不该用的工具对应的 token 概率压到零。

官方原话是用「上下文感知的状态机」来管工具可用性。

这条原则还有个更狠的推论,在泄露的 Modules.txt(⚠️ 非官方)里能看到:

- Data APIs must be called through Python code and cannot be used as tools
- Save retrieved data to files instead of outputting intermediate results

数据 API 必须用 Python 代码调,不能做成工具。 甚至给了代码样例:

import sys
sys.path.append('/opt/.manus/.sandbox-runtime')
from data_api import ApiClient
client = ApiClient()
weather = client.call_api('WeatherBank/get_weather', query={'location': 'Singapore'})
print(weather)

为什么要这么绕? 想象你要接 300 个数据源:

做法工具数前缀里的常驻开销加一个新数据源
每个数据源一个工具300+几万 token,每轮都要付工具列表变了 → 缓存全废
统一走 shell_exec 跑 Python1几百 token前缀不变,文档按需以事件注入

这是整篇里最值得抄的一个设计。 它跟「遮蔽而非删除」是同一个思路的两种落地:能不进工具列表的就别进,进了的就别再拿出来。

⚠️ /opt/.manus/.sandbox-runtime 这个路径来自泄露物,官方从未确认。

4.3 文件系统即上下文(容量)

100 个网页的正文,任何上下文窗口都装不下。而且按 Step 2 的原则,历史还不能删(一删缓存就废)。

Manus 的解法是:别把网页正文放进上下文,放进文件。

官方博客的说法是把文件系统当成「无限大、天然持久、Agent 自己就能直接操作」的上下文。

关键概念叫「可恢复的压缩」(restorable compression):

判断标准很简单:从上下文里拿掉的东西,能不能随时拿回来?

  • 网页正文可以丢,但 URL 必须留着 —— 留了 URL 就能重新抓
  • 文档内容可以丢,但文件路径必须留着 —— 留了路径就能重新读

丢得起,是因为找得回。

这就是为什么 29 个工具里有 5 个是文件操作,而且泄露的提示词里反复强调「把取到的数据存成文件,不要输出中间结果」。

4.4 复述操纵注意力(遗忘)

现在能跑很久了,但新问题来了:干到第 40 步,模型忘了最初要做什么。

Manus 的解法出乎意料地土:维护一个 todo.md 文件,每做完一项就更新它。

泄露的 Modules.txt(⚠️ 非官方)里的规则:

- Create todo.md file as checklist based on task planning from the Planner module
- Task planning takes precedence over todo.md, while todo.md contains more details
- Update markers in todo.md via text replacement tool immediately after completing each item
- Rebuild todo.md when task planning changes significantly

第一眼看上去,这就是个给人看的进度条。但官方博客揭示了真实用途

目的是把任务目标反复推进「最近的注意力范围」,对抗 lost-in-the-middle。

翻译一下:

「每完成一项立刻更新标记」这条规则,真实目的不是记录进度,是让目标不断出现在上下文末尾。

官方还给了一个数字:Manus 平均一个任务约 50 次工具调用。50 步里穿插十几次 todo 更新,目标就始终在视野内。

顺带对照几个数字,帮你建立量级感:Manus 实测均值约 50 步;MiniMax 的 Mini-Agent 默认上限 50 步;Kimi CLI 的上限是 1000 步。均值和上限差一个数量级是正常的。

4.5 保留错误轨迹(重复踩坑)

Agent 犯错了。某个网站要登录,它试了,失败了。

你的第一反应大概是:把这段失败清理掉,别污染上下文。

Manus 明确说这是错的。 官方原则第五条:

把失败的动作留在上下文里,模型会隐式地调整行为。错误恢复能力是「真 Agent」的核心指标。

为什么:

模型没有记忆,上下文就是它的全部记忆。你删掉的每一条失败记录,都是在让它重新踩一次坑。

顺带看一下泄露的错误处理规则(⚠️ 非官方),逻辑是一致的:

- Tool execution failures are provided as events in the event stream
- When errors occur, first verify tool names and arguments
- Attempt to fix issues based on error messages; if unsuccessful, try alternative methods
- When multiple approaches fail, report failure reasons to user and request assistance

失败作为事件进入流里,然后是一条「先检查参数 → 按报错修 → 换方法 → 还不行就问用户」的阶梯。

这跟 Kimi CLI 把子 Agent 的异常翻译成消息回传 是同一个思路:错误不是要藏起来的脏东西,是模型下一步决策的输入。

4.6 防 few-shot 模式锁定

官方第六条原则,比较微妙但很实用:

上下文里重复出现同一种模式,模型会一直跟着那个模式走,哪怕它已经不是最优解了

这叫「被自己 few-shot 了」。举例:你连续处理 20 个品牌,每个都是「打开官网 → 找价格页 → 提取」。到第 21 个品牌时,它的官网结构完全不同,价格在 PDF 里——但模型已经被前 20 次的模式锁死,会机械地重复「打开官网 → 找价格页」,然后失败。

解法是在序列化格式和措辞上故意引入结构化的变化。 不要让每一条记录都长得一模一样。

五、把六条原则串起来看

前面拆开讲了,现在合起来。这六条不是六个孤立技巧,是一条推理链

注意②③⑤三条都指向同一个根:因为前缀不能动,所以「事后删东西」这条路整个被封死了。 一旦接受这个约束,剩下的设计就只能是「一开始就别放进来」(③)、「放进来了就遮住」(②)、「留着还有好处」(⑤)。

这就是「上下文工程」这四个字的实际含义——不是写好提示词,是把上下文当成一个有物理约束的资源来经营。

六、Manus 架构里最容易被忽略的部分:三个外置模块

回到第三节那张事件流的图。④⑤⑥三种事件不是 Agent 产生的,是外部模块推进来的。

6.1 Planner Module——规划器在循环外面

泄露的 Modules.txt(⚠️ 非官方):

- System is equipped with planner module for overall task planning
- Task planning will be provided as events in the event stream
- Task plans use numbered pseudocode to represent execution steps
- Each planning update includes the current step number, status, and reflection
- Must complete all planned steps and reach the final step number by completion

这跟绝大多数框架的做法是反的。

规划在哪谁在规划
LangGraph / CrewAI 等框架循环Agent 自己调一个 plan 工具
Kimi CLI循环plan 是一个子 Agent 工种
Manus循环外独立的系统模块,结果当事件推进来

而且规划的形式是「带编号的伪代码」,主 Agent 必须走完所有编号步骤才算完成。

为什么要把规划提出去:因为规划和执行需要的上下文完全不同。规划需要的是「任务全貌 + 当前进度」,执行需要的是「这一步的细节」。放在一个上下文里,两边互相干扰——执行时读进来的一堆网页正文,对规划毫无用处,还会把规划的判断带偏。

这跟 todo.md 是什么关系? 泄露的规则说得很清楚:

- Task planning takes precedence over todo.md, while todo.md contains more details

Planner 的伪代码是权威,todo.md 是它的细化副本,冲突时以 Planner 为准。一个负责「大方向对不对」,一个负责「把目标顶到注意力窗口里」。

6.2 Knowledge Module——带作用域的经验注入

- Task-relevant knowledge will be provided as events in the event stream
- Each knowledge item has its scope and should only be adopted when conditions are met

每条知识有自己的作用域,只在条件满足时采纳」 —— 这是个 RAG 变体,但检索出来的不是资料,是行为规范(「遇到这类网站应该怎么做」)。

作用域这件事很关键:如果把所有经验都无条件塞进系统提示词,一是撑爆前缀,二是不相关的经验会误导模型。

6.3 Datasource Module——按需注入 API 文档

就是 Step 3 讲的那个:数据 API 不做成工具,文档按需以事件注入。

6.4 合起来的架构

大部分人复刻 Manus 只复刻了中间那条链(事件流 + 主 Agent + 沙箱),漏掉了上面三个黄色模块。 这也是为什么开源复刻版跑起来总觉得「差点意思」。

七、拆第五堵墙(太慢)——Wide Research

前面六节全在讲怎么让一个 Agent 撑住。但串行跑 100 个品牌,用户要等两小时。

Manus 的答案是 Wide Research,官方页面说得很直接:

问题官方说法
拆成多少个主 Agent 把请求拆成上百个独立子任务,可扩展到「hundreds」
一个子 Agent 是什么自己的虚拟机、自己的工具、自己的联网,全新的上下文
子 Agent 之间"Sub-agents never talk to each other." 理由:防止上下文污染、减少幻觉
结果怎么收主 Agent 收集全部结果,综合成最终报告
子 Agent 有角色吗没有,每个都是完整能力的 Manus 实例

7.1 两个值得琢磨的设计

① 子 Agent 不预设角色。

CrewAI、MetaGPT 那一派的核心卖点是「给 Agent 分配角色」——产品经理、架构师、工程师、测试。Manus 反着来:每个子 Agent 都是完整的通用 Manus,区别只在于分到的任务不同。

背后的判断是:角色分工的收益来自提示词特化,而模型越强,特化的边际收益越小;但角色分工的成本——角色之间的交接损耗、职责边界的扯皮——不会随模型变强而减少。

② 隔离粒度是「一台虚拟机」,本专题里最粗的一档。

对照一下:

隔离单位代表一个子 Agent 崩了会怎样并发量级
一台虚拟机Manus只死一台,其他 99 个照跑上百
一个沙箱容器Suna容器级隔离数十
一个上下文窗口Kimi CLI异常转成消息回传未见硬编码
一个 LangGraph 分支DeerFlow同上3

这里有个反直觉的规律:隔离越重,并发反而越高。

因为轻量隔离共享同一个进程的资源,并发天花板由进程决定;重隔离往外扩就是加机器,只受基础设施限制。

所以「要不要上重隔离」这个问题,实际等价于「我要不要几十上百路并行」。 要,就得付虚拟机的钱;不要,同进程三五路够用。

八、会在哪儿翻车:症状 → 原因 → 对策

你观察到的症状真正的原因对策
账单比预期高 10 倍前缀不稳定,KV-cache 完全不命中系统提示词里去掉时间戳等变化内容(Step 2)
加了个新工具之后突然变贵工具列表在前缀里,改动导致缓存全废工具列表定死,用遮蔽控制可用性(Step 3)
历史里的工具调用报 schema 错误动态删了工具,历史引用到不存在的工具同上,只遮蔽不删除(Step 3)
上下文很快就满网页正文、文件内容直接进了上下文存文件,上下文只留路径和 URL(Step 4)
干到一半跑偏,忘了原始目标lost-in-the-middle,开头的目标看不见了todo.md 每完成一项就更新,把目标推到末尾(Step 5)
同一个坑反复踩失败记录被清理掉了错误留在上下文里,它是决策输入(Step 6)
遇到结构不同的新情况还机械套老流程被自己的历史模式 few-shot 了序列化格式和措辞故意引入变化(Step 7)
接了几百个数据源之后系统变得又慢又贵每个数据源一个工具,工具描述吃掉几万 token数据 API 改成 Python 库,走 shell 调(Step 3)
规划总是被执行细节带偏规划和执行共用一个上下文把 Planner 提到循环外,结果以事件注入(第六节)
单任务太慢,用户等不起一次只调一个工具,串行Wide Research,一子任务一虚拟机(第七节)

九、全局定位

01 的五个维度 打分:

维度Manus 的答案
D1 隔离单位一台独立虚拟机,本专题最粗粒度
D2 通信拓扑严格星型,官方明文「子 Agent 之间从不交谈」
D3 结果回收主 Agent 收集全部结果后综合,具体裁剪策略未公开
D4 递归深度官方未公开;从「上百个子任务由主 Agent 拆分」推测为单层
D5 生命周期一次性,未见公开的 resume 机制

一句话总结:Manus 真正的护城河不在多 Agent 那一层。Wide Research 是「有钱就能堆」的东西,而前面六条上下文工程原则才是四次重写换来的经验。

9.1 和 Kimi CLI 横着比

ManusKimi CLI
一轮几个工具调用只能 1 个(保前缀线性)鼓励并行(保速度)
规划在哪循环外的独立模块循环内的 plan 子 Agent 工种
子 Agent 有角色吗没有,都是完整实例,coder / explore / plan
隔离单位一台虚拟机一个 context.jsonl 文件
几百个数据源怎么接写 Python 调库,不进工具列表MCP(但子 Agent 拿不到)
子 Agent 能否复活未公开可以resume=agent_id

两条路线的分歧点很清楚

  • Manus 信「模型够强就别搞结构」:子 Agent 不分角色、规划外置、工具尽量少
  • Kimi CLI 信「结构能省钱」:分工种、不同工种绑不同模型、按工种剥离工具权限

考虑到 Manus 底座用的是别家模型、Kimi 用的是自家模型,这个分歧还有一层商业逻辑:能控制模型的人倾向于把复杂度往模型里推,不能控制模型的人倾向于把复杂度留在工程层。 这条线在 08 里还会出现。

十、小结与自查清单

如果你要做一个「能连续干几小时」的 Agent:

成本

  • 系统提示词里有没有每轮都变的东西(时间戳、随机 ID、当前进度百分比)?
  • 工具列表是固定的吗?有没有按阶段动态增删?
  • 上下文是「只追加」的吗?有没有回头去改/删中间的内容?
  • 算过自己的输入输出比吗?如果远大于 1,优化重心应该全在输入侧

上下文容量

  • 大块内容(网页正文、文件、命令输出)是进上下文还是进文件?
  • 丢掉的东西「找得回来」吗?URL 和路径留了吗?

长任务不跑偏

  • 有没有机制让任务目标周期性地重新出现在上下文末尾?
  • 失败记录是留着还是清掉的?(应该留着)
  • 有没有防止「被自己的历史模式锁死」的措施?

架构

  • 规划和执行是共用一个上下文,还是分开的?
  • 有没有「显式表示任务完成」的工具?(别靠解析文字)
  • 数据源多的话,是每个一个工具,还是统一走代码执行?

要不要上多 Agent

  • 子任务之间真的互相独立吗?(不独立就别拆,见 08
  • 需要几路并行?几路的话轻量隔离够用,上百路才值得付虚拟机的钱

十一、参考