本文へスキップ
hdknr blog
戻る

Agentic RAGの3つのパターン:Router、Self-Correction、Multi-step Retrieval

はじめに

従来の RAG(Retrieval-Augmented Generation)は「検索して答える」一方通行のパイプラインです。シンプルな質問には効果的ですが、複雑な質問になると精度が落ちるという限界がありました。

その発展系として注目されているのが Agentic RAG です。エージェントが検索・評価・再検索を自律的に繰り返すことで、より高品質な回答を生成できます。本記事では Agentic RAG の代表的な3つのパターンを整理します。

従来の RAG の限界

従来の RAG は「ベクトル検索でドキュメントを取得し、そのコンテキストを LLM に渡して回答を生成する」シンプルなパイプラインで動作します。しかし以下のような課題があります。

Agentic RAG とは

Agentic RAG では、LLM がエージェントとして機能し、ツール呼び出しや思考ループを通じて検索戦略を動的に決定します。単なる「検索 → 生成」にとどまらず、反復・分岐・評価といったステップを自律的に実行できる点が特徴です。

以下の図に、Agentic RAG の主要な3つのパターンをまとめます。

Agentic RAGの3つのパターン(Router、Self-Correction、Multi-step Retrieval)を示すフロー図

3つの主要パターン

① Router:検索先の自動切り替え

Router パターンは、質問の内容に応じて最適なデータソースを自動的に選択します。質問をRouter Agentが分類し、社内DB・Web検索・APIなど複数のデータソースから最適なものを選んで検索します。

ユースケース:

LangGraph での実装イメージ:

from langgraph.graph import StateGraph, END
from typing import TypedDict

class State(TypedDict):
    question: str
    source: str
    context: str
    answer: str

def router_node(state: State) -> State:
    question = state["question"]
    # LLM でデータソースを判定
    source = classify_datasource(question)  # 補助関数は省略
    return {**state, "source": source}

def retrieve_node(state: State) -> State:
    if state["source"] == "internal":
        context = search_internal_db(state["question"])
    elif state["source"] == "web":
        context = search_web(state["question"])
    else:
        context = search_api(state["question"])
    return {**state, "context": context}

graph = StateGraph(State)
graph.add_node("router", router_node)
graph.add_node("retrieve", retrieve_node)
graph.add_edge("router", "retrieve")
app = graph.compile()

② Self-Correction:自己評価と再検索

Self-Correction パターンは CRAG(Corrective RAG)とも呼ばれます。検索で取得したドキュメントの関連性を LLM が評価し、関連性が低い場合は検索クエリを改善して再検索するサイクルを持ちます。

流れは「検索 → ドキュメント関連性評価 → OK なら回答生成、NG なら再検索」です。回答の精度だけでなく、そもそも取得したドキュメントが質問に適切かどうかを自己評価できる点が特徴です。

LangGraph での実装イメージ:

from langgraph.graph import StateGraph, END

def evaluator_node(state: State) -> State:
    # 取得ドキュメントの関連性を評価
    score = grade_document_relevance(
        state["question"], state["context"]
    )
    return {**state, "relevance_score": score}

def should_retry(state: State) -> str:
    if state["relevance_score"] < 0.7:
        return "retry"
    return "done"

graph.add_node("evaluate", evaluator_node)
graph.add_conditional_edges(
    "evaluate",
    should_retry,
    {"retry": "retrieve", "done": END}
)
app = graph.compile()

ユースケース:

③ Multi-step Retrieval:質問の分解と統合

Multi-step Retrieval パターンは、複雑な質問を複数のサブ質問に分解し、それぞれの検索結果を統合して最終回答を生成します。Planner がサブ質問を生成し、各サブ質問を並列に検索・回答した後、Synthesizer が統合します。

LlamaIndex Workflows での実装イメージ:

from llama_index.core.workflow import (
    Workflow, step, Event, StartEvent, StopEvent
)

class QuestionDecomposedEvent(Event):
    sub_questions: list[str]

class SubResultEvent(Event):
    question: str
    result: str

class MultiStepRAGWorkflow(Workflow):
    @step
    async def decompose(
        self, ev: StartEvent
    ) -> QuestionDecomposedEvent:
        sub_questions = decompose_question(ev.question)
        return QuestionDecomposedEvent(sub_questions=sub_questions)

    @step
    async def retrieve_each(
        self, ctx, ev: QuestionDecomposedEvent
    ) -> SubResultEvent:
        # 各サブ質問を個別のイベントとして送出
        for q in ev.sub_questions:
            result = await retrieve_and_generate(q)
            ctx.send_event(SubResultEvent(question=q, result=result))

    @step
    async def synthesize(
        self, ctx, ev: SubResultEvent
    ) -> StopEvent:
        # 全サブ質問の結果が揃うまで収集
        results = ctx.collect_events(
            ev, [SubResultEvent] * expected_count
        )
        if results is None:
            return  # まだ揃っていない
        final_answer = synthesize_results(results)
        return StopEvent(result=final_answer)

ユースケース:

実装技術の選択

フレームワーク特徴向いているパターン
LangGraphグラフベースの状態管理、サイクル(ループ)の表現が得意Router、Self-Correction
LlamaIndex Workflowsイベント駆動、並列ステップの記述が簡潔Multi-step Retrieval
LangChain LCELチェーンの組み合わせが直感的Router(シンプルな場合)

