Bootstrap

一文读懂:OpenManus

 

这两天的朋友圈算是被Manus彻底攻陷了,这个号称“数字实习生”的AI工具,能三分钟生成股票分析报告、自动筛简历,连PPT排版都包办。

马上一个叫OpenManus的开源项目突然杀出来,开发者是MetaGPT团队的五个程序员,据说只用了三小时就搞出了“平替版”。不用抢邀请码、不用交钱,代码直接甩在GitHub上,三四天的时间已经快16K的star了,看看这增速:官方地址:https://github.com/mannaandpoem/OpenManus

 

本文通过拆解OpenManus项目的核心概念、架构设计和实现细节。

 

1. OpenManus是什么

OpenManus 是一个开源的AI工具项目,旨在复刻或替代近期爆火的AI产品 Manus

它由MetaGPT团队的五名开发者在短短三小时内开发完成,并在GitHub上开源发布。OpenManus的核心目标是提供一个透明、可本地运行的AI工具,能够执行类似Manus的任务,例如自动化生成报告、处理复杂工作流等,但完全免费且无需邀请码。

OpenManus的出现挑战了Manus的“稀缺性”和“高门槛”,为普通用户提供了一个免费且易用的替代方案。

从技术实现上看,OpenManus是一个基于Python开发的智能代理系统,具有以下主要特点:

1. 项目架构

  • 采用模块化设计,主要包含agent、flow、tool等核心模块

  • 使用pydantic进行数据验证,确保系统稳定性

  • 支持异步操作,提高系统性能

2. 核心功能

  • 智能代理:实现了多种类型的代理Manus(ReAct)、Planning等

  • 工具集成:内置多个实用工具

    • PythonExecute:执行Python代码

    • GoogleSearch:网络搜索

    • BrowserUseTool:浏览器操作

    • FileSaver:文件保存

3. 配置灵活

  • 支持多种LLM模型配置(OpenAI、Azure等)

  • 可自定义系统提示词和工具集

4. 使用简便

  • 提供main.py和run_flow.py两种启动方式

  • 交互式命令行界面

该项目借鉴了anthropic-computer-use和browser-use项目的经验,是一个功能完整、易于使用的智能代理系统。

2. OpenManus 项目目录结构

OpenManus/
├── app/                    # 核心应用目录
│   ├── agent/             # 智能体实现模块
│   │   ├── base.py        # 基础智能体接口定义
│   │   ├── manus.py       # 主要智能体实现
│   │   ├── planning.py    # 任务规划模块
│   │   ├── react.py       # 反应式决策模块
│   │   ├── swe.py         # 软件工程相关能力
│   │   └── toolcall.py    # 工具调用处理模块
│   ├── flow/              # 流程控制模块
│   │   ├── base.py        # 流程管理基础类
│   │   ├── flow_factory.py # 流程工厂
│   │   └── planning.py     # 任务规划流程
│   ├── tool/              # 工具集合模块
│   │   ├── base.py        # 工具基础接口
│   │   ├── browser_use_tool.py  # 浏览器操作工具
│   │   ├── file_saver.py  # 文件操作工具
│   │   ├── google_search.py # 搜索工具
│   │   └── python_execute.py # Python代码执行工具
│   ├── prompt/            # 系统提示词模块
│   │   ├── manus.py       # Manus智能体提示词
│   │   ├── planning.py    # 规划相关提示词
│   │   └── toolcall.py    # 工具调用提示词
│   └── config.py          # 配置管理
├── config/                # 配置文件目录
│   ├── config.example.toml # 配置文件示例
│   └── config.toml        # 实际配置文件
├── main.py               # 主程序入口
├── run_flow.py           # 流程运行脚本
├── setup.py              # 项目安装配置
└── requirements.txt      # 项目依赖列表

3. OpenManus 处理流程

运行程序:

python main.py

整个程序的大概流程如下:

  1. 实例化Manus智能体实例,并初始化所有的工具

  2. 接收用户的提示词

  3. 进入ReAct循环,在循环内,根据大模型的决策选择调用不同的工具来完成用户提示词的需求

  4. 返回结果

这是一个典型的ReAct流程

3.1. ReAct是什么

自我反思是自主智能体通过细化过去的行动决策和纠正之前的错误来迭代改进的重要方面。

ReAct框架正是这个自我反思环节使用到的一个框架,用于指导大模型完成复杂任务的结构化思考和决策过程。ReAct框架包括一系列的步骤,使得大模型能够以更系统和高效的方式处理和回应查询,确保它能够全面和准确地回应用户的需求。

