設計成本與速度優先的 Multi-Agent 系統
前言
你是否也對 Multi-Agent 的潛力感到興奮,卻在實際建構時面臨成本、延遲與複雜度的挑戰?近年來,大型語言模型(LLM)的發展讓企業或個人可以透過導入Agent來自動執行任務或是日常工作,但單一 Agent 往往難以完美勝任所有任務。本篇文章將分享我近期在 Agent 系統設計,特別是 Multi-Agent 系統開發過程中的實戰心得與設計原則。目標是帶領讀者,尤其是想入門或優化 LLM 應用開發 的工程師們,一步步理解如何打造出既智慧又高效的 Multi-Agent 系統。讓我們一起探索如何駕馭這些聰明的數位助理,讓它們為我們解決更複雜的問題!
為何選擇 Multi-Agent 架構?
就我而言,Agent 的核心價值 在於其能夠根據目標與環境動態規劃自身流程,並執行特定工作流程(Workflow)。簡單來說, Agent 能理解你的需求,並自主選擇合適的工具來完成任務。例如,一個旅遊規劃 Agent 能根據你想去的國家與預算,自動規劃行程、並依照行程來選擇適合的交通與住宿並回報結果。這裡的「動態規劃」是關鍵,它意味著 Agent 能根據即時情況或前一步驟的結果,靈活調整接下來的行動。
然而,Agent 的設計並非易事,需要在「智慧」、「成本」與「延遲」三者間取得平衡。一個功能強大的 Agent(如整合機票、住宿、翻譯的旅遊 Agent)可能非常聰明,但其運算成本和反應時間也相對較高。這讓我們思考:是否有更好的方式來組織這些 Agent 的能力?
Multi-Agent 架構的出現 正是為了解決這個難題。我認為 Multi-Agent 系統是在兼顧性能與智慧的前提下,透過巧妙的系統設計來降低成本與回應時間(延遲)的有效手段。其核心概念是讓多個專注於特定領域的 Agent 協同工作,共同完成一個更大的目標。相較於讓一個「萬能」的單一大型 Agent 處理所有事情(這可能導致它在眾多工具中選擇困難,或因多次思考與嘗試而增加成本與延遲),Multi-Agent 系統具備以下顯著優勢:
- 分工與模組化:每個 Agent 都有明確的職責和專長,使用者提出的複雜問題會被分解,並指派給最適合的 Agent 或預設的工作流程。這在一定程度上犧牲了單一 Agent 的極致彈性,但換來了時間與成本的優化。同時,針對每個 Agent 的專業領域,我們可以建立更精細、更高效的 Workflow。
- 降低系統複雜度:透過分離不同 Agent 的功能,可以有效降低程式碼的耦合度,使得系統更易於維護和擴展。
- 平行處理能力:Multi-Agent 系統允許不同的 Agent 或 Workflow 同時處理任務的不同部分,這對於縮短複雜任務的整體回應時間至關重要。
6 個 Multi-Agent 系統的設計原則與實踐
在深入探討 Multi-Agent 系統的建構細節之前,我想先分享幾個我在開發過程中總結出的核心設計原則。這些原則不僅幫助我理清了思路,也讓系統的開發過程更加順暢。
原則 0:從簡單開始,逐步迭代
面對 LLM 應用的開發,無論是 Agent、Multi-Agent 還是 RAG(檢索增強生成),我們很容易被眾多的新技術和術語淹沒。因此,我建議從最直觀、最簡單的方式上手:
- 選擇強大的模型:在專案初期,可以先選用能力較強的 LLM 模型(例如 Grok3、Claude3.7、GPT4.1),暫時不必過度擔心成本問題,目標是快速驗證與建立核心功能。
- 建立效能基準 (Baseline):記錄完成一個基本任務所需的時間和 Token 使用量,這個基準將是你後續優化的重要參考。
- 迭代優化:當系統擁有雛形且能夠穩定運作,再開始考慮調整系統架構、更換更經濟的模型、或是優化提示詞(Prompt),以提升整體效能。
- 最終完善:當回答品質和執行速度都達到預期標準後,再投入資源進行使用者介面 (UI/UX) 設計、加入安全機制,並進行全面的系統測試。

