OpenManus:无需邀请码的通用 AI 智能体,一夜爆火的 Agent 开源实现

OpenManus:无需邀请码的通用 AI 智能体,一夜爆火的 Agent 开源实现

智能体

📖 简介

OpenManus 是社区复刻 Manus 的通用 AI 智能体,把规划、工具调用、浏览器操作、文件处理整合进一个极简 Python 框架,无需邀请码即可自己跑一个"数字员工",Agent 开源生态的爆款。

📝 详细介绍

1. 开篇

我们部门去年底接到个内部需求:给总部沉淀的 10 万条售后技术文档做一个智能问答入口。这些文档分布在几十个 SQL 库、SharePoint 和旧版 FAQ 页面里,工程师排查故障主要靠 Ctrl+F 和微信群问老员工,一次平均要花 1.5 个小时。业务方的要求很朴素:"做一个能直接问东西的框,答不上来的就转人工文档检索——别让我们用 App 再说一遍流程。"

最核心的约束是:文档内容涉及公司未公开设备参数,必须在内网部署,不能走外部 SaaS。我当时的直属上级丢给我一句话:"两周内给个原型,别让我再写 PPT 重新申请专有模型。"

2. 需求拆解

我们把业务问题拆成四条技术侧的需求:

  • 数据接入:要能批量吃下 docx / pdf / SharePoint 导出的 HTML 内容,统一清洗成纯文本后走向量化流程,同一份文档更新后旧向量必须能删掉;
  • 响应性能:单次提问端到端响应时间不能超过 8 秒,否则一线工程师会失去耐心直接关页面;
  • 成本上限:内网 GPU 只有一张 3090,模型推理+向量化每月的 token 预算折算下来不能超过 3000 元——相当于每天能跑大约 800 次问答;
  • 部署约束:必须跑在 Docker 容器里放在内网 DMZ 区域,不能对外暴露 80/443 以外的端口,也不允许有"邀请码"这类需外部鉴权的依赖。

我们本来的技术栈是 Python + llama_index,对 agent 框架完全没经验。

3. 方案设计

最开始我们拿了三个候选方案对比:

Microsoft Copilot Studio —— 评估时发现审批流程复杂,且知识库数据迁移到 Graph 后权限模型跟我们的文件目录不一致,弃掉。

Dify + 自建 Agent 工作流 —— 能快速搭 RAG,但它的工具定义是"表单式"的,也就是你回答问题的过程其实是被 Dify 的流程节点强行编排的,很死板,自定义代码块在 Docker 里还要挂载额外依赖。

OpenManus —— 看了一圈,它是 MetaGPT 团队开的源,核心亮点是"无需邀请码"(Manus 当时还要申请),模型底层可以自由切换 Qwen / DeepSeek / GPT,工具端默认就带 WebSearch 和 Python 执行的 ReAct 模式。

最终选 OpenManus 的取舍逻辑有两个:一是我要把工具调用能力和话术编排都收敛在我熟悉的那几个 Python 函数里,而不是学一套编排 UI;二是它的 agent 上下文管理逻辑足够裸,我们能把自研的知识库检索脚本直接塞进去当作一个 tool_execute 来处理。成本上,OpenManus 不是重框架,不会为了"每个工具都跑通"去额外请求接口,所以 token 开销是可控的。

4. 落地实现

4.1 数据准备:清洗与向量化

我先写了一个异步脚本把 10 万条文档里的段落拆出来,按段落级别丢进 pgvector。

# normalize_docs.py
import asyncio, hashlib
from pathlib import Path
from unstructured.partition.auto import partition

async def extract(path):
    elements = partition(filename = path, strategy="hi_res")
    for el in elements:
        if el.text.strip():
            yield {
                "doc_id": hashlib.md5(path.encode()).hexdigest()[:8],
                "text": el.text,
                "source": str(path)
            }

async def main(root="/data/raw_docs"):
    for p in Path(root).rglob("*.docx"):
        for blk in await extract(p):
            print(blk)
            # 写入 vector_db

关键点是我们把 embedding 模型换成了 BAAI/bge-m3,它在 3090 上用 ONNX 跑差不多 40ms/ 条,比 OpenAI embedding 省下走外网的带宽,而且中英混合的效果好。

4.2 构建 Agent:修改 tool_execute

OpenManus 默认启动时的工具名字和提示词不适合"内网知识库检索",我改动了它的 app/agent/openmanus.py 中的工具定义,加了可以同时查 PostgreSQL 的检索动作:

@tool
def knowledge_search(query: str, top_k: int = 3) -> str:
    """Search internal support docs for relevant paragraphs."""
    embedded_query = embed(query)          # bge-m3
    sql = """
        SELECT text, source FROM doc_chunks
        ORDER BY embedding  %(query_vec)s
        LIMIT %(k)s
    """
    with pool.connection() as conn:
        rows = conn.execute(sql, {"query_vec": embedded_query, "k": top_k}).fetchall()
    return json.dumps(rows, ensure_ascii=False)

config.toml 里锁定了模型相关配置:

[llm]
default_model = "qwen2.5:14b"  # 内网 ollama
max_tokens = 4096
temperature = 0.3

