惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
F
Fortinet All Blogs
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
小众软件
小众软件
有赞技术团队
有赞技术团队
雷峰网
雷峰网
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
AWS News Blog
AWS News Blog
C
Cisco Blogs
美团技术团队
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
人人都是产品经理
人人都是产品经理
宝玉的分享
宝玉的分享
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
W
WeLiveSecurity
D
DataBreaches.Net
博客园 - 司徒正美
Blog — PlanetScale
Blog — PlanetScale
IT之家
IT之家
云风的 BLOG
云风的 BLOG
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Simon Willison's Weblog
Simon Willison's Weblog
Google DeepMind News
Google DeepMind News
T
The Blog of Author Tim Ferriss
Know Your Adversary
Know Your Adversary
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Vercel News
Vercel News
月光博客
月光博客
T
Tailwind CSS Blog
H
Help Net Security
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Spread Privacy
Spread Privacy
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
Microsoft Security Blog
Microsoft Security Blog
V
V2EX
WordPress大学
WordPress大学
Cyberwarzone
Cyberwarzone
Recent Announcements
Recent Announcements

博客园 - zhang-yd

今日开源[第33期] Home Assistant Core 今日开源[第32期] Vibe-Trading 今日开源[第31期]RuView 今日开源[第30期]Chrome DevTools MCP 今日开源[第29期]RomM (ROM Manager) 今日开源[第28期]Page Agent 今日开源[第27期]video-use 今日开源[第26期]SimpleX Chat 今日开源[第25期]LingBot-Map 今日开源[第24期]OpenMontage 今日开源[第23期]Voicebox 今日开源[第22期]tw93/Pake 今日开源[第21期]yifanfeng97/Hyper-Extract 今日开源[第20期]google-research/timesfm 今日开源[第19期]Panniantong/Agent-Reach 今日开源[第18期]karpathy/autoresearch 今日开源[第17期]public-domain-books-translation 今日开源[第16期]soxoj/maigret 论文解读-《Dual-Kernel Graph Community Contrastive Learning》 今日开源[第15期]agent-skills 论文解读-《Hyperbolic Continuous Structural Entropy for Hierarchical Clustering》 今日开源[第14期]google/skills 今日开源[第13期]turbovec 今日开源[第12期]LiteParse 今日开源[第11期]OmniVoice-Studio 今日开源[第10期]ds4(DwarfStar) 今日开源[第9期]graphify 今日开源[第8期]open-notebook 今日开源[第7期]spec-kit 今日开源[第6期]Production Agentic RAG Course 今日开源[第5期]Headroom 今日开源[第4期]OpenTalking 今日开源[第3期]train-llm-from-scratch 今日开源[第2期]Project N.O.M.A.D. 今日开源[第1期]MoneyPrinterTurbo LearningCell代码解读 论文解读-《It Takes a Graph to Know a Graph Rewiring for Homophily with a Reference Graph》 论文解读-《Mitigating Over-Squashing in Graph Neural Networks by Spectrum-Preserving Sparsification》 论文解读-《Make Heterophily Graphs Better Fit GNN A Graph Rewiring Approach》 论文解读-《Temporal Graph Rewiring with Expander Graphs 》 论文解读-《Understanding Oversquashing in GNNs through the Lens of Effective Resistance》 论文解读-《Homophily-oriented Heterogeneous Graph Rewiring》 论文-Deep appearance modeling: A survey 代码阅读笔记-nanoclaw 论文解读-《An Empirical Evaluation of Rewiring Approaches in Graph Neural Networks》 论文解读-《Probabilistic Graph Rewiring via Virtual Nodes》 论文解读-《Probabilistically Rewired Message-Passing Neural Networks》 论文解读-《Joint Graph Rewiring and Feature Denoising via Spectral Resonance》 代码阅读笔记-nanobot 论文解读-《Oversquashing in GNNs through the lens of information contraction and graph expansion》 论文解读-《GNNs Getting ComFy Community and Feature Similarity Guided Rewiring》 论文解读-《PANDA Expanded Width-Aware Message Passing Beyond Rewiring》 代码阅读笔记-AiPyApp 论文解读-《Deep Graph Contrastive Representation Learning》 论文解读-《Community-Invariant Graph Contrastive Learning》 论文解读-《DiffWire Inductive Graph Rewiring via the Lovász Bound》 论文解读-《The Effectiveness of Curvature-Based Rewiring and the Role of Hyperparameters in GNNs Revisited》 论文解读-《Over-Squashing in GNNs and Causal Inference of Rewiring Strategies》 论文解读-《Uncertainty-Aware Graph Structure Learning》
代码阅读笔记-OpenManus
zhang-yd · 2026-03-10 · via 博客园 - zhang-yd

