05. Multi-agent / Subgraph¶
ゴール¶
- 単一エージェントの限界を理解する
- 専門家エージェントを組み合わせるパターンを2つ覚える: Supervisor と Handoff (Swarm)
- Subgraph で再利用可能な単位を作る
なぜ Multi-agent か¶
- システムプロンプトが肥大化して LLM が指示を取りこぼす
- ツールが20個を超えると LLM が選択ミスを起こす(Anthropic の調査 で言及)
- ドメインごとに責務を分けた方が評価とデバッグが楽
パターン1: Supervisor(中央集権型)¶
「上司エージェント」が下位エージェントを呼び分ける。
from langgraph.graph import StateGraph, START, END
def supervisor_node(state):
"""次にどの専門家を呼ぶか、または END するか決める"""
resp = supervisor_llm.invoke(state["messages"] + [
("system", "次の担当を選んで: researcher / coder / writer / FINISH")
])
return {"next": resp.content.strip()}
def researcher_node(state):
return {"messages": [researcher_llm.invoke(state["messages"])]}
# ...同様に coder_node, writer_node
def route(state):
return state["next"] if state["next"] != "FINISH" else END
builder = StateGraph(State)
builder.add_node("supervisor", supervisor_node)
builder.add_node("researcher", researcher_node)
builder.add_node("coder", coder_node)
builder.add_node("writer", writer_node)
builder.add_edge(START, "supervisor")
builder.add_conditional_edges("supervisor", route)
for name in ["researcher", "coder", "writer"]:
builder.add_edge(name, "supervisor")
graph = builder.compile()
強み: 制御が明示的、ロギングが楽 弱み: supervisor がボトルネック、毎ターン LLM 呼び出しが増える
パターン2: Handoff / Swarm(分散型)¶
各エージェントが 自分で次の担当を指名する。
from langgraph.types import Command
def researcher_node(state) -> Command:
resp = researcher_llm.invoke(state["messages"])
if "needs_code" in resp.content:
return Command(goto="coder", update={"messages": [resp]})
return Command(goto=END, update={"messages": [resp]})
公式の langgraph-swarm ライブラリがこのパターン。
強み: 各 agent の自律性が高い、軽量 弱み: 制御フローが追いづらい、無限ループのリスク
パターン3: Subgraph(再利用可能な単位)¶
複雑なグラフを「グラフの中にグラフ」として埋め込む。
# 専門家サブグラフ
research_builder = StateGraph(ResearchState)
research_builder.add_node("search", search_node)
research_builder.add_node("summarize", summarize_node)
research_builder.add_edge(START, "search")
research_builder.add_edge("search", "summarize")
research_builder.add_edge("summarize", END)
research_graph = research_builder.compile()
# 親グラフに subgraph として組み込む
parent = StateGraph(MainState)
parent.add_node("research", research_graph) # サブグラフをノード扱い
parent.add_node("write", write_node)
parent.add_edge(START, "research")
parent.add_edge("research", "write")
State の型が違う場合は変換関数で繋ぐ:
def research_subgraph_node(state: MainState) -> dict:
sub_input = {"query": state["topic"]}
result = research_graph.invoke(sub_input)
return {"research_result": result["summary"]}
設計判断: いつ multi-agent にするか¶
| 状況 | 推奨 |
|---|---|
| ツールが5個以下、ドメインが1つ | single agent で十分 |
| ツールが20個超 | 役割で分割(research / write / review) |
| 並列処理したい(複数ソース調査) | supervisor で fan-out / fan-in |
| エージェントごとに違うモデルを使いたい | multi-agent(Sonnet で計画、Haiku で実行など) |
| 評価・改善を独立にやりたい | subgraph で切り出す |
注意: 「multi-agent にすると賢くなる」は半分嘘。通信のオーバーヘッドで逆に劣化することも多い。 Anthropic の "Building effective agents" は「まずは単一 agent で十分か検討せよ」と言っている。
Try¶
- 「Web 調査 → 要約 → ブログ記事化」の3段 supervisor を組む
- 同じものを subgraph 構成で書き直し、コードの再利用性を比較
- researcher だけ Haiku に変えて、コスト/速度を測る
langgraph-swarmを入れて handoff パターンの公式実装を読む
学んだこと¶
- Multi-agent の主要パターンは Supervisor / Handoff / Subgraph
- まずは single agent。複雑さに見合うコストかを毎回問う
- Subgraph は再利用可能な単位を作る基本道具
- Anthropic は「simple > complex」の立場
次は最終章 06_temporal_integration。Temporal の Activity の中で LangGraph を呼ぶ。
作成: 2026-05-16 / 最終更新: 2026-05-16