通过 ReAct 框架,Agent获得了动态决策能力。当遇到自己内部知识无法解决的问题时,Agent先搜索或调用工具,拓展自己的知识面。Agent还利用工具的灵活性,协调使用各种工具,在多个数据点之间进行切换,以获得最终的决策数据。Agent在执行每一步后会观察结果,并将新信息用于接下来的决策过程,这体现了Agent出色的学习能力与适应性。

ReAct框架的设计哲学是:在动态和不确定的环境中,有效的决策需要持续的学习和适应,以及快速将推理转化为行动的能力,即形成有效的观察 一 思考 一 行动 一 再观察的循环(见图)

 

该循环过程主要涉及如下3个步骤

 

思考(Thought): 涉及对下一个行动进行推理。在这一步骤中需要评估当前情况并考虑可能的行动方案。

行动(Action): 基于思考的结果,决定采取什么行动。这一步骤是行动计划的选择过程。

观察(Observation): 执行行动后,需要观察并收集反馈。这一步将对行动结果进行评估。它可能影响或改变下一轮次思考的方向。

相关阅读:

从0到1开发AI Agent(智能体)(二)| 智能体推理引擎ReAct框架的快速入门

https://arxiv.org/abs/2210.03629

 

 

 

 

 

4. Manus智能体实现思路

 

 

4.1.BaseAgent类:

 

BaseAgent实现一个基本的智能体抽象类

class BaseAgent(BaseModel, ABC):
    """智能体基础抽象类,用于管理智能体状态和执行。
    提供状态转换、内存管理和基于步骤的执行循环的基础功能。
    子类必须实现'step'方法。
    """

第三章“OpenManus处理流程”中的ReAct循环,就是基于BaseAgent的run方法启动的,循环中调用step()执行下一步要处理的任务

  async def run(self, request: Optional[str] = None) -> str:
        """异步执行智能体的主循环。

        Args:
            request: 可选的初始用户请求。

        Returns:
            执行结果的总结字符串。

        Raises:
            RuntimeError: 如果智能体不在IDLE状态。
        """
        
        ... 
        
        async with self.state_context(AgentState.RUNNING):  # 在运行状态下执行
            while (self.current_step < self.max_steps and self.state != AgentState.FINISHED):
            
            ...
            step_result = await self.step()  # 执行单个步骤
            ...

step是个抽象方法,需要子类实现“具体下一步应该怎么做”

@abstractmethod
async def step(self) -> str:
    """执行智能体工作流中的单个步骤。
    子类必须实现此方法以定义具体行为。
    """

4.2.ReActAgent

ReActAgent是BaseAgent的子类,实现了step方法, step的方法主要完成思考/行动,这个过程在循环内不断重复,直到退出循环

class ReActAgent(BaseAgent, ABC):
    """ReAct模式的智能体基类,实现了思考-行动的执行模式"""
    
    ...

    asyncdef step(self) -> str:
        """执行单个步骤:思考和行动
        
        首先调用think方法进行思考,如果需要行动则调用act方法执行
        
        Returns:
            str: 步骤执行的结果描述
        """
        should_act = await self.think()  # 调用think方法进行思考
        ifnot should_act:
            return"Thinking complete - no action needed"# 如果不需要行动,返回思考完成信息
        returnawait self.act()  # 执行行动并返回结果
    

其中思考/行动,是ReActAgent新增的两个抽象方法,需要具体的子类来具体实现

    @abstractmethod
    async def think(self) -> bool:
        """处理当前状态并决定下一步行动
        
        Returns:
            bool: 是否需要执行行动,True表示需要执行act方法
        """

    @abstractmethod
    async def act(self) -> str:
        """执行已决定的行动
        
        Returns:
            str: 行动执行的结果描述
        """

4.3.ToolCallAgent

ToolCallAgent实现ReActAgent,是整个智能体系统中负责工具调用的核心实现。它通过继承ReActAgent,实现了think和act两个抽象方法,从而完成了ReAct模式中的思考-行动循环。

class ToolCallAgent(ReActAgent):
    """使用增强抽象的处理工具/功能调用的基础智能体类,提供了灵活的工具调用机制"""

4.3.1 think方法实现

    async def think(self) -> bool:
        """处理当前状态并使用工具决定下一步行动,返回是否需要执行行动"""
        # 如果存在下一步提示词,将其添加到消息列表中,用于指导决策
        ...
        
        # 调用语言模型获取带工具选项的响应,包含思考结果和工具选择
        response = await self.llm.ask_tool(
            # 传入当前的消息历史,作为上下文
            messages=self.messages,
            # 如果有系统提示词,创建系统消息,用于初始化行为
            system_msgs=[Message.system_message(self.system_prompt)]
            if self.system_prompt
            elseNone,
            # 转换可用工具为参数格式,供语言模型选择
            tools=self.available_tools.to_params(),
            # 设置工具选择模式,决定是否使用工具
            tool_choice=self.tool_choices,
        )
        

