Skip to content

开源 Agents - Open Manus 源码解读

ReAct

核心理念是 ReAct : "思考-行动"循环

框架思路参考: www.promptingguide.ai

ReAct 和 COT 的区别

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

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

Open Manus 主要架构图:

img

规划 Planning : 任务分解、子任务生成及自我反思

  • Reason + Act(ReAct)推理-行动-反馈
  • Plan-and-Solve(PS) 显式分解任务为子目标并分步执行,提升复杂任务的推理能力

记忆 Memory : 长期记忆存储与上下文管理,用于处理复杂任务

工具使用 Tool Usage : 通过API或外部工具增强Agent的能力(如搜索、文件操作,代码执行等) Open Manus 内所有的都是 Agent, 通过 Agent 之间的相互调用完成任务

Reason + Act(ReAct)

主要步骤

  1. 初始化:创建Manus实例,加载系统提示词和可用工具。
  2. 用户输入:接收用户的自然语言指令。
  3. 思考阶段:调用LLM分析当前状态,决定下一步行动。
  4. 行动阶段:执行选定的工具,获取结果。
  5. 循环迭代:将结果反馈给LLM,继续思考和行动,直到任务完成

核心方法

  • Think - 代理会根据当前状态进行推理,决定下一步的动作
  • Act - 代理会执行决定的动作,并返回结果 - Observation
  • Step - 记录步骤,驱动代理执行思考和行动-循环迭代

如下手画代码流程

img

img

详细框架流程图

img

源码:BaseAgent 核心属性

  1. 基本信息:
  • name:代理的唯一名称,必须提供
  • description:可选的代理描述
  1. 提示系统:
  • system_prompt:系统级指令提示,用于初始化代理
  • next_step_prompt:决定下一步行动的提示
  1. 依赖组件:
  • llm:语言模型实例,默认创建一个新的 LLM 实例
  • memory:代理的内存存储,用于保存消息历史
  • state:当前代理状态,默认为 IDLE
  1. 执行控制:
  • max_steps:终止前的最大步骤数,默认为 10
  • current_step:当前执行步骤,默认为 0
  • duplicate_threshold:检测重复响应的阈值,默认为 2

案例: 生成一篇关于熬夜对健康的影响的调研报告

以下流程展示了 Open Manus 基于 ReAct 模式,从接收用户任务到输出完整调研报告的完整执行过程。每一步都遵循「思考 → 行动 → 观察」的循环。

① 用户输入与任务解析:用户提交自然语言指令「生成一篇关于熬夜对健康的影响的调研报告」,Agent 接收并解析任务意图。

img

② 思考阶段(Think):LLM 分析当前状态,将复杂任务拆解为可执行的子目标,并决定首先需要检索相关文献或资料。

img

③ 行动阶段(Act):Agent 选择并调用合适的工具(如搜索 API),执行信息检索动作。

img

④ 观察结果(Observation):工具返回检索到的资料,Agent 将结果作为上下文反馈给 LLM。

img

⑤ 迭代推理:根据已有信息,LLM 判断是否需要继续搜索、补充数据,或进入报告撰写阶段。

img

⑥ 内容生成:在信息充足后,Agent 开始整合资料,按调研报告结构生成正文内容。

img

⑦ 输出完成:完成报告撰写,返回最终成果给用户,结束 ReAct 循环。

img

Planning

python
class PlanningFlow(BaseFlow):
"""A flow that manages planning and execution of tasks using agents."""

  llm: LLM =Field(default_factory=lambda: LLM())
  planning_tool:PlanningTool=Field(default_factory=PlanningTool)
  executor_keys:List[str]=Field(default_factory=list)
  active_plan_id:str=Field(default_factory=lambda:f"plan_{int(time.time())}")
  current_step_index:Optional[int]= None
  1. 依赖组件
  • llm:语言模型实例,用于与 LLM 交互
  • planning_tool:规划工具实例,用于创建和管理执行计划
  1. 执行控制
  • executor_keys:执行代理的键列表,默认为空列表
  • active_plan_id:当前活动计划的 ID,默认使用时间戳生成
  • current_step_index:当前步骤索引,默认为 None

执行流程:

  1. 验证主代理是否可用
  2. 如果提供了输入文本,创建初始计划
  3. 验证计划是否创建成功
  4. 进入执行循环:
  • 获取当前要执行的步骤
  • 如果没有更多步骤或计划已完成,调用 _finalize_plan并结束循环
  • 根据步骤类型选择合适的执行代理
  • 执行当前步骤并收集结果
  • 检查代理是否想要终止执行
  1. 返回执行结果
  2. 捕获并处理异常

Open Manus message

Open Manus 的对话与执行状态通过 Memory 中的 messages 列表维护。每条消息都有明确的 rolecontent,共同构成 Agent 的上下文与执行轨迹。

消息角色(role)

  • user:用户指令、系统引导提示(如「根据用户需求主动选择工具」)、浏览器截图等上下文
  • assistant:LLM 的推理、规划与回复,以及通过 tool_calls 触发的工具调用
  • tool:工具执行后的观测结果(如 browser_use 的搜索/提取结果、str_replace_editor 的文件创建结果等)

执行流程在 messages 中的体现:用户发起请求后,Agent 先规划步骤并回复,再发起工具调用;工具返回的 Observed output 作为新消息追加;系统会插入「下一步该做什么」等引导,驱动下一轮 Think-Act 循环,直到调用 terminate 结束任务。

img

Suna

类似 open manus (不过源码完整体不够,改了好多地方才跑起来) Suna 的 Agent 核心是整个系统最核心的部分,基于ReAct(Reasoning + Action)模式运作。

技术路线:

img

python
async def run_agent(thread_id, sandbox, stop_event, add_message):
    """Agent核心执行循环"""
    iteration = 0
    max_iterations = 10

    # 发送开始状态
    add_message(status_message("thread_run_start"))

    while iteration < max_iterations:
        # 1. 检查停止信号
        if stop_event.is_set():
            add_message(status_message("finish", reason="stopped"))
            break

        # 2. 获取视觉状态(如浏览器截图和DOM)
        browser_state = get_latest_browser_state(thread_id)
        temp_messages = []
        if browser_state:
            # 把浏览器状态转为临时消息(LLM能"看见"当前页面)
            temp_messages.append(format_browser_state_message(browser_state))

        # 3. 获取处理后的对话历史(可能已包含摘要)
        history = get_formatted_messages(thread_id)

        # 4. 准备完整上下文并调用LLM
        add_message(status_message("thinking"))

        response_processor = ResponseProcessor(
            sandbox=sandbox,
            tool_registry=tool_registry,
            add_message_callback=add_message
        )

        # 5. 流式处理LLM响应(实时解析XML并执行工具)
        finish_reason = await response_processor.process_streaming_response(
            call_llm(history + temp_messages)
        )

        # 6. 检查是否需要结束循环
        if finish_reason in ["ask", "complete"]:
            add_message(status_message("finish", reason=finish_reason))
            break

        iteration += 1

    # 如果达到最大迭代次数
    if iteration >= max_iterations:
        add_message(status_message("finish", reason="max_iterations"))

    # 发送结束状态
    add_message(status_message("thread_run_end"))

img

但在工程化上做的更好。 在内存、数据库、沙盒等方面有一定的参考价值

且每个工具使用@xml_schema装饰器定义其XML接口

思考

无论是哪一种 Agent 的路线,最感觉最关键的部分是 prompt 的设计,一好的 prompt 驱动整个流程。

Released under the MIT License.