大家好,我是双越。wangEditor 作者,前百度 滴滴 资深前端工程师,慕课网金牌讲师,PMP,前端面试派 作者。
我正致力于两个项目的开发和升级,感兴趣的可以私信我,加入项目小组。
从单个 LLM 调用,到多智能体协作系统------这篇文章带你搞清楚 Multi-Agent 的来龙去脉与工程实践。
为什么需要 Multi-Agent?
单个 LLM 调用有天然局限:
- 上下文窗口有限,无法处理超长任务
- 单点执行,复杂任务无法并行
- 专业能力单一,难以同时精通代码、搜索、数据库等领域
- 容错性差,一个环节失败整体崩溃
Multi-Agent 的诞生源于一个核心洞察:将复杂任务分解给多个专职 Agent 协作完成,就像一个高效团队。
核心架构模式
目前比较主流的有两种架构。
Orchestrator-Worker(编排者-工作者)
这是最常见的 Multi-Agent 架构。Orchestrator 是"大脑",负责理解任务、制定计划、分配工作、汇总结果;Worker 是"手脚",各司其职,专注执行某一类具体任务。
css
用户请求
↓
[Orchestrator Agent] ← 负责规划、分解、调度
↓ ↓ ↓
[Worker A] [Worker B] [Worker C]
代码执行 网络搜索 数据库查询
↓ ↓ ↓
[Orchestrator Agent] ← 汇总结果、决策下一步
↓
最终响应
适合场景:任务边界清晰、可并行拆分的复杂需求,例如"调研竞品 + 写报告 + 生成 PPT"。
Pipeline(流水线)
各 Agent 串行执行,上一个 Agent 的输出是下一个 Agent 的输入,像工厂流水线一样,每一道工序都有明确职责。
scss
Agent A → Agent B → Agent C → 输出
(研究) (写作) (校对)
适合场景:任务有明确先后依赖、每步都需要加工处理的工作流,例如"收集数据 → 清洗 → 分析 → 可视化"。
举个完整的例子
以"帮我开发一个 Todo 应用"为例,看 Multi-Agent 如何协作:
css
用户:"帮我开发一个 Todo 应用"
↓
[Orchestrator]
分解为 4 个子任务:
① 需求分析 ② 后端开发 ③ 前端开发 ④ 测试
↓
┌──────────────────────────────┐
│ 并行执行 ②③ │
│ [Backend Agent] │
│ → 工具:write_file, run_cmd │
│ → 产出:Express API │
│ │
│ [Frontend Agent] │
│ → 工具:write_file │
│ → 产出:React 组件 │
└──────────────────────────────┘
↓
[Test Agent] 串行执行
→ 工具:run_tests
→ 发现 Bug → 反馈给 Backend Agent
↓
[Orchestrator] 汇总
→ 最终交付
这个例子体现了两种架构的混合使用:②③ 并行是 Orchestrator-Worker 模式,Test → Backend 是 Pipeline 模式。实际项目中往往是两种模式组合使用。
Sub-Agent 是什么?
理解了 Multi-Agent 的架构后,我们来区分两个容易混淆的概念:
- Multi-Agent 是一个架构概念,泛指"多个 Agent 协作完成任务"的系统设计,强调的是整体架构形态。
- Sub-Agent 是一个角色概念,特指在某个 Agent 的管辖下运行的下级 Agent,强调的是层级从属关系。
所以:有 Sub-Agent 的系统一定是 Multi-Agent,但 Multi-Agent 不一定有 Sub-Agent。
Sub-Agent 最强大的地方在于它天然支持递归嵌套,这正是复杂 Multi-Agent 系统的基础:
vbnet
用户
└─ Orchestrator(顶层 Agent)
├─ Research Agent(Sub-Agent)
│ ├─ Web Search Agent(Sub-Sub-Agent)
│ └─ Paper Analysis Agent(Sub-Sub-Agent)
└─ Writing Agent(Sub-Agent)
├─ Outline Agent(Sub-Sub-Agent)
└─ Draft Agent(Sub-Sub-Agent)
每一层 Agent 只需要关心自己直接管辖的下级,不需要了解整棵树的全貌,这正是复杂系统可维护性的关键。
技术实现:LangGraph Supervisor
LangChain 的 Supervisor 来自 LangGraph 生态,是目前最推荐的 Multi-Agent 编排方式,专为动态路由和多 Agent 协作而设计。
Supervisor 的工作流程
css
用户输入
↓
[Supervisor Node] ← LLM 决策路由
↓ ↓ ↓
[Agent A] [Agent B] [Agent C]
↓ ↓ ↓
[Supervisor Node] ← 再次决策:继续?结束?换人?
↓
FINISH
Supervisor 本身也是一个 LLM 调用------它每一轮都重新审视当前对话状态,决定下一步该交给谁处理,或者宣告任务完成。
完整代码示例
下面是一个研究 + 编码的双 Agent 系统:
php
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { StateGraph, MessagesAnnotation } from "@langchain/langgraph";
import { ChatAnthropic } from "@langchain/anthropic";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
const llm = new ChatAnthropic({ model: "claude-opus-4-5" });
// ── 1. 定义各 Sub-Agent 的工具 ──────────────────────────
const searchTool = tool(async ({ query }) => {
return `搜索"${query}"的结果:找到3篇相关文章...`; // 替换为真实搜索
}, {
name: "web_search",
description: "搜索互联网信息",
schema: z.object({ query: z.string() }),
});
const writeCodeTool = tool(async ({ task }) => {
return `// 生成的代码\nconsole.log("${task}");`; // 替换为真实实现
}, {
name: "write_code",
description: "编写代码",
schema: z.object({ task: z.string() }),
});
// ── 2. 创建 Sub-Agent(用 createReactAgent)─────────────
const researchAgent = createReactAgent({
llm,
tools: [searchTool],
messageModifier: new SystemMessage("你是研究专家,负责搜集和分析信息。"),
});
const coderAgent = createReactAgent({
llm,
tools: [writeCodeTool],
messageModifier: new SystemMessage("你是编程专家,负责编写高质量代码。"),
});
// ── 3. 将 Sub-Agent 包装成 Graph Node ───────────────────
async function researchNode(state) {
const result = await researchAgent.invoke(state);
// 给消息打上来源标记,Supervisor 可以感知谁做了什么
const lastMsg = result.messages.at(-1);
lastMsg.name = "ResearchAgent";
return { messages: result.messages };
}
async function coderNode(state) {
const result = await coderAgent.invoke(state);
const lastMsg = result.messages.at(-1);
lastMsg.name = "CoderAgent";
return { messages: result.messages };
}
// ── 4. 创建 Supervisor ───────────────────────────────────
const members = ["ResearchAgent", "CoderAgent"];
const supervisorPrompt = `
你是一个任务调度 Supervisor,管理以下 Agent 团队:
${members.map(m => `- ${m}`).join("\n")}
根据当前对话,决定下一步由谁来执行,或者任务已完成返回 FINISH。
规则:
- 需要信息收集/研究 → ResearchAgent
- 需要编写/修改代码 → CoderAgent
- 任务已全部完成 → FINISH
只返回一个名字:${[...members, "FINISH"].join(" | ")}
`;
const routeSchema = z.object({
next: z.enum(["ResearchAgent", "CoderAgent", "FINISH"]),
});
async function supervisorNode(state) {
const response = await llm
.withStructuredOutput(routeSchema)
.invoke([
new SystemMessage(supervisorPrompt),
...state.messages,
]);
return { next: response.next };
}
// ── 5. 构建 StateGraph ───────────────────────────────────
const AgentState = MessagesAnnotation.spec({
// 扩展状态:记录路由决策
next: { value: (x, y) => y ?? x, default: () => "ResearchAgent" },
});
const graph = new StateGraph(AgentState)
.addNode("Supervisor", supervisorNode)
.addNode("ResearchAgent", researchNode)
.addNode("CoderAgent", coderNode)
// Supervisor → 动态路由到对应 Agent 或结束
.addConditionalEdges("Supervisor", (state) => state.next, {
ResearchAgent: "ResearchAgent",
CoderAgent: "CoderAgent",
FINISH: "__end__",
})
// 每个 Agent 完成后回到 Supervisor
.addEdge("ResearchAgent", "Supervisor")
.addEdge("CoderAgent", "Supervisor")
// 入口
.addEdge("__start__", "Supervisor");
const app = graph.compile();
// ── 6. 运行 ─────────────────────────────────────────────
const result = await app.invoke({
messages: [new HumanMessage("研究 Fastify 框架,然后写一个最简单的示例")]
});
console.log(result.messages.at(-1).content);
执行过程追踪
以"研究 Fastify,然后写示例"为输入,执行流程如下:
csharp
输入:"研究 Fastify,然后写示例"
↓
[Supervisor]
→ 判断:需要先研究 → "ResearchAgent"
↓
[ResearchAgent]
→ 调用 web_search 工具搜索 Fastify 相关资料
→ 完成,回到 Supervisor
↓
[Supervisor]
→ 判断:已有资料,需要写代码 → "CoderAgent"
↓
[CoderAgent]
→ 根据研究结果调用 write_code 工具生成示例
→ 完成,回到 Supervisor
↓
[Supervisor]
→ 判断:任务完成 → "FINISH"
↓
输出最终结果
Supervisor 的三大核心优势
动态路由:Supervisor 每轮都重新决策,可以根据上一个 Agent 的输出灵活调整执行路径,而不是预先硬编码流程。这意味着如果 ResearchAgent 返回的资料不足,Supervisor 可以再次调用它补充。
自动循环与重试:Agent 出错或结果不满意时,Supervisor 可以把任务重新交给同一个或另一个 Agent,天然支持重试逻辑,无需额外代码。
状态透明共享 :所有 Agent 共享同一个 messages 状态,每个 Agent 都能看到完整的对话上下文,无需手动在 Agent 之间传递数据。
关键设计原则
在实际搭建 Multi-Agent 系统时,有几个工程原则值得注意:
单一职责:每个 Agent 只做一件事,工具集尽量精简。职责越清晰,Supervisor 的路由决策越准确,Agent 的输出也越可预期。
明确的输入输出契约 :Agent 之间的消息格式要统一。上面代码中给消息打 name 标记,就是一种简单的契约------Supervisor 通过 name 知道是谁做了什么。
防止无限循环 :生产环境中要给 Supervisor 设置最大迭代轮次(recursionLimit),避免 Agent 互相踢皮球导致死循环。
ini
const app = graph.compile();
const result = await app.invoke(input, { recursionLimit: 20 });
错误隔离:Worker/Sub-Agent 内部的异常不应该直接崩溃整个图。可以在 Node 函数中 try/catch,将错误信息作为普通消息返回给 Supervisor,由它决定如何处理。
小结
Multi-Agent 并不是"多跑几次 LLM"那么简单,它是一套完整的软件架构思想:
| 概念 | 定位 | 关键特征 |
|---|---|---|
| Multi-Agent | 架构形态 | 多个 Agent 协作 |
| Orchestrator-Worker | 架构模式 | 中心调度 + 并行执行 |
| Pipeline | 架构模式 | 串行流水,顺序依赖 |
| Sub-Agent | 角色概念 | 层级从属,可递归嵌套 |
| Supervisor | 技术实现 | LangGraph 动态路由编排 |
生产环境下的智能体软件几乎都标配 Multi-Agent 架构,用于解决多任务、复杂任务的效率问题。典型案例如 Cursor 中的 Sub-Agent,能够更好地应对复杂的大型开发任务。
理解了这套架构,你就掌握了构建"真正能干活的 AI 系统"的基础框架。