Mark Ku's Blog
在 ChatGPT 開啟在 Claude 開啟

歡迎收聽 Mark 的 Tech Insights,我是主持人璦廷。當單一的人工智慧無法滿足複雜任務時,多個人工智慧代理協作的 Multi-Agent 架構就成了關鍵。 今天讓我們來看看,為什麼在眾多架構中,我們特別推薦 Supervisor 主管模式。相較於讓代理自由對話、容易失控的點對點網路,Supervisor 模式由中央主管負責流程編排,各個 Worker 代理只需專注於專業執行。 這個重點值得注意,在實作 Podcast 自動生成管線時,代理間不直接溝通,而是透過共享的 State 物件傳遞資訊。搭配 LangGraph 的 Reducer 機制,能確保代理平行運作時的錯誤紀錄不被覆蓋。這不僅讓系統完全解耦,更能輕鬆建立品質把關的回饋迴路與容錯策略。 總結來說,Supervisor 模式讓複雜的人工智慧工作流變得清晰可控。思考一下,您手邊有哪些任務,也適合拆解並交給專屬的數位員工來代勞呢?

Podcast 對話本文 AI 對話朗讀版
本文音訊由 VoAI 提供技術支援VoAI 絕好聲創

前言

2025 年 AI Agent 已經不稀奇了,真正開始捲的是 Multi-Agent — 讓多個 Agent 自己協調工作、分工合作。

單一 Agent 能力再強,碰到複雜任務還是會遇到瓶頸:context window 塞不下、一個 prompt 要兼顧搜尋 + 撰寫 + 校稿 + 生圖 + 語音合成,品質很難穩定。把任務拆給多個專精的 Agent,每個只做一件事,反而更可控。

但問題來了:多個 Agent 之間怎麼協調? 這篇整理兩種主流架構模式的差異,並用我實際做的 Podcast 自動生成管線當例子,分享為什麼我最後選了 Supervisor 模式。

兩種主流架構模式

在規劃 Multi-Agent 系統時,通常會碰到兩種設計模式:

1. Network / Peer-to-Peer(點對點協作)

Agent 之間直接互相溝通,沒有中心控制者。每個 Agent 可以自行決定要找誰對話、傳遞什麼資訊。

┌─────────┐     ┌─────────┐
│ Agent A │◄───►│ Agent B │
└────┬────┘     └────┬────┘
     │               │
     ▼               ▼
┌─────────┐     ┌─────────┐
│ Agent C │◄───►│ Agent D │
└─────────┘     └─────────┘
    (每個 Agent 都可以跟任意 Agent 溝通)

適合場景:開放性討論、腦力激盪、多觀點辯論 風險:流程難預測、容易陷入無限迴圈、Debug 困難

2. Supervisor(主管模式)

有一個中央 Supervisor Agent 負責評估目前狀態,決定下一步要派誰上場。Worker Agent 執行完後回報結果,由 Supervisor 決定後續動作。

                ┌────────────┐
                │ Supervisor │
                │  (協調者)   │
                └─────┬──────┘
           ┌──────────┼──────────┐
           ▼          ▼          ▼
      ┌─────────┐ ┌─────────┐ ┌─────────┐
      │Worker A │ │Worker B │ │Worker C │
      │(搜尋)   │ │(撰寫)   │ │(校稿)   │
      └─────────┘ └─────────┘ └─────────┘
    (Worker 只跟 Supervisor 溝通,彼此不直接對話)

適合場景:有明確流程的任務管線、需要品質把關、要可追蹤進度 優勢:流程可控、分工明確、容錯好設計

比較表

面向

Network (P2P)

Supervisor

控制方式

去中心化,Agent 自行協商

中央控制,Supervisor 分派

流程可預測性

❌ 低,路徑不固定

✅ 高,有明確的狀態機

Debug 難度

😰 高,訊息流向複雜

😌 低,每步都有 log

適合任務

開放性討論、創意發想

流程明確的生產管線

擴展性

新增 Agent 需考慮通訊拓撲

新增 Worker 只需註冊到 Supervisor

容錯設計

各 Agent 自行處理

Supervisor 統一管理降級策略

為什麼我選 Supervisor 模式

