社内の規程や製品資料について生成AIに質問しても、その資料を学習していなければ、根拠のある回答は返ってきません。資料を質問文へ毎回貼り付ける手もあります。ただし文書が増えるほど、どの部分を渡すかを人が選び続けることになります。

この「回答に必要な資料を選ぶ」工程を検索で補うのがRAG(Retrieval-Augmented Generation、検索拡張生成)です。質問を受けてから関係する文書を探し、見つけた内容を質問と一緒にLLM(大規模言語モデル。文章を受け取って続きの文章を生成するモデル)へ渡します。モデルを再学習しなくても、外部の情報を回答の材料にできます。

ただし、RAGを足しただけで回答が正確になるわけではありません。精度を考えるうえで、「検索」と「生成」の二分は粗すぎます。この記事では、文書を検索できる形にする準備から回答を返すまでを4段階に分けます。何を入力し、どこで失敗し、次に何を確かめるか。この粒度なら見えるようになります。

先に結論

  • RAGは、質問に関係する外部文書を探し、その内容をLLMへ渡して回答を作る仕組み
  • 社内文書や更新される情報を回答へ反映しやすいが、検索した文書が正しいことや、LLMが根拠どおりに答えることまでは保証しない
  • 精度が低いときは、文書の分割、検索、並べ替え、回答生成のどこで失敗したかを分けて調べる

この記事の前提知識

ベクトル検索を知らなくても読めます。ただし以降の説明は、文書を細かく切った断片を単位に進みます。この断片の呼び名から入ります。

  • チャンク: 検索できるように文書を短く切り分けた断片です。多くの構成では、RAGが探しているのは文書全体ではなく、この断片になります。
  • 埋め込みモデル: 文章を数値の並び(ベクトル)へ置き換えるモデルです。使われている語が違っても、意味が近ければ数値も近くなります。

この記事では工程を、文書の分割、検索、並べ替え、回答生成の4つで呼び分けます。実装の解説では、検索を一次検索、並べ替えをリランカー(候補を並べ直す別のモデル)と呼ぶこともあります。

RAGは、文書の分割・検索・並べ替え・回答生成の順に動く

通常のLLMは、質問と指示を入力として文章を生成します。RAGではその前に検索処理を置き、質問に関係する文書を入力へ追加します。2020年に発表された原論文では、モデル内部に持つ知識と、検索で参照する外部の知識を組み合わせる枠組みとして提案されました。現在のRAG実装にはさまざまな構成がありますが、「外部情報を検索し、その結果を使って生成する」という中心は共通しています。

ユーザーの質問を受けたRAGが関連文書を検索し、質問と根拠をLLMへ渡して回答と参照元を返す流れ。
図1: RAGが検索と生成を組み合わせて回答する流れ

追いかける場面を1つ決めておきます。社内の就業規則を検索対象に、「有給休暇の申請は何日前までか」と質問する場面です。以下は仕組みを説明するための架空の例で、実測ではありません。

最初の工程は、質問が届く前に済ませておきます。PDFやHTMLなどから取り出した本文をチャンクへ分け、文書名や見出し、元の位置といった情報を紐付けて保存する。ここまでが分割です。意味検索を使う構成では、さらに各チャンクを埋め込みモデルで数値ベクトルへ変換し、質問との近さを比較できる状態でベクトルDBなどの索引へ登録しておきます。就業規則なら、「休暇」の章がここでいくつかの断片に分かれます。申請期限を書いた一文と、その条件を書いた一文が同じ断片に残るかどうかは、この時点で決まります。

質問が届くと、その内容に関連するチャンクを索引から探します。探し方は大きく2つです。質問と同じ語句を含む断片を拾うのがキーワード検索で、順位づけにはBM25という計算方法が広く使われます。埋め込みモデルで質問と断片の意味の近さを比べるのが意味検索、別名dense検索。規則に「申請期限」とそのまま書いてあれば、キーワード検索で見つかります。「休暇を取る日より前に申し出る」のように質問と表現が異なると、キーワード検索では見つけにくくなることがあります。意味検索はこうした場合を補えることがありますが、正解を保証するわけではありません。両方を走らせて順位を混ぜ、候補を作る構成もあります。これをハイブリッド検索と呼び、混ぜ方は次の並べ替えの工程で扱います。

集めた候補の並び順をさらに調整したい場合は、リランカーに候補と質問の組を読ませて、関連度を計算し直します。

検索を終えたら、上位のチャンクを質問や回答時の指示とともにLLMへ入力し、その内容に基づく文章を生成させます。「休暇」の章の断片が上位に入っていても、利用者へ返るのはその断片ではありません。申請期限を答えた一文です。適切なチャンクが上位に入ったかという検索側の評価と、根拠どおりに答えたかという生成側の評価は、分けて考える必要があります。

できるのは材料を加えることまでで、その正しさは検査しない

RAGを使うと、LLMの学習時に含まれていない情報を質問のたびに外部から取り出せます。社内文書のような非公開情報。更新が続く手順書。どちらも検索対象を差し替えるだけで、モデルを再学習せずに次の質問から参照候補へ加えられます。回答に文書名や該当箇所を添えておけば、利用者が根拠へ戻って確かめられます。

