← シリーズに戻る

ハイブリッド検索 RAGの外れを3分の1に

Part 3 / 9 RAGとは 2017〜2026年の手法9段階

Advanced RAG は、素朴な RAG の「上位k件を取って貼る」の前と後ろに手を足したものです。検索の前に質問を書き換え、検索を BM25 と埋め込みの二本立てにして混ぜ、検索の後に別のモデルで候補の順位をつけ直します (再順位づけ)。素朴な RAG の困りごとは、正解が上位k件に入らないことと、入っても中ほどに置かれると読まれないことでした。前者には二本立てと書き換え、後者には再順位づけが効きます。

効き目の大きさは、Anthropic が2024年9月に自社の評価で段階ごとに出しています。コード・小説・arXiv の論文・科学論文の4つの領域の平均で、上位20件に正解が入らなかった割合 (1 − recall@20) が、埋め込みだけの5.7%から、文脈を足した埋め込みで3.7%、BM25 を併用して2.9%、再順位づけまで足して1.9%。

3分の1です。

ただしどの手をどの順で回すかはまだ人が決めた手順なので、簡単な質問にも難しい質問にも毎回同じ書き換えと同じ再順位づけがかかります。この「毎回同じ」を崩すのが、次の段階の自分で判断する RAG です。

日本語ではもう1つ事情が加わります。BM25 が単語の区切り方に左右され、再順位づけのモデルは国産のものが強い。JQaRA という日本語の評価では、BM25 の0.458に対して日本語の再順位づけのモデルが0.7712でした。

困りごと: 上位k件では外れる、中ほどが読まれない

素朴な RAG の外れ方のうち Advanced RAG が狙ったのは2つです。

1つ目は正解が上位k件に入らないこと。

私は rag-retriever-bench で、MIRACL の日本語版10万段落に OpenAI の text-embedding-3-small を使って測りました。全段落と比べる全件走査でも、上位10件の再現率は0.952でした。正解の約5%は、ベクトルデータベースをどう選んでも上位10件に入りません。埋め込み1本の限界です。型番の一致や否定のように埋め込みが苦手な質問ではもっと落ちるはずですが、これは私の推論で、質問の種類ごとには測っていません。

2つ目は入っても読まれないこと。Lost in the Middle の実験では、答えの書いてある文書を20件中10番目に置くと GPT-3.5-Turbo の正解率は53.8%で、文書を渡さないとき (56.1%) より下がりました (詳しくはベクトルデータベース7種を実測 素朴なRAG)。

上位k件の k を増やせば1つ目は減りますが、2つ目が悪化します。

だから k を増やさずに正解を上位に入れ、しかも上に置く工夫が要りました。

Gao らの3分類: Naive・Advanced・Modular

名前の出どころは2023年12月の Gao らのサーベイ論文です (arXiv:2312.10997)。RAG の研究を3段階に分類しました。

  • Naive RAG: 索引・検索・生成の3工程だけ。このシリーズの「素朴な RAG」です
  • Advanced RAG: 検索の前 (pre-retrieval) と後 (post-retrieval) に処理を足す。前はクエリの書き換えや展開、後は再順位づけや文脈の圧縮
  • Modular RAG: 部品をモジュールとして組み替える。検索を繰り返す、条件で分岐する、といった流れも含む

Modular RAG の側は、2024年7月の別の論文が、部品のつなぎ方を線形・条件・分岐・ループの4つの型に整理しています (arXiv:2407.21059)。このうち条件とループは、次の段階の「自分で判断する RAG」につながる話です。この章では、線形のまま前後に手を足す Advanced RAG を扱います。

この章の手3で扱う Rewrite-Retrieve-Read・HyDE・RAG-Fusion は Gao らの論文では Modular RAG の側に例として挙がっていますが、手順を固定したまま検索の前に足せる手なので、この章では Advanced RAG の側でまとめて扱います。

Gao らの3分類の図。Naive RAG は索引、検索、生成の3工程だけ。Advanced RAG は検索の前にクエリの書き換えや展開、検索に BM25 と埋め込みの二本立てと RRF での統合、検索の後に再順位づけと文脈の圧縮を足す。工程の順は固定で、毎回同じ処理が走る。Modular RAG は部品を組み替え、線形・条件・分岐・ループの4つの型でつなぐ。条件とループは次の段階の自分で判断する RAG へつながる。Gao らは Rewrite-Retrieve-Read・HyDE・RAG-Fusion を Modular RAG の例に挙げている。出典は arXiv.10997 と arXiv.21059

手1: BM25 と埋め込みを両方使う

