本文へスキップ
Dev Dailyエンジニア デイリーニュース

DEEP DIVE · AI・ML

中級

LLM エージェントの設計パターン: ReAct からマルチエージェントまで

LLM を「呼び出して終わり」から「自律的に動くシステム」へ引き上げる設計パターンを整理します。ReAct によるツール使用、メモリの持たせ方、オーケストレータ型のマルチエージェント、そして本番運用で避けて通れない評価まで、それぞれが解く課題と適用範囲を具体的に解説します。

執筆: kinjo8 分で読了

エージェントは「フレームワークを盛る」ことではなく、課題に合った最小のパターンを選ぶことから始まります。

概要

LLM エージェントの設計は、ReAct を起点に「ツール使用」「メモリ」「マルチエージェント」「評価」という 4 つの軸で整理できます。多くの本番システムは複雑なフレームワークを使わず、prompt chaining や routing といった単純で合成可能なパターンの組み合わせで動いています。本稿では各パターンが解く課題、向き不向き、そして自律性を上げるほど増える運用コストとのトレードオフを解説します。

前提知識

この記事を読み進めるうえで知っておくとスムーズなトピック。

LLM への基本的なプロンプト設計の経験REST API や関数呼び出し (function calling) の概念JSON スキーマの読み書き

要点

先に押さえておきたい、この深掘りの核となるポイント。

  • ReAct は推論とツール使用を分離する基盤パターン

    「考える (Reasoning)」トークンと「動く (Acting)」トークンを交互に出力させることで、ツール呼び出しの幻覚を減らし、軌跡を後から追跡できるようにします。多くのパターンはこの上に積み重なります。

  • ツール使用はスキーマ設計が品質を左右する

    ツールの説明文・引数スキーマ・エラー応答の設計は、プロンプト本文と同じくらいエージェントの成否を決めます。曖昧なツール定義は誤呼び出しの最大の原因です。

  • メモリは短期 (コンテキスト) と長期 (外部ストア) を分けて考える

    短期メモリは会話履歴やスクラッチパッド、長期メモリはベクトル検索や要約による圧縮が中心です。Reflexion のように失敗を言語化して次に活かす反省メモリも有効です。

  • マルチエージェントは orchestrator-workers が実用の主力

    中央のオーケストレータがタスクを動的に分割し、ワーカーに委譲して結果を統合します。サブタスクを事前に決め打ちできない複雑な課題に向きます。

  • 評価なしのエージェントは本番に載せられない

    span (各 LLM 呼び出し) / trace (実行全体) の 2 階層で、タスク完了率・ツール使用の正しさ・コストとレイテンシを継続的に計測する必要があります。

エージェントとワークフローを区別する

LLM を使ったシステムを設計するとき、最初に押さえておきたいのは「ワークフロー」と「エージェント」の違いです。Anthropic の整理では、ワークフローは LLM とツールがあらかじめ定義されたコードパスに沿って動くもの、エージェントは LLM が自分でプロセスとツールの使い方を判断するものとされています。

この区別が重要なのは、自律性を上げるほど柔軟性は増す一方で、レイテンシ・コスト・予測不能性も増えるからです。実際、本番で安定して動いているシステムの多くは、複雑なフレームワークを持ち込まず、単純で合成可能なパターンの組み合わせで作られています。「とりあえずエージェント化する」のではなく、課題が本当に動的な判断を要求しているかを最初に問うべきです。

固定的な手順で十分なら、次のような単純なワークフローから始めます。

  • Prompt Chaining: タスクを順番に並んだ複数の LLM 呼び出しに分解する。各ステップの間にプログラムによるチェック (ゲート) を挟める。
  • Routing: 入力を分類し、専用のプロンプトやモデルに振り分ける。問い合わせの種類が明確に分かれるカスタマーサポートなどに向きます。
  • Parallelization: 独立したサブタスクを並列に実行して集約する。

これらで足りなくなったとき、初めて ReAct のようなループ型のエージェントを検討します。

ReAct: 推論とツール使用を編む

ReAct (Reasoning + Acting) は、エージェント設計の事実上の基盤パターンです。アイデアはシンプルで、モデルに「思考 (Thought)」「行動 (Action)」「観測 (Observation)」を交互に生成させます。

Thought: ユーザーは東京の現在の気温を知りたい。天気 API を呼ぶ必要がある。
Action: get_weather(city="Tokyo")
Observation: { "temp_c": 24, "condition": "Cloudy" }
Thought: 必要な情報が揃った。回答を組み立てる。
Action: finish("東京は現在 24°C、くもりです。")

推論トークンと行動トークンを明示的に分離することで、モデルが「ツールを呼んだつもりで結果を捏造する」幻覚を大きく減らせます。さらに、この Thought/Action/Observation の連なりがそのまま実行軌跡 (trajectory) になるため、後からデバッグや評価がしやすくなる副次効果もあります。

一方で素の ReAct には弱点もあります。失敗から学ぶ仕組みがないこと、長いタスクで序盤の計画を見失いやすいことです。前者は後述の Reflexion 系の反省メモリで、後者はグローバルな目標を保持し続けるオーケストレーション層で補います。

ツール使用: スキーマこそが本体

エージェントの能力は、与えられたツールの質に直結します。そしてツールの「質」は実装そのものより、モデルから見えるインターフェイスで決まります。ツールの説明文・引数スキーマ・エラー時の応答は、プロンプト本文と同じ重みで設計すべき対象です。

