数据截至 (上游 commit 3309bf4e416f)
OpenManus — 通用 AI agent 骨架:架构与原理
30 秒导读: OpenManus 是 MetaGPT 团队做的开源版 Manus——你在终端敲一句话,它自己 决定调哪个工具、一步步执行,直到把事办完。它的价值不在功能多,而在骨架干净: 约 1.1 万行 Python,一条四层继承链就把「agent 循环」讲清楚了,而且外部能力全部通过 MCP 热插,不写死在代码里。想学「agent 到底是怎么写的」,这是最适合通读的样本之一。
本项目有多个子系统(智能体链、工具系统、MCP 双向桥、计划流、LLM 层、沙箱),所以拆成多篇。 先读本页建立全景,再按下方阅读地图下钻。
1. 这是什么(零基础也能懂)
一句话定义: OpenManus 是一个通用 AI agent 框架——给它一句自然语言任务,它反复 「问模型下一步干什么 → 真的去干 → 把结果喂回模型」,直到模型说「做完了」。
解决什么问题: 商业产品 Manus 很惊艳,但要邀请码。OpenManus 想做一个人人可跑、 可魔改的替代品(README 原话是「不用邀请码就能实现任何想法」)。
给谁用:
| 读者 | 用它干什么 |
|---|---|
| 想跑 agent 的开发者 | 配好 API key,直接在终端使唤它做事 |
| 想学 agent 原理的人 | 通读一遍源码,把 ReAct 循环和工具调用彻底搞懂 |
| 想造自己 agent 的人 | 继承 ToolCallAgent,换一套工具表就是一个新 agent |
它能做什么(靠工具):
- 读写、创建、精确替换本地文件(
str_replace_editor)。 - 执行 Python 代码片段(
python_execute)。 - 卡住时反问你一句(
ask_human)。 - 通过 MCP 挂上外部能力——默认自动挂上 Browser Use CLI 3.0,于是它会开浏览器。
- 觉得做完了就自己收工(
terminate)。
用起来什么样:
# 1. 配模型(示例配置里默认是 claude-3-7-sonnet)
cp config/config.example.toml config/config.toml
# 编辑 config.toml,填 api_key
# 2. 跑
python main.py
# Enter your prompt: 把 workspace 下的 sales.csv 汇总成月度报表,存成 report.md
入口就是 main.py:17 的 Manus.create() + main.py:26 的 agent.run(prompt) 两行;
默认模型与 base_url 来自 config/config.example.toml:1-7。
一句话直觉: 把 LLM 当成一个只会说话、没有手脚的大脑。OpenManus 干的事就是 给它接上手脚(工具),再套一个「问一句、动一下、看结果、再问一句」的循环—— 循环的每一轮都是一次完整的对话补全,记忆就是那条不断变长的消息列表。
2. 顶层全景(它大概怎么转)
2.1 一次任务的骨架
怎么读这张图:左边是你的输入,中间竖着的是每一步都会走两遍的循环(先想后做), 右下是动作真正落地的地方。
┌─────────────────────────┐
一句话任务 ─────────▶│ Manus 智能体 │
│ 最多 N 步的主循环 │
└────┬───────────────┬────┘
① 想:该做啥│ │② 做:执行工具
▼ ▼
┌──────────────┐ ┌────────────────────┐
│ LLM 封装层 │ │ 工具表 │
│ 返回 tool_ │ │ 本地工具 + MCP 代理│
│ calls │ └──────┬──────────┬──┘
└──────────────┘ ▼ ▼
本机 / Docker 外部 MCP
文件 · shell 服务器(浏览器…)
每走完一轮,工具的输出会以 tool 角色的消息写回记忆(app/agent/toolcall.py:155-161),
下一轮模型就看得见了。
2.2 部件一句话职责
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
BaseAgent | 跑「最多 N 步」的主循环,管状态、记忆、卡死检测 | app/agent/base.py |
ReActAgent | 把一步拆成 think()(想)+ act()(做)两个抽象方法 | app/agent/react.py |
ToolCallAgent | 用 function calling 让模型选工具,再真的执行并回写结果 | app/agent/toolcall.py |
Manus | 通用智能体:4 个本地工具 + 自动连接 MCP 服务器 | app/agent/manus.py |
LLM | 统一模型调用:消息格式化、token 计数、限额、重试 | app/llm.py |
BaseTool / ToolCollection | 工具基类与工具表,产出 OpenAI function schema | app/tool/base.py、app/tool/tool_collection.py |
MCPClients / MCPClientTool | 把远程 MCP 服务器的工具伪装成本地工具 | app/tool/mcp.py |
MCPServer | 反过来,把 OpenManus 的工具暴露成 MCP 服务器 | app/mcp/server.py |
PlanningFlow / PlanningTool | 先让模型出计划,再逐步把每步派给某个智能体 | app/flow/planning.py、app/tool/planning.py |
DockerSandbox | 把 shell 与文件操作关进带资源限额的容器 | app/sandbox/core/sandbox.py |
2.3 主线走一遍(高层,不进代码)
- 建智能体。
Manus.create()先实例化,再去连所有配置好的 MCP 服务器,把远程工具 合并进本地工具表(app/agent/manus.py:75-81)。 - 进主循环。
run()把你的话作为user消息写进记忆,然后while到max_steps或状态变成FINISHED(app/agent/base.py:116-154)。 - 想(think)。 把整条记忆 + 系统提示 + 全部工具的 JSON schema 发给模型,
要它回一个
tool_calls(app/agent/toolcall.py:47-56)。 - 做(act)。 逐个解析
tool_calls的 JSON 参数,在工具表里按名字找到工具执行, 结果包成tool消息写回记忆(app/agent/toolcall.py:131-172)。 - 收工。 模型调用
terminate这个「特殊工具」时,智能体状态被置成FINISHED, 下一轮while条件不成立,循环结束(app/agent/toolcall.py:218-231)。
3. 三种跑法(仓库里有五个入口)
| 入口 | 命令 | 干什么 | 文件 |
|---|---|---|---|
| 单智能体 | python main.py | 起一个 Manus,一路 ReAct 到 terminate | main.py |
| 计划流 | python run_flow.py | 先让 LLM 出计划,再逐步派活;可加 DataAnalysis 智能体 | run_flow.py |
| MCP 客户端 | python run_mcp.py | 起 MCPAgent,只用某台 MCP 服务器的工具 | run_mcp.py |
| MCP 服务端 | python run_mcp_server.py | 把 bash/editor/terminate 暴露给别的 agent 用 | run_mcp_server.py |
| 云沙箱版 | python sandbox_main.py | Daytona 远程沙箱版 Manus(带 VNC 预览链接) | sandbox_main.py |
run_flow.py:15-16 里那句 if config.run_flow_config.use_data_analysis_agent 就是
README 说的「在 config.toml 里加 [runflow] 才启用数据分析智能体」。
4. 阅读地图(建议顺序)
| 章节 | 讲什么 | 什么时候读 |
|---|---|---|
| 01-agent-core.md | BaseAgent 的主循环、状态上下文管理器、Memory、卡死检测 | 必读,一切的地基 |
| 02-react-toolcall.md | think()/act() 怎么把模型输出落成动作;Manus 与它的兄弟们 | 必读,项目的心脏 |
| 03-tools-and-mcp.md | 工具基类与 schema 生成;MCP 客户端/服务端双向桥 | 想加工具、想接外部能力时读 |
| 04-planning-flow.md | 计划流:出计划、按 [TAG] 选智能体、逐步执行 | 关心多智能体调度时读 |
| 05-llm-layer.md | 单例、format_messages、token 计数(含图片瓦片)、重试 | 关心成本/多模态/多供应商时读 |
| 06-sandbox.md | Docker 沙箱、FileOperator 双实现、Daytona 云沙箱 | 关心「代码在哪跑、安全吗」时读 |
| 07-insights-and-limits.md | 可借鉴的技术、已知坑与边界、横向对比、总代码地图 | 读完想带走精华时读 |
只有 20 分钟? 读 01 + 02,再跳到 07 的「巧妙之处」。
5. 代码地图(顶层导航)
| 主题 | 文件路径 | 符号名 |
|---|---|---|
| 单智能体入口 | main.py | main |
| 计划流入口 | run_flow.py | run_flow |
| MCP 客户端入口 | run_mcp.py | MCPRunner |
| MCP 服务端入口 | run_mcp_server.py | MCPServer |
| 云沙箱入口 | sandbox_main.py | main |
| 智能体基类 | app/agent/base.py | BaseAgent、BaseAgent.run |
| 通用智能体 | app/agent/manus.py | Manus、Manus.create |
| 工具基类 | app/tool/base.py | BaseTool、ToolResult |
| 全局配置单例 | app/config.py | Config、AppConfig、config |
| 消息与记忆模型 | app/schema.py | Message、Memory、AgentState |
| 模型调用封装 | app/llm.py | LLM、LLM.ask_tool、TokenCounter |