エージェント設計パターン
効果的なエージェントを構築するには、強力なモデルとツールの集合だけでは不十分です。アーキテクチャ、すなわちLLMをどのようにオーケストレーションし、タスクをどのように分解し、コンポーネント間で制御をどのように流すかによって、エージェントの信頼性、デバッグ可能性、費用対効果が決まります。本章では、Anthropic、OpenAI、Google、オープンソースコミュニティの本番導入から生まれた代表的な設計パターンを紹介します。
Tip
エージェントとワークフローの使い分け
すべてのタスクに自律エージェントが必要なわけではありません。重要な違いは次のとおりです。
ワークフロー: 制御フローがあらかじめ定義され、特定のステップでLLMを呼び出します。予測しやすく、テスト可能で、安価です。タスク構造が既知の場合に使います。
エージェント: LLMが次に何をするかを動的に決めます。柔軟で、新しい状況に対応できます。適応的な意思決定が必要なタスクに使います。
まずワークフローから始めましょう。 タスクが本当に動的なルーティングやオープンエンドな探索を必要とする場合にだけ、エージェントへ移行します。
ワークフローパターン
これらのパターンは、Anthropicによるエージェント構成要素の分類(Anthropic 2024a)を応用したものです。LLMをあらかじめ定義された制御フロー内で使い、システム(モデルではない)が実行順序を決定します。
プロンプトチェーン
最も単純なパターンです。複雑なタスクを固定されたLLM呼び出しの列に分解し、ある呼び出しの結果を次の呼び出しのコンテキストとして渡します。ステップ間の検証ゲートにより、エラーが下流へ伝播する前に早期発見できます。
使う場面: コンテンツ生成、データ変換、複数段階の分析など、自然に逐次的なタスク。
主な利点: 各ステップで異なるプロンプト、モデル、temperatureを使えます。中間結果を検査・デバッグできます。
ルーティング
分類器(LLMまたは従来型)が入力を調べ、専門ハンドラへディスパッチします。
使う場面: 最適なプロンプト、ツール、モデルが異なる明確なタスク種別。カスタマーサポートのトリアージ、マルチモーダル入力の処理など。
並列化
複数のLLM呼び出しを並行実行し、プログラム層が出力を組み合わせます。ここから2つのサブパターンが生まれます。
-
セクション分割(ファンアウト): 入力を互いに重ならないチャンクへ分割し、それぞれを独立して処理します。例えば、コードベースに対するセキュリティ、性能、スタイルのチェックを同時に実行します。
-
投票(冗長性): 同じプロンプトを異なるシードやtemperatureで\(N\)回発行し、多数決(X. Wang, Wei, Schuurmans, Q. V. Le, et al. 2023)、報酬モデルのスコアリング、またはLLM-as-judgeによって最良の結果を選びます。
Note
並列化の例:コードレビュー
並列呼び出し: セキュリティレビュー \(\\vert\) パフォーマンスレビュー \(\\vert\) スタイルレビュー
集約: すべての指摘を統合し、重複を除去して、重大度で順位付けします。
レイテンシ = \(\max\)(個々の呼び出し)であり、\(\sum\)(個々の呼び出し)ではありません。
オーケストレータ・ワーカー
ここではLLM自身が作業の分割方法を決めます。オーケストレータモデルがタスクを分析し、サブタスクの計画を作り、各サブタスクをワーカーLLM(異なるプロンプトやツールを使う場合もあります)へディスパッチし、最後に出力を一貫した結果へ統合します。並列化との主な違いは、分解ロジックがハードコードされておらず、モデルによって生成されることです。
使う場面: 設計時にサブタスクの数や性質を列挙できないオープンエンドな問題。例えば「このコードベースをリファクタリングして」という要求では、どのファイルを変更するか決める前に依存関係グラフを理解する必要があります。
評価器・オプティマイザ
2つのモデルによるフィードバックループです(Madaan et al. 2023)。生成器が候補出力を作り、別の評価器が明示的な基準に照らしてスコアを付けます。スコアがしきい値を下回ると、評価器の批評を生成器のコンテキストに追加し、品質基準を満たすか再試行予算を使い切るまでサイクルを繰り返します。
使う場面: 明確な品質基準があるタスク。テストに合格しなければならないコード、意味を保たなければならない翻訳、スタイルガイドに従う必要がある文章など。
自律エージェントパターン
これらのパターンでは、LLM自身が実行フローを制御します。
ReAct(推論+行動)
基礎となるエージェントパターンです(S. Yao, Zhao, et al. 2023)。LLMが思考(内部推論)、行動(ツール呼び出し)、観察(結果の処理)をループ内で交互に実行し、最終回答を生成するまで続けます。
Important
ReAct実装の要点
スクラッチパッド: 「Thought」ステップをログに記録しますが、ユーザーには表示しません。
ツール解析: ハーネスがモデル出力から構造化されたツール呼び出しを抽出します。
最大反復回数: 必ずループに上限を設けます(通常は10〜25回)。
終了: モデルが特殊なアクション(例:
final_answer)を出力するか、ツール呼び出しが検出されないと終了します。
計画エージェント
エージェントは実行前に明示的な計画を生成し、実行途中で計画を修正できます(L. Wang et al. 2023)。
| 戦略 | 再計画 | 特徴 |
|---|---|---|
| Plan-then-Execute | なし | 単純だが、予期しない結果に弱い |
| Adaptive | 失敗時 | ステップが失敗したときだけ再計画。コストは中程度 |
| Continuous | 各ステップ | 観察ごとに完全再評価。高価だが堅牢 |
| Hierarchical | サブ計画完了時 | 高レベル計画は固定。サブ計画を動的に生成 |
計画戦略の比較
Note
計画エージェント:調査レポートの生成
ユーザー要求: 「時系列予測向けのTransformerアーキテクチャを比較する2ページのレポートを書いてください。」
ステップ1 — 計画生成 (単一のLLM呼び出し):
plan = [ {"id": 1, "task": "Search for recent transformer-based " "time-series models (2023-2025)", "tool": "search_web", "deps": []}, {"id": 2, "task": "Read top 5 papers, extract key methods", "tool": "read_papers", "deps": [1]}, {"id": 3, "task": "Build comparison table (architecture, " "dataset, metrics)", "tool": "none", "deps": [2]}, {"id": 4, "task": "Write introduction + methodology section", "tool": "none", "deps": [2]}, {"id": 5, "task": "Write results + conclusion", "tool": "none", "deps": [3, 4]}, {"id": 6, "task": "Review and polish final report", "tool": "none", "deps": [5]}, ]ステップ2 — 適応的な再計画を伴う実行: エージェントは依存関係の順序でステップを実行します。ステップ1の後、検索結果が関連論文を3本しか返さなかったとします。エージェントは再計画し、隣接領域(PatchTST、iTransformerなど)へ検索を広げるサブステップを追加します。修正された計画は、拡張されたコーパスを使ってステップ2から続行します。
重要な洞察: 計画は生きた文書です。構造を与えながら、観察結果に適応します。ハーネスは依存関係をDAGとして追跡し、先行ステップが完了したステップだけを実行します。
リフレクションと自己批評
エージェントは一時停止して自分の軌跡を評価し、方針を修正します。
-
出力検証: 「これは正しいか?何か見落としていないか?」
-
軌跡レビュー: 直前の\(k\)ステップを見直し、間違いや非効率を特定します。
-
戦略修正: 全体的なアプローチを再考します(「正しい問題を解いているか?」)。
Tip
Reflexion:失敗から学ぶ
Reflexion パターン(Shinn et al. 2023)は、永続的な「リフレクションメモリ」を維持します。失敗するたびに、エージェントは自然言語のリフレクション(「エッジケースを確認しなかったため失敗した」)を書きます。次の試行ではこれらのリフレクションをプロンプトに含め、重みを更新せずにエピソード間の学習を可能にします。
ツール利用パターン
エージェントがツールを呼び出す方法は、信頼性、レイテンシ、コストに大きく影響します。代表的なパターンが5つあります(Schick et al. 2023)。
| パターン | 説明 | 例 |
|---|---|---|
| Single-turn | LLM応答あたり1回のツール呼び出し | 検索を使う単純なQ&A |
| Multi-tool | 1つの応答で複数のツールを並列呼び出し | 検索+計算+整形 |
| Sequential | ツール出力を次のツール呼び出しへ渡す | 検索 \(\to\) 読み取り \(\to\) 抽出 |
| Nested | ツール呼び出しが別のエージェントを起動 | コードエージェントがテストランナーを呼び出す |
| Fallback | 優先ツールが失敗したら代替を試す | API \(\to\) スクレイピング \(\to\) キャッシュ |
ツール呼び出しパターン
単一ターンのツール利用
最も単純なパターンです。モデルが1回のツール呼び出しを発行し、結果を受け取り、最終回答を生成します。事実検索、単位変換、単一APIへの問い合わせに十分です。ハーネスは正確に2回LLMを呼び出します(ツールを決める呼び出しと、結果を統合する呼び出しです)。
マルチツール(並列)
現代のAPI(OpenAI、Anthropic)では、モデルが1つの応答で複数のツール呼び出しを要求できます。ハーネスはそれらを並行実行し、すべての結果をまとめて返します。これにより、株価、天気、カレンダーを同時に取得するなど、複数のソースから独立した情報を必要とするタスクのレイテンシを大幅に削減できます。重要な制約は、ツールが独立していなければならないことです(あるツールの出力を別のツールの入力として必要としないこと)。
逐次(パイプライン)
各ツールの出力を次のツールの入力へ渡し、データパイプラインを形成します。モデルは前の結果に基づいて次のツールを決めます。調査ワークフローでよく使われます。例:search \(\to\) fetch_page \(\to\) extract_data \(\to\) analyze。ハーネスは増大するコンテキストを追跡し、予算内に収めるため中間結果を要約する必要が生じることがあります。
ネスト(エージェント・アズ・ツール)
ツール呼び出しが、独自のプロンプト、ツール、コンテキストを持つ完全に別のエージェントを起動します。親エージェントはサブエージェントをブラックボックス関数として扱います。これにより専門化が可能になります。例えば、調査エージェントがコード実行を、サンドボックスとテストランナーにアクセスできるコーディングエージェントへ委譲します。Swarmパターン(OpenAI 2024b)は、専門エージェント間のハンドオフによってこれを一般化します。
フォールバック(段階的な機能縮退)
ハーネスは優先順位に従ってツールを試します。優先ツールが失敗(タイムアウト、レート制限、APIエラー)すると、自動的に代替へフォールバックします。モデルがフォールバックロジックを知る必要はなく、ハーネスが透過的に処理します。例:主要検索API \(\to\) 代替検索 \(\to\) キャッシュ済み結果 \(\to\) 検索が利用できないことをモデルへ通知。
設計原則
以下の原則は、Anthropicの効果的なエージェント構築ガイド(Anthropic 2024a)から抽出したもので、すべてのパターンに適用できます。
-
シンプルに保つ。 動作する最も単純なアーキテクチャを使います。必要性が実証された場合だけ複雑さを加えます。問題を解決するプロンプトチェーンのほうが、解決できるかもしれないマルチエージェントシステムより常に好ましい選択です。
-
巧妙さより透明性。 すべてのステップを検査可能にします。隠れた状態や暗黙的な推論を避けます。エージェントが失敗したときは、その理由を理解する必要があります。透明性のないアーキテクチャではデバッグできません。
-
良いツールを提供する。 十分に文書化され、型が明確で、分かりやすいエラーメッセージを持つツールは能力を増幅します。説明が曖昧なツールは誤用されますが、正確なスキーマと使用方法を持つツールは正しく選択されます。
-
失敗に備える。 すべてのツール呼び出しは失敗する可能性があります。モデルがインフラストラクチャの失敗を推論しなくて済むよう、ハーネスレベルで再試行ロジック、フォールバック、段階的な機能縮退を構築します。
-
構造化出力を使う。 制約付き生成(JSONスキーマ、Function Calling)により解析失敗を防ぎます。正規表現による解析が必要な自由形式テキストを生成するエージェントは脆弱ですが、検証済みJSONを生成するエージェントは堅牢です。
-
多様な入力でテストする。 エージェントの挙動は単一ターンのチャットより変動しやすいものです。同じプロンプトでも、実行ごとに異なるツール呼び出し列を生成することがあります。エッジケース、曖昧な要求、整形式でない入力を使い、敵対的にテストします。
パターン選択ガイド
適切なパターンの選択は、3つの要因に依存します。(1) タスク構造がどの程度予測可能か、(2) レイテンシとコストの面で何回のLLM呼び出しまで許容できるか、(3) 品質に反復が必要かどうかです。以下の表を意思決定マトリクスとして使い、上(最も単純)から始め、より単純なパターンでは明らかに不十分な場合だけ下へ進みます。
| パターン | 複雑性 | LLM呼び出し | 適した用途 |
|---|---|---|---|
| プロンプトチェーン | 低 | \(N\)(固定) | 逐次タスク、コンテンツパイプライン |
| Routing | 低 | 1 + 1 | 複数種別の入力、トリアージ |
| 並列化 | 低 | \(N\)(並列) | 独立したサブタスク、投票 |
| Orchestrator-workers | 中 | 可変 | 未知の分解 |
| Evaluator-optimizer | 中 | 2〜10(ループ) | 品質が重要な出力 |
| ReAct | 中 | 3〜25(ループ) | 一般的なツール利用、探索 |
| Planning agent | 高 | 5〜50以上 | 長期的なマルチステップタスク |
| Reflection | 高 | 50%増のオーバーヘッド | 初回の試行が失敗しやすいタスク |
| Multi-agent | 高 | 多数 | 複雑な領域、専門化 |
各エージェント設計パターンの使いどころ
パターンは組み合わせ可能です。計画エージェントが個々のステップにプロンプトチェーンを使い、レビュー段階で評価器・オプティマイザを使い、サブタスクを専門家へディスパッチするためにルーティングを使うこともできます。重要なのは、いつ層の追加を止めるかを見極めることです。