简介:这份《2025 Manus核心揭秘:下一代AI+Agent的多智能体架构》PPT,面向AI产品经理、应用开发者与智能体技术学习者,帮助读者建立对通用AI Agent整体架构的系统认知,理解多智能体如何协作完成复杂任务。全包为1个pptx文件,压缩包约35.49MB,内容按产品概述、多智能体系统原理、运转逻辑与工作流程、技术特点与创新、应用场景与未来展望等章节逐层展开。讲解深入到记忆模块、规划模块、工具使用模块三大核心,并拆解Search Agent、Code Agent、Data Analysis Agent的分工协同与动态质量检测机制,涵盖多模态输入、意图识别、任务分解为DAG、资源分配与结果整合交付等完整链路。目前已有677人学习下载,适合团队内部分享或方案设计时作为参考。

1. 从 Manus 说起:多智能体架构到底解决了单 Agent 的哪些死结

用过 Manus 这类产品的人往往有个共同体感:它不像在聊天,更像在派活。你说「把这份年报里的营收数据提出来做成对比图」,它不会立刻吐一段话,而是先列步骤、开浏览器、写脚本、再回头检查图表是不是空的。这种「派活感」的来源就是多智能体架构。单 Agent 的经典写法是把规划、执行、校验全塞进一个 while 循环里,任务一长,上下文被工具返回的原始 HTML、堆栈日志、失败重试撑满,模型就开始丢约束、编参数、反复做同一件事。多智能体架构把这几件事拆给不同角色,各自拿裁剪过的上下文工作,谁出错谁负责,链路才稳得住。下面讲三件事:这类系统为什么按角色切分,最小可跑的骨架怎么搭,参数和排错该盯哪里。适合已经写过一两个 Agent demo、准备往长链路任务上推的开发者。

2. Manus 多智能体架构的三层拆解:Planner、Executor 与 Verifier

2.1 为什么单体 Agent 在长链路任务上必然失稳

单体 Agent 的循环通常是「看历史 → 决定动作 → 执行工具 → 把结果拼回历史」。前三轮没问题,到第十轮就出事了。原因不是模型变笨,而是三个结构性缺陷同时发作。

第一是上下文污染。浏览器工具一次返回的 DOM 文本动辄几万 token,里面有导航栏、广告、页脚,真正有用的那行数字埋在中段。这些噪声一旦进入历史,就会稀释掉最初的用户约束,模型开始忘记「只要 2023 和 2024 两年的数据」这种限定。

第二是角色冲突。同一个 Prompt 里既要它「大胆拆解、多试几条路」,又要它「严谨核对、不确定就别写」,两种指令在解码时互相拉扯,最后表现成既不敢拆又爱乱编。

第三是没有独立的验收环节。自己写的脚本自己判断对不对,等于让学生自己批卷子,错了也没人拦。

多智能体架构的价值不在「多个模型并行跑得快」,而在于给每个环节一个有限的、职责单一的上下文。规划器只看目标和任务约束,执行器只看当前这一步和手头的工具,校验器只看这一步的产出能不能支撑目标。上下文一窄,指令遵循度就上来了,这是最实在的收益。

2.2 规划器:把一句模糊需求拆成可验证的步骤

规划器的输出必须是结构化的,最常见做法是让模型吐 JSON,而不是让它写一段自然语言计划。自然语言计划在执行器那边还得再做一次解析,等于多了一层不确定性。规划节点通常约束三件事:步骤数量上限、每步必须是单一动作、每步必须写清验收标准。

一个可用的规划输出长这样:

{
  "goal": "对比 2023 与 2024 年营收并出图",
  "steps": [
    {"id": "s1", "goal": "从 report.pdf 提取 2023、2024 营收数字", "tool_hint": "read_pdf", "accept": "返回两个带年份的数字"},
    {"id": "s2", "goal": "用这两个数字生成柱状图并保存为 png", "tool_hint": "python", "accept": "文件存在且大小大于 0"},
    {"id": "s3", "goal": "核对图中数值与 s1 结果一致", "tool_hint": null, "accept": "逐项比对通过"}
  ]
}

accept 字段是多智能体架构里最容易被忽略、但收益最高的一个设计。它把「这步做完了吗」从主观判断变成可检查的条件,校验器不用理解业务,只需要拿证据去比对 accept 。 tool_hint 允许为 null ,意味着执行器可以自己挑工具,这保留了灵活性,但要求规划器在不确定时明确留空,而不是硬猜一个工具名。

