大多數人看到多 Agent 系統,第一反應是「多幾個 Agent 就能平行加速」。 工程現實卻是:沒有協調機制的多 Agent,比單 Agent 更慢、更貴、更難除錯。 正確答案是:先確定協調模式,再決定幾個 Agent——而不是反過來。 協調成本才是多 Agent 系統的真正瓶頸,比 LLM token 更貴。
這篇給已經把單一 Agent 跑穩、正打算「多加幾個 Agent 來分工」的工程師看。全文用一個貫穿的例子:研究助理平台把複雜問題拆成子任務,分派給搜尋、摘要、數據分析、引用驗證等專業 Agent,再整合成報告,目標是 2,000 個並發研究任務、每個任務平均 8 個子 Agent。讀完你會能在 Supervisor、Peer-to-Peer 與 Market 三種協調模式之間做選擇、為 Agent 間通訊挑對機制、用樂觀鎖與分段所有權處理兩個 Agent 搶同一份資源的衝突,並且知道什麼時候多 Agent 共識值得它的延遲成本。
一、核心問題:多 Agent 協調比單 Agent 難在哪裡
1.1 單 Agent 的極限在哪裡
單一 LLM Agent 在以下情境開始出現瓶頸:
| 情境 | 問題 | 數字 |
|---|---|---|
| 超長 context | 精度隨 token 數下降 | > 32K tokens 後 recall 掉 15–30% |
| 串行任務鏈 | 無法利用並行,延遲線性增長 | 10 步 × 3s = 30s |
| 異構技能需求 | 同一 Agent 無法同時是程式碼專家與法律專家 | prompt 膨脹、精度下降 |
| 長時間運行 | 上下文視窗耗盡,需要切割狀態 | 超過 4 小時任務必須外化記憶 |
多 Agent 解決了以上問題——但引入了一整類新問題:
協調成本 = 通訊延遲 + 同步開銷 + 衝突解決 + 狀態一致性
在任務粒度太細時,協調成本 > 並行收益,整體反而更慢。
1.2 協調的三個根本挑戰
挑戰一:誰負責什麼(任務分配)
- 靜態分工:事先定義每個 Agent 的職責邊界
- 動態分工:任務在執行時才決定由誰承擔
- 兩者都需要「知識地圖」——Agent 有什麼能力
挑戰二:誰知道什麼(資訊共享)
- Agent A 找到的資訊,Agent B 何時能看到?
- 共享記憶體的一致性 vs 訊息傳遞的隔離性
- 資訊過時(stale)導致重複工作或決策矛盾
挑戰三:誰說了算(衝突仲裁)
- 兩個 Agent 對同一問題得出不同結論
- 兩個 Agent 同時想寫同一個輸出
- 優先級衝突:Agent A 認為現在該停止,Agent B 認為應繼續
二、何時該升級:從腳本編排到 Supervisor 與佇列、再到分片的觸發條件
最省事的起點是一支編排腳本(Python 或 LangGraph 的線性 DAG)直接同步呼叫每個 Agent,結果放在一個共享 dict 裡傳遞:不做重試、不做衝突檢測、不留審計日誌,一兩天就能建好。只要並發任務數是個位數、任務之間互不重疊、而且一個 Agent 失敗整個流程中斷是可以接受的,這就夠了。該升級的訊號是:同一份輸出開始被兩個 Agent 覆寫(共享 dict 無鎖的競爭條件)、失敗需要自動重試而不是回報給使用者、或是子任務必須真正並行而不是串行等待。這時引入 Supervisor Agent 做分配(§三)、Redis Streams 之類的持久化佇列(§四)、共享狀態加上版本鎖(§六),失敗任務回佇列最多重試 3 次。
第二道門檻是 Supervisor 本身成為瓶頸:它是單點,所有分配決策都經過它,當它的 CPU 飽和、分配佇列的等待時間開始隨並發數上升,就該按任務 ID hash 把 Supervisor 水平分片;同一時間,若佇列需要按 Agent 類型分區並行、或跨 datacenter 複製,Redis Streams 換成 Kafka;Worker Pool 改為按 Agent 類型獨立擴縮,並加上 circuit breaker 讓下游 LLM API 超載時快速失敗。合規要求審計日誌時,再把 Postgres 加進狀態層。這些升級各有各的訊號,不必一次全上。
| 從 | 到 | 觸發訊號 |
|---|---|---|
| 編排腳本 + 共享 dict | Supervisor + Redis Streams + 版本鎖 | 共享狀態出現覆寫;需要自動重試;子任務必須真正並行 |
| 單一 Supervisor | 按任務 ID hash 分片的 Supervisor | Supervisor CPU 飽和、分配等待時間隨並發數上升(§八 決策 1) |
| Redis Streams | Kafka topic per type + 獨立 Worker Pool | 需要按類型分區並行、跨 datacenter 複製、或長期保留重播 |
三、協調架構:Supervisor vs Peer-to-Peer vs Market
3.1 三種架構模式
模式一:Supervisor(集中式)
┌─────────────┐
│ Supervisor │◀── 全局視圖、分配決策
└──────┬──────┘
┌────┼────┐
▼ ▼ ▼
A1 A2 A3 ← Worker,只執行,不決策
模式二:Peer-to-Peer(分散式)
A1 ◀──▶ A2
▲ ▲
│ │
▼ ▼
A3 ◀──▶ A4 ← 每個 Agent 都有部分決策權
模式三:Market(競價式)
┌─────────────────┐
│ Task Board │ ← 任務公告欄
└────────┬────────┘
A1 出價 $3 A2 出價 $2 A3 出價 $5
└──────────────────────┘
▼
最低價 A2 得標 ← 去中心化分配
3.2 三種模式比較
| 維度 | Supervisor | Peer-to-Peer | Market |
|---|---|---|---|
| 全局最優性 | 高(中心化視圖) | 中(局部最優) | 中高(競價近似) |
| 單點失敗風險 | 高 | 低 | 低 |
| 協調延遲 | 低(1 hop) | 高(N hops) | 中(出價輪) |
| 動態適應性 | 低(需重新分配) | 高 | 高 |
| 實作複雜度 | 低 | 高 | 高 |
| 適用規模 | < 50 Agent | 任意 | 任意 |
| 典型場景 | 研究報告生成 | 模擬/遊戲 AI | 算力市場 |
選擇原則:
- 任務有明確 DAG 依賴 → Supervisor
- 任務高度動態、無法預知 → Peer-to-Peer
- 資源有限、需要效率最大化 → Market
四、Agent 間通訊:共享記憶體 vs 訊息佇列 vs 直接呼叫
4.1 三種通訊機制
共享記憶體(Shared Memory)
1# Agent A 寫入
2state["search_results"] = results
3state["search_done"] = True
4
5# Agent B 讀取
6if state.get("search_done"):
7 data = state["search_results"]
- 延遲:< 1ms(本地),1–5ms(Redis)
- 問題:競爭條件(race condition),需要鎖機制
- 適用:同一進程內的緊密協作 Agent
訊息佇列(Message Queue)
1# Agent A 發布
2queue.publish("task.search.done", {
3 "task_id": "t123",
4 "results": results,
5 "timestamp": now()
6})
7
8# Agent B 訂閱
9@queue.subscribe("task.search.done")
10def handle_search_done(msg):
11 process(msg["results"])
- 延遲:5–50ms(Redis Streams),10–100ms(Kafka)
- 優點:解耦、可重播、天然背壓
- 適用:跨服務、需要審計軌跡的場景
直接 HTTP/RPC 呼叫
1# Agent A 同步呼叫 Agent B
2result = await agent_b.execute(
3 task="summarize",
4 content=search_results,
5 timeout=30
6)
- 延遲:10–200ms(含網路)
- 優點:簡單、強類型、可追蹤
- 問題:緊耦合,Agent B 失敗直接影響 A
4.2 通訊機制選型
| 場景 | 推薦機制 | 原因 |
|---|---|---|
| 同進程、高頻小訊息 | 共享記憶體 + 樂觀鎖 | < 1ms 延遲 |
| 跨服務、非同步任務 | Redis Streams / Kafka | 解耦、可重播 |
| 需要即時回應的 RPC | gRPC / HTTP | 強型別、超時控制 |
| 大型檔案/向量傳遞 | 物件儲存(S3)+ 訊息通知 | 避免佇列膨脹 |
黃金法則: 訊息大小 > 64KB 時,永遠用引用傳遞(傳 URL)而非值傳遞(傳內容)。
五、任務分配:靜態分工 vs 動態競標
5.1 靜態分工
事先定義每個 Agent 的職責,Supervisor 按規則路由:
Task Type Routing Table
┌──────────────────┬─────────────────┬──────────────────┐
│ 任務類型 │ 負責 Agent │ 備援 Agent │
├──────────────────┼─────────────────┼──────────────────┤
│ web_search │ SearchAgent-1 │ SearchAgent-2 │
│ pdf_extract │ DocAgent-1 │ DocAgent-2 │
│ code_execution │ CodeAgent-1 │ CodeAgent-2 │
│ citation_verify │ FactAgent-1 │ FactAgent-2 │
│ final_synthesis │ WriterAgent-1 │ WriterAgent-2 │
└──────────────────┴─────────────────┴──────────────────┘
優點: 可預測、低延遲(不需要協調決策)、易除錯 缺點: 負載不均(某類型任務突發時某 Agent 空轉)
5.2 動態競標
動態任務分配流程
新任務到達
│
▼
┌──────────────┐
│ 任務公告板 │──▶ 廣播給所有可用 Agent
└──────┬───────┘
│
│ Agent 評估自身負載 + 能力匹配度
│
┌────┴────┐
│ 出價 │
│A1: 0.8s │
│A2: 1.2s │ ← 預估完成時間(越短越好)
│A3: 0.6s │
└────┬────┘
│
▼
A3 得標(最短預估時間)
│
▼
執行 + 回報結果
出價函數範例:
1def bid_score(agent, task):
2 capacity = 1.0 - agent.current_load # 0.0–1.0
3 skill_match = agent.skill_score(task) # 0.0–1.0
4 estimated_time = task.complexity / agent.speed
5 return estimated_time / (capacity * skill_match)
6 # 分數越低越有競爭力
靜態 vs 動態比較:
| 維度 | 靜態分工 | 動態競標 |
|---|---|---|
| 分配延遲 | < 1ms | 50–200ms(出價輪) |
| 負載均衡品質 | 中 | 高 |
| 實作複雜度 | 低 | 高 |
| 適應突發流量 | 差 | 佳 |
| 除錯難度 | 低 | 高(非確定性) |
建議: 初期用靜態,規模化後混用(靜態路由 + 動態負載均衡)。
六、衝突解決:資源競爭/目標衝突/優先級仲裁
6.1 資源競爭衝突
最常見:兩個 Agent 同時想寫同一個輸出位置。
解法一:樂觀鎖(Optimistic Locking)
1# 讀取時記錄版本號
2doc, version = state.get("report_draft", with_version=True)
3
4# 修改後寫回,帶版本校驗
5success = state.set(
6 "report_draft",
7 updated_doc,
8 expected_version=version # 若版本不符則失敗
9)
10if not success:
11 # 衝突:重新讀取、合併、重試
12 retry()
解法二:分段所有權(Partition Ownership)
- 每個 Agent 只寫自己負責的 section(section_1, section_2…)
- 最終由 Writer Agent 合併,避免直接競爭
6.2 目標衝突
Agent A 的子目標與 Agent B 的子目標互相矛盾(如:A 要最小化成本,B 要最大化覆蓋率)。
解法:目標優先級層級
L1(不可違背): 安全約束(不輸出有害內容、不超預算)
L2(高優先): 使用者明確要求
L3(中優先): 品質指標(精度、完整性)
L4(低優先): 效率指標(速度、成本)
衝突發生時,高層級目標自動覆蓋低層級。若同層衝突,升級至 Supervisor 決策。
6.3 優先級仲裁
當多個任務同時競爭有限 Agent 資源時:
仲裁矩陣
┌─────────────────┬──────┬────────────┬─────────────┐
│ 任務屬性 │ 分數 │ 範例 │ 處理方式 │
├─────────────────┼──────┼────────────┼─────────────┤
│ 使用者等待中 │ 10 │ 即時查詢 │ 搶占式優先 │
│ SLA 剩餘 < 30s │ 8 │ 批次報告 │ 提升佇列位置 │
│ 已重試 > 2 次 │ 6 │ 失敗重試 │ 給予新資源 │
│ 背景批次 │ 2 │ 夜間統計 │ 填補空閒 │
└─────────────────┴──────┴────────────┴─────────────┘
仲裁規則: 分數最高者優先取得 Agent 資源,同分者 FIFO。
七、共識機制:多 Agent 決策的一致性保障
7.1 為什麼需要共識?
在以下場景,多個 Agent 必須達成一致才能繼續:
- 分叉決策:Agent A 說「資料足夠」,Agent B 說「需要更多搜尋」
- 品質閘門:至少 N 個 Agent 同意報告品質達標才能輸出
- 危險操作確認:刪除資料、發送通知等不可逆操作
7.2 三種共識方法
方法一:投票(Voting)
1votes = {
2 "agent_search": "sufficient", # 3 票
3 "agent_fact": "sufficient",
4 "agent_logic": "need_more", # 1 票
5 "agent_quality": "sufficient"
6}
7decision = majority_vote(votes) # → "sufficient"(3:1)
適用:決策較明確,Agent 能力相近
方法二:加權投票(Weighted Voting)
1weighted_votes = {
2 "agent_domain_expert": ("sufficient", 3.0), # (投票, 權重)
3 "agent_generalist": ("need_more", 1.0),
4}
5# 加權後:sufficient=3.0, need_more=1.0 → sufficient
適用:Agent 能力有差異,專家 Agent 應有更大影響力
方法三:否決機制(Veto) 某些特定 Agent 具有一票否決權(通常是安全/合規 Agent):
1if safety_agent.verdict == "unsafe":
2 return "BLOCKED" # 無論其他 Agent 如何投票
適用:有硬性約束(安全、法律合規)的場景
7.3 共識的延遲成本
| 共識方法 | 額外延遲 | 適用決策頻率 |
|---|---|---|
| 無共識(單 Agent 決定) | 0ms | 高頻、低風險 |
| 多數投票(N Agent) | 串行問詢時 N × 平均延遲;並行問詢時約為中位數 Agent 的延遲 | 中頻 |
| 加權投票 | N × 平均延遲 + 計算 | 低頻、高風險 |
| 人工確認(HITL) | 秒~分鐘 | 極低頻、關鍵決策 |
實務原則: 只在以下情況引入多 Agent 共識:(1) 決策不可逆,(2) 單 Agent 錯誤率 > 5%,(3) 有明確的損失函數可衡量一致性的價值。
八、為什麼選 X 不選 Y
先處理兩個不需要整張表的選擇。狀態儲存用 Redis 而不是進程內記憶體:Agent crash 後狀態可恢復、多個 Agent 實例共享同一份狀態、TTL 自動清理過期任務,1–5 ms 的延遲遠低於一次 LLM 呼叫;只有單機 POC、任務量 < 100/天、沒有容錯需求時,純記憶體 dict 才夠。佇列用 Redis Streams 而不是 RabbitMQ:已有 Redis 就零增量基建,Consumer Group 支援 N:M 消費,訊息可按 ID 重播、除錯友善;任務量 > 100K/天、或需要跨 datacenter 複製時換 Kafka(Kafka 是批次設計,延遲 10–50 ms,換早了只是多付維運)。下面四個決策才真的需要權衡。
決策 1:協調架構選 Supervisor 不選 Peer-to-Peer
| 選擇 | 選 Supervisor 的理由 | 不選 P2P 的理由 |
|---|---|---|
| 分配品質 | 全局任務視圖,分配最優 | 協調訊息量 O(N²) |
| 除錯 | 一個決策節點,DAG 依賴容易表達 | 死鎖風險難排查,需要分散式共識算法 |
| 延遲 | 1 hop | N hop 累積延遲高 |
Flip condition: Supervisor 成為瓶頸(CPU > 80%、分配等待時間隨並發數上升)→ 先切成分片 Supervisor;任務高度動態、無法預先列出 DAG 時才改 P2P。
決策 2:共享狀態選樂觀鎖不選悲觀鎖
| 選擇 | 選樂觀鎖的理由 | 不選悲觀鎖的理由 |
|---|---|---|
| 吞吐 | 衝突率低(< 5%)時不持鎖,Agent 可並行讀取 | 持鎖期間其他 Agent 阻塞,等待時間不可控 |
| 實作 | Redis 的 WATCH/MULTI/EXEC 或 Lua 腳本可做 compare-and-set | 需要鎖服務,鎖服務自身成為瓶頸 |
| 失敗模式 | 衝突時重試成本低(毫秒級) | 死鎖風險 |
Flip condition: 衝突率 > 20%(多個 Agent 頻繁競爭同一資源)→ 悲觀鎖,或改成 §六 的分段所有權讓競爭消失。
決策 3:任務分配選靜態路由不選動態競標(初期)
| 選擇 | 選靜態路由的理由 | 不選動態競標的理由 |
|---|---|---|
| 延遲 | 分配 < 1 ms | 50–200 ms 出價輪延遲 |
| 可預測性 | 完全可預測,易於除錯 | 非確定性,難重現 bug |
| 成本 | 實作 1 天;任務類型穩定時適合 80% 場景 | 實作 1 週,出價函數需要調參 |
Flip condition: 不同 Agent 負載差異 > 3x,或任務類型分佈高度不均 → 保留靜態路由,加入動態負載均衡。
決策 4:共識方法選多數投票不選全體一致
| 選擇 | 選多數投票的理由 | 不選全體一致的理由 |
|---|---|---|
| 可用性 | 一個 Agent 超時不阻塞決策,容忍單 Agent 噪聲 | 任一 Agent 異常即卡住 |
| 延遲 | 並行投票時由中位數 Agent 決定,不是最慢者 | 最慢 Agent 決定速度 |
| 規模 | 適合 3–7 個 Agent 的決策群組 | > 5 Agent 時幾乎不可用 |
Flip condition: 決策涉及安全/合規,不容許任何錯誤 → 在多數投票之上加否決機制(§七 方法三),讓特定 Agent 一票否決。
九、系統效應(單 Agent vs 多 Agent 協調)
| 指標 | 單 Agent | 多 Agent(無協調) | 多 Agent(有協調) |
|---|---|---|---|
| 並發任務吞吐 | 1 task/s | 5 task/s(不穩定) | 8 task/s(穩定) |
| 平均任務延遲(10 步) | 30s | 15s(部分並行) | 8s(全並行) |
| 任務失敗率 | 8% | 25%(無協調衝突) | 3%(有重試+鎖) |
| LLM token 使用/任務 | 15K | 18K(重複工作) | 12K(分工更精準) |
| 月成本(1K 任務/天) | $450 | $540 | $360 |
| 除錯時間/incident | 30 分鐘 | 2 小時 | 45 分鐘 |
| 水平擴展能力 | 無 | 部分 | 線性 |
示意估算,非實測數據。
關鍵洞察: 「多 Agent 無協調」是最差選項——比單 Agent 更貴、更不可靠。協調機制本身帶來的開銷(約 20% token overhead)遠小於它消除的重複工作和衝突損失(節省 33% token)。
規模臨界點:
- < 3 個 Agent:用 Supervisor + 靜態路由,不要過度設計
- 3–20 個 Agent:加入訊息佇列 + 樂觀鎖
20 個 Agent:分片 Supervisor + Kafka + 動態負載均衡
相關文章與正典版本
- 系列總覽與六大策略 — 多 Agent Token 優化系列 pt.1:完整指南
- Agent 間的選擇性 Context 傳遞(正典) — 多 Agent Token 優化系列 pt.5:選擇性 Context 傳遞
- 專責化與每次呼叫的 token 經濟(正典) — 多 Agent Token 優化系列 pt.6:Agent 專責化實戰指南
- 協作模式與 token 預算路由的完整實作 — 多 Agent Token 優化系列 pt.7:專責化 Agent 協作模式
- 狀態管理、重試與死鎖排除(正典) — FDE 面試準備指南(十六):Multi-Agent 狀態管理與死鎖排除
十、系列導航
| ← 上一篇 | Phase 15 Part 2:自我改進與 2026 安全技術棧 |
| → 下一篇 | Phase 16 Part 2:湧現與集體智慧 — 群體行為的工程設計 |
本文為「AI 工程從零開始」系列 Phase 16 Part 1。系列總覽:AI 工程從零開始 。
