📃

RAGのRetrieve戦略 — Adaptive RAGの変遷

に公開

Adaptive RAGとは

Adaptive RAG(または Adaptive Retrieval)は、retrieve するタイミング・回数・戦略をクエリやモデル状態に応じて動的に変えるRAG手法群を指す総称です。

素朴なSingle-step RAGが抱える構造的な問題に対応するための手法です。

Skill-RAG という論文で「検索がうまくいかなかった時に、失敗の原因を見分けて対処を切り替える」という新しいRAGのretrieve戦略が提案されていて、そもそも今までどんな手法があったのかと気になり、SKR / FLARE / DRAGIN / Self-RAG / CRAG / Adaptive-RAG / Speculative RAG / Probing-RAG / Skill-RAG を一通り調べてみました。本記事はその簡単なまとめになります。


Single-step RAGで出てくる問題

Single-step RAGは「クエリが来たら1回retrieveして文書を詰めて生成する」というシンプルな設計ですが、以下のような状況で詰まります。

  • モデルが既に知っていることまでretrieveする → コンテキスト汚染・コスト増
  • 1回では足りない(multi-hop QAなど) → 情報不足で答えられない
  • 取ってきた文書が低品質 → ノイズで生成品質が下がる
  • クエリと文書の意図がズレている → そもそも関係ない文書が返ってくる

Adaptive RAG の定義

これらに対して、Adaptive RAGは 「retrieveの挙動を固定しない」 方向で解決を図る手法群です。具体的には、以下のいずれか(または複数)を動的に決めます。

Query ─▶ retrieve ─▶ docs ─▶ generate ─▶ Answer
         │   │  │     │
         │   │  │     └─ ⑤ そのまま/補正  (CRAG, Skill-RAG)
         │   │  └─────── ③ いつ          (FLARE, DRAGIN)
         │   │           ④ 戦略          (Adaptive-RAG)
         │   └────────── ② 回数          (IRCoT, Iter-RetGen)
         └────────────── ① する/しない    (SKR, Self-RAG, Probing-RAG)

判断シグナルは手法ごとに違って、logprob・classifier出力・モデル自身のspecial token・hidden state など様々です。

類義の呼称

カテゴリを指す言葉として、以下も同義で使われます。

  • Active Retrieval(FLAREの命名)
  • Dynamic RAG(DRAGINの命名)
  • Selective Retrieval(retrieve要否の二値判定に絞った狭義の呼称)

変遷マップ

先にマップを貼っておきます。この記事の全体像です。

2020  Single-step RAG         "1回だけretrieve"

2023  IRCoT / Iter-RetGen     "反復retrieve"
2023  SKR                     "分類器でretrieve要否判定"
2023  FLARE                   "logprobが下がったらretrieve"

2024  DRAGIN                  "attentionとentropyで判定"
2024  Self-RAG                "モデル自身がretrieve判断"
2024  Adaptive-RAG            "クエリ複雑度で戦略分岐"
2024  CRAG                    "検索結果を評価して修正"
2024  Speculative RAG         "draft→verifyで分業"

2025  Probing-RAG             "hidden stateでretrieve判断"

2026  Skill-RAG               "失敗を診断して修正スキル適用"

さきほどの定義にあった「何を動的に決めるか」「何をシグナルにするか」は多様であることが見えます。


2020: Single-step RAG — RAGの始まり

"Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks" (Lewis et al., NeurIPS 2020)
https://arxiv.org/abs/2005.11401

Query → Retrieve (1回) → Generate

私たちが普段「RAG」と呼んでいるのはこれです

ここではまだ「retrieveするかどうか」「何回retrieveするか」という問題は考えてません。常に1回retrieveして、出てきた文書を全部コンテキストに入れて生成します。

この素朴さに対するツッコミが、以降の手法に繋がっていきます。

  • そもそもretrieveは本当に必要?(モデルが既に知ってるかも)
  • 1回で足りなかったらどうする?
  • 取ってきた文書が的外れだったら?

