Home 論文解説: Adaptive-RAG — クエリ複雑度分類で検索戦略を動的に選択するRAGフレームワーク
投稿
キャンセル

📄 論文解説: Adaptive-RAG — クエリ複雑度分類で検索戦略を動的に選択するRAGフレームワーク

本記事は Adaptive-RAG: Learning to Adapt Retrieval-Augmented Large Language Models through Question Complexity (arXiv:2404.19756) の解説記事です。

論文概要(Abstract)

Adaptive-RAGは、クエリの複雑度に基づいてRAGの検索戦略を動的に選択するフレームワークである。著者らは、小型言語モデルで訓練した複雑度分類器を用いて、(A)検索なし(パラメトリック知識のみ)、(B)単一ステップ検索、(C)反復的検索・推論の3戦略から最適なものを自動選択する手法を提案している。実験では、常に最も高コストな反復的検索を使用した場合と同等の精度を維持しつつ、計算コストを大幅に削減できることが報告されている。

この記事は Zenn記事: LangGraph×Claude 4.6で推論精度と応答速度を両立するマルチエージェントRAG の深掘りです。

情報源

  • arXiv ID: 2404.19756
  • URL: https://arxiv.org/abs/2404.19756
  • 著者: Soyeong Jeong, Jinheon Baek, Sukmin Cho, Sung Ju Hwang, Jong C. Park
  • 発表年: 2024
  • 分野: cs.CL, cs.AI, cs.IR

背景と動機(Background & Motivation)

知識集約型タスクにおけるRAGシステムでは、クエリに対して外部データベースから情報を検索し、LLMに統合して回答を生成する。著者らは、既存研究がLLM自体の改善か検索コンポーネントの改善のいずれかに集中しており、クエリの複雑度に基づいて検索戦略を適応的に選択するアプローチが未探索であることを指摘している。

現実のRAGシステムでは、クエリの複雑度は多様である。「Pythonの最新バージョンは?」のような単純な事実確認には検索すら不要かもしれないが、「3つのフレームワークのアーキテクチャの違いを比較して」のようなmulti-hop推論には反復的な検索と推論が必要になる。すべてのクエリに対して最も高コストな反復的検索を適用するのは非効率である。

この問題はZenn記事で解説しているeffortパラメータ("low" / "medium" / "high")による推論深度制御と直接対応する。Adaptive-RAGは検索戦略のレベルでこの適応的選択を行い、effortパラメータはLLMの思考深度のレベルで同様の最適化を行う。

主要な貢献(Key Contributions)

  • 貢献1: クエリ複雑度に基づいてRAG戦略を適応的に選択するフレームワーク(Adaptive-RAG)の提案
  • 貢献2: LLM自身の出力を使った弱教師ありラベル生成手法により、人手のアノテーションなしで複雑度分類器を訓練する方法論
  • 貢献3: 6種のQAデータセットにおいて、常に反復的検索を使用する手法と同等以上の精度を維持しつつ計算コストを削減できることの実証

技術的詳細(Technical Details)

3段階の検索戦略

著者らは、クエリの処理に必要な検索の深さに基づいて3つの戦略クラスを定義している。

\[\text{Strategy}(q) = \begin{cases} \text{Class A: No Retrieval} & \text{if } c(q) = \text{simple} \\ \text{Class B: Single-Step RAG} & \text{if } c(q) = \text{moderate} \\ \text{Class C: Iterative RAG} & \text{if } c(q) = \text{complex} \end{cases}\]

ここで、

  • $q$: 入力クエリ
  • $c(q)$: 分類器が予測するクエリの複雑度クラス
  • Class A(No Retrieval): LLMのパラメトリック知識のみで回答。外部検索なし
  • Class B(Single-Step RAG): 1回の検索ステップ後にLLMが回答を生成
  • Class C(Iterative RAG): 複数回の検索と推論を繰り返すmulti-step処理

複雑度分類器の訓練(弱教師あり学習)

著者らの核心的な手法は、人手のラベリングなしで分類器の訓練データを自動生成する手法である。

