第8章 エージェントデザインパターン
更新日:2025年12月16日
1. パターン概要
エージェントデザインパターンは、LLMエージェントの構造と動作を定義する設計テンプレートである。適切なパターンを選択することで、タスクに最適なエージェントを効率的に構築できる。
Table 1. 主要なエージェントデザインパターン
| カテゴリ | パターン | 特徴 | 適用場面 |
|---|---|---|---|
| シングル | ReAct | 思考→行動→観察のループ | 汎用タスク |
| Plan-and-Execute | 計画立案後に実行 | 複雑なタスク | |
| Reflection | 自己評価と改善 | 品質重視タスク | |
| マルチ | Supervisor | 監督者が作業者を管理 | 専門性の分離 |
| Hierarchical | 階層的な管理構造 | 大規模・複雑なタスク |
これらのパターンは排他的ではなく、組み合わせて使用することも多い。例えば、Supervisor内の各作業者がReActパターンで動作する構成などが考えられる。
2. シングルエージェント
シングルエージェントパターンは、1つのLLMがタスクを遂行する構成である。シンプルな構造で、多くのユースケースに対応できる。
2.1 ReAct
ReAct(Reasoning and Acting)は、第6章で解説した基本パターンである。LLMが「思考」「行動」「観察」を繰り返してタスクを遂行する。
Fig 1. ReActパターンのグラフ構造
┌──────────┐
│ START │
└────┬─────┘
│
┌────▼─────┐
┌───▶│ agent │◀──────┐
│ └────┬─────┘ │
│ │ │
│ ┌────▼─────┐ │
│ │ 条件分岐 │ │
│ └────┬─────┘ │
│ │ │
│ ┌─────┴─────┐ │
│ │ │ │
│ ┌─▼──┐ ┌──▼──┐ │
│ │END │ │tools│────┘
│ └────┘ └─────┘
└─────────────────────────
Table 2. ReActパターンの特徴
| 項目 | 内容 |
|---|---|
| 利点 | シンプル、汎用性が高い、推論過程が追跡可能 |
| 欠点 | 長いタスクでループする可能性、計画性に欠ける |
| 適用場面 | 情報検索、簡単な計算、Q&A |
2.2 Plan-and-Execute
Plan-and-Executeパターンは、タスクを最初に計画(分解)してから、各サブタスクを順次実行する構成である。複雑なタスクに対して、ReActよりも構造化されたアプローチを提供する。
Fig 2. Plan-and-Executeのグラフ構造
┌──────────┐
│ START │
└────┬─────┘
│
┌────▼─────┐
│ planner │ ←── タスクを分解
└────┬─────┘
│
┌────▼─────┐
┌───▶│ executor │ ←── サブタスクを実行
│ └────┬─────┘
│ │
│ ┌────▼─────┐
│ │ 条件分岐 │
│ └────┬─────┘
│ │
│ ┌─────┴─────┐
│ │ │
│ ┌─▼──┐ ┌──▼───┐
│ │END │ │次タスク│
│ └────┘ └───────┘
└─────────────────────
Fig 3. Plan-and-Executeの実装例
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, List
class PlanExecuteState(TypedDict):
task: str
plan: List[str]
current_step: int
results: List[str]
def planner(state: PlanExecuteState) -> dict:
"""タスクを分解して計画を立てる"""
task = state["task"]
# LLMでタスクを分解
plan = llm_plan(task) # ["ステップ1", "ステップ2", ...]
return {"plan": plan, "current_step": 0}
def executor(state: PlanExecuteState) -> dict:
"""現在のステップを実行"""
step = state["plan"][state["current_step"]]
result = llm_execute(step)
return {
"results": [result],
"current_step": state["current_step"] + 1
}
def should_continue(state: PlanExecuteState) -> str:
if state["current_step"] >= len(state["plan"]):
return END
return "executor"
graph = StateGraph(PlanExecuteState)
graph.add_node("planner", planner)
graph.add_node("executor", executor)
graph.add_edge(START, "planner")
graph.add_edge("planner", "executor")
graph.add_conditional_edges("executor", should_continue)
2.3 Reflection
Reflectionパターンは、エージェントが自身の出力を評価し、改善するサイクルを持つ構成である。コード生成、文章作成など、品質が重要なタスクに有効である。
Fig 4. Reflectionのグラフ構造
┌──────────┐
│ START │
└────┬─────┘
│
┌────▼─────┐
┌───▶│ generate │ ←── 初期出力を生成
│ └────┬─────┘
│ │
│ ┌────▼─────┐
│ │ reflect │ ←── 出力を評価
│ └────┬─────┘
│ │
│ ┌────▼─────┐
│ │ 条件分岐 │
│ └────┬─────┘
│ │
│ ┌─────┴─────┐
│ │ │
│ ┌─▼──┐ ┌──▼───┐
│ │END │ │revise │───┐
│ └────┘ └───────┘ │
└───────────────────────┘
Fig 5. Reflectionの実装例
class ReflectionState(TypedDict):
task: str
draft: str
critique: str
revision_count: int
def generate(state: ReflectionState) -> dict:
"""初期ドラフトを生成"""
draft = llm_generate(state["task"])
return {"draft": draft}
def reflect(state: ReflectionState) -> dict:
"""ドラフトを批評"""
critique = llm_critique(state["draft"])
return {"critique": critique}
def revise(state: ReflectionState) -> dict:
"""批評に基づいて修正"""
revised = llm_revise(state["draft"], state["critique"])
return {
"draft": revised,
"revision_count": state["revision_count"] + 1
}
def should_continue(state: ReflectionState) -> str:
# 最大3回の修正、または批評が良好なら終了
if state["revision_count"] >= 3:
return END
if "excellent" in state["critique"].lower():
return END
return "revise"
3. マルチエージェント
マルチエージェントパターンは、複数のLLMエージェントが協調してタスクを遂行する構成である。専門性の分離、並列処理、複雑なワークフローの実現に適している。
3.1 Supervisor
Supervisorパターンは、監督者(Supervisor)エージェントが複数の作業者(Worker)エージェントを管理する構成である。監督者がタスクを適切な作業者に振り分け、結果を統合する。
Fig 6. Supervisorパターンの構造
┌────────────┐
│ Supervisor │
└──────┬─────┘
│
┌────────┼────────┐
│ │ │
┌────▼───┐┌───▼───┐┌───▼────┐
│Researcher││Coder ││Writer │
└─────────┘└───────┘└────────┘
検索担当 コード担当 文章担当
Fig 7. Supervisorの実装例
from langgraph.graph import StateGraph, START, END
from typing import Literal
class SupervisorState(TypedDict):
messages: Annotated[list, add]
next_worker: str
# 作業者の定義
workers = ["researcher", "coder", "writer"]
def supervisor(state: SupervisorState) -> dict:
"""次に作業する作業者を決定"""
response = llm_with_tools.invoke([
SystemMessage(content=f"作業者: {workers}. 次に誰が作業すべきか決定してください。"),
*state["messages"]
])
return {"next_worker": response.next_worker}
def researcher(state: SupervisorState) -> dict:
"""検索・調査を担当"""
result = research_agent.invoke(state["messages"])
return {"messages": [AIMessage(content=result, name="researcher")]}
def coder(state: SupervisorState) -> dict:
"""コード作成を担当"""
result = coding_agent.invoke(state["messages"])
return {"messages": [AIMessage(content=result, name="coder")]}
def writer(state: SupervisorState) -> dict:
"""文章作成を担当"""
result = writing_agent.invoke(state["messages"])
return {"messages": [AIMessage(content=result, name="writer")]}
def route_to_worker(state: SupervisorState) -> str:
return state["next_worker"]
# グラフ構築
graph = StateGraph(SupervisorState)
graph.add_node("supervisor", supervisor)
graph.add_node("researcher", researcher)
graph.add_node("coder", coder)
graph.add_node("writer", writer)
graph.add_edge(START, "supervisor")
graph.add_conditional_edges("supervisor", route_to_worker,
{w: w for w in workers} | {END: END})
for worker in workers:
graph.add_edge(worker, "supervisor")
3.2 Hierarchical
Hierarchicalパターンは、Supervisorパターンを階層的に拡張したものである。大規模なタスクを複数のチームに分割し、各チームに監督者を配置する。
Fig 8. Hierarchicalパターンの構造
┌─────────────┐
│ Top Manager │
└──────┬──────┘
│
┌───────────┼───────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│Research │ │Dev Team │ │QA Team │
│ Lead │ │ Lead │ │ Lead │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│Workers │ │Workers │ │Workers │
└─────────┘ └─────────┘ └─────────┘
Table 3. マルチエージェントパターンの比較
| パターン | 構造 | 利点 | 適用場面 |
|---|---|---|---|
| Supervisor | フラット | シンプル、柔軟 | 3〜5人の専門家 |
| Hierarchical | 階層的 | スケーラブル | 大規模チーム |
4. 実装例
実際のプロジェクトでの適用例を示す。
Table 4. ユースケース別の推奨パターン
| ユースケース | 推奨パターン | 理由 |
|---|---|---|
| カスタマーサポート | ReAct + RAG | シンプル、FAQ検索との連携 |
| レポート作成 | Plan-and-Execute | 構造化された出力が必要 |
| コード生成 | Reflection | 品質向上のための反復 |
| 研究アシスタント | Supervisor | 検索・分析・執筆の分担 |
| ソフトウェア開発 | Hierarchical | 設計・実装・テストの階層 |
Fig 9. パターン選択のフローチャート
タスクの複雑さは?
├── シンプル → ReAct
└── 複雑
├── 計画が必要?
│ └── Yes → Plan-and-Execute
└── 品質向上が必要?
└── Yes → Reflection
専門性の分離が必要?
├── No → シングルエージェント
└── Yes → マルチエージェント
├── チーム数 ≤ 5 → Supervisor
└── チーム数 > 5 → Hierarchical
エージェントデザインパターンは、タスクの性質、求められる品質、スケーラビリティを考慮して選択する。最初はシンプルなReActから始め、必要に応じてより複雑なパターンに移行することを推奨する。
本コンテンツは2025年12月時点の情報に基づいて作成されています。エージェントデザインパターンは研究が活発な分野であり、新しいパターンが提案される可能性があります。参考文献: Liu et al. (2024) "Agent Design Pattern Catalogue"