think方法负责分析当前状态并决定下一步行动:

  1. 使用LLM分析当前状态,生成思考结果

  2. 根据LLM的响应选择合适的工具

  3. 根据不同的工具选择模式(none/auto/required)决定是否需要执行行动

4.3.2 act方法实现

    async def act(self) -> str:
        """执行工具调用并处理其结果,返回执行结果描述"""
        
        ...
        
        # 遍历执行每个工具调用
        for command in self.tool_calls:
            # 执行单个工具调用并获取结果
            result = await self.execute_tool(command)

            # 将工具响应添加到内存中,记录执行历史
            tool_msg = Message.tool_message(
                content=result, tool_call_id=command.id, name=command.function.name
            )
            self.memory.add_message(tool_msg)
            # 将结果添加到结果列表
            results.append(result)

        # 返回所有结果的组合
        return"\n\n".join(results)

act方法负责执行工具调用并处理结果:

  1. 遍历执行每个工具调用

  2. 收集和处理工具执行结果

  3. 更新内存中的执行历史

相关阅读:LangChain实战 | Tool Calling :让AI真正动起来的关键技术

4.4 Manus类

class Manus(ToolCallAgent):
    """
    一种多功能的通用智能体,使用规划能力来解决各种任务。

    该智能体通过集成一套全面的工具和功能扩展了基础的规划能力,
    包括Python代码执行、Web浏览、文件操作和信息检索等功能,
    能够处理广泛的用户请求。
    """

 ...

    # 系统级提示词,用于初始化智能体的行为模式
    system_prompt: str = SYSTEM_PROMPT
    # 用于指导智能体决定下一步行动的提示词
    next_step_prompt: str = NEXT_STEP_PROMPT

    # 为智能体配置可用的工具集合
    available_tools: ToolCollection = Field(
        default_factory=lambda: ToolCollection(
            # Python代码执行工具:用于执行Python代码
            PythonExecute(),
            # Google搜索工具:用于检索网络信息
            GoogleSearch(),
            # 浏览器操作工具:用于网页交互
            BrowserUseTool(),
            # 文件保存工具:用于文件操作
            FileSaver(),
            # 终止工具:用于结束任务
            Terminate()
        )
    )

Manus类是OpenManus智能体系统的最终实现类,它继承自ToolCallAgent,通过继承获得了工具调用的核心能力。作为系统的主要智能体实现,Manus类主要完成以下配置:

提示词管理

  • system_prompt:系统级提示词,用于初始化智能体的行为模式

  • next_step_prompt:用于指导智能体决定下一步行动的提示词

工具集成

Manus类通过ToolCollection配置了一套完整的工具集合:

  • PythonExecute:用于执行Python代码的工具

  • GoogleSearch:用于网络信息检索的搜索工具

  • BrowserUseTool:用于网页交互的浏览器操作工具

  • FileSaver:用于文件操作的工具

  • Terminate:用于结束任务的终止工具


一、安装环境

首先按照项目官方提供的文档来安装各种必备环境工具就行。项目地址在此,https://github.com/mannaandpoem/OpenManus。按里面的readme一步步来

1. 安装conda(这步readme没写)

在官网https://www.anaconda.com/download/上一顿下载安装即可

没啥难度,唯一需要注意的是装完要把conda加入系统环境变量

2. 打开powershell(或其他终端),创建一个新的conda环境

conda create -n open_manus python=3.12
conda activate open_manus

注意activate时在Windows上可能会碰到这个错误

CondaError: Run 'conda init' before 'conda activate'

先按他的直接conda init,但运行完打开powershell后应该还是会报错

无法加载文件 C:\Users\***\Documents\WindowsPowerShell\profile.ps1

这时候要做如下设置,再打开powershell就没问题了

# 设置用户级别的执行策略
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

3. Clone git仓库

git clone https://github.com/mannaandpoem/OpenManus.git
cd OpenManus

4. 安装各种依赖

pip install -r requirements.txt

5. 配置模型API

OpenManus智能Agent的运行依赖于后面的大模型,他会不断调用模型的API来完成Agent的操作,所以这里要给他配置好调用模型的API

在上面clone好的OpenManus文件夹下,创建文件config/config.toml

然后在新创建的config.toml里配置你想要他调用的模型API的key和url

# Global LLM configuration
[llm]
model = "gpt-4o"
base_url = "https://api.openai.com/v1"
api_key = "sk-..."  # Replace with your actual API key
max_tokens = 4096
temperature = 0.0
# Optional configuration for specific LLM models
[llm.vision]
model = "gpt-4o"
base_url = "https://api.openai.com/v1"
api_key = "sk-..."  # Replace with your actual API key