BM25 は、このシリーズの第1章「原論文 2017〜22年」で出てきた、語の重なりで点数をつける古典的な検索です。DPR はこれに平均で勝ちましたが、語の一致が決め手になる質問では BM25 が強いままです。「型番 KX-1234 の保証期間」と聞かれたら、KX-1234 という文字列を含むチャンクを引くべきで、意味が近いだけの別の型番のチャンクは外れです。逆に「電源が入らない」と聞かれて「起動しない」と書いた文書を引くのは、埋め込みの仕事です。

そこで両方で検索し、結果を1本の順位に混ぜます。これをハイブリッド検索と呼びます。混ぜ方の定番が RRF (Reciprocal Rank Fusion、逆順位の足し合わせ) で、2009年の SIGIR で Cormack らが出したものです (PDF)。

各文書の点数は、それぞれの検索での順位 r から 1/(60 + r) を計算して足すだけです。60 は論文が使った定数です。BM25 の点数と埋め込みの近さは単位が違うので、そのまま足せません。RRF は順位しか見ないので、単位をそろえる必要がありません。例で計算します。

文書BM25 の順位埋め込みの順位RRF の点数混ぜた順位
C3位2位1/63 + 1/62 = 0.03201位
A1位5位1/61 + 1/65 = 0.03182位
B圏外1位1/61 = 0.01643位

片方で1位でももう片方で圏外の B は3位です。両方の検索がそこそこ上に置いた文書が勝つのが RRF の性格です。

RRF で BM25 と埋め込みの2つの順位を混ぜる図。BM25 の順位は A が1位、D が2位、C が3位。埋め込みの順位は B が1位、C が2位、A が5位。各文書の点数は 1/(60+順位) を足したもので、C は 1/63+1/62=0.0320、A は 1/61+1/65=0.0318、B は 1/61=0.0164。混ぜた順位は C、A、B の順。点数の単位が違う2つの検索を、順位だけで混ぜられる。定数60は Cormack ら (SIGIR 2009)

手2: 並べ直す (再順位づけ、rerank)

検索で集めた候補を、別のもっと精密なモデルで点数づけし直して並べ直すことを、このシリーズでは再順位づけ (rerank) と呼びます。

埋め込み検索 (ベクトル検索) は、質問と文書を別々に数値の並びに変えて比べます。文書側は前もって計算しておけるので速いのですが、質問と文書の細かい対応は見ていません。再順位づけのモデルは、質問と文書を1つに並べて同じモデルに通し、関連の強さを直接出します。この形をクロスエンコーダと呼びます。

2019年1月の monoBERT は、BERT をこの形で使って、MS MARCO の段落検索で従来の最高を MRR@10 (正解が何番目に来たかの逆数の平均) で相対27%上回りました (arXiv:1901.04085)。代わりに、質問が来るたびに候補の数だけモデルを通すので遅く、全文書には使えません。

だから二段構えにします。速い検索 (BM25 や埋め込み) で上位100件ほどを集め、その中だけを再順位づけのモデルで並べ直し、上位k件を LLM に渡します。正解が上に来るので、k を小さくでき、Lost in the Middle の中ほども減ります。

中間の形もあります。2020年4月の ColBERT は、質問と文書を別々に処理しつつ単語ごとの数値の並びを残しておき、最後に単語どうしで細かく照合します。遅い相互作用 (late interaction) です (arXiv:2004.12832、SIGIR 2020)。論文は、BERT で並べ直す方式に近い精度のまま、2桁速いと報告しています。

再順位づけの二段構えの図。左は2つのモデルの形の違いで、埋め込み (バイエンコーダ) は質問と文書を別々に数値の並びにして比べるので文書側を前もって計算でき速いが、細かい対応は見ない。クロスエンコーダは質問と文書を1つに並べて同じモデルに通すので精密だが、候補ごとにモデルを通すので遅い。ColBERT はその間で、単語ごとの数値の並びを残して最後に照合する。右は二段構えの流れで、全文書から速い検索 (BM25・埋め込み) で上位100件ほど、再順位づけのモデルで上位k件にして LLM へ。正解が上に来るので k を小さくでき、中ほどに置かれる文書が減る

手3: 質問のほうを書き換える

ここまでは引いてきたものの扱い方でした。もう1つの方向は、検索に投げる質問そのものを変えることです。利用者の質問文が、検索に向いたクエリとは限りません。最初の手は、それを書き換えることです。2023年5月の Rewrite-Retrieve-Read は、検索の前に LLM に検索用のクエリを書かせます (arXiv:2305.14283、EMNLP 2023)。さらに、書き換えを担う小さなモデルを、答える側の LLM の反応を報酬にして強化学習で鍛えました。答える LLM 本体は固定したままです。第1章「原論文 2017〜22年」の頃は検索器を学習していましたが、ここでは固定した LLM の手前の、小さな部品だけを学習しているのが面白いところです。

