Bootstrap

OpenManus-通过源码方式本地运行OpenManus,含踩坑及处理方案,chrome.exe位置修改

前言:最近 Manus 火得一塌糊涂啊,OpenManus 也一夜之间爆火,那么作为程序员应该来尝尝鲜

1、前期准备

  • FastGithub:如果有科学上网且能正常访问 github 则不需要下载此软件,此软件是提供国内直接访问 github
  • Git:通过 git 远程拉去 github 代码,当然也可以不用安装
  • Anaconda 或者 Miniconda:python 依赖管理工具
  • 科学上网:如果想去谷歌搜索,则需要支持访问 google.com,如果不需要,则配置访问路径为 百度,请往下看

2、进入 github 下载源码

点我进入OpenManus 仓库

阅读官方提供的文档:OpenManus 中文文档

2.1、下载源码

下载源码分两种方式:

  • 第一种是安装了 Git 的,直接通过命令
git clone https://github.com/mannaandpoem/OpenManus.git

2.2、准备工作

  • 创建 python 虚拟环境
# 创建虚拟环境
conda create -p D:\dev\py_repo\open_manus python=3.12
# 激活这个环境
conda activate open_manus
  • 支持 function calling 的大模型 API key

这里推荐使用 阿里云百炼平台,百炼开通后180天内送一定额度的 token,基本上是属于免费级别的

获得 API-KEY
在这里插入图片描述
在这里插入图片描述

  • 获取模型

每个模型都有相应的说明,注意看每个模型的注意事项描述,如果说明了不支持 Function calling 的模型,是无法使用到 OpenManus 中的
在这里插入图片描述
比如这个图片中,deepseek-r1 模型就不支持 Function calling

亲测有效的是 qwen-plus 模型,qwq-32b 也是支持的,不过我没亲测

3、使用 PyCharm 打开源码,并配置虚拟环境

这一步主要是为了阅读源码和启动源码,如果不需要阅读源码的可以直接跳过本步骤

  • 配置解释器
    启动 PyCharm 打开源码,并配置刚刚设置的 open_manus conda 环境,我这里已经配置过了,没有配置过第一步显示的是 Add interpreter
    在这里插入图片描述

  • 选择虚拟环境
    在这里插入图片描述
    选择好以后,点击 OK ,等待环境的初始化和加载,大概也就 10 来分钟左右

4、配置 OpenManus 环境

  • 如果是 PyCharm 启动,则直接手动复制 /config/config.example.toml 将复制出来的文件名改为 config.toml 即可
# Global LLM configuration
[llm]
model = "qwen-plus"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key = "sk-.................................."
max_tokens = 4096
temperature = 0.0

model :一定要是支持 function calling 的模型
base_url:百炼云平台的接口地址,只要是百炼的模型,接口地址几乎是相同的,不用修改
api_key:这个就是之前注册的 api-key,直接复制接口
其他的都不用修改

  • 如果是通过 CMD 启动的,则使用命令复制文件,然后将正确的内容填写进去即可
cp config/config.example.toml config/config.toml

5、依赖拉取

5.1、激活环境

PyCharm 打开 terminal 窗口,激活 conda 环境,注意这里一定要是在项目的根目录下才可以

conda activate open_manus

5.2、安装依赖

pip install -r .\requirements.txt

完整命令截图如下:
在这里插入图片描述

6、各种踩坑

6.1、不支持 function calling

不支持 tool call,选择支持 function calling 的模型

<400> InternalError.Algo.InvalidParameter: The tool call is not supported.

6.2、模型名字错误

检查模型的名字,是否拼写错误

'The model `xxxxxx` does not exist or you do not have access to it.'

6.3、google_search 无法调用

⚠️ Tool 'google_search' encountered a problem: HTTPSConnectionPool(host='www.google.com', port=443): Max retries exceeded with url: /search?q=Google+homepage&num=12&hl=en&start=0&safe=active (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x0000020960CF1520>, 'Connection to www.google.com timed out. (connect timeout=5)'))
  • 方式1:科学上网全局代理,或者切换稳定的谷歌代理站点
  • 方式2:添加配置,有大佬提交了 pr,支持百度搜索
[llm]
model = "qwen-plus"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key = "sk-.................................."
max_tokens = 4096
temperature = 0.0

# 添加此项代码,走百度搜索
search_agent_config = "baidu"

6.4、循环打印日志 playwright install