项目介绍

OpenManus 是由 MetaGPT 团队孵化的开源通用 AI 智能体框架,核心目标是无需邀请码即可实现任意创意的智能体开发,支持多工具扩展、多智能体协作、强化学习(RL)调优(OpenManus-RL),并兼容 Google A2A 协议生态。

项目的定位是通用LLM智能体开发框架,支持远程和本地的工具调用。
项目代码的仓库地址:https://github.com/FoundationAgents/OpenManus

项目结构

整个项目使用分层架构设计
交互层: (终端输入,A2A Client, HuggingFace Demo) 接受用户任务输入,输出执行结果
启动层: (main.py run_mcp.py run_flow.py) 提供不同运行模式,单智能体,MCP工具,多智能体流程版
流程调度层: (多智能体规划 PlanningFlow) 任务规划,多智能体调度,步骤状态管理
智能体核心层: (Manus(通用智能体),DataAnalysis(专用智能体)) 通用智能体核心,管理工具集,MCP连接,浏览器上下文,决策逻辑
工具/协议扩展层: (本地工具,MCP远程工具, A2A协议工具) 内置本地工具,远程MCP工具,A2A协议工具

使用方法

One line for run OpenManus:

python main.py

Then input your idea via terminal!

For MCP tool version, you can run:

python run_mcp.py

For unstable multi-agent version, you also can run:

python run_flow.py

代码解读

智能体核心

代码在 app/agent/manus.py 中,核心类是 Manus,负责管理工具集,MCP连接,浏览器上下文,决策逻辑
关键的方法是:

  • initialize_mcp_servers:根据配置信息进行初始化MCP服务器
  • connect_mcp_server:分为connect_stdio 和 connect_sse 两种方式,分别对应标准输入输出和服务器发送事件。并将远程工具添加到 available_tools 列表中
  • think: 智能体决策核心:分析当前状态,若使用浏览器则格式化提示词,调用父类决策
  • cleanup: 资源清理:关闭浏览器、断开 MCP 服务器连接

Manus 继承自 ToolCallAgent, 代码在 app/agent/toolcall.py 中, ToolCallAgent 是一个通用的智能体框架,提供了一些基础的工具调用功能,如调用工具、管理工具集等。Manus 在 ToolCallAgent 的基础上,添加了更多的功能,如管理浏览器上下文、管理MCP连接等。
关键的方法有:

  • think: 先使用message和工具集合,去chat LLM,得到工具调用的方法
  • act: 循环所有的工具,进行工具调用
  • execute_tool: 执行单个工具调用,并进行可靠的错误处理
  • cleanup: 将self.available_tools.tool_map中的所有工具进行清理
  • run: 执行父类的run(request)的方法,执行有错则执行cleanup进行清理

ToolCallAgent 继承自 ReActAgent, ReActAgent的代码在 中,ReActAgent是很简单的基础类,包含了三个方法,分别是 think,act,step,其中think 和 act 方法都是没有实现的,step中简单构建了整个框架,先进行think,根据返回内容看是否需要act,或者进行 act ,或者直接返回think的结果。

Agent类

基础的Agent类,BaseAgent 类,代码是在 app/agent/base.py
BaseAgent类的有几个核心的属性:

  • system_prompt
  • next_step_prompt
  • LLM
  • memory
  • state
  • max_steps current_step

浏览器上下文Agent
结合browser和Agent类,记录当前的Agent的state和Memory的信息,共同进行下一步的规划。

数据分析Agent
代码是 app/agent/data_analysis.py 中,仅仅包含了工具集合为:NormalPythonExecute, VisualizationPrepare, DataVisualization, Terminate四类工具

