在前幾天(CoT → RAG → Tool Use → Planning → ReAct → Reflection → Memory),我們讓單一 AI 擁有「思考、查資料、用工具、規劃、反思與記憶」等能力。
看起來已經很強大,但在現實世界的任務中,一個 AI 往往還是會捉襟見肘。
例如:要規劃一趟維也納旅行,不只要考慮 景點順序,還要顧及 交通時間、餐廳選擇、個人偏好(不吃牛肉、喜歡維也納豬排)與 結束時間限制。
如果全部交給單一 AI,容易顧此失彼。
這時候,就需要 Multi-Agent。
就像交響樂團一樣,樂手各司其職、彼此呼應,最後由指揮統籌整合 — 合奏的樂曲更精彩,正如音樂之都維也納所孕育的和諧篇章。
如果一個 AI 要同時處理「規劃景點、挑餐廳、估交通、顧好使用者偏好」,它的 Prompt 會越來越龐雜,容易出錯。
Multi-Agent Design Pattern 的精神,就是把任務拆分,讓 多個角色各司其職,再透過協作把結果整合。這樣更容易理解、維護,也更貼近人類團隊合作。
分工(Specialization)
每個 Agent 有明確的角色定位,例如:規劃師、交通顧問、美食顧問。
好處:Prompt 精準、輸出專一。
協作(Collaboration)
角色之間互相傳遞資訊、補足彼此盲點。
好處:任務更完整,不會因單一角色的限制而失效。
統籌(Orchestration)
最後需要一個「總召」來整合大家的意見,並檢查是否符合限制(像是必須在 18:00 前結束)。
好處:結果一致、能符合全局條件。
圖:Multi-Agent Design Pattern 的三層結構 —— ① 分工(Specialization):各角色各司其職;② 協作(Collaboration):角色之間資訊交換,互補盲點;③ 統籌(Orchestration):由 Coordinator 整合檢查,確保最終結果符合需求。
這張圖呈現了完整的三層次流程:
在今天的 Demo,我們採用 Supervisor 模式:Planner、Foodie、Transport 各自輸出,最後由 Coordinator 統籌整合。
這就是最簡單的 Multi-Agent Design Pattern:分工 → 協作 → 統籌。
這種設計模式不只適用在旅遊行程,未來你會看到它在 軟體開發、商業決策、研究助理 等場景同樣發揮威力,讓 AI 團隊真正成為我們的協作夥伴。
為了簡單掌握 Multi-Agent 的精神,我們做一個 Naive Demo:
由四個代理人分工合作完成「兩日行程規劃」。
圖:Multi-Agent 系統架構。Planner 負責行程規劃(分工)、Foodie 依據 Memory 選餐廳並回饋(協作)、Transport 呼叫工具取得交通時間(協作),最後 Coordinator 統籌整合並檢查超時(統籌)。完整展現了「分工 → 協作 → 統籌」的流程。
以下程式先用最簡單的方式幫助大家理解這四個代理如何協作:Planner 規劃景點、Foodie 挑餐廳、Transport 呼叫工具估算交通、Coordinator 統籌檢查是否超時。
之後的主題還會介紹好用的技術框架如(LangChain/LangGraph)可以實作。
pip install google-generativeai python-dateutil
import os, json, random
from datetime import datetime, timedelta
import google.generativeai as genai
import re, json
def safe_json_loads(text, fallback=None):
"""
嘗試解析 JSON,會自動移除 ```json ... ``` code fence。
如果失敗,就回傳 fallback。
"""
if not text:
return fallback
# 移除 Markdown code block 標記
clean = re.sub(r"^```json\s*|\s*```$", "", text.strip(), flags=re.IGNORECASE|re.MULTILINE)
try:
return json.loads(clean)
except:
return fallback
# ===== 0) 初始化 =====
os.environ["GEMINI_API_KEY"] = "YOUR_API_KEY"
genai.configure(api_key=os.environ["GEMINI_API_KEY"])
LLM = genai.GenerativeModel("gemini-2.5-flash")
# ===== 1) Memory (使用者偏好) =====
MEMORY = {
"diet": "不吃牛肉",
"pref": "維也納豬排"
}
# ===== 2) Tool Use 模擬 =====
def travel_time_tool(from_place, to_place):
"""
模擬呼叫外部 API 查交通時間。
這裡用隨機數 20–40 分鐘。
"""
return random.randint(20, 40)
# ===== 3) Agents 定義 =====
def planner_agent():
prompt = """
請規劃維也納 2 日行程,每天上午與下午各安排一個景點,輸出 JSON 格式。
範例:
{
"Day1": {"am": "美泉宮", "pm": "聖史蒂芬大教堂"},
"Day2": {"am": "奧地利國家圖書館", "pm": "維也納歌劇院"}
}
"""
resp = LLM.generate_content(prompt)
try:
return safe_json_loads(resp.text)
except:
return None
def foodie_agent(plan):
prompt = f"""根據以下行程,挑選午餐餐廳。
需符合條件:{MEMORY['diet']},並偏好 {MEMORY['pref']}。
輸出 JSON 格式,
範例:{{"Day1": "Figlmüller(維也納豬排)", "Day2": "Gasthaus Pöschl"}}
每天一間餐廳。行程: {plan}"""
resp = LLM.generate_content(prompt)
try:
return safe_json_loads(resp.text)
except:
return None
def transport_agent(plan, food):
"""
Transport Agent:呼叫 travel_time_tool 取得所有需要的時間,
再交給 LLM 整理成 {DayX: {am_to_lunch, lunch_to_pm}} 的格式。
"""
# Step 1: 先收集原始資料
raw_data = []
for day, schedule in plan.items():
am_to_lunch = travel_time_tool(schedule["am"], food[day])
lunch_to_pm = travel_time_tool(food[day], schedule["pm"])
raw_data.append({
"day": day,
"am": schedule["am"],
"lunch": food[day],
"pm": schedule["pm"],
"am_to_lunch": am_to_lunch,
"lunch_to_pm": lunch_to_pm
})
# Step 2: 請 LLM 整理成結構化 JSON
prompt = f"""
以下是交通估算的原始資料,請整理成 JSON 格式:
{raw_data}
格式範例:
{{
"Day1": {{"am_to_lunch": 25, "lunch_to_pm": 30}},
"Day2": {{"am_to_lunch": 22, "lunch_to_pm": 35}}
}}
"""
resp = LLM.generate_content(prompt)
return safe_json_loads(resp.text, {})
def coordinator_agent(plan, food, transit):
"""
Coordinator Agent:統籌行程,檢查是否超時 (09:00 ~ 18:00)
"""
day_start = datetime.strptime("09:00", "%H:%M")
end_limit = datetime.strptime("18:00", "%H:%M")
result = {}
for day, schedule in plan.items():
cur = day_start
steps = []
# 上午景點
steps.append(f"{cur.strftime('%H:%M')}–{(cur:=cur+timedelta(minutes=180)).strftime('%H:%M')} {schedule['am']}")
# 上午 → 午餐
cur += timedelta(minutes=transit[day]["am_to_lunch"])
steps.append(f"{cur.strftime('%H:%M')} 午餐:{food[day]} (90 分鐘)")
cur += timedelta(minutes=90)
# 午餐 → 下午
cur += timedelta(minutes=transit[day]["lunch_to_pm"])
steps.append(f"{cur.strftime('%H:%M')}–{(cur:=cur+timedelta(minutes=150)).strftime('%H:%M')} {schedule['pm']}")
feasible = "行程可行!" if cur <= end_limit else "行程超時!"
result[day] = {"timeline": steps, "status": feasible}
return result
# ===== 4) 執行 Demo =====
if __name__ == "__main__":
print("=== Multi-Agent + Tool Use Demo ===")
plan = planner_agent()
print("Planner:", plan)
food = foodie_agent(plan)
print("Foodie:", food)
transit = transport_agent(plan, food)
print("Transport (Tool Use):", transit)
final = coordinator_agent(plan, food, transit)
print("\n=== 最終統籌結果 ===")
for day, info in final.items():
print(f"\n{day}")
for s in info["timeline"]:
print(" ", s)
print(" ", info["status"])
圖:Multi-Agent + Tool Use Demo 的實際輸出結果。四個代理各司其職:Planner 負責規劃景點(分工)、Foodie 依據 Memory 選擇符合偏好的餐廳(協作)、Transport 呼叫工具取得交通時間(協作),最後 Coordinator 統籌檢查是否超時(統籌)。結果成功輸出可行的完整行程。
這個範例完整展示了這四個 Agent 的分工合作:
結果:
圖:Figlmüller 的維也納豬排(Wiener Schnitzel)。這塊金黃酥脆的豬排大到覆滿整個餐盤,第一眼就讓人驚艷。薄薄的麵衣、樸實的調味,卻意外耐吃,正是維也納經典美食之一;而 Figlmüller 也正是維也納豬排的招牌百年老店。(攝影:作者自攝)
今天的範例展示了從 單一 AI 到 多代理協作的演進:
而且這個 Demo 不只是 Multi-Agent,本身還用到了 Day 10 的記憶,讓美食顧問能避開「牛肉」並推薦「維也納豬排」。
這代表 AI 不只是「多角色」,還能「共享經驗」。
到這裡,我們已經讓 AI 進化成能夠 分工合作的隊伍。
正如維也納交響樂的精神:合奏更能交織出真正的和諧與力量。
圖:維也納卡爾教堂(Karlskirche):韋瓦第《四季》音樂會(Vivaldi The Four Seasons Concert)。巴洛克華麗的祭壇與穹頂壁畫下,在音樂之都維也納,樂手們分工演奏、彼此呼應,最後在指揮的統籌下交織出和諧樂章。這正是 Multi-Agent 的精神:各角色專精分工、互相協作,最終由統籌整合,讓結果比單打獨鬥更完整、更精彩。(攝影:作者自攝)