OpenManus 是一个基于 LLM 的任务规划和执行框架,其核心功能是通过 LLM 智能拆分任务并动态执行。本文详细介绍 OpenManus 中的任务拆分和动态规划实现机制。
一、框架概述
OpenManus 采用多层架构设计实现任务拆分和动态规划,主要包括以下核心组件:
- FlowFactory:工厂模式创建流程实例
- PlanningFlow:管理任务规划和执行
- PlanningTool:提供计划的创建、更新、执行等功能
- Manus:执行具体任务的代理
整体工作流程:
- 使用 PlanningFlow 进行任务规划和拆解
- 通过 LLM 动态生成执行计划
- 使用 Manus 代理执行具体任务
- 支持任务状态追踪和动态调整
二、任务拆分机制
2.1 任务规划初始化
任务规划初始化是通过向 LLM 发送特定的提示来实现的:
async def _create_initial_plan(self, request: str):
# 创建系统消息指导LLM进行规划
system_message = Message.system_message(
"您是任务规划助手。创建一个简洁、可执行的计划,包括明确的步骤。"
"优先考虑关键里程碑,而不是详细的子步骤。"
"优化清晰度和效率。"
)
# 创建用户消息描述任务
user_message = Message.user_message(
f"创建一个合理的计划,包括明确的步骤,以完成任务:{request}"
)
系统通过向 LLM 发送特定的提示,引导其分析用户任务并生成执行计划。这种方式允许 LLM 根据任务的复杂性和特点动态决定需要的步骤数量和类型。
2.2 步骤类型识别
系统会自动从步骤描述中识别步骤类型:
# 尝试从步骤文本中提取步骤类型(例如,[SEARCH] 或 [CODE])
import re
type_match = re.search(r"\[([A-Z_]+)\]", step)
if type_match:
step_info["type"] = type_match.group(1).lower()
这种机制使系统能够根据步骤类型选择合适的执行器,例如搜索步骤使用搜索执行器,编码步骤使用代码执行器等。
2.3 默认计划创建
如果 LLM 未能生成有效计划,系统会创建一个默认计划:
# 创建默认计划
await self.planning_tool.execute(
**{
"command": "create",
"plan_id": self.active_plan_id,
"title": f"计划:{request[:50]}{'...' if len(request) > 50 else ''}",
"steps": ["分析请求", "执行任务", "验证结果"],
}
)
这确保了即使在 LLM 规划失败的情况下,系统仍然能够继续执行任务。
三、动态规划实现
3.1 执行循环
系统通过循环执行以下步骤来实现动态规划:
while True:
# 获取当前步骤信息
self.current_step_index, step_info = await self._get_current_step_info()
# 如果没有活动步骤,则退出
if self.current_step_index is None:
result += await self._finalize_plan()
break
# 执行当前步骤
step_type = step_info.get("type") if step_info else None
executor = self.get_executor(step_type)
step_result = await self._execute_step(executor, step_info)
result += step_result + "\n"
这个循环会不断获取当前待执行的步骤,选择合适的执行器,执行步骤并记录结果,直到所有步骤都执行完毕。
3.2 执行器选择
系统会根据步骤类型动态选择最合适的执行器:
def get_executor(self, step_type: Optional[str] = None) -> BaseAgent:
# 如果步骤类型匹配,则使用该类型的代理
if step_type and step_type in self.agents:
return self.agents[step_type]
# 否则,选择第一个可用的执行器代理或回退到主代理
for key in self.executor_keys:
if key in self.agents:
return self.agents[key]
# 回退到主代理
return self.primary_agent
这种机制确保每个步骤都由最合适的执行器处理,提高了执行效率和成功率。
3.3 步骤执行
每个步骤执行时,系统会准备完整的执行上下文:
async def _execute_step(self, executor: BaseAgent, step_info: dict) -> str:
# 准备代理执行上下文
plan_status = await self._get_plan_text()
step_text = step_info.get("text", f"步骤 {self.current_step_index}")
# 创建代理执行提示
step_prompt = f"""
当前计划状态:
{plan_status}
您当前的任务:
您现在正在执行步骤 {self.current_step_index}:"{step_text}"
请执行此步骤并提供执行结果。
"""
# 执行代理的run方法
step_result = await executor.run(step_prompt)
# 标记步骤为完成
await self._mark_step_completed()
return step_result
这种方式确保执行器拥有执行步骤所需的所有上下文信息,包括当前计划状态和具体任务。
3.4 状态管理
系统使用 PlanStepStatus
枚举跟踪每个步骤的状态:
async def _mark_step_completed(self) -> None:
# 标记步骤为完成
await self.planning_tool.execute(
command="mark_step",
plan_id=self.active_plan_id,
step_index=self.current_step_index,
step_status=PlanStepStatus.COMPLETED.value,
)
这种状态管理机制使系统能够准确跟踪任务执行进度,并在需要时进行动态调整。
3.5 计划完成
当所有步骤执行完毕后,系统会生成总结报告:
async def _finalize_plan(self) -> str:
# 创建总结
system_message = Message.system_message(
"您是任务规划助手。您的任务是总结完成的计划。"
)
user_message = Message.user_message(
f"计划已经完成。以下是最终计划状态:\n\n{plan_text}\n\n请提供总结和最终想法。"
)
response = await self.llm.ask(
messages=[user_message],
system_msgs=[system_message],
)
return f"计划完成:\n\n{response}"
这个总结报告提供了任务执行的整体情况和最终结果,便于用户了解任务完成情况。
四、实际执行流程示例
以"打开百度"任务为例,完整执行流程如下:
4.1 用户输入与初始化
用户输入:
打开百度
系统初始化:
# 创建 PlanningFlow 实例
planning_flow = PlanningFlow(agents={"primary": planning_agent, "executor": executor_agent})
# 执行流程
result = await planning_flow.execute("打开百度")
4.2 任务分析与计划创建
LLM 分析任务:
[System] 您是任务规划助手。创建一个简洁、可执行的计划,包括明确的步骤。优先考虑关键里程碑,而不是详细的子步骤。优化清晰度和效率。
[User] 创建一个合理的计划,包括明确的步骤,以完成任务:打开百度
LLM 响应(工具调用):
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "planning",
"arguments": "{\"command\":\"create\",\"plan_id\":\"plan_1234\",\"title\":\"打开百度\",\"steps\":[\"使用浏览器导航到百度网站\",\"确认页面加载成功\",\"验证任务完成\"]}"
}
}
系统执行工具调用结果:
已创建计划 plan_1234: 打开百度
- 步骤 1: 使用浏览器导航到百度网站 [待执行]
- 步骤 2: 确认页面加载成功 [待执行]
- 步骤 3: 验证任务完成 [待执行]
4.3 步骤 1 执行
获取当前步骤信息:
current_step_index, step_info = await self._get_current_step_info()
# 返回: 0, {"text": "使用浏览器导航到百度网站", "status": "pending"}
选择执行器:
executor = self.get_executor(step_info.get("type"))
# 返回: executor_agent (BrowserAgent)
准备执行上下文:
当前计划状态:
计划: 打开百度
- 步骤 1: 使用浏览器导航到百度网站 [进行中]
- 步骤 2: 确认页面加载成功 [待执行]
- 步骤 3: 验证任务完成 [待执行]
您当前的任务:
您现在正在执行步骤 1:"使用浏览器导航到百度网站"
请执行此步骤并提供执行结果。
执行器分析并生成工具调用:
{
"id": "call_def456",
"type": "function",
"function": {
"name": "browser_use",
"arguments": "{\"command\":\"navigate\",\"url\":\"https://www.baidu.com\"}"
}
}
浏览器工具执行结果:
{
"output": "已成功导航到 https://www.baidu.com",
"error": null,
"base64_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"system": "页面标题: 百度一下,你就知道"
}
步骤执行结果:
已成功导航到百度网站 (https://www.baidu.com)。
页面标题: 百度一下,你就知道
页面已完全加载,可以看到百度搜索框和相关功能。
更新步骤状态:
await self.planning_tool.execute(
command="mark_step",
plan_id="plan_1234",
step_index=0,
step_status="completed",
)
4.4 步骤 2 执行
获取当前步骤信息:
current_step_index, step_info = await self._get_current_step_info()
# 返回: 1, {"text": "确认页面加载成功", "status": "pending"}
选择执行器:
executor = self.get_executor(step_info.get("type"))
# 返回: executor_agent (BrowserAgent)
准备执行上下文:
当前计划状态:
计划: 打开百度
- 步骤 1: 使用浏览器导航到百度网站 [已完成]
- 步骤 2: 确认页面加载成功 [进行中]
- 步骤 3: 验证任务完成 [待执行]
您当前的任务:
您现在正在执行步骤 2:"确认页面加载成功"
请执行此步骤并提供执行结果。
执行器分析并生成工具调用:
{
"id": "call_ghi789",
"type": "function",
"function": {
"name": "browser_use",
"arguments": "{\"command\":\"get_page_info\"}"
}
}
浏览器工具执行结果:
{
"output": {
"url": "https://www.baidu.com/",
"title": "百度一下,你就知道",
"ready_state": "complete",
"elements": {
"input": 5,
"button": 8,
"link": 42,
"image": 15
}
},
"error": null
}
步骤执行结果:
页面加载状态检查:
- URL: https://www.baidu.com/
- 标题: 百度一下,你就知道
- 加载状态: complete (完全加载)
- 页面元素: 发现搜索输入框、按钮和其他交互元素
- 响应时间: 0.42秒
确认: 百度页面已成功加载,所有元素可见且可交互。
更新步骤状态:
await self.planning_tool.execute(
command="mark_step",
plan_id="plan_1234",
step_index=1,
step_status="completed",
)
4.5 步骤 3 执行
获取当前步骤信息:
current_step_index, step_info = await self._get_current_step_info()
# 返回: 2, {"text": "验证任务完成", "status": "pending"}
选择执行器:
executor = self.get_executor(step_info.get("type"))
# 返回: executor_agent (PlanningAgent)
准备执行上下文:
当前计划状态:
计划: 打开百度
- 步骤 1: 使用浏览器导航到百度网站 [已完成]
- 步骤 2: 确认页面加载成功 [已完成]
- 步骤 3: 验证任务完成 [进行中]
您当前的任务:
您现在正在执行步骤 3:"验证任务完成"
请执行此步骤并提供执行结果。
执行器分析并生成响应:
任务验证总结:
1. 浏览器成功导航到 https://www.baidu.com
2. 页面完全加载,标题为"百度一下,你就知道"
3. 所有页面元素可见且可交互
4. 用户可以在搜索框中输入内容并进行搜索
结论: 任务"打开百度"已成功完成。百度搜索引擎页面已打开并准备好供用户使用。
更新步骤状态:
await self.planning_tool.execute(
command="mark_step",
plan_id="plan_1234",
step_index=2,
step_status="completed",
)
4.6 计划完成与总结
获取当前步骤信息:
current_step_index, step_info = await self._get_current_step_info()
# 返回: None, None (所有步骤已完成)
生成计划总结:
[System] 您是任务规划助手。您的任务是总结完成的计划。
[User] 计划已经完成。以下是最终计划状态:
计划: 打开百度
- 步骤 1: 使用浏览器导航到百度网站 [已完成]
- 步骤 2: 确认页面加载成功 [已完成]
- 步骤 3: 验证任务完成 [已完成]
请提供总结和最终想法。
LLM 生成总结:
计划"打开百度"已成功执行完毕。系统按照预定步骤,首先通过浏览器导航到百度官方网站(https://www.baidu.com),然后确认页面已完全加载,所有元素可见且可交互,最后验证了任务的完成状态。整个过程顺利,没有遇到任何错误或异常。用户现在可以在百度搜索引擎上进行搜索或使用其他功能。任务目标已完全达成。
最终返回结果:
计划完成:
计划"打开百度"已成功执行完毕。系统按照预定步骤,首先通过浏览器导航到百度官方网站(https://www.baidu.com),然后确认页面已完全加载,所有元素可见且可交互,最后验证了任务的完成状态。整个过程顺利,没有遇到任何错误或异常。用户现在可以在百度搜索引擎上进行搜索或使用其他功能。任务目标已完全达成。
五、设计优势
OpenManus 的任务拆分和动态规划机制具有以下优势:
- 灵活性:可以处理各种类型的任务,从简单的网页浏览到复杂的数据分析
- 可扩展性:易于添加新的执行器和工具,扩展系统功能
- 鲁棒性:完善的状态管理和错误处理机制,确保任务执行的稳定性
- 智能性:利用 LLM 的理解能力动态规划任务,自适应不同任务特点
- 可追踪性:详细记录每个步骤的执行过程和结果,便于调试和优化
六、总结
OpenManus 通过 LLM 驱动的任务规划系统实现了智能的任务拆分和动态规划,能够根据不同任务的特点自适应地创建和执行计划。这种设计不仅提高了系统的灵活性和可扩展性,还充分利用了 LLM 的智能决策能力,为自动化任务执行提供了强大的支持。
通过将任务分解为明确的步骤,并为每个步骤选择最合适的执行器,OpenManus 能够高效地处理各种复杂任务,从而实现真正的智能任务自动化。