这里顺便区分一个常被问到的概念:skill 和 agent 的区别。skill 更像一个无状态的技能包,输入输出固定,比如「读 PDF」「调图表库」;agent 是有记忆、有决策循环、会自己选下一步的执行主体。规划器、执行器、校验器都是 agent,它们调用的工具才是 skill。把这两层混在一起写,代码会迅速失控。

2.3 执行器:工具调用、沙箱与证据留存

执行器接到的输入只有一条步骤描述和一份工具清单,它不该看到整条任务历史。这样做的代价是执行器可能缺少上下文,解决办法是让规划器把必要信息写进 goal ,比如把文件路径、年份范围直接写进去,而不是指望执行器去翻历史。

执行器还有一项经常被低估的职责:留存证据。每一步执行完,不能只把「完成」写回状态,要把可复核的产物存下来——文件路径、脚本输出、页面摘要的哈希。后面校验器靠这些证据判断,排错时也靠它们回溯。

工具执行环境要考虑 agent 安全。常见做法是把代码执行放进一次性容器,限制网络出口、挂载只读输入目录、给 CPU 和内存设上限。跑 PPT 生成、PDF 解析这类任务时,最容易出事的是路径穿越和无限循环,前者靠白名单目录解决,后者靠硬性超时解决。

2.4 校验器:不通过就回炉,但要有上限

校验器是整个架构的刹车。它的 Prompt 应该极短,只回答一个问题: evidence 能不能直接支撑 accept 。判断通过就放行,不通过就返回一句修正指令给执行器,比如「s1 返回的数字缺少年份标注,请重新提取并保留原文行」。

角色 输入上下文 输出 主要失败模式 兜底策略
Planner 用户目标 + 任务约束 结构化步骤列表 步骤过粗、缺少验收条件 限制步骤数,强制 accept 字段
Executor 单步 goal + 工具清单 证据产物 工具参数错、返回噪声过大 超时 + 摘要压缩 + 重试上限
Verifier goal + accept + evidence 通过 / 修正指令 过度宽松、放行空结果 断言可判定化,禁止主观评判

校验失败的重试次数一般设 2 到 3 次,超过就标记该步失败并交给规划器重规划。没有上限的重试是多智能体系统烧钱的第一大原因,一个卡住的环境变量能让整个循环跑到天亮。

3. 用 Python 搭一个最小可跑的多智能体骨架

3.1 先定共享状态,再谈 agent 框架

选 agent 框架之前,先把状态契约定下来。很多项目一上来就挑框架,结果框架的消息格式绑死了后续设计。手写一版最小骨架,反而更容易看清哪些是框架该承担的、哪些是业务必须自己管的。

共享状态只放三样东西:计划、每步的证据、预算计数器。原始工具返回值不进状态,只进摘要。

# state.py —— 多智能体共享状态的最小契约
from dataclasses import dataclass, field
from typing import Any, Literal

@dataclass
class Step:
    id: str
    goal: str
    accept: str                     # 验收条件,必须是可判定的
    tool_hint: str | None = None    # 允许为空,执行器自行选工具
    status: Literal["todo", "doing", "done", "failed"] = "todo"
    evidence: list[str] = field(default_factory=list)
    attempts: int = 0

@dataclass
class TaskState:
    user_goal: str
    plan: list[Step] = field(default_factory=list)
    notes: list[str] = field(default_factory=list)   # 只存摘要,不存原始返回值
    budget: dict[str, int] = field(
        default_factory=lambda: {"steps": 20, "tokens": 120_000, "retries": 3}
    )

evidence 存字符串而不是任意对象,是为了方便直接拼进校验器的 Prompt。 budget 三项各有用途: steps 防止规划器越拆越细, tokens 防止上下文失控, retries 防止单步卡死。这三个数在多智能体系统里比模型选型更影响最终成败。

3.2 规划节点:用 Prompt 约束 JSON 输出

规划节点的 Prompt 要点是「只输出 JSON」「步骤数上限」「强制 accept」。别指望后处理兜底,模型一旦开始写解释文字,解析失败率会陡增。