此处,你需要拥有一个可以调用的模型API。如果没有,网上有很多可以付费或免费使用的,比如阿里云、天翼云等等。当然,你也可以自己搭一套,或者使用你的机构给你本地搭的。比如湖大的同志们就可以用我们自己的DeepSeek模型服务

6. 配置完毕,启动运行!

python main.py

二、解决运行时的问题

上面的环境都配好了?启动命令运行了?看到下面的框框让你输入指令了?

 

别急着高兴,大概率你还会碰到以下的一系列问题。。。

1. 模型API问题

OpenManus会调用符合OpenAI接口规范的模型API,但是有些模型API的接口可能由于各种原因并不完全符合规范,这时候一般会报下面的错误

 

这个时候换一个符合规范的API就行,大公司提供的比较常见的模型API一般都没问题,别用太小众的就行。

2. 只生成文字步骤,不调用任何工具

他可以调用模型API分析你的问题了,但是总是不调用任何工具,只会不停的分析并产生文字步骤,如下

 

这大概率是使用的模型不匹配的问题,我在这个问题上卡了好几个小时。最后经学生提醒,才发现模型可能有影响。有些模型就不适合OpenManus的逻辑,不论迭代多少步后模型给出的指令都不会调用工具。

注意,这里并不是模型越强大就越能更好地调用工具,经个人的不完全测试,DeepSeek R1和V3都无法触发OpenManus的工具调用,但是qwen-plus就可以很好地触发工具调用,学生反馈claude 3.5或3.7 sonnet也可以。此处背后的原因为何,我就没有深究了,估计是代码的逻辑和模型返回的格式不太匹配的原因。大家可以直接用我试出来的这几个模型来驱动OpenManus即可。

匹配的模型,执行过程中会清晰地看到调用了工具,如下图

 

3. 浏览器工具调用失败

以上问题都解决后,还可能会碰到浏览器调用失败的问题,如下图

 

这是因为默认OpenManus会调用playwright这个工具来执行浏览器操作,但是playwright默认是没有下载任何浏览器内核因此无法执行浏览器操作的。所以要执行以下命令先安装playwright浏览器内核后,即可正常调用浏览器了

playwright install

4. 搜索引擎调用失败

OpenManus默认会调用pip里面的googlesearch这个包里的API进行搜索。但因为众所周知的原因,这个搜索API在国内难以访问,所以调用到搜索引擎时可能会碰到下面的问题

 

解决这个问题除了用不可说的方法外,还可以通过替换OpenManus默认调用的搜索引擎来实现。这里以换成baidusearch为例,感谢网上的众多雷锋程序员给我们提供了一个baidusearch的pip包,并且只需要通过下面的命令即可装上

pip install baidusearch

装上后,需对OpenManus的源码稍作修改,具体把app/tool/google_search.py这个文件中的以下几处位置改了即可

 

至此,应该常见的问题都解决的差不多了,可以愉快地运行了!

三、案例演示

全部搞通后,让我们来试试效果。我这里试了两个案例,咱们一起看看他运行的效果

案例1: 从网上搜集信息并整理成网页显示出来

输入提示词:

从网上搜索整理湖南大学超算中心陈果主任的资料, 生成一个图文并茂的介绍网页

运行过程如下:

他首先调用了搜索引擎,搜索我的信息

 

接着他调用浏览器尝试生成我的介绍网页

 

接着他调用python_execute和file_saver尝试给我做一个网页,并且保存成名字为chen_guo_profile.html的网页文件。不过有点遗憾的是,图片没有真的生成成功,只是放了一个placeholder假装有个图的框框

 

最后经过了15步的迭代,出来的效果,自动打开浏览器给我看了这样一个网页:

 

【效果评述】:整体流程体现出了OpenManus多工具的调用能力以及比较出色的问题自主分析能力,但是最后的网页效果还是比较丑。看起来具备了一定的通用自主智能,能在不断的迭代中分析我的诉求并调用多个工具一起完成最终的功能,但是因为多次调用后原始的语义理解就不够到位了,所以生成的网页效果还很一般。总的来说,离直接给普通人实用还有距离。

案例2:从网上搜集信息并整合设计成图片,显示出来

输入提示词:

搜索并总结国家超级计算长沙中心的最大特色,据此设计一个卡通形象,生成图片打开给我看

运行过程如下:

同样首先调用了搜索引擎,搜索长沙超算的信息

 

然后总结了特色,并且调用python_execute画了一个卡通形象出来,并尝试用浏览器打开

 

 

;