もっとも、RAGは情報源そのものの正しさを検査しません。古い文書や互いに矛盾する文書を索引へ入れれば、それらも区別なく検索候補になります。LLMへ渡った後も同じです。一部の記述が読み落とされたり、別々の内容が誤って結び付けられたりする可能性は残ります。つまり外部文書は、事実でない内容をもっともらしく答えてしまう現象(ハルシネーション)を抑える材料にはなっても、回答の正しさを保証するものではありません。

精度が落ちる場所は4段階に分けて調べる

どの段階で失敗したかによって、直す場所が変わります。上の段階で消えた情報は、下の段階では取り戻せません。だから確認も上から順に進めます。

根拠を含むチャンクが作られていない

文書を細かく切りすぎると、回答に必要な一続きの記述が境界で分断されます。大きくしても解決しません。今度は複数の話題が一つのチャンクへ入り込み、質問との関連がぼやけます。検索モデルを替える前に確かめたいのは、評価対象の質問へ答えるための根拠が、途中で欠けずにチャンク内へ残っているかどうかです。

分割方法の選び方と実測値は「RAGのチャンクサイズと分割方法を実測比較」で扱っています。この記事の結論を固定値として使うのではなく、自分の文書で根拠が残る分割かを確かめるための起点として利用してください。

正解チャンクが検索候補に入らない

根拠を含むチャンクが存在していても、検索で拾えなければLLMには届きません。先の例で言えば、質問が「有給休暇」なのに規則側は「年次有給休暇」としか書いておらず、分かち書きの結果によってはキーワード検索がその断片を拾えない、といった場合です。取りこぼしに関係する要素は検索方式によって異なります。意味検索では埋め込みモデル、キーワード検索では分かち書き(日本語の文を単語へ区切る処理)や索引、ハイブリッド検索では両方式から集める候補数などを確認します。

この段階では、上位数件だけでなく、少し広い候補範囲まで正解が入っているかを見ます。正解が広い範囲にも現れないなら、候補を並べ直すリランカーだけを足しても救えません。日本語向けモデルの比較は「日本語RAGの埋め込みモデル9種を実測比較」にまとめています。

正解は候補にあるが上位へ来ない

正解チャンクが候補には入っていても、LLMへ渡す件数より下に沈んでいるなら、見直す対象は並べ替えです。方法は2つあります。1つ目は、キーワード検索と意味検索の順位を1つに混ぜ合わせる方法(RRF、Reciprocal Rank Fusion)で、ハイブリッド検索の候補の並びはこの混ぜ方で決まります。2つ目は、リランカーで候補を並べ直す方法です。ただしどちらも、検索で取得していないチャンクを新しく見つける処理ではありません。期限を書いた断片が候補の下のほうにあるなら並べ替えで上へ動かせますが、候補にまったく入っていなければ、並べ替えでは救えません。

RRFの効果と運用コストは「RAGのハイブリッド検索を実測比較」、リランカーが動かした順位とレイテンシは「日本語RAGのリランカー5種を実測比較」で確認できます。

根拠を渡しても回答を正しく生成できない

検索結果に十分な根拠があるのに回答が誤る場合は、回答生成の段階を切り分けます。LLMへ渡す指示、コンテキストの長さ(1回の入力へまとめて渡す文章の量)、根拠がない場合の応答方針、引用の対応などを確認します。検索指標が改善しても、最終回答の正解率が同じように上がるとは限りません。

最初に評価用の質問と根拠を用意する

改善を始める前に、実際に答えたい質問を集め、根拠となる文書と原文範囲を質問ごとに対応させます。件数はまだ少なくてかまいません。ただし、普段使う言い回しだけに偏らせないでください。固有名詞や型番を含むもの、答えが文書内に存在しないものを混ぜておけば、平均値だけでは隠れる失敗を見つけやすくなります。

検索側で記録するのは、根拠を含むチャンクの有無、正解が入った候補範囲、最初の正解順位です。生成側については、根拠どおりに答えたか、根拠がないときに無理な回答をしていないか、表示した参照元が回答を支えているかを切り離して確認します。両者を一つの点数へまとめず、どちらで失敗したかを残すことで、変更すべき工程を判断できます。

具体的な診断順序と集計コードは「RAGの検索精度を上げる方法」にあります。すでにRAGを動かしていて、次にどこを直すか決めたい場合はこちらから進めます。

この記事で言えること、言えないこと

この記事はRAGの仕組みと、失敗箇所を切り分ける順序を説明したものです。手法どうしを比べた実測値はここにはありません。数値はそれぞれリンク先の記事にあります。

このサイトの日本語RAGシリーズで実測しているのは主に検索側です。生成モデルやプロンプトを含む最終回答品質の比較は行っていないため、検索実験の数値を回答品質の改善幅として読むことはできません。

まとめ

4段のどこで落ちているかは、症状で見分けられます。根拠が候補のどこにも現れないなら、分割か検索。候補の下位にはあるのに回答へ使われていないなら、並べ替え。根拠が上位にあるのに答えが違うなら、回答生成です。いずれも、埋め込みモデルやLLMを先に交換して確かめるものではありません。

この見分けに先に要るのが、実際に答えたい質問と、その根拠になる原文範囲です。これが無いままモデルを入れ替えると、どの段が良くなったのかを記録できません。用意ができたら、いちばん上の段から。区切り方を比べた実測は「RAGのチャンクサイズと分割方法」にあります。


参考資料: RAGの原論文: Lewis et al., “Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks”。仕組みと外部データ利用の概説: Google Cloud「検索拡張生成(RAG)とは」AWS Prescriptive Guidance “Understanding Retrieval Augmented Generation”