訓練データ生成アルゴリズム:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def generate_training_labels(
    dataset: list[dict],
    llm,
    retriever,
) -> list[tuple[str, str]]:
    """弱教師ありで複雑度ラベルを自動生成する

    各クエリについて3つの戦略で回答を生成し、
    正解を出せる最も単純な戦略をラベルとして割り当てる

    Args:
        dataset: クエリと正解のペアのリスト
        llm: 回答生成に使用するLLM
        retriever: 検索コンポーネント

    Returns:
        (query, label)のペアのリスト
    """
    labeled_data = []

    for item in dataset:
        query = item["question"]
        gold_answer = item["answer"]

        # 戦略A: 検索なし(パラメトリック知識のみ)
        answer_a = llm.generate(query)

        # 戦略B: 単一ステップ検索
        docs = retriever.retrieve(query, k=5)
        answer_b = llm.generate_with_context(query, docs)

        # 戦略C: 反復的検索
        answer_c = iterative_rag(query, llm, retriever, max_steps=3)

        # 最も単純で正解できる戦略をラベルとして採用
        if is_correct(answer_a, gold_answer):
            label = "A"  # 検索不要
        elif is_correct(answer_b, gold_answer):
            label = "B"  # 単一ステップで十分
        else:
            label = "C"  # 反復的検索が必要

        labeled_data.append((query, label))

    return labeled_data

この手法の利点は、ターゲットLLMの能力に合わせた「正しい」ラベルが自動生成される点にある。LLMが強力であれば、より多くのクエリがClass A(検索不要)に分類される。

分類器のアーキテクチャ

著者らはT5-smallやDeBERTaなどの軽量モデルをファインチューニングして分類器を構築している。

\[\hat{c}(q) = \arg\max_{k \in \{A, B, C\}} \; \text{softmax}(\mathbf{W} \cdot \text{Encoder}(q) + \mathbf{b})_k\]

ここで、

  • $\hat{c}(q)$: クエリ$q$の予測複雑度クラス
  • $\mathbf{W}$: 分類ヘッドの重み行列
  • $\text{Encoder}(q)$: T5-small等のエンコーダ出力
  • $\mathbf{b}$: バイアスベクトル

分類器の推論コストはLLMの推論コストと比較して無視できるレベル(数ミリ秒)であり、全体のレイテンシへの影響は極めて小さい。

Zenn記事のeffortルーティングとの対応関係

Adaptive-RAGの3クラス分類は、Zenn記事で解説しているeffortパラメータによる推論深度制御と概念的に対応する。

Adaptive-RAGZenn記事のeffort用途
Class A (No Retrieval)effort=”low”単純な事実確認、思考スキップ
Class B (Single-Step)effort=”medium”文書要約、関連度判定
Class C (Iterative)effort=”high”複数文書の統合推論、比較分析

Adaptive-RAGは検索戦略のレベルで適応的選択を行い、effortパラメータはLLMの推論深度のレベルで適応的選択を行う。両者を組み合わせることで、検索と推論の両方でコスト最適化が可能になる。

実装のポイント(Implementation)

分類器の精度がボトルネックになる

著者らの実験では、分類器の精度は75-85%と報告されている。つまり15-25%のクエリで最適でない戦略が選択される。実運用上は以下の考慮が必要である。

  • 安全側に倒す: 分類器の確信度が低い場合、より高コストな戦略にフォールバックする。Zenn記事のclassify_query関数でquery_type not in ("factual", "summary", "analytical")の場合に"analytical"(安全側)をデフォルトにしている設計と同じアプローチ
  • 分類器の継続的改善: プロダクション環境でのログデータを用いて分類器を定期的に再訓練する

LangGraphでの実装パターン

Adaptive-RAGのルーティングロジックは、LangGraphのCommand primitiveで自然に実装できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from langgraph.types import Command
from typing import Literal

def adaptive_router(state: dict) -> Command[Literal[
    "no_retrieval", "single_step_rag", "iterative_rag"
]]:
    """Adaptive-RAGスタイルのルーティングエージェント

    軽量分類器でクエリ複雑度を判定し、適切な戦略にルーティングする
    """
    query = state["query"]

    # 軽量分類器で複雑度予測(数ms)
    complexity_class = classifier.predict(query)
    confidence = classifier.predict_proba(query).max()

    # 確信度が低い場合は安全側にフォールバック
    if confidence < 0.6:
        complexity_class = "C"

    strategy_map = {
        "A": "no_retrieval",
        "B": "single_step_rag",
        "C": "iterative_rag",
    }

    return Command(
        goto=strategy_map[complexity_class],
        update={
            "complexity_class": complexity_class,
            "routing_confidence": confidence,
        }
    )

effortパラメータとの組み合わせ

Adaptive-RAGの検索戦略選択とeffortパラメータの推論深度制御を組み合わせることで、二重の最適化が可能になる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Adaptive-RAGの複雑度クラスに基づくeffort設定
COMPLEXITY_TO_EFFORT = {
    "A": "low",    # 検索不要 → 思考もスキップ
    "B": "medium", # 単一検索 → 中程度の推論
    "C": "high",   # 反復検索 → 深い推論
}