2023: 反復retrieval系 — 「1回で足りない」問題

IRCoT (ACL 2023)

"Interleaving Retrieval with Chain-of-Thought Reasoning for Knowledge-Intensive Multi-Step Questions"
https://aclanthology.org/2023.acl-long.557/

CoTの各ステップごとにretrieveする手法です。

Q: "Xの出身大学の創設者の国籍は?"
  → Step 1: Xの出身大学を調べる (retrieve)
  → Step 2: 創設者を調べる (retrieve)
  → Step 3: 国籍を調べる (retrieve)
  → Answer

実装はfew-shot promptingで例示するだけで学習不要。プロンプトだけで実装できます。


Iter-RetGen (EMNLP 2023 Findings)

IRCoTをより単純にしたもので、前回の生成結果を次のクエリに連結してN回反復します。学習なし、これもプロンプトだけで動きます。

Q: "Xの出身大学の創設者の国籍は?"
  → Round 1: retrieve(Q)              → 生成1 ("XはY大学出身")
  → Round 2: retrieve(Q + 生成1)      → 生成2 ("Y大学の創設者はZ")
  → Round 3: retrieve(Q + 生成2)      → 生成3 ("ZはW国籍")
  → Answer

IRCoTがCoTステップごとにサブクエリを切り替えるのに対し、Iter-RetGenは元クエリ + 直前の生成結果を毎回連結するだけ。サブクエリへの分解はせず、生成結果がクエリのコンテキストを徐々に補強していくイメージです。

2023: SKR — Adaptive RAG系の源流

"Self-Knowledge Guided Retrieval Augmentation for Large Language Models" (EMNLP 2023 Findings)
https://aclanthology.org/2023.findings-emnlp.691/

「モデルが既に知っているなら retrieve しない」という発想を形にした論文です。

判定の仕組みはシンプルで、「過去にLLMが解けた / 解けなかった質問」をたくさんストックしておいて、新しい質問が来たら似た質問を探して真似するだけです。

事前準備: 過去の質問を大量にストック
  ├─ LLM単体で解けた質問     → "Known" タグを付ける
  └─ retrieveしないと解けない質問 → "Unknown" タグを付ける

本番:
  新しいQuery → ストックから似た質問を数件探す

              似た質問のタグを多数決

                ├─ [Known]   → retrieveしない
                └─ [Unknown] → retrieve

「似た質問を探す」のは文の埋め込みベクトルで類似度を測るだけで、追加の学習はいりません。

過去の質問プールに付けるKnown/Unknownラベルは、**「retrieveしてもしなくても性能が変わらない/なしの方が良い問題 → Known、retrieveで改善する問題 → Unknown」**という比較で機械的に作ります。人手を介さず自動生成した(ノイズはあるが大量に集まる)ラベルを silver label と呼びます(人手のgold labelに対する呼称)。

Adaptive-RAGの「各戦略で解けたかで3値ラベル付けする」発想の原型がここにあります。SKRが2値(Known/Unknown)なのに対し、Adaptive-RAGは3値(Simple/Mid/Complex)となっています。

2023: FLARE — 「いつ」を信頼度で決める

"Active Retrieval Augmented Generation" (EMNLP 2023)
https://aclanthology.org/2023.emnlp-main.495/

IRCoTの問題意識は**「毎ステップ必ずretrieveは無駄」** ということでした。FLAREは「信頼度が下がった時だけretrieve」する手法です。

次の文を仮生成 → 各tokenのlogprobで信頼度をチェック:

  仮の次文ŝ_t → 全tokenの生成確率を観測

  どこかのtoken logprob < 閾値 ?
    ├─ Yes (モデルが迷っている) → ŝ_t の低信頼tokenをマスク or 質問生成でクエリ化
    │                            → retrieve → 次文を再生成
    └─ No  (信頼度OK)            → ŝ_t をそのまま採用して生成を続ける

