多 Agent 的分工與編排
一個 Agent 什麼都做,上下文會越塞越滿,指示也越來越雜。這堂課認識三種分工方式:單一 Agent、主管與助手、交接,動手寫一個平行分析客戶回饋的主管與助手程式,並學會判斷什麼時候其實一個 Agent 就夠了。
前兩堂我們把工具做成了 MCP Server,任何 App 都能接。接下來自然會想:工具越接越多、任務越來越大,一個 Agent 撐得住嗎?
還記得「上下文與記憶」那堂課嗎?Agent 每讀一個檔案,messages 就變長一點。如果你請一個 Agent 讀完三十份客戶回饋再寫週報,它讀到第二十份時,上下文已經塞滿前面的原文,又慢又貴,前面的細節也可能被淹沒。
這時候,可以像一個小團隊那樣分工。
先記住一句話:大多數時候一個就夠
在講怎麼拆之前,先說最重要的提醒。多 Agent 很吸引人,但它不是升級版,而是一種取捨:
- 更貴:每位助手都是一個獨立的 Agent,各自呼叫模型。整體用掉的 token 常常是單一 Agent 的好幾倍。
- 更難除錯:出錯時要先找出是哪一位、在哪一步出的錯。
- 資訊會掉:助手只交回摘要,主管看不到原文細節。
所以順序永遠是:先用一個 Agent 加上好的工具和說明試試看,真的碰到瓶頸再拆。
三種常見的分工方式
差別在於「主導權在誰手上」。
| 方式 | 怎麼運作 | 適合 |
|---|---|---|
| 單一 Agent | 一個 Agent 配幾個工具,自己跑完 | 大多數任務 |
| 主管與助手 | 主管拆任務、派給助手,助手各自完成後交回報告,主管整合 | 可以拆成互不相干、能平行做的子任務 |
| 交接 Handoff | 第一位 Agent 判斷需求後,把整段對話轉給專門的 Agent 接手 | 客服分流:一般問題、帳務、技術支援各有專員 |
主管與助手模式英文常叫 orchestrator-worker(編排者與工作者),是最常見、也最值得先學的一種。
主管與助手:為什麼有效
每位助手只讀自己那一份,主管只讀三份精簡報告。
關鍵在於上下文隔離:助手 A 讀門市回饋時,上下文裡只有門市回饋,不會被網路評論干擾;主管最後拿到的也不是三十份原文,而是三份整理好的重點。每個人的桌面都很乾淨。
其實你可能已經用過這個模式了:Claude Code 處理大任務時,會派出子代理(subagent) 去搜尋程式碼或研究某個問題,子代理做完只回報結論,主對話就不會被大量搜尋結果塞滿。
動手做:平行分析客戶回饋
我們先寫最簡單、也最穩的版本:由程式當主管。任務怎麼拆是你決定的(一個檔案派一位助手),模型負責分析和整合。
準備一個 feedback 資料夾,放幾個文字檔,例如 store.txt(門市回饋)、reviews.txt(網路評論)、emails.txt(客服信件),每個寫幾段假的回饋就好。
建立 team.py:
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from dotenv import load_dotenv
import anthropic
load_dotenv()
MODEL = "claude-sonnet-5-5" # 可以換成其他模型 ID
client = anthropic.Anthropic()
WORKER_SYSTEM = (
"你是客戶回饋分析員。只根據提供的內容回答,不要猜測內容沒寫的事。"
"請列出:主要問題(最多 3 點,附出現次數)、正面意見(最多 2 點)、"
"一句最有代表性的原文引用。用繁體中文,控制在 200 字內。"
)
LEAD_SYSTEM = (
"你是產品經理的助理。你會收到幾份來自不同管道的回饋分析,"
"請整合成一份週報:跨管道的共同問題(依嚴重程度排序)、"
"只出現在單一管道的特殊意見、建議下週優先處理的一件事與理由。用繁體中文。"
)
def ask(system: str, content: str) -> str:
response = client.messages.create(
model=MODEL,
max_tokens=16000,
system=system,
messages=[{"role": "user", "content": content}],
)
return "".join(b.text for b in response.content if b.type == "text")
def worker(path: Path) -> str:
"""一位助手:只讀一個檔案,交回精簡報告。"""
print(f"助手開始分析 {path.name}")
report = ask(WORKER_SYSTEM, path.read_text(encoding="utf-8"))
return f"## 來源:{path.name}\n{report}"
def main() -> None:
files = sorted(Path("feedback").glob("*.txt"))
if not files:
print("feedback 資料夾裡沒有 txt 檔")
return
# 1. 分派:每個檔案一位助手,同時進行
with ThreadPoolExecutor(max_workers=4) as pool:
reports = list(pool.map(worker, files))
# 2. 整合:主管只看精簡報告,不看原文
print("\n" + ask(LEAD_SYSTEM, "\n\n".join(reports)))
if __name__ == "__main__":
main()
執行:
python team.py
你會看到三位助手幾乎同時開始,最後印出一份整合好的週報。
逐段拆解
WORKER_SYSTEM 和 LEAD_SYSTEM:兩種角色各有一份專注的系統提示。助手只管「從一份資料裡挑重點」,主管只管「整合與判斷」。分開寫,各自都比一份什麼都要的大提示更清楚。
「控制在 200 字內」:這一句很重要。助手交回的報告越精簡,主管的上下文就越乾淨。
ThreadPoolExecutor:Python 內建的工具,讓好幾個函式同時執行。呼叫 API 大部分時間都在等網路回應,同時送出三個請求,總時間差不多就是最慢的那一個。max_workers=4 限制最多同時四個,避免一次送太多請求被限流。
主管沒有讀原文:這是優點也是代價。如果週報裡需要原文細節,就要在助手的指示裡要求它附上。
進一步:讓模型當主管
如果任務沒辦法事先決定怎麼拆,例如「研究一下我們該不該進軍日本市場」,就可以讓模型當主管。做法是把「派助手」也做成一個工具:
DELEGATE_TOOL = {
"name": "delegate",
"description": (
"把一個獨立、範圍明確的子任務交給一位助手處理。"
"助手看不到你和使用者的對話,所以 task 必須寫完整:"
"目標是什麼、可以看哪些檔案、要交回什麼格式、多長。"
"互不相干的子任務可以一次呼叫多個 delegate,它們會分別進行。"
"回傳助手的精簡報告。"
),
"input_schema": {
"type": "object",
"properties": {
"task": {"type": "string", "description": "完整的子任務說明"}
},
"required": ["task"],
"additionalProperties": False,
},
}
在主管的 run_tool 裡,delegate 被呼叫時,就用一份全新的 messages、助手專用的系統提示和工具,再跑一次你在 Agent 原理單元寫的 Agent 迴圈,最後把助手的回答當成 tool_result 交回給主管。
換句話說,助手就是一個工具,只是這個工具的內部又是一個 Agent。
注意說明書裡那句「助手看不到你的對話」。這是多 Agent 最常出錯的地方:主管寫「去查一下那個問題」,助手根本不知道「那個」是什麼。把交派任務想成寫工作說明給第一天上班的新同事,和寫工具說明書是同一種功夫。
交接:把對話整個轉出去
交接的情境比較像客服中心。使用者先跟「接待」聊,接待判斷這是帳務問題,就把對話轉給帳務專員,之後使用者直接跟專員對話,接待不再參與。
實作上常見的做法是:給接待一個 transfer_to_billing 之類的工具,當它被呼叫時,你的程式就換上帳務專員的系統提示和工具,帶著目前的對話繼續。重點是兩件事:
- 交接時要帶上必要的背景,例如使用者是誰、已經問過什麼,不要讓使用者重講一次。
- 每位專員只拿它需要的工具。帳務專員才有查帳單的工具,接待沒有。這也呼應第五堂要談的「最小權限」。
判斷該不該拆的小清單
在動手拆之前,問自己這四個問題:
- 單一 Agent 真的試過了嗎?問題是出在上下文太滿、指示太雜,還是只是工具說明沒寫好?
- 子任務彼此獨立嗎?如果 B 一定要等 A 的結果,平行也快不了多少。
- 多花幾倍的 token,換來的品質或速度值得嗎?
- 出錯時,你有辦法看出是哪一位出錯嗎?(下一堂的 Evals 和最後一堂的日誌會幫你。)
這是我的 team.py,用主管與助手模式平行分析 feedback 資料夾的客戶回饋。請幫我改成:助手除了文字報告,也回傳一個 JSON,包含 problems(問題清單,每項有 title 和 count),主管再根據所有 JSON 統計出前三大問題。請保留平行執行,並說明你改了哪些地方。
- 建立
feedback資料夾與三個回饋檔,執行team.py,讀讀看週報是否抓到跨管道的共同問題。 - 為了比較,寫一個「單一 Agent」版本:把三個檔案的內容全部貼在一起,用
LEAD_SYSTEM一次處理。比較兩份週報的品質,再用response.usage比較兩種做法各花了多少 token。 - 把
WORKER_SYSTEM裡「控制在 200 字內」拿掉,觀察主管收到的內容和最後週報有什麼變化。 - 想一個你工作中的任務,用上面的四個問題判斷:它適合單一 Agent、主管與助手,還是交接?寫下理由。
讀完了嗎?
標記完成後,單元與專案的進度會自動更新(只存在這台裝置的瀏覽器)。
留言與討論
卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。