代码编程 SWEAgent
代码在 app/agent/swe.py 下,包含了自动化编码的prompt,和相关的工具集合,bash,StrReplaceEditor,Terminate三个工具。

流程管理

流程的代码在 app.flow下,有三个文件,base.py flow_factory.py planning.py

base.py 中定义了 BaseFlow 类,是所有流程的基类,包含了简单地管理Agent的方法等。
如 属性primary_agent_key 是多个agent中的主agent,
还有 get_agent, add_agent, execute 方法,来管理agent。其中execute方法未定义。

flow_factory.py 中定义了 FlowFactory 类,是流程工厂类,负责创建流程。目前只支持一个流程,PlanningFlow。

planning.py 中定义了核心类 PlanningFlow 类,是流程的具体实现类,继承自 BaseFlow。
具有的属性有:

  • llm:大语言模型的实例
  • planning_tool:上下文
  • executor_keys:
  • activate_plan_id:状态
  • current_step_index: 当前执行步骤的索引

核心方法只有一个,就是 execute方法,该方法会根据当前状态,在多个Agent上执行不同的操作,如调用工具、更新状态等。
核心代码为

    async def execute(self, input_text: str) -> str:
        """Execute the planning flow with agents."""
        try:
            if not self.primary_agent:
                raise ValueError("No primary agent available")

            # Create initial plan if input provided  # 如果提供了输入,则说明是新的任务或者有新内容增加,则需要重新制定执行计划。
            if input_text:
                await self._create_initial_plan(input_text)

                # Verify plan was created successfully
                if self.active_plan_id not in self.planning_tool.plans:
                    logger.error(
                        f"Plan creation failed. Plan ID {self.active_plan_id} not found in planning tool."
                    )
                    return f"Failed to create plan for: {input_text}"

            result = ""
            while True:
                # Get current step to execute
                self.current_step_index, step_info = await self._get_current_step_info()

                # Exit if no more steps or plan completed
                if self.current_step_index is None:
                    result += await self._finalize_plan()
                    break

                # Execute current step with appropriate agent
                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"

                # Check if agent wants to terminate
                if hasattr(executor, "state") and executor.state == AgentState.FINISHED:
                    break

该方法的主要的做的内容是

  • 根据输入内容进行制定执行计划
  • 根据执行计划划分得到多个执行步骤,从而进行分步骤执行。

方法 def _create_initial_plan 将要prompt转为Message,并带有工具调用去chat LLM,得到tool_calls后

PlanningFlow 在execute 中的最常调用的是 PlanningTool 这个类的 execute 函数。
核心函数代码为:

def execute(self, *, command: Literal["create", "update", "list", "get", "set_active", "mark_step", "delete"],
        plan_id: Optional[str] = None,
        title: Optional[str] = None,
        steps: Optional[List[str]] = None,
        step_index: Optional[int] = None,
        step_status: Optional[Literal["not_started", "in_progress", "completed", "blocked"]] = None,
        step_notes: Optional[str] = None,
        **kwargs,
    ):
        """
        Execute the planning tool with the given command and parameters.
        Parameters:
        - command: The operation to perform
        - plan_id: Unique identifier for the plan
        - title: Title for the plan (used with create command)
        - steps: List of steps for the plan (used with create command)
        - step_index: Index of the step to update (used with mark_step command)
        - step_status: Status to set for a step (used with mark_step command)
        - step_notes: Additional notes for a step (used with mark_step command)
        """

        if command == "create":
            return self._create_plan(plan_id, title, steps)
        elif command == "update":
            return self._update_plan(plan_id, title, steps)
        elif command == "list":
            return self._list_plans()
        elif command == "get":
            return self._get_plan(plan_id)
        elif command == "set_active":
            return self._set_active_plan(plan_id)
        elif command == "mark_step":
            return self._mark_step(plan_id, step_index, step_status, step_notes)
        elif command == "delete":
            return self._delete_plan(plan_id)
        else:
            raise ToolError()

这个类主要在管理 plans 格式为dict{dict_name: plan_info_dict}的形式。

LLM模块

代码在 app/llm.py 下,使用单例模式来实现,每一个配置名只会创建一次的实例。
LLM类会首先进行tokenier 的初始化
代码为:self.tokenizer = tiktoken.encoding_for_model(self.model)
根据指定的模型名称返回对应的预训练分词器。不在集合中的模型,则统一使用 cl100k_base 预训练模型。