token-level logprob(各トークンの生成確率)を見て、閾値を下回ったら「モデルが迷ってる」と判断してretrieveします。

この設計はシンプルで強そうに見えますが、後の評価で再現性の問題が指摘されます(後述)。

2024: DRAGIN — 多シグナルでtimingとqueryを決める

"DRAGIN: Dynamic Retrieval Augmented Generation based on the Real-time Information Needs of Large Language Models" (ACL 2024 Long, Oral)
https://arxiv.org/abs/2403.10081

FLAREは「いつretrieveするか」をlogprob1つで決めていました。DRAGINはここを掘り下げて、

  • いつretrieveするか を複数のシグナルを組み合わせて判定する仕組み(RIND)
  • 何をクエリにするか をモデルのattentionから組み立てる仕組み(QFS)

の2つに分けてアップグレードしました。

RIND — timingの多シグナル判定

RINDは3つのシグナルを組み合わせてretrieveタイミングを決めます。

生成中の各tokenについて、3つのシグナルを掛け合わせて判定:

  entropy   (不確実性:   次tokenの予測がブレているか)
       ×
  attention (重要性:     そのtokenが後続生成でどれだけ参照されたか)
       ×
  semantics (stopword除外: stopwordなら 0、それ以外なら 1)

  積 > 閾値 ?
    ├─ Yes → attentionが集中しているtokenからクエリを構成 → retrieve → 生成し直し
    └─ No  → そのまま生成を続ける

entropyとattentionは別の対象を測っています。

  • entropy: 「モデルが次のtokenを出すとき、どれくらい候補がバラついて迷っているか」を見る。迷い度のシグナル。
  • attention: 「そのtokenが、後で続きを生成するときにどれくらい振り返られているか」を見る。重要度のシグナル。
  • semantics: stopword(is, the など)を弾いて、内容語のみを判定対象にする二値フィルタ。

同じくモデル内部の値ですが、片方はモデルの「迷い」、もう片方はそのtokenの「重要度」を測っているので、別物として組み合わせることでretrieveすべき箇所をより正確に掴もうとしています。

QFS — attentionでクエリを組む

タイミングが決まったら、クエリは前後テキストから作るのではなく、self-attentionが集中しているトークンから構成します。「今モデルが何を気にしているか」をattentionから直接読みとる設計です。

生成中のコンテキスト: "XはY大学出身で、その大学の創設者は..."
                                        ↑ ここでretrieveが発動したとする

  各tokenのattention weightを観測:
    ├─ "Y大学"     → attention 大
    ├─ "創設者"    → attention 大
    ├─ "出身"      → attention 小
    └─ "は", "で"  → attention 小

  attentionが集中している上位tokenを集めてクエリ化:
    → query = "Y大学 創設者"
    → retrieve(query)

前後テキストを丸ごとクエリにすると無関係な語が混じりますが、attentionで「今モデルが見ている語」を抜き出すことでクエリの精度を上げる、というアイデアです。

FLAREがlogprob1本で判定していたのに対し、DRAGINはentropy × attention × semanticsの積で判定する。判定ノイズを減らすという思想です。

ただしattention weightを返す商用APIは存在せず、localLLMでしか実装できません。FLAREとDRAGINは「モデル内部シグナルに閾値を引く」手法で、商用APIで実装できないという制約があります。後のProbing-RAG/Skill-RAGも同じ制約があります。

2024: Self-RAG — モデル自身がretrieve判断

"Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection" (ICLR 2024)
https://arxiv.org/abs/2310.11511

モデル自身がretrieve判断用のspecial tokenを出す ようにfine-tuneします。

Q: 日本の首都は?
→ [Retrieve: No] 東京 [IsUse: utility:5]

Q: 2024年のオリンピックの金メダル数は?
→ [Retrieve: Yes] <docs> 日本は20個... [IsRel: relevant] [IsSup: fully supported]