これらのフレームワークはいずれも Python ベースで、既存の LLM・ベクターストアと組み合わせやすい設計になっています。

構造化データへの応用:金融取引履歴・株価

Agentic RAG の対象データはテキスト文書に限りません。金融取引履歴や株価推移のような構造化・数値・時系列データを Arrow 形式や PostgreSQL のような RDBMS に持たせ、それを検索対象にすることも可能です。むしろ、こうした数値データこそ Agentic RAG が従来 RAG より効く典型例です。

Router が数値質問を Text-to-SQL・DuckDB 経由で PostgreSQL や Arrow/Parquet に、文書質問をベクトル検索に振り分け、結果を統合して回答するフロー図

なぜベクトル検索ではなくクエリなのか

従来 RAG は「テキストを埋め込みベクトルに変換し、意味的類似度で検索する」ことが前提でした。しかし「2026年 Q1 の平均株価」のような質問は、埋め込みの類似度では正確に取得できません。集計・フィルタ・結合はクエリエンジンに任せるのが正解です。

Agentic RAG における「検索(retrieval)」の実体は、エージェントが呼び出すツールです。ツールはベクトル検索に限らず、SQL クエリでも DataFrame 操作でも構いません。前掲の Router パターンで search_api や社内 DB を候補にしていたのは、まさにこの発想です。

データ形式ごとの使い分け

形式向いている用途retrieval ツール
PostgreSQL(RDBMS)ライブ/トランザクショナルな取引履歴、更新頻度の高いデータ、権限制御Text-to-SQL(エージェントが SQL を生成・実行)
Arrow / Parquet大量の株価ヒストリカルデータの列指向分析、インメモリ高速集計DuckDB / Polars(Arrow/Parquet をゼロコピーで読み、SQL・DataFrame クエリ)

3つのパターンへの対応

実務上の注意点

  1. 計算は LLM にさせない — 合計・平均・成長率などの計算は必ず SQL / DataFrame エンジンに任せ、LLM は結果の解釈に専念させる(数値のハルシネーション回避)。
  2. Text-to-SQL の安全性 — 生成された SQL は read-only ロール・タイムアウト・行数上限で囲う。
  3. スキーマをコンテキストに渡す — テーブル定義やカラムの説明をツールの記述に含めると、SQL 生成の精度が上がる。

実際の応用例

社内ナレッジ検索

Router を使って「この機能の仕様は?」には社内 Wiki を、「競合他社の最新動向は?」には Web 検索を自動選択します。「仕様を確認してレポートを作成して」のような複合的な依頼には Multi-step Retrieval を活用します。

法律・医療領域

Self-Correction を活用し、取得したドキュメントが質問に適切かどうかを LLM がチェックします。関連性の低いドキュメントは自動的に再検索・再取得されます。

研究タスクの自動化

Multi-step Retrieval で複数の論文を並列検索し、Synthesizer が矛盾点や共通点を整理した上で最終的な考察を生成します。

バックエンド LLM の選び方

Agentic RAG は1回の質問で LLM を何度も呼び出します(Router 判定 → クエリ生成 → 関連性評価 → 統合…)。すべてを最上位モデルで回すとコストとレイテンシが跳ね上がるため、役割ごとにモデルを使い分けるのが定石です。バックエンドに求められる資質は次の3点です。

  1. ツール/関数呼び出しの信頼性 — Agentic ループの根幹。ここが弱いと Router の振り分けや Text-to-SQL が壊れる
  2. 推論力 — 質問分解(Multi-step)、関連性評価(Self-Correction)、統合(Synthesizer)
  3. コスト/レイテンシ — 呼び出し回数が多いので、安いモデルに寄せられる部分は寄せる

階層構成の例(Claude を使う場合)

モデル価格(入力 / 出力 per 1M)Agentic RAG での役割
Claude Opus 4.8$5 / $25オーケストレーション全体、複雑な Planner・Synthesizer、長時間の自律ループ
Claude Sonnet 5$3 / $15常用の主力。コーディング・エージェント用途で Opus に迫る品質を Sonnet 価格で。Router・クエリ生成・統合
Claude Haiku 4.5$1 / $5安く速い分類・評価。Router の質問分類、Self-Correction の関連性スコアリング

3つのパターンへの割り当て例

実装上のポイント

価格やモデル名は 2026年7月時点のものです。最新の情報は各社の公式ドキュメントを確認してください。

まとめ

Agentic RAG の3つのパターンをまとめると以下になります。

パターン解決する課題キーワード
Router検索先が単一で最適な情報源を使えない分類・振り分け
Self-Correction取得ドキュメントの関連性を保証できない評価・再試行
Multi-step Retrieval複雑な質問を一度の検索で解決できない分解・並列・統合

これらのパターンは組み合わせることも可能です。たとえば「Router で検索先を選択 → Multi-step で分解して検索 → Self-Correction で関連性チェック」という複合的なパイプラインを構築することで、より高度な RAG システムを実現できます。

LangGraph と LlamaIndex Workflows はそれぞれの得意領域が異なります。既存の RAG パイプラインの限界を感じている方は、ユースケースに合ったパターンと実装フレームワークを選んで Agentic RAG への移行を検討してみてください。



前の記事
AIDesigner MCP:気に入ったWebサイトのデザインをClaude Codeで数秒で解析・再現する
次の記事
「動くけど雑」なAIコードを卒業する — Addy Osmaniの agent-skills