為何強調從簡單開始? 因為這能讓開發者快速推出功能與驗證,並在核心功能的基礎上逐步構建出一個穩健且有效的系統。
原則 1:擁抱 Workflow,而非盲目追求 REACT
許多人初識 Agent 時,會被 REACT 模式(Reasoning and Acting,即反覆進行思考 -> 行動 -> 觀察/評估的循環)所吸引,認為這是實現 Agent 最大彈性的方式。然而,在實際生產應用中,過度依賴 REACT 可能導致高昂的 API 成本、過長的執行時間,甚至產生不可預測的 Agent 行為。想像一個資料查詢 Agent,如果沒有固定的處理流程,它可能會因為多次不必要的 API 呼叫或無效的思考循環而遲遲無法給出答案,嚴重影響使用者體驗。
我的建議是:
為你的 Agent 系統設計明確且固定的工作流程 (Workflow)。
我們可以有專門負責任務規劃與分解的 Agent(例如 Task Planner)來讓你整個系統擁有較高的彈性,負責指揮Workers(專精於不同任務的Agent或是Workflow)來完成任務最後在整合執行結果或是整理成一個完整的報告。
- 固定 Workflow 的優勢:
- 穩定快速:明確的流程能顯著降低執行時間和 API 呼叫成本。例如,餐廳查詢 Agent 可以事先定義「解析使用者意圖(想吃的食物種類、預算、指定地點等) -> 查詢指定API或是資料庫 -> 生成回應內容」的標準流程。
- 易於測試與除錯:清晰的執行路徑使得測試和除錯更加容易。
- 風險可控:避免讓自由度過高的 Agent 意外執行刪除資料庫或是付款等高風險操作。
總結來說,在 Multi-Agent 系統中,透過固定 Workflow 來平衡彈性與穩定性,往往是更務實且可靠的選擇。
原則 2:最小化 LLM 的使用
這個原則很簡單,不要把所有的處理邏輯都丟給 LLM !!!
只讓 LLM 處理無法依靠程式邏輯處理的任務、或是處理起來非常複雜的問題,例如自然語言理解、命名實體辨識、複雜推理或特定風格的文字生成。
命名實體辨識:從文字中找出特定的值,例如從路況查詢中分析地點
以一個 SQL 資料庫查詢 Agent 為例,比較直覺但可能不是最佳的做法是:
- 賦予 LLM 直接存取和執行 SQL 指令的能力。
- 撰寫非常複雜的 System Prompt,並附上許多 Few-shot 範例,指導 LLM 如何根據使用者問題生成 SQL。
- 讓 LLM 整理查詢結果並輸出最終回答。
這樣的設計雖然可行,但通常伴隨著幾個問題:
- 成本過高:需要能力較強的 LLM 才能準確生成複雜 SQL,這意味著更高的 API 費用和更長的執行時間。同時,系統提示內提供的資料庫 Schema 或範例可能會佔用 LLM 的 Context Window。
- 安全風險:賦予 LLM 直接執行 SQL 的能力存在潛在風險,它可能產生非預期的指令,例如意外修改或刪除資料。
一個更優雅且高效的方式是:
只讓 LLM 參與問題解析、必要的錯誤處理與最終回答的生成。
由於 SQL 的查詢語法本身是固定的,大部分情況下我們需要的只是動態修改查詢條件(即 WHERE
子句)。因此,完全可以:
- 預先定義好 SQL 查詢模板。
- 使用 LLM 分析使用者的自然語言問題,提取出關鍵的查詢條件(例如,時間、地點、特定指標)。
- 使用傳統的程式邏輯(例如 Python 字串格式化或查詢構建庫)將 LLM 解析出的條件填充到 SQL 模板中。
- 執行這個由程式邏輯構建的 SQL 查詢。
- 最後,將查詢到的結構化資料和原始使用者問題一起傳遞給 LLM,讓它生成一個自然、易懂的回答。
--- config: look: handDrawn layout: dagre --- flowchart TD subgraph subGraph0["不好的 Workflow"] A1["使用者輸入問題"] B1["LLM 思考並生成 SQL 查詢"] C1["LLM 執行 SQL 查詢"] D1["LLM 整理查詢結果"] E1["輸出最終回答"] F1["LLM 進行錯誤處理"] end subgraph subGraph1["推薦的 Workflow"] A2["使用者輸入問題"] B2["LLM NER SQL 查詢條件"] C2["程式邏輯填充預定義 SQL 模板"] D2["執行 SQL 查詢"] E2["LLM 整理查詢結果"] F2["輸出最終回答"] G2["LLM 進行錯誤處理"] end A1 --> B1 B1 --> C1 C1 --> D1 & F1 D1 --> E1 F1 -- 最大重試次數
避免無限迴圈 --> C1 A2 --> B2 B2 --> C2 C2 --> D2 D2 --> G2 & E2 G2 -- 最大重試次數
避免無限迴圈 --> D2 E2 --> F2 F1 -- 超過最大重試次數
請使用者釐清 --> A1 G2 -- 超過最大重試次數
請使用者釐清 --> A2 style B1 fill:#FFCDD2 style C1 fill:#FFE0B2 style F1 fill:#FFCDD2 style B2 fill:#FFE0B2 style G2 fill:#FFCDD2 style subGraph0 fill:#C8E6C9 style subGraph1 fill:#BBDEFB
圖中有用不同顏色來區別,橘色跟紅色區塊會是整個系統中有LLM參與的流程,同時也會是系統的時間瓶頸,而我們應該盡量減少LLM參與,來減少每次任務的成本(時間與金錢)和潛在風險。
原則 3:善用平行處理
平行處理是 Multi-Agent 系統的核心優勢之一,能夠顯著提升複雜任務的執行效率。當一個任務可以被分解為多個可以同時執行的子任務時,讓不同的 Agent 平行處理它們,可以大幅縮短使用者的等待時間。然而,在設計平行處理機制時,必須特別注意資料併發問題,例如多個 Agent 同時嘗試寫入同一個資料庫記錄,可能導致資料衝突或不一致。
在架構選擇上,許多開發者初期可能會嘗試所謂的 Supervisor 架構。即由一個中心化的 Supervisor Agent 負責接收所有任務,然後將任務分配給不同的 Workers 執行,並回收結果產生回答。這種架構的挑戰在於:
- 實作複雜度高:尤其在使用像 LangGraph 這樣的框架時,Supervisor 的任務分配、結果收集與流程控制邏輯可能變得非常複雜,難以實現且不易除錯。追蹤整個執行流程也會變得困難。
- 擴展性較差:每當新增或修改一個 Worker 的功能時,往往需要回頭修改 Supervisor Agent 的核心邏輯,增加了系統的維護成本。
- 潛在的效能瓶頸與高成本:Supervisor Agent 通常需要具備較強的推理能力來理解和分配任務,這可能意味著需要使用更強大(也更昂貴)的 LLM 模型,而且它本身也可能成為系統效能的瓶頸。
相較之下,我更推薦參考 Anthropic 在其《Build Effective Agents》中提到的 Orchestrator-Workers 架構(或類似的思路)。其核心思想是:
- 結構更簡單清晰:由一個 Orchestrator(協調器)負責初步的任務分解與整體流程的協調。而各個 Worker Agent 則專注於獨立執行分配給它們的、通常是固定的子任務或 Workflow。這種模式能自然地減少多個 Agent 同時寫入共享資源的衝突。
- 易於除錯與追蹤:由於每個 Worker Agent 的職責和執行路徑相對固定和獨立,因此更容易進行單元測試和問題追蹤。
- 高效擴展與維護:新增一個 Worker Agent 通常不需要大幅修改 Orchestrator 的核心邏輯,使得系統更容易適應新的需求和功能擴展。
在我的系統設計中,「Task Planner」就扮演了 Orchestrator 的角色,它負責理解使用者問題並將其分解、指派給不同的 Sub-Agents(Workers)。
原則 4:減少系統耦合度
降低耦合度是軟體工程中的一個經典原則,在 Multi-Agent 系統中同樣重要。它不僅能提高系統的可維護性和可擴展性,也是實現高效平行處理(原則 3)的基礎。我主要從「資料」和「功能」兩個層面來進行解耦。
資料層面的解耦:State 的分層管理
在像 LangGraph 這樣的框架中,我們通常使用一個共享的「State」物件來管理 Agent 執行過程中的各種資料。為了減少不同 Agent 或模組間不必要的資料依賴,我建議對 State 進行分層管理:
- Global State :
- 用於管理整個系統或一次完整對話生命週期中需要共享的資料。
- 例如:完整的對話歷史紀錄、Task Planner 分派給各 Sub-Agent 的任務列表、所有 Sub-Agent 執行完成後回傳的結果集合。
- 如果系統需要支援多輪修正或複雜的錯誤重試機制,Global State 可能還需要儲存重試次數、歷史錯誤訊息等,以便進行更精細的流程控制和錯誤追蹤。
- Local State :
- 用於管理單一 Sub-Agent 在其獨立執行 Workflow 過程中所需的資料,這些資料通常不被其他 Agent 直接存取。
- 例如:
- Traffic Agent (交通查詢 Agent) 的 Local State 可能包含使用者指定的路況查詢條件(如特定路段、時間範圍)、API 返回的原始路況資料等。
- Weather Agent (天氣查詢 Agent) 的 Local State 可能包含目標城市、查詢日期等參數。
- 每個 Sub-Agent 獨立維護和更新其 Local State,這樣可以最大限度地減少因共享資料而引發的潛在衝突和不必要的資料依賴。