[Retrieve] [IsRel] [IsSup] [IsUse] という4種類のreflection tokenをGPT-4で生成したデータでSFTします。

retrieveするかどうかもモデルが判断する点が新しいところで、Single-step RAGが無条件にretrieveしていたのを、Self-RAGでは「retrieveすべきか先に決めてから実行する」形に変えています。

ただしメインLLMを自分でfine-tuneする必要があり、そもそもの学習コストが高いです。

2024: Adaptive-RAG — クエリ複雑度で戦略分岐

"Adaptive-RAG: Learning to Adapt Retrieval-Augmented Large Language Models through Question Complexity" (NAACL 2024)
https://aclanthology.org/2024.naacl-long.389/

クエリの複雑度を分類器で判定して、retrieval戦略を分岐させる手法です。

Query → Complexity Classifier (T5-Large)
  ├─ [Simple]    → No retrieval (モデルが知ってる)
  ├─ [Mid]       → Single-step RAG
  └─ [Complex]   → Multi-step RAG (IRCoT)

silver labelは、「各戦略で正解できたか」を自動ラベル付け します。no retrievalで解けた問題は「Simple」、single-stepで初めて解けたら「Mid」、みたいな感じです。

メインLLMはfrozen(学習させない)でOKなのでGPT-4やClaudeのようなAPIモデルでも使うことができます。

2024: CRAG — 検索結果の品質を評価して修正

"Corrective Retrieval Augmented Generation" (2024)
https://arxiv.org/abs/2401.15884

こっちの着眼点は 「retrieveしたけど取ってきた文書が低品質だったらどうする?」 です。

Query → Retrieve → Evaluator
  ├─ [Correct]     → 関連部分だけ抜き出して使う
  ├─ [Ambiguous]   → 関連部分の抽出 + web検索で補完
  └─ [Incorrect]   → web検索にfallback

仕組みとしては、「取ってきた文書が使えるか判定する小さなモデル」を別に学習させて、クエリと取ってきた文書のペアを 「使える / 怪しい / 使えない」 の3段階で判定します。

  • 使える → 文書を細かい断片に分割し、関連スコアでフィルタしてから渡す(refinement)
  • 怪しい → refineした内部文書 + web検索の結果を併用
  • 使えない → 元の文書を捨てて、web検索の結果に切り替える

ただし注意点として、CRAGの評価器が学習しているのは「クエリと文書のトピック的な一致」だけです。文書が古い・事実が間違っている・他文書と矛盾している、といった内容の正しさは判定できません。明らかにズレた文書を弾く フィルタとしては有効ですが、古い社内ドキュメント のような単に情報が古くて使えないというケースまでは弾けません。

2024: Speculative RAG — draft→verifyで分業する

"Speculative RAG: Enhancing Retrieval Augmented Generation through Drafting" (Google, ICLR 2025)
https://arxiv.org/abs/2407.08223

ここまでの手法が全部「いつ retrieve するか」の話だったのに対し、Speculative RAGはアプローチが異なります。retrieveは必ずやる前提で、生成側を2段階に分業するアプローチです。

Query + Retrieved docs
  → Small LLM (specialist) が複数drafts生成
  → Large LLM (generalist) がverify + best選択
  → Answer

小さなモデルはretrieval-augmented生成に特化してfine-tune、大きなモデルは検証だけに徹っします。役割を明確に分けることでレイテンシを下げつつ精度を上げるという手法です。

補足:LLM推論には speculative decoding という、軽量モデルに下書きを書かせて、大きなモデルがそれを検証することで生成速度を稼ぐテクニックがあり、この考え方をRAGに適用したものです。

内部状態系(Probing-RAG / Skill-RAG)が「判定の精度を上げる」方向だとすると、Speculative RAGは「retrieveは固定して生成制度を上げる」という思想です。

2025: Probing-RAG — 内部状態を使う