[web_search]
enable = false   # 不允许访问外网

这句配置是折腾了最久的地方:如果 web_search.enable 保持默认 true,agent 一旦认为文档内容不够,就会跳出内网走必应搜索,直接因为超时挂掉。

4.3 部署:Docker 与 API 封装

内网目标机器没有公网访问,我把整个镜像脱网后导入。实际用到的 Dockerfile 只有三层:

FROM python:3.11
RUN pip install openmanus pgvector psycopg[binary] accelerate -i https://pypi.tuna.tsinghua.edu.cn/simple
COPY ./internal_tools /app/internal_tools
COPY ./config.toml /root/.openmanus/config.toml
EXPOSE 8000
CMD ["uvicorn", "gateway:app", "--host", "0.0.0.0", "--port", "8000"]

然后对外暴露的就是一个标准的 FastAPI 的 /ask 端点,只接收公司内部的 SSO 头,另外加了一层简单的提示词模板,限制回答只说"基于知识库的内容"。

5. 效果与数据

上线两周,我们对一线工程师调研和汇总内部的调用日志,得到这组成果数据(其中单个 token 成本为估算值):

指标上线前上线后变化
平均故障排查时长约 1.5 小时 / 单约 15 分钟 / 单↓83%
答案可采纳率(通过日志给 4 分以上打分)不足 50%78.4%(抽样 300 条)↑28 个百分点
端到端响应时间 P95——6.2s满足 <8s 目标
每单平均 token 成本(含答案生成 & 检索);GPU 电费分摊已计原人工折算可忽略约 0.02 元 / 次远低于预算
开发工时——6 人日相比外包报价省 2 周

最让我满意的不是成本,而是知识库覆盖不到了以后,agent 会明说"内部文档中未找到相关内容",而不是强行编一段话出来误导维修动作。

6. 踩过的坑

6.1 上下文爆掉与回复截断

现象:进行到第 12 轮对话后,返回内容开始残缺,出现"…"。

排查:打开调试发现 OpenAI 兼容接口报 400 context_length_exceeded。默认 OpenManus 是把整个历史消息发给模型,没有自动切窗口。

解决:我改用了定向记忆策略:history 只保留最近一轮完整问答,加一个不变的 system prompt,把超出 6 条后的进行摘要剪枝。具体改了 config.tomlmax_history_messages = 6,而 agent 检索出的文档片段最长只取原文前 1200 字符。

6.2 检索召回的低级 bug:embedding 做在了子进程里

现象:用户反映搜索"扳手规格"能出结果,但搜"六角套筒"返回空。我发现日志里两条相近表达只匹配到完全无关文档。

排查:查了 pgvector 中片段——原来我把 embedding 函数挂在了 asyncio.to_thread 里,而 bge-m3 的 tokenizer 不是线程安全的,导致多次并发时偶发 encode 结果全为零向量。然后用 ORDER BY <=> 算距离时,所有零向量排在文档最后。

解决:改成进程池单线程执行 embedding 调用,并做了输入长度逐条排序。同时加了一个小的校验:如果某个 query 的 embedding 向量 L2 长度等于 0,就报出一个显眼错误。

6.3 内网 DNS 解析引起 10 秒级阻塞

现象:生产环境提问后经常等很久,但 p95 比测试环境多 2 秒。

排查:测试机用的 Docker bridge 网络,生产环境机器 hosts 里未配置 pgvector 所在的数据库域名,Python 驱动每次建连接都要卡在内网 DNS 超时上。

解决:pgvector 的连接地址直接改为 IP 加连接池预热,另外顺手把代码里的同步 SQLAlchemy 引擎换成了 psycopg_pool 异步池。

7. 复盘与扩展

这次选择 OpenManus 的最正确的点在"框架化小、自定义没有黑魔法"——我们能在 6 个工作日内完成数据清洗、代码接入和去外网依赖,换做任何以对话流编排的框架,我估计还得再花 2 周学会怎么绕过他们的后台存储。另一个对的决定:修改了它的默认工具列表,把不用的 WebSearch / Browsing 直接禁用,这让 agent 不会闲着没事自己去做网络请求。

做得不好的方面是:我们没有主动去测 长尾问题并发(比如 30 个用户同时提问),导致刚上线第三天出现过两回 PG 连接被打爆和数据库 OOM 的警告。如果重新来一次,我会在一开始就上 pgbouncer 而不是用裸的连接池撑过去。

后续扩展的方向,在基础设施架构上没有太大改动空间的话,可以横向做两件事:第一是把 OpenManus 的检索工具从"只能读片段"改成"可以写工单"——也就是让 agent 能直接在工作流里引用同部门的老工单作为案例给用户参考;第二是对知识库的片段做定时重向量化,在文档更新后自动执行一遍,让 agent 不会再基于过期的保养手册给建议。总体来说,如果你要做的不是"展示 demo"而是"真刀真枪塞进业务系统",这个框架足够轻巧,适合做基座自行演进。

🚀

AI 项目推荐

智能体
标签
#智能体 #通用Agent #自动化 #开源
浏览
👁️ 7
发布日期
2026-09-09