async def adaptive_rag_with_effort(query: str) -> str:
    complexity_class = classifier.predict(query)
    effort = COMPLEXITY_TO_EFFORT[complexity_class]

    llm = create_adaptive_llm(effort=effort)

    if complexity_class == "A":
        return await llm.ainvoke(query)
    elif complexity_class == "B":
        docs = await retrieve(query, k=5)
        return await llm.ainvoke(query, context=docs)
    else:
        return await iterative_rag(query, llm, max_steps=3)

Production Deployment Guide

AWS実装パターン(コスト最適化重視)

Adaptive-RAGのコスト最適化効果を最大限に活かすため、分類器をエッジに配置しLLM呼び出しを最小化する構成を推奨する。

トラフィック量別の推奨構成:

規模月間リクエスト推奨構成月額コスト主要サービス
Small~3,000 (100/日)Serverless$30-100Lambda + Bedrock + DynamoDB
Medium~30,000 (1,000/日)Hybrid$200-600Lambda + ECS Fargate + ElastiCache
Large300,000+ (10,000/日)Container$1,500-4,000EKS + Karpenter + EC2 Spot

Adaptive-RAGのコスト削減効果により、全クエリにIterative RAGを適用する場合と比較して月額30-50%の削減が見込まれる(著者らの実験ではClass A/B判定が全体の50-70%を占める)。

Small構成の詳細(月額$30-100):

  • Lambda(分類器): 256MB RAM, Python 3.12(DeBERTa推論, $5/月)
  • Lambda(生成): 1GB RAM, Bedrock呼び出し($15/月)
  • Bedrock: Class A→Haiku($0.25/MTok), Class B/C→Sonnet($3/MTok)
  • DynamoDB: キャッシュ, On-Demand($5/月)

コスト試算の注意事項: 上記は2026年2月時点のAWS ap-northeast-1(東京)リージョン料金に基づく概算値です。最新料金は AWS料金計算ツール で確認してください。

Terraformインフラコード

Small構成: Lambda(分類器)+ Lambda(生成)+ Bedrock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# --- 分類器Lambda(軽量、DeBERTa推論) ---
resource "aws_lambda_function" "classifier" {
  filename      = "classifier.zip"
  function_name = "adaptive-rag-classifier"
  role          = aws_iam_role.classifier_lambda.arn
  handler       = "index.handler"
  runtime       = "python3.12"
  timeout       = 10
  memory_size   = 256

  environment {
    variables = {
      MODEL_PATH = "/opt/ml/model"
    }
  }

  layers = [aws_lambda_layer_version.deberta_model.arn]
}

# --- 生成Lambda(Bedrock呼び出し) ---
resource "aws_lambda_function" "generator" {
  filename      = "generator.zip"
  function_name = "adaptive-rag-generator"
  role          = aws_iam_role.generator_lambda.arn
  handler       = "index.handler"
  runtime       = "python3.12"
  timeout       = 60
  memory_size   = 1024

  environment {
    variables = {
      HAIKU_MODEL_ID  = "anthropic.claude-3-5-haiku-20241022-v1:0"
      SONNET_MODEL_ID = "anthropic.claude-sonnet-4-6-20260514-v1:0"
      DYNAMODB_TABLE  = aws_dynamodb_table.cache.name
    }
  }
}

# --- DynamoDB: 分類結果キャッシュ ---
resource "aws_dynamodb_table" "cache" {
  name         = "adaptive-rag-cache"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "query_hash"

  attribute {
    name = "query_hash"
    type = "S"
  }

  ttl {
    attribute_name = "expire_at"
    enabled        = true
  }
}

運用・監視設定

CloudWatch Logs Insights: 複雑度クラス別の分布分析

1
2
3
4
5
fields @timestamp, complexity_class, strategy, latency_ms, token_count
| stats count(*) as request_count,
        avg(latency_ms) as avg_latency,
        avg(token_count) as avg_tokens
  by complexity_class, bin(1h)

コスト異常検知: Class C(反復検索)の比率監視

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import boto3

cloudwatch = boto3.client('cloudwatch')

cloudwatch.put_metric_alarm(
    AlarmName='adaptive-rag-class-c-ratio',
    ComparisonOperator='GreaterThanThreshold',
    EvaluationPeriods=2,
    MetricName='ClassCRatio',
    Namespace='AdaptiveRAG',
    Period=3600,
    Statistic='Average',
    Threshold=0.5,
    AlarmDescription='Class C(反復検索)の比率が50%超過。分類器の再訓練を検討'
)