"Probing-RAG: Self-Probing to Guide Language Models in Selective Document Retrieval" (Baek et al., NAACL 2025 Findings)
https://arxiv.org/abs/2410.13339

Probing-RAGは、LLMの中間層の隠れ状態(入力をモデルに通したときに各層が一時的に持つ計算途中の数値)を、別の小さな分類器に渡して「retrieveすべきかどうか」を判定する 手法です。

ざっくり言うと、LLMに 「retrieveが必要?」と聞く のではなく、LLMの頭の中を直接見ることで判定する、という発想です。

Query → LLMにCoTで仮の答えを生成させる (rationale r + answer â)

        r と â の hidden state を中間層から抽出

        小さな分類器(probe)にかける

        retrieveが必要?
          ├─ Yes → retrieve → 文書を加えて再度 r/â 生成 → 再 probe(反復)
          └─ No  → その答えを採用

probeは1隠れ層の極小モデル(メインLLMより遥かに軽量)で、メインのLLMは触らずそのまま使えます。

今までになかった、「モデルが本当に知っているか」をモデルの外側から検出しようとする発送です。

Self-RAGは「モデルに聞けば分かる」前提でtoken生成させていましたが、Probing-RAGは 「モデルは自分で正確に『知らない』と言えないかもしれない」 という仮定で、外から観測しています。

ただし、これもhidden stateをが見れないと実装できないので、一般的な商用APIモデルに実装することはできません。

2026: Skill-RAG — typed correction

"Skill-RAG: Failure-State-Aware Retrieval Augmentation via Hidden-State Probing and Skill Routing"
https://arxiv.org/abs/2604.15771

ここまでの手法は「retrieveするかしないか」の二値判断が基本でした。Skill-RAGはこれを拡張して、失敗したときに何で直すかまで考えます。

Query → Retrieve → Probe → Skill Router で失敗タイプごとに修正:
  ├─ クエリと文書がズレている    → クエリを書き直す
  ├─ 質問に複数の前提が絡んでいる → サブ質問に分解する
  ├─ クエリが広すぎる            → 関連箇所だけに絞り込む
  └─ そもそも答えられない         → retrieveを中断する

失敗のタイプを4つに分類して、それぞれに対応する修正スキルをルーティングします。

この論文で個人的に面白かったのが、失敗したときのLLMの内部の数値を2次元に可視化してみたら、失敗のタイプごとにきれいにグループ化できた というものです。

要するに、retrieveが失敗するときはランダムに失敗しているのではなく、失敗にはある程度の規則性があるということで、そのため4種類のスキルで分類してルーティングできるようです。

実装可否マトリクス

最後にここまで見てきた手法を実際にどこで動くかまとめたいと思います。

手法 Claude API OpenAI API local LLM 学習必要?
Single-step RAG
IRCoT
Iter-RetGen
SKR
FLARE ❌ (logprob無)
DRAGIN ❌ (attention無) △ (eager attentionモードが必要)
Self-RAG ❌ (SFT必要) ✅ (メインLLM)
Adaptive-RAG ✅ (分類器のみ)
CRAG ✅ (評価器のみ)
Speculative RAG ❌ (logprob無) △ (verifyのみ可) ✅ (draft LLM)
Probing-RAG ❌ (hidden state無) ✅ (probeのみ)
Skill-RAG ❌ (hidden state無) ✅ (probeのみ)

logprobについては、OpenAI API のように返してくれるモデルもあるので、FLARE のようにlogprobだけを使う手法は商用APIでも実装できます。一方で、attention weight や hidden state といったより詳細な内部ステータスを返す商用APIは現状存在しないため、DRAGIN・Probing-RAG・Skill-RAG のようなモデルの内部を見るタイプの手法は、自前でホスティングしたローカルLLM(HuggingFace transformers / vLLM など)に限られます。

一方、プロンプトベース・外付けclassifier系(IRCoT、Adaptive-RAG、CRAGなど)は商用APIでも試すことができます。

参考

NCDC テックブログ

Discussion