HyDE。 2022年12月の HyDE は、質問から LLM に「答えが書いてありそうな仮の文書」を書かせ、その仮の文書の埋め込みで検索します (arXiv:2212.10496)。質問文と文書は書き方が違うので、文書の書き方をした仮の文書のほうが、本物の文書の近くに落ちやすいという考え方です。仮の文書は嘘の細部を含みます。それでも埋め込みに変える段階で細部が落ち、近くにある本物の文書が引ける、と論文は説明しています。

複数のクエリ (RAG-Fusion)。 質問を LLM に何通りかに言い換えさせ、それぞれで検索し、結果を RRF で混ぜます。手1の RRF を、クエリの数だけ回す形です。arXiv の 2402.03367 はよく引かれますが、これは手法の原典ではありません。 Infineon の社員1人が、エンジニア・営業担当・顧客が製品情報を引く用途に当てた適用報告で、論文自身が「新しく広まった RAG-Fusion を評価した」と書いています。評価は人手で、言い換えたクエリが元の質問からずれると、答えが話題から外れることもあったと報告しています。

質問のほうを書き換える3つの手の図。クエリの書き換え (Rewrite-Retrieve-Read、2023年5月) は、質問から検索用のクエリを書き直して検索する。書き換えの小さなモデルだけを強化学習で鍛え、答える LLM は固定。HyDE (2022年12月) は、LLM に答えが書いてありそうな仮の文書を書かせ、その埋め込みで本物の文書を探す。仮の文書の嘘の細部は埋め込みの段階で落ちる。複数のクエリ (RAG-Fusion) は、質問を何通りかに言い換えてそれぞれ検索し RRF で混ぜる。arXiv 2402.03367 は Infineon の適用報告で、手法の原典ではない。言い換えがずれると話題から外れることもあった

Contextual Retrieval: 手を足すごとの効き目

手を重ねるとどれだけ効くのか。2024年9月19日の Anthropic の Contextual Retrieval が、段階ごとの数字を出しています (Anthropic)。

Contextual Retrieval そのものは分割のときの工夫で、チャンクを索引に入れる前に LLM に「このチャンクは文書全体の中で何の話か」を50〜100トークンで書かせ、チャンクの頭に足してから埋め込みと BM25 の索引を作ります。素朴な RAG の外れ方の1つ目、「分割で切れる」への手当てです。物差しは、上位20件に正解のチャンクが入らなかった割合 (1 − 上位20件の再現率) です。文書はコードベース・小説・arXiv の論文・科学論文の4つの領域で、その平均です。埋め込みは Gemini の Text 004、再順位づけは Cohere のモデルでした。

段階取りこぼし減り方
埋め込みだけ5.7%—
文脈を足した埋め込み3.7%35%減
+ 文脈を足した BM252.9%49%減
+ 再順位づけ1.9%67%減

チャンクに文脈を書き足す費用は、文書100万トークンあたり1.02ドルと試算されています (チャンク800トークン、文書8,000トークン、プロンプトキャッシュを使う前提)。

この数字は Anthropic の自社評価で、文書の言語は書かれていません。それにここで重ねた3段階 (文脈を足した埋め込み・文脈を足した BM25・再順位づけ) は、この章の3つの手と同じではありません。書き換えは入っておらず、BM25 も文脈を足したものです。どの段がどの外れ方に効いたかの内訳も出ていないので、ここから言えるのは重ねるほど取りこぼしが減ったところまでです。

Contextual Retrieval の段階ごとの取りこぼしの棒グラフ。上位20件に正解が入らなかった割合で、埋め込みだけ5.7%、チャンクに文脈を足した埋め込み3.7% (35%減)、文脈を足した BM25 を併用して2.9% (49%減)、再順位づけを足して1.9% (67%減)。足すたびに減り、最後は3分の1になる。どの段がどの外れ方に効いたかの内訳は出ていない。コード・小説・arXiv の論文・科学論文の4つの領域の平均での Anthropic の自社評価で、埋め込みは Gemini Text 004、再順位づけは Cohere

まだ人が判断している

ここまでの手はどれも人が決めた手順を毎回同じ順で回します。 書き換えるかどうか、何件取るか、並べ直すかどうかは作った人が設定ファイルで決めているので、挨拶にも答えが1か所に書いてある質問にも同じ処理が走ります。何段も推論が要る質問でも、回す手は変わりません。

簡単な質問には過剰で、難しい質問には足りない。

検索するかどうか、何回検索するかを質問を見て LLM 自身に決めさせる。それが次の段階です。

日本では

日本語で RAG を組むと、英語の記事には出てこない論点が2つあります。