コスト最適化チェックリスト

  • 分類器をLambda Edge/CloudFront Functionsに配置(レイテンシ最小化)
  • Class A→Haiku, Class B→Sonnet, Class C→Sonnetのモデル使い分け
  • Class A応答のキャッシュ(DynamoDB TTL 24h)
  • Bedrock Batch API: Class C非リアルタイム処理に50%割引適用
  • Prompt Caching: システムプロンプト固定で30-90%削減
  • 分類器モデルをLambda Layer化(Cold Start最小化)
  • 分類結果の統計をCloudWatch Custom Metricsに送信
  • Class C比率のアラーム設定(分類器劣化の早期検知)
  • AWS Budgets: 月額予算設定
  • 日次コストレポート: SNS通知
  • 分類器の定期再訓練パイプライン(月次推奨)

実験結果(Results)

著者らは6種のQAデータセットで評価を行っている。

ベンチマーク結果:

データセットカテゴリIterative RAG (常時)Adaptive-RAG備考
HotpotQAmulti-hopベースライン同等Class C判定で反復検索
MuSiQuemulti-hopベースライン同等Class C判定で反復検索
2WikiMultiHopQAmulti-hopベースライン同等Class C判定で反復検索
Natural Questionsopen-domainベースライン同等以上Class A/Bで高速化
TriviaQAopen-domainベースライン同等以上Class A判定が多数
SQuADsingle-hopベースライン同等以上Class Bで十分

(出典: 論文Section Experimental Results)

著者らの報告による主要な知見は以下の通りである。

  1. 分類器精度: 75-85%の精度で最適な戦略を選択。多様なクエリ複雑度を持つデータセットで効果が最大化される
  2. コスト削減: 常に反復的検索を使う場合と比較して、API呼び出し回数とレイテンシが大幅に削減
  3. 品質維持: multi-hopベンチマークでもIterative RAG常時使用と同等の精度を維持
  4. アブレーション: 分類器を除去するとランダム戦略選択となり性能が劣化。分類器ベースのルーティングが効率-品質バランスに不可欠

制約: 分類器の精度が全体性能の上限を決定する。また、ターゲットLLMへのアクセスなしにはラベル生成ができないため、LLMの変更時に分類器の再訓練が必要となる。

実運用への応用(Practical Applications)

Adaptive-RAGのクエリ複雑度に基づく戦略選択は、Zenn記事のeffortルーティングと組み合わせることで、検索と推論の両レイヤーでのコスト最適化を実現できる。

プロダクション視点での適用:

  • 社内FAQ: 多くのクエリがClass A/Bに分類され、Iterative RAGの計算コストを回避
  • カスタマーサポート: 製品仕様の確認(Class A)、トラブルシューティング(Class B/C)を自動分類
  • リサーチツール: 論文検索はClass C(multi-hop推論必須)、著者検索はClass A

運用上の注意: 分類器のドリフト(時間とともに精度が低下する現象)に対して、定期的な再訓練パイプラインの構築が推奨される。

関連研究(Related Work)

  • Self-RAG (Asai et al., 2023, arXiv:2310.11511): 反省トークンで検索の要否を自己判断するアプローチ。Adaptive-RAGは明示的な分類器で戦略を選択する点が異なる
  • CRAG (Yan et al., 2024, arXiv:2401.15884): 検索結果の品質を評価して修正する手法。Adaptive-RAGは事前にクエリ複雑度を判定する点で補完的
  • MARA (Singh et al., 2025, arXiv:2504.04603): LangGraphベースのマルチエージェントRAG。Adaptive-RAGのルーティング概念をTriage Agentとして実装している

まとめと今後の展望

Adaptive-RAGは、クエリ複雑度に基づくRAG戦略の適応的選択が、精度維持とコスト削減を両立できることを実証した論文である。弱教師ありによる分類器訓練手法は、人手のアノテーションなしでターゲットLLMに最適化されたラベルを生成する点で実用的である。

Zenn記事のeffortパラメータ("low" / "medium" / "high")による推論深度制御は、Adaptive-RAGの検索戦略選択と概念的に同一の最適化を推論レイヤーで実現するものと位置付けられる。両者を組み合わせた二重最適化は、プロダクション環境でのコスト効率を大きく向上させる可能性がある。

参考文献


:::message 本記事はAI(Claude Code)により自動生成されました。内容は論文に基づいていますが、実際の利用時は原論文もご確認ください。 :::

この投稿は CC BY 4.0 でライセンスされています。