2025-03-10 22:07:44.834 | INFO     | app.agent.base:run:137 - Executing step 1/30
2025-03-10 22:07:48.030 | INFO     | app.agent.toolcall:think:53 - ✨ Manus's thoughts: 
2025-03-10 22:07:48.030 | INFO     | app.agent.toolcall:think:54 - 🛠️ Manus selected 1 tools to use
2025-03-10 22:07:48.031 | INFO     | app.agent.toolcall:think:58 - 🧰 Tools being prepared: ['browser_use']
2025-03-10 22:07:48.031 | INFO     | app.agent.toolcall:execute_tool:140 - 🔧 Activating tool: 'browser_use'...
ERROR    [browser] Failed to initialize Playwright browser: BrowserType.launch: Executable doesn't exist at C:\Users\admin\AppData\Local\ms-playwright\chromium-1148\chrome-win\chrome.exe
╔════════════════════════════════════════════════════════════╗
║ Looks like Playwright was just installed or updated.       ║
║ Please run the following command to download new browsers: ║
║                                                            ║
║     playwright install                                     ║
║                                                            ║
║ <3 Playwright Team                                         ║
╚════════════════════════════════════════════════════════════╝
2025-03-10 22:07:48.464 | INFO     | app.agent.toolcall:act:113 - 🎯 Tool 'browser_use' completed its mission! Result: Observed output of cmd `browser_use` executed:
Error: Browser action 'navigate' failed: BrowserType.launch: Executable doesn't exist at C:\Users\admin\AppData\Local\ms-playwright\chromium-1148\chrome-win\chrome.exe
╔════════════════════════════════════════════════════════════╗
║ Looks like Playwright was just installed or updated.       ║
║ Please run the following command to download new browsers: ║
║                                                            ║
║     playwright install                                     ║
║                                                            ║
║ <3 Playwright Team                                         ║
╚════════════════════════════════════════════════════════════╝
2025-03-10 22:07:48.476 | INFO     | app.agent.base:run:137 - Executing step 2/30

首先这个问题是缺少了浏览器,那么需要先下载浏览器组件

python -m playwright install chromium

pip install playwright

安装不上,那么就暴力安装

  • 下载 chromium

下载地址:https://playwright-verizon.azureedge.net/builds/chromium/1148/chromium-win64.zip

  • 解压后放入指定目录

根据错误日志可以看到,程序去这个路径下面寻找 Browser action 'navigate' failed: BrowserType.launch: Executable doesn't exist at C:\Users\admin\AppData\Local\ms-playwright\chromium-1148\chrome-win\chrome.exe,那么就直接把浏览器复制到这个路径下即可

在这里插入图片描述

6.5、其他踩坑

如果你遇到了其他坑,就去这里面搜索问题:

https://github.com/mannaandpoem/OpenManus/issues

总能找到问题的解决办法

7、补充

2025-03-11补充

deepseek-r1 模型均不可用

deepseek-r1 不管是阿里云百炼平台,还是 deepseek 官网,都是不支持 Function calling 的,亲测结果
在这里插入图片描述
deepseek官网唯一支持 Function calling 的模型 deepseek-chat 在官方的描述如下:
在这里插入图片描述
deepseek-chat 模型亲测有效:

提示词:搜索整理昨天的所有AI相关的最新咨询,整理成markdown文件,文件名为:news_ai

经过漫长的等待,最终得到了如下的结果:超时了

修改 chrome.exe 位置

修改位置需要修改源代码,有三处地方需要修改

  • /app/config.py 文件

第四行代码和第 26 行代码修改
在这里插入图片描述

from typing import Dict, Optional  # ,Optional 为添加项

class LLMSettings(BaseModel):
    model: str = Field(..., description="Model name")
    base_url: str = Field(..., description="API base URL")
    api_key: str = Field(..., description="API key")
    max_tokens: int = Field(4096, description="Maximum number of tokens per request")
    temperature: float = Field(1.0, description="Sampling temperature")
    api_type: str = Field(..., description="AzureOpenai or Openai")
    api_version: str = Field(..., description="Azure Openai version if AzureOpenai")
    chrome_instance_path: Optional[str] = Field(None, description="Local Chrome installation path") # 为添加项
  • browser_use_tool.py 修改

将 _ensure_browser_initialized 函数替换为如下代码

    async def _ensure_browser_initialized(self) -> BrowserContext:
        """Ensure browser and context are initialized."""
        if self.browser is None:
        	# 舍弃本句代码
            # self.browser = BrowserUseBrowser(BrowserConfig(headless=False))

			# 新增如下代码
            llm_config = config.llm['default']
            chrome_instance_path = llm_config.chrome_instance_path
            print(chrome_instance_path)
            self.browser = BrowserUseBrowser(BrowserConfig(headless=False, chrome_instance_path=chrome_instance_path))
        if self.context is None:
            self.context = await self.browser.new_context()
            self.dom_service = DomService(await self.context.get_current_page())
        return self.context
  • config.toml 新增配置项
[llm]
model = "qwen-plus"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key = "sk-xxxxxx"
chrome_instance_path = "D:\\software\\chrome-win\\chrome.exe"   # 此项为新增配置项
max_tokens = 4096
temperature = 0.0

亲测有效

2025-03-13 补充

关于百度搜索无法生效的解决办法,由于本文中提到了配置百度,但是还是有部分小伙伴无法成功,本次补充提供完整的百度搜索代码

  • requirements.txt 新增依赖
