OpenManus 源码解析

运行方式

官方文档中,给出了三种运行方式,分别是:

一行命令运行 OpenManus:

1
python main.py

如需使用 MCP 工具版本,可运行:

1
python run_mcp.py

如需体验不稳定的多智能体版本,可运行:

1
python run_flow.py

17434758038881743475802956.png

代码关系图

先看代码之间的继承关系,有助于理解后续的各种模式的实现。

其中,绿色的为未实现的部分,蓝色的为已经实现的部分,可以看出 OpenManus 是想使用 ReAct 和 COT 两种增强模型推理的能力,但 COT 目前暂未完善,红色部分为关键函数

1743477602887openmanus.drawio.png

主要的关键函数为 run,think,act。这几个函数的大致作用如下:

run: 执行整个流程,并且为了防止一直执行下去,判断是否达到最大的步数(step)

step: 执行 think 和 act 的过程称为一个 step

think: 调用大模型的过程,将任务和工具给到大模型,让其选择是否需要工具来完成本次任务

act: 一个工具的执行叫做一个 action

针对于每个 Agent 之间的 think,run,act 之间有什么细微区别,可以在后面运行模式中详细说明。

目前时间为 2025-04-01,后续代码可能会有变动

COT 和 ReAct 的区别:

特性 Chain-of-Thought (COT) ReAct
推理方式 内部推理,仅依赖模型自身的知识和逻辑推导 内部推理 + 外部行动,允许与环境交互
外部依赖 无外部依赖 可以依赖外部工具或知识库
适用场景 需要多步逻辑推理的任务 需要动态决策和与环境交互的任务
输出形式 显式的推理链条 推理链条 + 行动记录
灵活性 固定在模型内部,无法动态获取新信息 动态性强,可根据外部反馈调整策略

COT 举例:

问题: 如果一个房间有 3 张桌子,每张桌子上有 4 把椅子,总共有多少把椅子?
推理: 每张桌子有 4 把椅子,一共有 3 张桌子,所以总数是 3 × 4 = 12。
答案: 12 把椅子。

ReAct 举例:

问题: 北京的天气如何?
推理: 我需要查询北京的实时天气信息。
行动: 查询天气 API。
结果: 北京当前温度为 20°C,晴天。
答案: 北京当前温度为 20°C,晴天。

Manus 模式

直接实例化 Manus 对象,运行了 BaseAgent 中的 run 方法,run 方法中,判断当前 Agent 的状态是否已经完成,并且步数是否已经达到最大步数(默认为 10),如果二者满足其一,那么其实整个 Agent 就已经结束或者该结束了,不会执行下面的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async def run(self, request: Optional[str] = None) -> str:
results: List[str] = []
async with self.state_context(AgentState.RUNNING):
# 判断当前 Agent 的状态是否已经完成,并且步数是否已经达到最大步数(默认为 10)
while (self.current_step < self.max_steps and self.state != AgentState.FINISHED):
# 步数+1
self.current_step += 1
# 执行一次 step
step_result = await self.step()
results.append(f"Step {self.current_step}: {step_result}")

# 已经超过最大步数了
if self.current_step >= self.max_steps:
self.current_step = 0
self.state = AgentState.IDLE
results.append(f"Terminated: Reached max steps ({self.max_steps})")

执行每一个 step(COT 和 ReAct 中都有 step 的实现,因为这里是Manus 模式,所以执行的是 ReActAgent 中的 step),step 中的逻辑也很简单,就是先进行一次模型的调用,然后判断是否调用工具

1
2
3
4
5
6
7
async def step(self) -> str:
# 先执行 think
should_act = await self.think()
if not should_act:
return "Thinking complete - no action needed"
# 如果需要执行 act,那么再调用 act
return await self.act()

think 执行的过程就是去调用大模型的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
async def think(self) -> bool:
try:
response = await self.llm.ask_tool(
messages=self.messages,
system_msgs=(
[Message.system_message(self.system_prompt)]
if self.system_prompt
else None
),
tools=self.available_tools.to_params(),
tool_choice=self.tool_choices,
)
......
# 判断是否需要使用工具
self.tool_calls = tool_calls = (
response.tool_calls if response and response.tool_calls else []
)

因为 Manus 是继承自 BrowserAgent 的,二者中都有 think 方法,但其中的 think 方法都在为生成一个叫 next_step_prompt 的变量做准备,这是将当前的浏览器窗口信息传递到模型中,然后让大模型做出后续决定的 prompt,prompt 翻译后如下所示:

为了实现目标,我接下来应该做什么?

当你看到[Current state starts here]时,请关注以下内容:

  • 当前 URL 和页面标题{url_placeholder}
  • 可用标签页{tabs_placeholder}
  • 交互元素及其索引
  • 视口上方{content_above_placeholder}或下方{content_below_placeholder}的内容(如已标注)
  • 任何操作结果或错误{results_placeholder}