1つ目は、BM25 が単語の区切り方に左右されること。 BM25 は語の一致を数えます。日本語には単語の間の空白がありません。MeCab や Sudachi のような形態素解析で単語に切るか、文字を2つずつ切る n-gram にするかで、何が「一致」になるかが変わります。表記ゆれ (「サーバー」と「サーバ」) を同じ語とみなすかも、解析器の辞書と正規化の設定次第です。手1のハイブリッド検索は、日本語ではまず BM25 の側の作り込みが要ります。

日本語の BM25 で、区切り方によって一致が変わる例の図。文書「東京都庁の窓口」を2文字ずつ切る bigram にすると、東京・京都・都庁・庁の・の窓・窓口になり、質問「京都の観光案内」の「京都」と一致してしまう。辞書が要らず未知語に強いが、こうした誤一致が混ざる。形態素解析 (MeCab・Sudachi など) で単語に切ると東京・都庁・の・窓口になり、京都とは一致しない。代わりに区切り方は辞書次第で、表記ゆれをまとめるかも設定で変わる。形態素解析の区切りは説明用の例

2つ目は、埋め込みと再順位づけのモデルを、国産で選べるようになったこと。 日本語の検索の評価に、hotchpotch さんが2024年3月に公開した JQaRA があります (Hugging Face)。第1章「原論文 2017〜22年」で出てきた AI王 (JAQKET) の質問に、1問あたり100件の候補段落を付け、正解の段落を上位に並べられるかを nDCG@10 (上位10件の並びの良さ。正解が上にあるほど高い) で測ります。

方式モデルnDCG@10
BM25—0.458
埋め込み (多言語)bge-m30.539
埋め込み (多言語)multilingual-e5-large0.554
埋め込み (国産)GLuCoSE-base-ja-v20.606
埋め込み (国産)ruri-large0.6287
疎ベクトル (国産)japanese-splade-base-v10.6441
再順位づけjapanese-reranker-cross-encoder-large-v10.71
再順位づけruri-reranker-large0.7712

並びはこの章の3つの手の効き方と同じ向きです。BM25 より埋め込み、多言語より国産、そして再順位づけが一段上です。ただし JQaRA の候補100件は埋め込みの類似度で集められているので、BM25 には少し不利な条件かもしれません。これは私の推論で、確かめてはいません。

埋め込みの総合評価 JMTEB の検索の項目では、名古屋大学の ruri-v3-310m が81.89で、小さい ruri-v3-130m も同じ81.89です。OpenAI の text-embedding-3-large は74.48、text-embedding-3-small は66.39でした (cl-nagoya/ruri-v3-310m、Ruri の技術報告は arXiv:2409.07737)。私が rag-retriever-bench で使ったのは、この表でいちばん低い text-embedding-3-small でした。素朴な RAG で見た「上限0.952」は、埋め込みを国産に替えれば上がる余地があります。ここもまだ測っていません。

業務の文書での例もあります。弥生と筑波大学は2025年の言語処理学会で、弥生の会計の解説ページ2,454件を検索の対象にした結果を報告しています (NLP2025 E7-4)。質問は、記事をもとに GPT-4o に作らせたものです。埋め込み検索 (FAISS、埋め込みは ruri-large) で引いた上位5件を Google の LLM (Gemini 1.5 Pro) に並べ直させると、「経理お役立ち情報」の質問260問で、1位の正答率が74.23から86.15に上がりました。

この86.15は順位をつけた理由も書かせる (CoT) 形での値で、理由を書かせないと81.54でした。ほかの2つの質問セットでは、CoT ありで60.53→72.63と72.39→78.62です。CoT なしだと後者は72.22で、並べ直す前をわずかに下回りました。専用の再順位づけモデルでなく、LLM そのものに並べ直させた例です。書かせ方でも効き目が変わります。

JQaRA の nDCG@10 の横棒グラフ。BM25 0.458、多言語の埋め込み bge-m3 0.539 と multilingual-e5-large 0.554、国産の埋め込み GLuCoSE-base-ja-v2 0.606 と ruri-large 0.6287、国産の疎ベクトル japanese-splade-base-v1 0.6441、再順位づけ japanese-reranker-cross-encoder-large-v1 0.71 と ruri-reranker-large 0.7712。BM25 より埋め込み、多言語より国産、再順位づけが一段上。AI王 (JAQKET) の質問に候補100件を並べ直す評価で、候補は埋め込みの類似度で集められている。数値は JQaRA の公開ページから

次に読む

検索するかどうかや何回検索するかを質問ごとに LLM に決めさせる段階は、Self-RAGとCRAG 検索を判断する7手法で扱います。手順を決める役が、人から LLM に移り始めるところです。

ナレッジグラフ活用大全 関連書籍 ナレッジグラフ活用大全 ナレッジグラフ 活用大全 | GraphRAG・Neo4j・RDF・Property Graph・Emotion AI の実践書 書籍ページを見る →