功能層面的解耦:明確職責分離
除了資料的分離,功能上的拆分也同樣關鍵。核心原則是讓每個 Agent 或系統模組都專注於單一、明確的職責,避免出現一個 Agent 承擔過多不相關功能的情況。
- 職責分離 (Separation of Concerns):
- 將一個複雜的任務鏈拆解,分配給不同的 Agent 負責。例如,在一個旅遊規劃的場景中,查詢航班資訊、預訂飯店、翻譯當地資訊,這些都應該由各自專門的 Agent 來處理,而不是試圖讓一個 Agent 包辦所有事情。
- 在我設計的系統中,有一個專門的
Respond Agent
,它的唯一職責就是整合來自各個 Sub-Agent 的執行結果以及原始使用者問題,然後輸出最終的自然語言回答。它本身不參與任何資料的查詢或複雜的業務邏輯處理,確保了職責分離。
- 模組化設計 (Modular Design):
- 每個 Agent 的核心功能應該被封裝為一個獨立的模組。這些模組之間透過定義良好且穩定的介面(例如,接受固定格式的字典作為輸入,輸出也是固定格式的字典)來傳遞資料和協同工作。
- 例如,Traffic Agent 只負責輸出結構化的路況資料,具體如何將這些資料呈現給使用者,則交由 Respond Agen 來處理。
透過在資料和功能層面進行解耦,我們可以建構出一個更加靈活、更易於維護和擴展的 Multi-Agent 系統。
原則 5:重視資料前處理
Garbage in, garbage out. 這個觀念在 LLM 應用中依然適用。即使你使用了再強大的 LLM,如果輸入給它的資料品質不佳、充滿雜訊或格式混亂,其輸出的品質和效率也很難得到保障。因此,原則 5 強調在將資料餵給 LLM 之前進行資料前處理。
提升回答時間與品質的關鍵
直接將從 API 獲取的大量未經處理的 JSON 資料,或是從網頁抓取的原始 HTML 文本直接拋給 LLM,雖然看起來賦予了 LLM 最大的彈性,但在實務中,這往往會導致回應時間拉長、回答品質不穩定,甚至消耗大量的 Token。例如,在一個交通查詢系統中,如果直接將包含各種無關資訊和複雜巢狀結構的原始路況 API 回應丟給 LLM 解析,它可能需要很長時間才能提取出有效資訊,而且結果的準確性也難以保證。
一個更好的方式是引入資料前處理的環節:
- 資料工程Pipeline:透過必要的資料清理、過濾、轉換和結構化,將原始的、混亂的資料轉換為乾淨、格式統一、易於 LLM 理解的格式。例如,在路況查詢中,這可能包括移除無效或過期的路況記錄、統一時間和地理位置的表示格式、提取核心指標(如預計行程時間、壅塞路段)。
- 善用資料庫:將經過預處理的結構化資料存儲到資料庫中(例如,我專案中使用的 Supabase,一個高度整合的 PostgreSQL 服務)。這樣,Agent 就可以直接查詢這些已經被清理和組織好的資料,大大減輕 LLM 在即時處理資料時的負擔。
例如有個電子商務訂單查詢系統,其可能運作的方式為:
- 資料預處理與儲存
利用Data Pipeline 批次處理原始訂單資料,並將其結構化後存入公司內部資料庫。這確保資料格式一致,便於後續查詢。 - 結構化 SQL 查詢
Order Agent 透過事先定義的靜態 SQL 查詢模板,直接從資料庫中提取資料。查詢條件(如訂單編號或日期範圍)可由 LLM 詢問使用者來輔助生成,但查詢邏輯本身是固定的,無需 LLM 從0到1生成完整 SQL 語句。 - 查詢結果與回答生成
系統能夠快速查詢特定訂單編號在指定日期範圍內的狀態資料(例如「訂單 ORD123 在 2025-05-01 至 2025-05-07 的狀態」),並輸出給使用者。
簡化 Prompt 與系統架構
乾淨、結構化的輸入資料能夠顯著簡化你的 Prompt 設計和整體系統架構。 如果輸入資料本身就已經非常清晰,你就不需要在 Prompt 中編寫大量複雜的指令來引導 LLM 如何解析和處理這些資料。系統的設計也可以因此變得更輕量化。
發揮未來潛力
當你擁有一個預處理過的、結構化的資料庫後,還可以進一步結合更進階的技術來提升系統的表現,例如:
- RAG (Retrieval Augmented Generation):從你的結構化資料庫中精準檢索最相關的上下文資訊,供 LLM 在生成回答時參考,進一步提升回答的準確性和深度。
- 全文搜尋或向量檢索:針對特定的資訊查詢需求,可以利用資料庫的全文搜尋功能或結合向量資料庫進行快速的資訊定位,從而減少 LLM 需要處理的上下文總量,降低成本並加快速度。
原則 6:讓 LLM 協助你優化 Prompt
Prompt 是與 LLM 溝通的橋樑,其品質直接影響 LLM 的表現。然而,撰寫一個既簡潔又高效的 Prompt 並非易事,往往需要反覆試驗和調整。一個非常實用的技巧是:讓 LLM 參與到 Prompt 的優化過程中,因為它最了解自己是如何理解和處理指令的。
以下是一些我常用的 Prompt 優化方法:
- 參考別人怎麼寫Prompt: 通常LLM巨頭都會指導如何寫一個好的Prompt
- 確認 LLM 的理解程度:在你給出一個初步的 Prompt 後,可以反問 LLM:「你是否完全明白我的指令?如果有哪些地方不清楚或可能產生歧義,請直接指出來。」這有助於你發現 Prompt 中潛在的問題。
- 請求 LLM 協助改進:直接要求 LLM 幫你優化 Prompt。例如:「這是我目前版本的 Prompt:『[你的 Prompt 內容]』。請你以一個大型語言模型的角度,幫我分析這個 Prompt 有哪些可以改進的地方,讓指令更清晰、更易於你理解,並且能夠引導你產生更符合我預期的輸出。請你提供一個改進後的版本。」
- 生成 Few-shot 範例:如果你的任務需要 LLM 遵循特定的輸出格式或風格,可以請 LLM 根據任務需求生成一些 Few-shot QA 範例。例如:「我正在設計一個用於交通路況查詢的 Agent。請你為我生成 3 組高品質的問答範例(包含使用者問題和理想的 Agent 回答),這些範例將用於我的 Prompt 中作為引導。」
- 迭代測試與評估:使用自動化的評測工具(例如 LangSmith、DeepEval,或者更簡單的腳本)來客觀地測試不同版本 Prompt 的效果。比較它們在回答準確率、一致性、Token 消耗等方面的表現,並根據評估結果持續迭代優化。
採用對 LLM 友善的格式:在撰寫較為複雜的 Prompt 時,盡量使用結構化的格式,如 Markdown 或 JSON ( OpenAI表示 XML >> JSON )。這有助於 LLM 更好地解析 Prompt 的不同部分和層次。例如讓LLM來幫你生成每周的工作日誌
# 角色與目標
你是一個專業的日誌記錄助手,負責根據使用者提供的任務描述生成結構化的工作日誌。你的目標是記錄任務的進度、執行步驟、工具調用結果、以及任何相關的反思或錯誤處理,確保日誌清晰、詳盡且易於閱讀。
# 指令
- 始終以專業且簡潔的語氣生成工作日誌。
- 根據用戶提供的任務描述,分析任務需求並生成日誌,記錄以下內容:
- 任務概述
- 執行步驟(包括任何工具調用)
- 結果與反思
- 錯誤處理(若有)
- 如果需要調用工具來獲取資訊(如查詢資料庫或執行程式碼),在日誌中明確記錄工具調用前後的步驟,並在最終輸出中包含工具調用的結果。
- 如果任務描述不夠明確,記錄一個請求澄清的步驟,並說明需要哪些額外資訊。
- 遵循以下「分步推理策略」生成日誌。
- 使用 Markdown 格式輸出日誌,包含標題、列表和代碼塊(若涉及工具調用或程式碼)。
- 避免討論禁止話題(政治、宗教、爭議性事件、醫療、法律或財務建議)。
# 分步推理策略
1. **任務分析**:
- 仔細分析用戶提供的任務描述,識別核心需求和任何潛在的模糊點。
- 如果任務描述不完整,記錄一個請求澄清的步驟,並說明需要哪些資訊。
2. **計劃制定**:
- 列出完成任務所需的具體步驟,包括任何必要的工具調用。
- 確保步驟簡單且可驗證。
3. **執行與工具調用**:
- 執行計劃中的每個步驟,並記錄執行過程。
- 如果需要調用工具,在日誌中明確說明調用目的,並在調用後記錄結果。
- 如果工具調用失敗,記錄錯誤並嘗試最多 3 次重試;若仍失敗,記錄請求用戶澄清的步驟。
4. **反思與驗證**:
- 檢查任務是否已解決,確保所有要求均已滿足。
- 記錄任何邊界情況或潛在改進。
- 如果任務未完全解決,說明後續行動或需要的額外資訊。
5. **日誌輸出**:
- 將所有步驟、工具調用結果和反思整理成結構化的 Markdown 格式日誌。
# 輸出格式
```markdown
# 工作日誌:{任務標題}
## 任務概述
- **描述**:{簡述用戶提供的任務描述}
- **目標**:{明確任務的預期結果}
## 執行步驟
1. {步驟 1 描述}
- {詳細說明,包括工具調用或具體行動}
2. {步驟 2 描述}
- {詳細說明,包括工具調用或具體行動}
...
## 工具調用結果
- **工具名稱**:{工具名稱}
- **輸入**:{工具調用的輸入參數}
- **輸出**:{工具返回的結果}
- **反思**:{對結果的分析或後續行動}
## 錯誤處理
- {記錄任何錯誤、嘗試的重試次數、以及最終解決方式或澄清請求}
## 最終反思
- **任務狀態**:{已解決/部分解決/需要澄清}
- **邊界情況**:{任何潛在問題或未涵蓋的場景}
- **後續行動**:{下一步計劃或建議}
## 是否需要進一步協助?
- {詢問用戶是否需要處理其他任務}
讓 LLM 成為你 Prompt 優化過程中的夥伴,往往能事半功倍。
簡單範例
為了更直觀地理解我所提倡的設 Multi-Agent 系統,以下展示一個簡單的旅遊規劃Agent流程。
--- config: look: handDrawn layout: dagre --- flowchart TD A["使用者輸入旅遊需求"] --> B{"Task Planner
任務規劃"} B --> Check{"需求檢測與驗證"} Check -- 符合旅遊助理設計
需求明確 --> Valid["分派任務"] Check -- 不符合設計
惡意指令/需求不清/常識問題 --> Invalid["直接回應 Or
生成拒絕或請使用者澄清問題"] Valid --> C["WeatherAgent
天氣查詢"] & D["AttractionAgent
景點推薦"] & E["AccommodationAgent
住宿建議"] & F["TransportAgent
交通規劃"] C --> G{"Respond Agent
結果整合"} D --> G E --> G F --> G G --> H["生成個人化旅遊建議"] H --> I["回覆使用者"] Invalid --> I style A fill:#E3F2FD style B fill:#FFF3E0 style Check fill:#FFE0B2 style Valid fill:#C8E6C9 style Invalid fill:#FFCDD2 style C fill:#E8F5E8 style D fill:#E8F5E8 style E fill:#E8F5E8 style F fill:#E8F5E8 style G fill:#FFF3E0 style H fill:#F3E5F5 style I fill:#E3F2FD
使用者輸入「我想要三天兩夜的台南旅遊,喜歡古蹟和美食,預算中等」,系統會:
- Task Planner檢查使用者查詢是否符合系統設計
- 使用者問題符合設計需求,繼續思考並分配任務
- WeatherAgent 查詢台南三日天氣
- AttractionAgent 推薦古蹟景點和美食餐廳
- AccommodationAgent 建議中等價位住宿
- TransportAgent 規劃交通路線
- 最後整合成完整的旅遊建議
- 因為問題模糊/不符合需求/惡意查詢/可以直接回答的問題,則不繼續進行任務,並輸出對應回答給使用者
--- config: look: handDrawn layout: dagre --- flowchart TD Start[解析使用者偏好
地點、類型、預算] --> Parse{提取關鍵條件} Parse --> Query[查詢景點資料庫
評價、位置、類型] Query --> Filter[篩選與排序
依據評分和熱門度] Filter --> Success{查詢成功?} Success -->|是| Generate[生成個人化推薦
包含景點介紹與建議] Success -->|否| Error[錯誤處理] Error --> Retry{可重試?} Retry -->|是| Query Retry -->|否| Fallback[提供預設推薦] Generate --> End[輸出景點推薦清單] Fallback --> End style Start fill:#E3F2FD style Parse fill:#FFF3E0 style Query fill:#E8F5E8 style Filter fill:#E8F5E8 style Success fill:#FFF3E0 style Generate fill:#F3E5F5 style Error fill:#FFEBEE style End fill:#E3F2FD
Attraction Agent 首先解析使用者的偏好(如「喜歡古蹟和美食」),提取關鍵條件後查詢預先整理好的景點資料庫或是API,根據評價和熱門度進行篩選排序。如果查詢成功,則生成個人化的景點推薦;如果失敗,會進入錯誤處理流程,可能重試或提供預設推薦。
提問
在分享了這些設計原則和實例後,我想整理一些常見的疑問,並加入我個人的一些反思。
問題:您設計的 Multi-Agent 系統看起來更像是多個 Workflow 的整合,與傳統 REACT(Reason-Act)Agent 的自主思考、執行、觀察模式不同,是否會缺乏彈性?
回答:確實,我強調的 Workflow 設計與 LLM 最小化使用看似限制了 Agent 的「自由度」。傳統 REACT 框架允許 Agent 透過內部循環(思考 → 行動 → 觀察)動態調整下一步行動,這在處理高度不確定或複雜、需要探索性解決方案的任務(如即興旅遊行程規劃)時,展現了其「動態規劃」的潛力。
然而,在旅遊規劃等實務應用場景中,過高的自由度可能帶來以下挑戰:
- 高成本:LLM 的每次「思考」或「推理」均需 API 調用,多次循環導致成本快速累積。
- 長延遲:多次 LLM 調用和工具使用會顯著增加回應時間,例如從 5-10 秒延長至更久。
- 難以預測的行為:Agent 的執行路徑多樣化,增加了測試、除錯的難度,並可能導致非預期或不一致的旅遊建議,影響使用者體驗。
因此,我的設計哲學是在「有界限的彈性」中尋求平衡。系統整體架構(如 Task Planner 負責解析使用者需求並分派任務給 Sub-Agent)保留了任務處理的動態性和適應性。在 Sub-Agent 層面,特別是對成本和延遲敏感的任務(如交通規劃或景點推薦),採用相對固定的 Workflow,優先考慮穩定性、可測試性和成本效益。
這並不意味著完全放棄彈性。我們可以為特定情境設計「有限的」動態調整能力,例如:
- TransportAgent 的重試機制:若查詢交通資料(如某航線票價)失敗,TransportAgent 可根據錯誤類型(例如 API 超時)自動重試最多 3 次,或嘗試備用資料來源(如另一航空公司 API)。
- Task Planner 的任務重新分派:若某 Sub-Agent(如 AttractionAgent)無法完成任務(例如某景點無資料),Task Planner 可將任務重新分派給其他 Agent(如推薦附近替代景點)或調整查詢參數後重試。
這種設計在充分理解使用者需求(例如快速生成旅遊行程)、資源限制(API 預算、回應時間)和可接受風險後,在理論理想化與工程實用性間取得平衡。系統在大多數常規旅遊查詢場景下高效穩定運作,同時保留應對複雜需求(如多城市行程或特殊偏好)的潛力。
Q2:在設計 Multi-Agent 系統時,如何有效地進行除錯 (Debug)?
A: Multi-Agent 系統的除錯確實比單體應用複雜,因為你可能需要同時追蹤多個 Agent 的狀態和它們之間的訊息交換。以下是一些有用的策略:
- 日誌 (Logging):為每個 Agent 和關鍵的流程節點添加詳細的日誌記錄,包括輸入、輸出、重要狀態變化、錯誤訊息等。結構化的日誌(例如 JSON 格式)更容易被後續的分析工具處理。
- 可視化工具:LangGraph 、PydanticAI提供了可視化追蹤工具,可以清晰地看到每個節點的執行情況和數據流動。這對於理解複雜的 Agent 互動非常有幫助。
- 單元測試與整合測試:為每個獨立的 Sub-Agent 編寫單元測試,確保其在給定輸入下能產生預期輸出。同時,也需要編寫整合測試來驗證多個 Agent協同工作的正確性。
- State 的快照與回溯:在關鍵決策點或容易出錯的地方,可以考慮保存當時的 Global State 或 Local State 快照。一旦出現問題,可以利用這些快照來重現錯誤場景,方便分析。
- Mocking 外部依賴:在測試時,將外部依賴(如 LLM API、資料庫、第三方服務 API)Mock 掉,這樣可以專注於測試 Agent 本身的邏輯,並使測試更快速、更穩定、成本更低。
結語
開發 LLM應用是一個不斷學習和探索的過程。技術(尤其是 LLM 相關技術)發展非常迅速,框架、工具、模型每半年就會重新大洗牌。保持開放的心態,持續關注社群的最新進展,並願意根據實際情況調整自己的設計理念和技術選型十分重要。同時,也要記住,沒有一體適用的完美架構,最好的設計總是那個能夠在具體需求、資源限制和期望目標之間取得最佳平衡的方案。
希望透過這次的分享,各位對 Multi-Agent 系統的設計原則有了更深入的理解。從確立清晰的 Workflow、最小化 LLM 的依賴,到重視資料處理和不斷優化 Prompt,每一個環節都是打造高效能 Agent 的關鍵。實際動手建構一個簡單的 Multi-Agent 系統,例如一個整合了天氣查詢和今日新聞摘要的個人助理,會是體驗這些原則的最好方式。
你對 Multi-Agent 系統有什麼獨特的見解或實戰經驗嗎?或者在你的應用場景中,有哪些問題特別適合用 Multi-Agent 來解決?歡迎在下方留言分享你的想法。