baidusearch~=1.0.3
aiohttp~=3.11.13
beautifulsoup4~=4.13.3
  • tool 包下新增百度搜索工具类
import asyncio
from typing import List

from baidusearch.baidusearch import search

from app.tool.base import BaseTool


class BaiduSearch(BaseTool):
    name: str = "baidu_search"
    description: str = """Perform a Baidu search and return a list of relevant links.
Use this tool when you need to find information on the web, get up-to-date data, or research specific topics.
The tool returns a list of URLs that match the search query.
"""
    parameters: dict = {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "(required) The search query to submit to Baidu.",
            },
            "num_results": {
                "type": "integer",
                "description": "(optional) The number of search results to return. Default is 10.",
                "default": 10,
            },
        },
        "required": ["query"],
    }

    async def execute(self, query: str, num_results: int = 10) -> List[str]:
        """
        Execute a Baidu search and return a list of URLs.
        Args:
            query (str): The search query to submit to Baidu.
            num_results (int, optional): The number of search results to return. Default is 10.
        Returns:
            List[str]: A list of URLs matching the search query.
        """
        # Run the search in a thread pool to prevent blocking
        loop = asyncio.get_event_loop()
        links = await loop.run_in_executor(
            None,
            lambda: [
                result["url"] for result in search(query, num_results=num_results)
            ],
        )

        return links
  • config.py 新增内容,新增的代码上有注释,注意看
class LLMSettings(BaseModel):
    model: str = Field(..., description="Model name")
    base_url: str = Field(..., description="API base URL")
    api_key: str = Field(..., description="API key")
    max_tokens: int = Field(4096, description="Maximum number of tokens per request")
    temperature: float = Field(1.0, description="Sampling temperature")
    api_type: str = Field(..., description="AzureOpenai or Openai")
    api_version: str = Field(..., description="Azure Openai version if AzureOpenai")
    chrome_instance_path: Optional[str] = Field(None, description="Local Chrome installation path")
	# 这一句是新增的
    search_agent_config: str = Field(..., description="Search agent used search url")


    def _load_initial_config(self):
        raw_config = self._load_config()
        base_llm = raw_config.get("llm", {})
        llm_overrides = {
            k: v for k, v in raw_config.get("llm", {}).items() if isinstance(v, dict)
        }

        default_settings = {
            "model": base_llm.get("model"),
            "base_url": base_llm.get("base_url"),
            "api_key": base_llm.get("api_key"),
            "max_tokens": base_llm.get("max_tokens", 4096),
            "temperature": base_llm.get("temperature", 1.0),
            "api_type": base_llm.get("api_type", ""),
            "api_version": base_llm.get("api_version", ""),
            "chrome_instance_path": base_llm.get("chrome_instance_path", None),
			# 这一句是新增的
            "search_agent_config": base_llm.get("search_agent_config", "google"),
        }

        config_dict = {
            "llm": {
                "default": default_settings,
                **{
                    name: {**default_settings, **override_config}
                    for name, override_config in llm_overrides.items()
                },
            }
        }

        self._config = AppConfig(**config_dict)
  • manus.py 新增,下面是完整的 manus.py 文件
from pydantic import Field

from app.agent.toolcall import ToolCallAgent
from app.prompt.manus import NEXT_STEP_PROMPT, SYSTEM_PROMPT
from app.tool import Terminate, ToolCollection
from app.tool.browser_use_tool import BrowserUseTool
from app.tool.file_saver import FileSaver
from app.tool.google_search import GoogleSearch
from app.tool.baidu_search import BaiduSearch
from app.tool.python_execute import PythonExecute
from app.config import config


class Manus(ToolCallAgent):
    """
    A versatile general-purpose agent that uses planning to solve various tasks.

    This agent extends PlanningAgent with a comprehensive set of tools and capabilities,
    including Python execution, web browsing, file operations, and information retrieval
    to handle a wide range of user requests.
    """

    name: str = "Manus"
    description: str = (
        "A versatile agent that can solve various tasks using multiple tools"
    )

    system_prompt: str = SYSTEM_PROMPT
    next_step_prompt: str = NEXT_STEP_PROMPT

    # Add general-purpose tools to the tool collection
    available_tools: ToolCollection = Field(
        default_factory=lambda: ToolCollection(
            PythonExecute(), BrowserUseTool(), FileSaver(), Terminate(), get_search_agent(),
        )
    )


def get_search_agent():
	"""
    Read config. Choose search agent
    """
    search_agent_config = config.llm["default"].search_agent_config
    search_agent = GoogleSearch()
    if search_agent_config == "baidu":
        search_agent = BaiduSearch()
    return search_agent
  • config.toml 新增搜索引擎配置
search_agent_config='baidu' # baidu or google

最后测试效果:

在这里插入图片描述

;