核心原因:Supervisor 只需要知道「誰能做什麼」,而 Worker 只需要知道「怎麼把這件事做好」。

這個分工非常乾淨:

  • Supervisor 負責「流程編排」— 誰先做、誰後做、失敗了怎麼辦

  • Worker 負責「專業執行」— 搜新聞就搜新聞、寫稿就寫稿、校稿就校稿

這跟軟體工程的 單一職責原則(SRP) 一樣 — 每個 Agent 只做一件事,做好就回報。

而且在實務上,大多數 AI 自動化任務都有明確的前後依賴關係(搜尋完才能寫、寫完才能校),Supervisor 模式天然適合這種管線型工作流。

跨 Agent 怎麼協調?共享狀態是唯一溝通管道

在 Supervisor 模式裡,Agent 之間不直接通訊。所有協調都透過一個共享的 State 物件:

┌─────────────────────────────────────────────┐
│           共享狀態(Shared State)             │
│                                             │
│  rawSources ← Research 寫入                  │
│  podcastMarkdown ← Writer 寫入               │
│  editorFeedback ← Editor 寫入                │
│  coverImagePath ← CoverArt 寫入              │
│  audioPath ← TTS 寫入                        │
│  errors ← 所有 Agent 可寫入(append 模式)     │
│                                             │
│  Supervisor 讀取 State → 決定下一步           │
└─────────────────────────────────────────────┘

