大家好,我是雙越。wangEditor 作者,前百度、滴滴 資深前端工程師,慕課網金牌講師,PMP,前端面試派 作者。
我目前在進行兩個專案的開發與升級,有興趣的可以私訊我,加入專案小組。
從單一 LLM 呼叫,到多智能體協作系統——這篇文章帶你搞清楚 Multi-Agent 的來龍去脈與工程實作。
單一 LLM 呼叫有天然侷限:
Multi-Agent 的誕生來自一個核心洞察:將複雜任務拆分給多個專職 Agent 協作完成,就像一個高效團隊。
目前比較主流的有兩種架構。
這是最常見的 Multi-Agent 架構。Orchestrator 是「大腦」,負責理解任務、制定計畫、分配工作、彙總結果;Worker 是「手腳」,各司其職,專注執行某一類具體任務。
使用流程(示意):
用戶請求
↓
Orchestrator Agent(負責規劃、分解、調度)
↓ ↓ ↓
Worker A Worker B Worker C
(程式執行) (網路搜索) (資料庫查詢)
↓ ↓ ↓
Orchestrator Agent(彙總結果、決策下一步)
↓
最終回應
適合場景:任務邊界清晰、可並行拆分的複雜需求,例如「調研競品 + 撰寫報告 + 產生 PPT」。
各 Agent 串行執行,上個 Agent 的輸出是下個 Agent 的輸入,像工廠流水線一樣,每一道工序都有明確職責。
示意: Agent A → Agent B → Agent C → 輸出
(研究) (寫作) (校對)
適合場景:任務有明確先後依賴、每步都需加工處理的工作流程,例如「收集資料 → 清洗 → 分析 → 視覺化」。
以「幫我開發一個 Todo 應用」為例,看 Multi-Agent 如何協作:
用戶:「幫我開發一個 Todo 應用」
↓
[Orchestrator]
分解為 4 個子任務:
① 需求分析 ② 後端開發 ③ 前端開發 ④ 測試
↓
並行執行 ②、③:
這個例子體現了兩種架構的混合使用:②③ 並行是 Orchestrator-Worker 模式,Test → Backend 是 Pipeline 模式。實際專案中往往會混合使用這兩種模式。
理解了 Multi-Agent 的架構後,我們來區分兩個容易混淆的概念:
所以:有 Sub-Agent 的系統一定是 Multi-Agent,但 Multi-Agent 不一定有 Sub-Agent。
Sub-Agent 最強大的地方在於它天然支援遞迴嵌套,這正是複雜 Multi-Agent 系統的基礎:
示意樹狀結構:
使用者
└─ 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 只需要關心自己直接管轄的下級,不需了解整棵樹的全貌,這就是複雜系統可維護性的關鍵。
LangChain 的 Supervisor 概念來自 LangGraph 生態,是目前最推薦的 Multi-Agent 編排方式,專為動態路由與多 Agent 協作而設計。
使用流程(示意):
使用者輸入
↓
[Supervisor Node] ← 由 LLM 決策路由
↓ ↓ ↓
[Agent A] [Agent B] [Agent C]
↓ ↓ ↓
[Supervisor Node] ← 再次決策:繼續?結束?換人?
↓
FINISH
Supervisor 本身也是一次 LLM 呼叫——它每一輪會重新審視當前對話狀態,決定下一步交給誰處理,或宣告任務完成。
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,然後寫範例」為輸入,執行流程如下:
輸入:「研究 Fastify,然後寫範例」
↓
[Supervisor]
→ 判斷:需要先研究 → "ResearchAgent"
↓
[ResearchAgent]
→ 呼叫 web_search 工具搜尋 Fastify 相關資料
→ 完成,回到 Supervisor
↓
[Supervisor]
→ 判斷:已有資料,需要寫程式 → "CoderAgent"
↓
[CoderAgent]
→ 根據研究結果呼叫 write_code 工具生成範例
→ 完成,回到 Supervisor
↓
[Supervisor]
→ 判斷:任務完成 → "FINISH"
↓
輸出最終結果
在實際搭建 Multi-Agent 系統時,有幾個工程原則值得注意:
單一職責:每個 Agent 只做一件事,工具集盡量精簡。職責越清晰,Supervisor 的路由決策越準確,Agent 的輸出也越可預期。
明確的輸入輸出契約:Agent 之間的訊息格式要統一。上面程式中給訊息打 name 標記,就是一種簡單的契約——Supervisor 可以透過 name 知道誰做了什麼。
防止無限迴圈:生產環境中要給 Supervisor 設定最大迭代次數(recursionLimit),避免 Agent 互相踢皮球導致死循環。
const app = graph.compile();
const result = await app.invoke(input, { recursionLimit: 20 });
錯誤隔離:Worker/Sub-Agent 內部的例外不應直接讓整個圖崩潰。可以在 Node 函式中 try/catch,將錯誤資訊作為普通訊息回傳給 Supervisor,由它決定如何處理。
Multi-Agent 並不是「多跑幾次 LLM」那麼簡單,它是一套完整的軟體架構思維:
在生產環境下,智能體軟體幾乎都會採用 Multi-Agent 架構,用以解決多任務、複雜任務的效率問題。典型案例例如 Cursor 中的 Sub-Agent,可以更好地應對大型複雜的開發任務。
理解了這套架構,你就掌握了構建「真正能幹事的 AI 系統」的基礎框架。