LLM类的几个关键方法
def ask(self,
messages: List[Union[dict, Message]],
system_msgs: Optional[List[Union[dict, Message]]] = None,
stream: bool = True,
temperature: Optional[float] = None,
) -> str:
发送一段Prompt给LLM以返回 response。
先将List[Message]的列表格式中的转为 List[dict{'role':'', 'content':''}]的格式。
然后,计算总的token的长度,判断是否需要满足不超过最大token数量。
最后,调用LLM的chat,分streaming 和 not stream的方式分别处理。

方法
def ask_with_images(self,
messages: List[Union[dict, Message]],
images: List[Union[str, dict]],
system_msgs: Optional[List[Union[dict, Message]]] = None,
stream: bool = False,
temperature: Optional[float] = None,
) -> str
方法
def ask_tool(self,
messages: List[Union[dict, Message]],
system_msgs: Optional[List[Union[dict, Message]]] = None,
timeout: int = 300,
tools: Optional[List[dict]] = None,
tool_choice: TOOL_CHOICE_TYPE = ToolChoice.AUTO, # type: ignore
temperature: Optional[float] = None,
** kwargs,
) -> ChatCompletionMessage | None
这两个方法的实现都类似 chat,只是增加对image和工具调用的支持。

还有一个有意思的类是 TokenCounter 类,负责计算token的数量。基于上面创建的tokenizer对象,来计算每一个文本的token,TokenCounter实现封装,可以计算纯文本的,也可以计算带图片的,还支持本项目的Message格式的token数量的计算。

沙箱sandbox agent代理

该模块的核心类是SandboxManus类。
代码是在 app/agent/sandbox_agent.py 上。一个多功能代理,可以使用多个沙盒工具(包括基于MCP的工具)解决各种任务
该类的核心方法有几个
create方法,根据输入的参数进行 SandboxManus的创建。只有三个步骤:

  • 类初始化;
  • initialize_mcp_servers:根据服务的类型(sse或者stdio)来进行mcp服务器的链接
  • initialize_sandbox_tools: 初始化沙箱,基于Python的daytona来实现。然后设置属性initialized 为True,从而完成创建。
    SandboxManus类同样跟 Manus 继承自 ToolCallAgent。

沙箱sandbox

该模式是在 app/sandbox 文件夹下,核心类是 LocalSandboxClient ,代码在 app/sandbox/client.py 下
类LocalSandboxClient下有很多关键的方法:

  • create 创建一个 DockerSandbox 对象,以提供一个容器化的执行环境。(确保资源限制,文件操作,指令执行的安全和独立)
  • run_command
  • copy_from 把文件从容器拷贝到运行的本地
  • copy_to 将文件从本地拷贝到容器内部
  • read_file 从容器中读取文件,直接调用 self.sandbox.read_file 完成读取
  • write_file 往容器中写入文件
  • clearnup 清理sandbox
    LocalSandboxClient类就是简单对 app/sandbox/core/sandbox.py 下的 DockerSandbox 进行了简单的封装

DockerSandbox类的解析
初始化该类的时候传入两个参数,config和volume_bindings,其中config是Sandbox的配置,volume_bindings是格式为{host_path: container_path}的卷映射

  • create 方法,根据docker创建一个docker容器,首先是 host_config来创建docker容器的配置,然后再使用 asyncio.to_thread 异步创建一个docker容器,最后创建一个 terminal 终端来连接到该docker终端,绑定好该docker容器并保持session。
  • run_command 方法,将命令cmd交给 self.terminal 进行执行
  • read_file 从容器中读取文件,另外起一个进程来读取docker中的文件,
asyncio.to_thread(self.container.get_archive, resolved_path)

然后从该对象中读取tar流,并使用临时文件保存下该tar流,然后一次性 tar.extractfile 得到文件内容。

  • write_file 写入文件,如果没有该路径,则进行创建路径,然后创建tar流,将文件内容以tar流的形式写入到容器对应的文件下。