浏览器交互操作:

  • 导航跳转:使用 browser_use 并设置 action=”go_to_url”, url=”…”
  • 点击元素:使用 browser_use 并设置 action=”click_element”, index=N
  • 输入文本:使用 browser_use 并设置 action=”input_text”, index=N, text=”…”
  • 提取操作:使用浏览器功能,动作属性为“extract_content”,目标为“…”
  • 滚动操作:使用浏览器功能,动作属性为“scroll_down”或“scroll_up”

同时考虑当前可见内容及视口之外可能存在的部分。
保持条理性——记住你的进度和目前已掌握的信息。

act 的执行过程,就是调用每个工具的过程了

1
2
3
4
5
6
async def act(self) -> str:
results = []
# 循环调用 think 出来的工具
for command in self.tool_calls:
result = await self.execute_tool(command)
......

MCP 模式

MCP 的运行流程和 Manus 的流程是一样的,只不过工具的来源是 MCP,并且 MCP 的 think 中没有了 next_step_prompt 这个 prompt

1
2
3
4
5
6
7
8
9
10
11
12
13
async def _initialize_and_list_tools(self) -> None:
# 获取 MCP Server 的工具列表
response = await self.session.list_tools()

for tool in response.tools:
server_tool = MCPClientTool(
name=tool.name,
description=tool.description,
parameters=tool.inputSchema,
session=self.session,
)
self.tool_map[tool.name] = server_tool
self.tools = tuple(self.tool_map.values())

而 MCP Server 的 run 方法会注册支持的所有工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MCPServer:
def __init__(self, name: str = "openmanus"):
self.tools["bash"] = Bash()
self.tools["browser"] = BrowserUseTool()
self.tools["editor"] = StrReplaceEditor()
self.tools["terminate"] = Terminate()

def register_all_tools(self) -> None:
# 注册所有工具
for tool in self.tools.values():
self.register_tool(tool)

def run(self, transport: str = "stdio") -> None:
"""Run the MCP server."""
self.register_all_tools()
......

Flow 模式

Flow 模式也是未完成的状态,目前仅支持 PlanningFlow,原理是通过 prompt,将 planning_tool 作为工具描述给大模型,然后大模型做出相应的 plan(planning_tool 中提供了create,update 等操作), System Prompt 如下:

1
2
3
4
5
6
7
system message:
你是一名规划助手。制定一个简洁、可操作的计划,包含清晰的步骤。
重点关注关键里程碑,而非详细的子步骤。
以清晰和高效为优化目标。

user message:
制定一个合理的计划,包含清晰的步骤以完成任务:{request}

得到一个 plan 之后,会去循环执行 plan 的每一步,其中每一步都会通过大模型然后选择出适当的工具来执行,prompt 如下,这里就和之前的逻辑一样了,会去执行每一个 step,然后执行 think 和 act。

1
2
3
4
5
6
7
当前计划状态:
{plan_status}

你的当前任务:
你现在正在处理第 {self.current_step_index} 步:“{step_text}”

请使用适当的工具执行此步骤。完成后,请提供你所完成内容的简要总结。

1743585371204openmanus-flow.drawio.png

内置的工具列表

工具类别 具体名称 功能描述
WebSearch GoogleSearchEngine,BaiduSearchEngine,DuckDuckGoSearchEngine,BingSearchEngine 执行网络搜索并返回相关链接的列表。这个函数尝试使用搜索引擎API来获取最新的结果。如果出现错误,它会返回到另一个搜索引擎。
FileSaver FileSaver 将内容保存到指定路径的本地文件中。当您需要将文本、代码或生成的内容保存到本地文件系统上的文件中时,可以使用此工具。该工具接受内容和文件路径,并将内容保存到该位置。
StrReplaceEditor StrReplaceEditor 支持沙盒功能的文件查看、创建和编辑工具。
CreateChatCompletion CreateChatCompletion 创建一个具有指定输出格式的结构化内容
BrowserUseTool BrowserUseTool 浏览器操作
PythonExecute PythonExecute 安全的执行 Python 代码
Terminal Terminal 执行系统命令
Terminate Terminate 当无法继续运行或者完成任务时调用
PlanningTool PlanningTool 一种规划工具,允许 Agent 创建和管理用于解决复杂任务的计划。该工具提供了创建计划、更新计划步骤以及跟踪进度的功能。
MCPClientTool MCPClientTool MCP 客户端工具

官方后续计划

1
2
3
4
5
6
7
1. 增强Planning能力 
2. 引入标准化评测 - 采用GAIA和SWE-Bench作为基准,持续评估和优化性能
3. 拓展模型适配 - 从Claude-3-5扩展到DeepSeek V2.5,优化低成本应用场景
4. 实现容器化部署 - 简化安装和使用流程
5. 丰富示例库 - 增加更多实用案例,包含成功和失败示例的分析
6. 前后端开发 - 提供用户体验
7. RAG 知识库

官方项目参考

‍‍‬‬‌‍‍⁠‍⁠‌‍‌‌‬‬‬‍‍⁠⁠OpenManus投票 - 飞书云文档

附件

代码关系图:

https://fastly.jsdelivr.net/gh/rexyan/warehouse@master/openmanus.drawio

https://fastly.jsdelivr.net/gh/rexyan/warehouse@master/openmanus-flow%20(4).drawio