実務でつまずきやすいポイントを挙げます。

  • 説明が曖昧: search のような名前だけでは、何を検索するツールか判断できません。search_internal_docs(query) のように用途を名前と説明に込めます。
  • 引数の型が緩い: 自由文字列の引数は誤入力の温床です。enum や日付フォーマットを JSON スキーマで縛ると誤呼び出しが減ります。
  • エラーが不親切: ツールが失敗したとき、Error とだけ返すと再試行のしようがありません。「どの引数が不正か」を含む構造化エラーを返すと、エージェントは自己修正できます。

Toolformer のように、モデル自身がどこで API を呼ぶべきかを学習する研究もありますが、本番では「人が丁寧に定義した少数のツール」のほうが扱いやすいことが多いです。ツールは増やすほど選択を誤りやすくなるため、まず必要最小限に絞るのが定石です。

メモリ: 短期と長期を分ける

メモリは「短期」と「長期」を分けて設計すると見通しが良くなります。

短期メモリは、現在のタスクを進めるための一時的な情報です。会話履歴、ReAct のスクラッチパッド、直近の観測結果などが該当します。これらはコンテキストウィンドウに乗りますが、長いセッションでは古い情報を要約して圧縮する必要があります。

長期メモリは、セッションをまたいで保持したい知識です。典型的にはベクトルデータベースに埋め込みを保存し、関連する記憶を検索して必要なぶんだけコンテキストに差し込みます。ここで重要なのは「全部入れる」のではなく「いま関係するものだけ取り出す」設計です。

第三の軸として反省メモリがあります。Reflexion は、タスクに失敗したエージェントにその原因を自然言語で言語化させ、次の試行のコンテキストに加える手法です。重みの更新を伴わない「言語的な強化学習」とも言え、評価器からのフィードバックを次のループに活かす点で評価パイプラインと相性が良いパターンです。

マルチエージェント: orchestrator-workers

単一エージェントで手に負えない複雑なタスクには、複数のエージェントを協調させます。実用上もっとも扱いやすいのが orchestrator-workers です。

中央のオーケストレータ LLM がタスクを動的にサブタスクへ分割し、それぞれを専門のワーカー LLM に委譲し、最後に結果を統合します。parallelization との違いは、サブタスクを事前に決め打ちしない点です。どう分割するかは入力に応じてオーケストレータが判断するため、必要な手順を予測できない調査タスクやコード変更タスクに向きます。

Orchestrator: 「このリポジトリのテストを全て修正して」を受領
  → サブタスク 1: 失敗しているテストを列挙 (worker A)
  → サブタスク 2: 各ファイルの原因を特定 (worker B 群を並列起動)
  → 統合: 修正方針をまとめてレビュー用に出力

関連して evaluator-optimizer も有用です。生成役の LLM が成果物を作り、評価役の LLM がフィードバックを返すループを回します。翻訳の品質改善のように「良し悪しの基準が明確で、反復が効く」課題で効果を発揮します。

ただしマルチエージェントは銀の弾丸ではありません。エージェント間の通信が増えるほどトークン消費とレイテンシが膨らみ、失敗の切り分けも難しくなります。冒頭の図のとおり自律性レベルが上がるほど運用コストも上がるため、単一の ReAct で解けないと確認できてからマルチエージェントに進むのが安全です。

評価: 本番運用の前提条件

設計パターンを正しく選んでも、評価の仕組みがなければ本番には載せられません。エージェントの評価は、少なくとも 2 つの階層で考えます。

  • span レベル: 個々の LLM 呼び出しを採点します。出力の忠実性 (faithfulness)、ツール使用の正しさ、根拠への接地 (grounding) などを見ます。
  • trace レベル: 実行全体を採点します。タスク完了率、計画への追従、そしてコストとレイテンシの予算内に収まっているかを評価します。

評価は一度きりのベンチマークではなく、デプロイ後も回し続ける継続的なプロセスです。実際のトラフィックから難しいケースを収集してテストセットに加え、プロンプトやツール定義を変えたときに回帰が起きていないかを確認します。Reflexion のような反省メモリを組み込むなら、評価器の出力をそのまま次のループのフィードバックに使えるため、評価パイプラインとエージェント本体は地続きに設計しておくと無駄がありません。

まとめ: 最小から積み上げる

LLM エージェントの設計は、「高度なパターンを最初から盛る」のではなく、課題に合った最小構成から積み上げるのが王道です。Prompt Chaining や Routing で足りるならそれで十分ですし、動的な判断が必要になったら ReAct、単一では手に負えなくなったら orchestrator-workers、というように段階を踏みます。

どの段階でも共通して効くのは、丁寧なツール設計、短期と長期を分けたメモリ、そして span/trace の 2 階層の評価です。フレームワークの華やかさに惑わされず、各パターンが「どの課題を解くために存在するのか」を理解しておくことが、壊れにくいエージェントへの近道です。

Prompt Chaining
Lv.2
手順が固定。最も予測しやすく安価
Routing
Lv.3
入力に応じて分岐
ReAct (単一)
Lv.6
推論とツール使用のループ
Orchestrator-Workers
Lv.9
動的分割。柔軟だが高コスト
主要パターンの相対的な自律性レベル (0=固定ワークフロー, 10=完全自律。運用コストもおおむね右肩上がり)
この記事を共有:でポストはてブ

関連するデイリーニュース

このテーマが取り上げられた平日のノート。

出典

注記: 本記事は公開情報をもとにした技術情報の提供を目的としています。 最新の仕様や挙動は必ず一次情報 (公式ドキュメント・リリースノート) をご確認ください。