await asyncio.to_thread(self.container.put_archive, parent_dir or "/", tar_stream)
  • cleanup 清理,先关闭 self.terminal, 然后 异步调用 asyncio.to_thread(self.container.stop, timeout=5) 等待容器关闭。
  • copy_to copy_from 这两个拷贝文件操作,其实就是对读写文件的一种封装

AsyncDockerizedTerminal类的解析
主要是维护一个DockerSession,通过init函数初始化好Terminal的session,以传递命令到docker中。
负责在client和Docker之间传输命令

SandboxManager类
代码是在 app/sandbox/core/manager.py ,该类主要负责管理多个SandBox,

  • 提供访问 SandBox 的锁机制,
  • 创建SandBox 并加入到管理字典中
  • 清理所有的SandBox,先获得全局锁,然后将所有使用过的SandBox进行清理和释放,并释放相关的锁
  • 提供两种清理的方式, 清理IDEA状态的SandBox,另一种是全部清理(先等任务执行完成后再进行清理)

mcp服务

启动脚本是根目录下的 run_mcp.py,其中核心是 MCPRunner 类
MCPRunner类负责封装 MCPAgent,提供了三个核心方法:

  • initialize方法: 代表 MCPAgent 进行初始化 stdio 和 see 两个方式
  • run 和 run的衍生方法(run_interactive, run_default, run_single_prompt)都是封装了 MCPAgent.run 函数。
    其中 run_single_prompt 传入单个prompt从而实现一次的执行
    其中 run_interactive 交互式地传入prompt的对话
    其中 run_default 默认的执行模式,传入一次prompt后输出

MCPAgent 是核心类,继承于ToolCallAgent

prompt提示词

代码在app/prompt文件夹。该文件夹下存放的是各个模块的prompt。
在browser.py, manus.py, mcp.py, planning.py, swe.py, toolcall.py, visualization.py 下,有 SYSTEM_PROMPT, NEXT_STEP_PROMPT 两个提示词。
整个项目的核心在于这些提示词的质量。

工具

所有的工具集合都在这个文件夹 app/tool 下。
所有工具类的基础类是 BaseTool,用于组合BaseModel和工具功能的所有工具

AskHuman类,代码在 app/tool/ask_human.py 中,让LLM在信息不够详细的时候需求使用人类的介入

网络搜索工具,代码在 app/tool/search 文件夹下,含有多个不同的网络搜索,baidu,bing,google,duckduckgo

  • baiduSearch: 直接调用baiduSearch的lib实现简单封装
  • bingSearch: 使用requests库基于URL的方式来实现搜索结果的返回
  • googleSearch:也使用GoogleSearch的库来实现search的简单封装
  • duckduckgoSearch: 开源的搜索引擎,使用duckduckgo_search.DDGS实现搜索

SandBox工具
基于daytona来实现SandBox的管理

  • sb_vision_tool 要执行的视觉动作,将SandBox中的图片进行下载下来并压缩读取
  • sb_shell_tool 一个基于tmux session的命令行管理工具,支持四种方式,"execute_command","check_command_output", "terminate_command", "list_commands"
  • sb_files_tool 支持在安全的SandBox环境下进行文件操作,支持 create_file, str_replace, full_file_rewrite, delete_file 四个操作。
  • sb_browser_tool 浏览器操作工具,在SandBox下支持和Web进行多种的互动操作,"navigate_to","go_back", "wait", "click_element", "input_text", "send_keys", "switch_tab", "close_tab", "scroll_down", "scroll_up", "scroll_to_text", "get_dropdown_options", "select_dropdown_option", "click_coordinates", "drag_drop"

bash工具,直接在项目本地进行bash操作,安全性较差的方式
通过 asyncio.create_subprocess_shell 的方式完成

浏览器使用工具 browser_use_tool.py ,基于Python的browser_use library库来实现

文件操作工具 file_operators.py

mcp服务封装 mcp.py

任务规划和计划管理模块 planning.py

Python代码执行模型,python_execute.py 直接开启线程调用 exec 来执行代码并返回

工具收集模块 tool_collection.py 收集和管理所有的工具

网络搜索模块 web_search.py 管理所有的搜索引擎,并设置不同的搜索方式。

总结

OpenManus相比最近火热的OpenClaw来说,仅仅是和LLM交互的仍然为prompt,后续的Skills也就是prompt的另一种表现形式。