PLANNER_SYSTEM = """你是任务规划器,只输出 JSON,不要输出任何解释文字。
格式:{"steps":[{"id":"s1","goal":"...","accept":"...","tool_hint":"read_pdf|python|search|null"}]}
约束:
1) 步骤数不超过 8;
2) 每个 goal 只能是单一可执行动作;
3) accept 必须能用证据直接判断真假,禁止写"结果合理"这类主观描述;
4) 需要外部事实的步骤必须给 tool_hint,不确定时填 null。"""

def plan(client, state: TaskState) -> list[Step]:
    resp = client.chat(
        system=PLANNER_SYSTEM,
        user=state.user_goal,
        temperature=0.2,          # 规划要稳,温度压低
        response_format={"type": "json_object"},
    )
    data = json.loads(resp.text)
    return [Step(**s) for s in data["steps"][:8]]

temperature 设 0.2 是因为规划阶段不需要发散,探索性留给执行器。 response_format 用 JSON 模式能显著降低解析失败率,如果所用模型不支持,就退化成「取第一个 { 到最后一个 } 」的粗暴截取。 [:8] 是硬截断,宁可少拆几步,也不要让计划膨胀成三十步。

3.3 执行节点:超时、摘要、重试三件套

执行器最容易写歪的地方是把工具原始返回值直接塞回状态。正确做法是先压缩,再决定是否重试。

def execute(step: Step, tools: dict, state: TaskState, timeout: int = 60) -> Step:
    step.status = "doing"
    while step.attempts < state.budget["retries"]:
        step.attempts += 1
        try:
            raw = tools[step.tool_hint or "python"].run(step.goal, timeout=timeout)
        except TimeoutError:
            state.notes.append(f"{step.id} 超时,第 {step.attempts} 次")
            continue
        summary = compress(raw, max_chars=800, keep_keywords=("error", "营收", "total"))
        if summary.is_empty():
            state.notes.append(f"{step.id} 返回为空")
            continue
        step.evidence.append(summary.text)
        step.status = "done"
        return step
    step.status = "failed"
    return step

timeout=60 是硬性上限,工具层必须真的能中断,只在 Python 层包一层 signal.alarm 对子进程是无效的,要落到容器或子进程的 kill 上。 max_chars=800 控制单步回灌的体量, keep_keywords 保证报错行和关键数字不会被摘要丢掉。重试计数写在 step.attempts 上而不是循环变量上,是为了让状态可持久化、可恢复。

3.4 校验节点:把判断变成断言

校验器 Prompt 越短越准。不要让它评价「质量好不好」,只让它做一次匹配。

VERIFIER_SYSTEM = """你是校验器。判断依据只有一条:evidence 是否能直接支撑 accept。
只输出 JSON:{"pass": true|false, "reason": "一句话", "fix": "给执行器的修正指令"}"""

def verify(client, step: Step) -> dict:
    resp = client.chat(
        system=VERIFIER_SYSTEM,
        user=f"accept: {step.accept}\nevidence: {step.evidence}",
        temperature=0.0,
    )
    return json.loads(resp.text)

temperature=0.0 是必须的,校验结果不稳定会直接导致链路反复回炉。 fix 字段要尽量短,它会作为下一轮执行时的补充约束拼进 goal ,写长了又会污染执行器上下文。校验不通过时,把 fix 追加到 step.goal 后面重新执行,而不是新建一步,这样重试次数才好统计。

4. 多智能体架构的关键参数与上下文工程

4.1 上下文预算怎么分

多智能体相比单体的最大优势是上下文可以按角色裁剪,但裁剪要有预算表,否则规划器一样会被撑爆。

角色 建议上下文占比 包含内容 明确排除
Planner 20% 用户目标、约束、已有计划摘要 工具原始返回值
Executor 60% 当前单步 goal、工具 schema、最近两条证据 完整任务历史
Verifier 20% accept、单步 evidence、必要原始片段 其他步骤的产出

执行器占大头是因为它要带工具 schema。工具多了以后,schema 本身的 token 消耗可能超过任务内容,这时候要做工具分组,按当前步骤的 tool_hint 只加载相关的那几个。

4.2 任务粒度与重规划触发条件

步骤粒度的判断标准很朴素:一步的产出能不能用一句话描述清楚验收条件。能,就是合适;描述不出来,说明这步还得拆或者本来就不该存在。常见的反面例子是「整理并分析数据」这种步骤,它既没法验收,也不知道该调什么工具。