每個 Agent 的溝通方式:

  • :從 State 拿到自己需要的輸入(例如 Writer 讀 rawSources

  • :把自己的產出寫回 State(例如 Writer 寫 podcastMarkdown

  • 不需要知道:前一步是誰做的、下一步是誰接手

這樣的好處是 Agent 完全解耦 — 你可以隨時替換任何一個 Agent 的實作(例如把 Gemini Writer 換成 Claude Writer),只要輸入輸出的 State 欄位不變,其他 Agent 完全不受影響。

LangGraph State 管理機制:Annotation 與 Reducer

LangGraph 用 Annotation 來定義共享狀態,這是整個 Multi-Agent 協調的基礎。

核心概念:每個欄位可以有自己的 reducer

一般的 State 管理是「後寫覆蓋前寫」,但在 Multi-Agent 場景下這樣會出問題。例如 Agent A 記了一個 error,Agent B 又記了一個 error,如果沒有 reducer,B 的 error 會把 A 的覆蓋掉。

LangGraph 的解法是讓每個欄位定義自己的 reducer(合併策略)

export const PodcastAnnotation = Annotation.Root({
  // 普通欄位:後寫覆蓋(預設行為)
  date: Annotation<string>,
  podcastMarkdown: Annotation<string>,

  // append reducer:新值追加到陣列,不覆蓋舊值
  errors: Annotation<AgentError[], AgentError[]>({
    reducer: (existing, update) => [...existing, ...update],
    default: () => [],
  }),

  // merge reducer:合併物件的 key-value
  retryCount: Annotation<Record<string, number>>({
    reducer: (existing, update) => ({ ...existing, ...update }),
    default: () => ({}),
  }),
})

Reducer 運作方式

Reducer 類型

行為

適用場景

無(預設)

後寫覆蓋前寫

單一 Agent 產出的欄位(podcastMarkdown

append

新值追加到陣列

多個 Agent 都可能寫入的欄位(errors

merge

合併物件 key

計數器、狀態追蹤(retryCount

custom

自訂邏輯

任何特殊需求

為什麼這很重要?

沒有 reducer 的 Multi-Agent 系統,最常見的 bug 就是狀態被意外覆蓋。想像這個場景:

  1. CoverArt Agent 和 TTS Agent 平行執行

  2. CoverArt 遇到錯誤,寫入 errors: [{ agent: 'coverArt', message: '...' }]

  3. TTS 也遇到錯誤,寫入 errors: [{ agent: 'tts', message: '...' }]

  4. 沒有 append reducer → TTS 的 error 覆蓋 CoverArt 的 error → 你永遠不知道封面生成失敗了

有了 append reducer,兩個 error 都會被保留。這是 Multi-Agent 系統 State 管理的基本功。

設計概念:用 LangGraph StateGraph 實作 Supervisor

我用 LangGraphStateGraph 來實作 Supervisor。核心思路是:

  1. 共享狀態(State):所有 Agent 讀寫同一個 State 物件(上面講的 Annotation)

  2. 節點(Node):每個 Agent 是一個節點

  3. 邊(Edge):定義節點之間的執行順序

  4. 條件路由(Conditional Edge):Supervisor 根據 State 決定下一步走哪條路

START → Research → Writer → Editor ─┬─→ Publisher → [CoverArt + TTS] → END
                     ▲               │
                     │    (score < 60, retry ≤ 2)
                     └───────────────┘
                      回饋迴路:帶著問題清單重寫

實作案例:Podcast 自動生成管線

我用這個架構做了一個「科技新聞 Podcast 自動生成器」,6 個 Agent 各司其職:

Agent

職責

使用技術

🔍 ResearchAgent

搜尋最新 AI 新聞(8-12 則)

Claude CLI + web_search

✍️ WriterAgent

將新聞素材寫成 Podcast 文章

Gemini 3.1 Pro

📝 EditorAgent

品質評分 + 清理 AI 痕跡

Gemini 3.1 Pro + regex

📦 PublisherAgent

組裝 frontmatter、寫入 MDX

Filesystem

🎨 CoverArtAgent

生成封面圖

Gemini Image + sharp

🎙️ TTSAgent

生成多角色對話語音

Gemini + VoAI TTS

完整架構圖

┌─────────────────────────────────────────────────────────────────────┐
│                        LangGraph StateGraph                         │
│                        (Supervisor 協調者)                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────────┐  │
│  │ Research  │───▶│  Writer  │───▶│  Editor  │───▶│  Publisher   │  │
│  │  Agent   │    │  Agent   │◀───│  Agent   │    │    Agent     │  │
│  │          │    │          │回饋 │          │    │              │  │
│  │ Claude   │    │ Gemini   │迴路 │ Gemini   │    │  Filesystem  │  │
│  │ CLI +    │    │ 3.1 Pro  │(≤2) │ 3.1 Pro  │    │  MDX 寫入    │  │
│  │web_search│    │          │    │          │    │              │  │
│  └──────────┘    └──────────┘    └──────────┘    └──────┬───────┘  │
│                                                         │          │
│                                              ┌──────────┴────┐     │
│                                              │   平行執行     │     │
│                                         ┌────▼────┐  ┌──────▼──┐  │
│                                         │CoverArt │  │  TTS    │  │
│                                         │ Agent   │  │  Agent  │  │
│                                         │ Gemini  │  │ Gemini  │  │
│                                         │ Image + │  │ + VoAI  │  │
│                                         │ sharp   │  │         │  │
│                                         └────┬────┘  └────┬────┘  │
│                                              ▼            ▼       │
│                                             END          END      │
└─────────────────────────────────────────────────────────────────────┘

程式碼重點解析

1. 共享狀態定義(LangGraph Annotation)

所有 Agent 讀寫同一個 State,用 Annotation 定義資料結構與 reducer:

import { Annotation } from '@langchain/langgraph'

export const PodcastAnnotation = Annotation.Root({
  // ─── 輸入 ───
  date: Annotation<string>,
  config: Annotation<PodcastConfig>,

  // ─── 各階段產出 ───
  rawSources: Annotation<NewsSource[]>,        // Research 寫入
  podcastMarkdown: Annotation<string>,          // Writer 寫入
  editorFeedback: Annotation<EditorFeedback>,   // Editor 寫入
  cleanedContent: Annotation<string>,           // Editor 寫入
  coverImagePath: Annotation<string | null>,    // CoverArt 寫入
  audioPath: Annotation<string | null>,         // TTS 寫入

  // ─── 控制欄位 ───
  errors: Annotation<AgentError[]>({
    reducer: (existing, update) => [...existing, ...update],
    default: () => [],
  }),
  retryCount: Annotation<Record<string, number>>({
    reducer: (existing, update) => ({ ...existing, ...update }),
    default: () => ({}),
  }),
})

💡 重點errors 用 append reducer,不會被後面的 Agent 覆蓋掉前面的錯誤紀錄。

2. StateGraph 組裝:節點 + 邊 + 條件路由

import { StateGraph, END } from '@langchain/langgraph'

export function buildGraph() {
  const graph = new StateGraph(PodcastAnnotation)
    // 註冊節點(每個 Agent 都是一個 function)
    .addNode('research', researchAgent)
    .addNode('writer', writerAgent)
    .addNode('editor', editorAgent)
    .addNode('publisher', publisherAgent)
    .addNode('coverArt', coverArtAgent)
    .addNode('tts', ttsAgent)

    // 順序執行
    .addEdge('__start__', 'research')
    .addEdge('research', 'writer')
    .addEdge('writer', 'editor')

    // 條件路由:Editor 決定要重寫還是放行
    .addConditionalEdges('editor', routeAfterEditor, {
      publisher: 'publisher',
      writerRetry: 'writerRetry',
    })

    // Publisher 後:平行執行 CoverArt + TTS
    .addConditionalEdges('publisher', routeAfterPublisher, {
      coverArt: 'coverArt',
      tts: 'tts',
      end: 'end',
    })

    .addEdge('coverArt', END)
    .addEdge('tts', END)

  return graph.compile()
}

💡 重點addConditionalEdges 就是 Supervisor 的核心 — 根據目前 State 決定下一步走哪條路。

3. Worker Agent 的實作(以 WriterAgent 為例)

每個 Worker 只做一件事:接收 State → 執行任務 → 回寫結果:

export async function writerAgent(
  state: PodcastState
): Promise<Partial<PodcastState>> {
  const model = await createVertexModel({
    model: state.config.writerModel,
    temperature: 0.8,
  })

  // 如果是 retry,帶入 Editor 的回饋
  let feedbackContext = ''
  if (state.editorFeedback && !state.editorFeedback.passed) {
    feedbackContext = state.editorFeedback.issues
      .map(i => `- ${i}`)
      .join('\n')
  }

  const prompt = buildWriterPrompt(state.date, newsContext) + feedbackContext
  const response = await model.invoke([{ role: 'user', content: prompt }])

  return {
    podcastMarkdown: response.content.trim(),
    currentStep: 'writing_done',
  }
}

Worker 不需要知道自己是第幾次被叫、前後是誰,它只管「把稿子寫好」。

回饋迴路:品質守門員模式

這是 Supervisor 模式最強大的地方 — 可以設計回饋迴路(Feedback Loop)

Writer ──寫稿──▶ Editor ──評分──┬──▶ ✅ 通過 → Publisher
                                │
                          ❌ 不合格(score < 60)
                                │
                    帶回饋重寫(最多 2 次)
                                │
                                └──▶ Writer
function routeAfterEditor(state: PodcastState): string {
  // 通過 → 下一步
  if (state.editorFeedback?.passed) return 'publisher'

  // 沒通過但還有重試次數 → 帶回饋重寫
  const retries = state.retryCount?.['writer'] ?? 0
  if (retries < MAX_WRITER_RETRIES) return 'writerRetry'

  // 超過重試次數 → 帶警告繼續
  return 'publisher'
}

類比:Coding Agent 場景

同樣的模式可以套在程式碼審查上:

Coding Agent ──提交代碼──▶ Supervisor Agent ──檢查──┬──▶ ✅ 通過 → Merge
                                                     │
                                               ❌ 資安漏洞 / 不符規定
                                                     │
                                         帶回饋改程式碼(最多 N 次)
                                                     │
                                                     └──▶ Coding Agent

Supervisor 只需要評估「這段 code 有沒有問題」,Coding Agent 只需要「根據回饋修正」。兩邊職責清楚,不會互相干擾。

容錯與降級策略

在 Multi-Agent 系統裡,不是每個 Agent 都同樣重要。好的 Supervisor 要設計分級容錯

失敗情境

處理方式

嚴重度

Research 搜尋失敗

Writer 用 LLM 自身知識生成

⚠️ 降級

Editor 多次不合格

帶警告繼續發布

⚠️ 降級

CoverArt 生成失敗

文章照常發布(無封面)

💡 可接受

TTS 合成失敗

文章照常發布(無音檔)

💡 可接受

Publisher 寫入失敗

中止管線

🔴 硬性失敗

💡 設計原則:核心流程(Research → Write → Edit → Publish)失敗要降級處理,附加功能(Cover、TTS)失敗不應影響主線。

注意事項 / PS

實務踩坑

  • 共享狀態要用 reducer:如果多個 Agent 同時寫入 errors,不用 append reducer 會互相覆蓋。LangGraph 的 Annotation reducer 是救命的

  • 平行執行要注意獨立性:CoverArt 和 TTS 可以平行,是因為它們沒有資料依賴。如果有依賴就必須串行

  • 回饋迴路要設上限:沒有 MAX_RETRIES 的回饋迴路 = 無限迴圈。我設 2 次,超過就帶警告繼續

  • 不同 Agent 可以用不同模型:Research 用 Claude(搜尋能力強)、Writer/Editor 用 Gemini(便宜 + 長 context)、TTS 用專門的語音 API,混搭反而效果更好

效能參考

模式

耗時

說明

純文字(skip-tts + skip-cover)

~2 分鐘

Research → Writer → Editor → Publisher

含封面

~3 分鐘

加上 CoverArt 生成

完整管線

~4 分鐘

CoverArt + TTS 平行執行

什麼時候不該用 Supervisor

  • 如果任務本身就是開放性的(例如多 Agent 辯論、創意發想),Supervisor 反而會限制 Agent 的自主性

  • 如果只有 2 個 Agent 且流程是線性的,直接串接就好,不需要搬出 Supervisor 架構

結論

Multi-Agent 的核心不是「Agent 越多越好」,而是分工明確 + 流程可控

Supervisor 模式的三個設計原則:

  1. Supervisor 管流程,Worker 管執行 — 單一職責、各司其職

  2. 回饋迴路保品質 — Editor/Reviewer 當守門員,不合格就打回去

  3. 分級容錯 — 核心流程降級、附加功能 graceful fail

如果你也在規劃 Multi-Agent 系統,建議先想清楚「這個任務有沒有明確的前後順序」。有的話,Supervisor 模式是最穩的起點。

AI Agent 執行新聞搜尋、內容撰寫與品質審核流程AI文章生成系統的Pipeline流程圖介面

作者

Mark Ku

擁有 10+ 年經驗的資深軟體工程師,現為 AI 應用 Builder,專注於大型平台架構與簡化複雜系統設計,從電商系統到訂閱與收費平台,結合 AI Agent、AI 整合與自動化開發,打造高效率且可持續演進的產品技術基礎。閱讀更多

覺得這篇有幫助?

作者做的免費工具、每日 Podcast 與電子報,都在這裡。

Mark Ku · 本文採用 CC BY 4.0 授權,轉載請註明作者並附上原文連結。

留言

訂閱電子報

訂閱後即時收到新文章通知,不錯過任何技術分享。

提交即表示同意接收電子報,隨時可

熱門文章

View all
Mark Ku
··601

Oracle Cloud 永久免費方案 Linux 主機及固定 IP :0 元打造雲端解決方案

Oracle Cloud 永久免費方案 Linux 主機及固定 IP :0 元打造雲端解決方案
Mark Ku
··441

告別 Postman 收費陷阱!開源 Git 原生 API 測試神器 Bruno 實戰指南

告別 Postman 收費陷阱!開源 Git 原生 API 測試神器 Bruno 實戰指南
Mark Ku
··318

一款免費開源類似於 Notion 類知識庫系統 — Outline Wiki 佈署與備份全攻略

一款免費開源類似於 Notion 類知識庫系統 — Outline Wiki 佈署與備份全攻略
Mark Ku
··239

打造高效 API 管理平台:從 0 開始部署 Kong Gateway - Part 1

打造高效 API 管理平台:從 0 開始部署 Kong Gateway - Part 1
Mark Ku
··223

在 Ubuntu 上設置 Samba 來共享資料夾,讓 Windows 11 用戶可以存取

在 Ubuntu 上設置 Samba 來共享資料夾,讓 Windows 11 用戶可以存取
Mark Ku
··202

訓練自己的 AI 語音:硬體門檻、開源模型比較與 LoRA 微調

訓練自己的 AI 語音:硬體門檻、開源模型比較與 LoRA 微調