重规划不要设成「任意一步失败就重来」,那会导致前期已完成的工作被丢弃。触发条件建议设为:同一规划下的失败步数超过总数的三分之一,或者出现了规划阶段完全没有预料到的前置依赖,比如要读的文件根本不存在,需要先去找文件。

4.3 工具 schema 的写法差别

工具描述是给模型看的接口文档,写法和给人看的文档不一样。对比一下:

{
  "name": "read_pdf",
  "description": "读取本地 PDF 并返回按页切分的纯文本。当输入是 PDF 文件路径时使用;读取网页请用 fetch_url,不要用这个。",
  "parameters": {
    "type": "object",
    "properties": {
      "path": {"type": "string", "description": "绝对路径,例如 /data/report.pdf,不支持通配符"},
      "pages": {"type": "string", "description": "页码范围如 1-5,省略表示前 10 页"}
    },
    "required": ["path"]
  }
}

三个细节值得注意。 description 里写了「什么时候不要用它」,这比只写「它能做什么」更能减少误调用。参数描述里给了具体示例路径,模型编造路径的概率会明显下降。 pages 用字符串而不是数组,是因为模型对 "1-5" 这种自然表达的处理比构造数组更稳,代价是解析端要多写几行。

4.4 agent 记忆:短期、工作记忆与长期

agent 记忆一般分三层,混用会出问题。短期记忆是当前步骤的上下文,任务结束即丢;工作记忆是整个任务的计划、证据摘要和预算计数,持久化到任务结束;长期记忆是跨任务复用的事实,比如「用户的报告模板在 /templates 目录」。

实践中最容易搞砸的是把长期记忆直接塞进每个步骤的上下文,结果执行器被一堆历史偏好干扰。稳妥做法是长期记忆只做检索式注入:当前步骤的 goal 里出现相关关键词时才召回对应条目,并限制条数,一般不超过 3 条。

5. 多智能体架构的可观测性与排错路径

5.1 用 trace 做链路回放

多智能体系统出问题时,只看最终结果是没法定位的。要在状态里给每个动作打上 trace id,记录规划、执行、校验三个节点的输入摘要、输出摘要、耗时和 token 消耗,落到一张可以按任务 id 查的表里。出错的典型查法是:先看哪一步 status 是 failed,再看它上一轮的 evidence 是不是空的,最后看校验器返回的 fix 有没有被正确拼进下一轮 goal。这三个点一过,八成问题就现形了。

5.2 常见失败态与对应动作

现象 大概率原因 处理动作
计划步骤数为上限值 规划器把「拆细」理解成「多拆」 加入「步骤数不超过 5」的更强约束
执行器反复调同一个工具 工具报错信息没进 evidence 在 compress 的 keep_keywords 里加 "error"
校验器全部放行 accept 写成主观描述 回改规划 Prompt,强制可判定
任务中途 token 超预算 原始返回值未被压缩 检查 compress 是否被绕过

5.3 一个能省一半成本的技巧

把校验器的判断尽量改成代码断言。数字对不对、文件在不在、图片尺寸够不够,这些都不需要模型来判断,写成函数几毫秒就能跑完。模型只负责判断那些无法用代码表达的部分,比如「提取的这句话是否真的在回答用户的问题」。

ASSERTS = {
    "file_exists": lambda ev: all(os.path.exists(p) for p in ev.paths),
    "has_two_years": lambda ev: len(re.findall(r"20\d{2}", ev.text)) >= 2,
    "image_ok": lambda ev: ev.image_size and ev.image_size[0] > 200,
}

def cheap_verify(step: Step, rules: list[str]) -> bool | None:
    for name in rules:
        ok = ASSERTS[name](step)
        if not ok:
            return False          # 代码判负,直接回炉,不调模型
    return None                   # 交给模型做主观判断

规则命中的步骤先跑一遍代码断言,返回 False 就立刻重试,返回 None 才走模型校验。在数据提取、文件生成这两类高频步骤上,这套组合能把校验环节的模型调用次数压掉一大半,同时把误判率降到接近零,因为代码不会像模型那样对空结果睁一只眼闭一只眼。

如果要在本地复现整套链路,建议从三个角色的 Prompt 开始改,而不是先换模型。多数情况下,把 accept 写清楚、把重试上限压到 3、把压缩函数调对,比换一个更大的模型带来的稳定性提升更明显。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

更多推荐