RAGの基礎と設計パターン — 埋め込み・チャンク・リランキング・評価を1から
検索拡張生成(RAG)を前提知識ゼロから解説。仕組みの直感、チャンク分割の戦略、ハイブリッド検索とリランキング、そして最重要の評価設計まで。
要点
- RAGは、検索した関連ページをプロンプトに入れてLLMに答えさせる「持ち込み可の試験」方式である。
- ファインチューニングと違いモデルを変更しないため、知識の更新は資料の差し替えだけで済み、出典も示せる。
- 埋め込みは、意味が近い文がベクトル空間でも近くに配置されるよう学習されており、単語が一致しなくても意味で引ける。
- ハイブリッド検索とcross-encoderによる2段階リランキングで、上位50〜100件を上位5〜10件に絞る。
- 検索はRecall@kで、生成はFaithfulnessとAnswer Relevanceで、分けて評価するのが原則である。
RAGとは何か: LLMに「持ち込み可の試験」を受けさせる
LLMには構造的な弱点が2つあります。知識が学習時点で止まっていること、そして知らないことを聞かれるともっともらしい嘘(ハルシネーション)を生成しがちなことです。社内規程や最新の製品仕様など、モデルが学習していない情報には答えられません。
RAG(Retrieval-Augmented Generation, 検索拡張生成)はこれを「試験の受け方を変える」ことで解決します。閉卷試験(記憶だけで答える)ではなく、持ち込み可の試験にするのです。
- 質問が来たら、まず手元の資料棚から関連ページを検索する
- 見つけたページを質問と一緒にプロンプトに入れる
- LLMは「この資料に基づいて答えて」と指示されて回答する
用語としてのRAGは Lewis らの2020年の論文に由来しますが、現在は「外部知識を検索してプロンプトに注入する構成」全般を指す言葉として定着しています。ファインチューニングと違ってモデル自体は変更しないため、知識の更新が資料の差し替えだけで済み、回答の根拠(出典)を示せるのが大きな利点です。
全体パイプライン: 5つの工程
RAGは大きく「仕込み(インデックス構築)」と「実行(検索と生成)」に分かれます。
[仕込み] 文書 → チャンク分割 → 埋め込み → ベクトルDBに保存
[実行] 質問 → 埋め込み → 類似検索 → (リランキング) → プロンプト合成 → 生成
この記事では各工程を順に分解し、最後に「どこが壊れやすいか」を評価の観点から整理します。
埋め込み: 意味を座標にする
埋め込み(embedding)とは、テキストを数百〜数千次元の数値ベクトルに変換することです。ポイントはただ1つ、意味が近い文は、ベクトル空間でも近くに配置されるよう学習されていることです。
v1 = embed("有給休暇の申請方法")
v2 = embed("休みを取るにはどうすればいい?")
v3 = embed("サーバーの再起動手順")
cosine_sim(v1, v2) # 高い(言い回しが違っても意味が近い)
cosine_sim(v1, v3) # 低い
キーワード検索と違い、単語が一致しなくても意味で引けるのが強みです。逆に、型番・人名・エラーコードのような「文字列そのものの一致」が重要な検索は苦手で、これが後述のハイブリッド検索の動機になります。
ここで出てきた「類似度」の実体は、ベクトルどうしの内積(コサイン類似度)です。2本のベクトルが指す方向が近いほど値が大きくなる——線形代数の記事で扱った内積の幾何そのものなので、下の図で角度と内積の関係を触って確かめてみてください。
チャンク戦略: RAGの品質はここで大半が決まる
文書を丸ごと埋め込むと意味が平均化されてぼやけ、細かすぎると文脈が失われます。分割(チャンキング)の設計指針は次の通りです。
- 固定長分割: 実装が最も簡単。例として512〜1024トークン程度+10〜20%のオーバーラップ(文脈の切断を緩和)から始めるのが定番
- 構造ベース分割: Markdownの見出し、段落、条項など文書の論理構造で切る。構造を持つ文書(規程・マニュアル・API文書)では固定長より一貫して良い結果になりやすい
- セマンティック分割: 隣接文の埋め込み類似度が急落する点で切る。計算コストと引き換えに話題の境界を尊重できる
- 親子チャンク(small-to-big): 検索は小さいチャンクで精度を上げ、LLMに渡すのはその親(前後を含む大きな塊)にするパターン。検索精度と文脈量のトレードオフを両取りできる実務の定番
検索の物差し(内積・コサイン・距離)の違いは、事故が起きる形で理解しておくべきです。クエリをドラッグして、内積のときだけ「長いベクトルの房」が割り込むのを確かめてください。
内積そのものから固有値・低ランクまでの数学はLoRAとRAGを支える線形代数で1本にまとめています。
もう1つ効くのがメタデータの付与です。チャンクに「文書タイトル・章・更新日」を持たせ、検索時のフィルタ(例: 最新版のみ)や、チャンク先頭へのタイトル埋め込みに使うと精度が上がります。
逆に事故になりやすいのは、表・コードブロック・箇条書きの途中で機械的に切ることです。表の数行だけが切り出されたチャンクは「何の表か」という情報が消えており、埋め込んでも検索にかからず、運よく生成に渡っても根拠として機能しません。固定長分割を使う場合でも、最低限、表とコードは分割境界をまたがせない前処理を入れる——これだけで「検索は当たっているのに答えが壊れる」型の不具合がかなり減ります。同様に、PDFからのテキスト抽出が崩れている(段組みの読み順が入れ替わる、ヘッダー・フッターが本文に混入する)と、その後の工程をどれだけ磨いても取り返せません。チャンク設計の前に、まず抽出されたテキストを目視するのが遠回りに見えて最短です。
検索: dense・BM25・ハイブリッド
- ベクトル検索(dense): 埋め込みの近傍探索。言い換えに強い
- BM25(キーワード・sparse): 古典的な全文検索スコアリング。固有名詞・型番・コード片に強い
- ハイブリッド: 両方で検索して結果を統合する。統合には RRF(Reciprocal Rank Fusion)—各ランキングでの順位の逆数を足し合わせる方式—がシンプルで広く使われます
実務ではハイブリッドを既定にするのが安全です。ユーザーの質問には「意味で聞くもの」と「文字列で聞くもの」が必ず混在するからです。
リランキング: 荒く拾って、賢く並べ直す
ベクトル検索は「質問とチャンクを別々にベクトル化して距離を測る」ため高速ですが、精度には限界があります(bi-encoder方式)。そこで2段構えにします。
- 1段目(Retrieval): ベクトル/ハイブリッド検索で上位50〜100件を高速に取得
- 2段目(Reranking): cross-encoder(質問とチャンクを連結して1つのモデルに入れ、関連度を直接採点)で並べ直し、上位5〜10件だけをLLMに渡す
cross-encoderは1ペアごとに推論が必要で遅いため全件には使えませんが、候補を絞った後なら現実的です。「速いが粗い網で広く獲り、遅いが正確な目で選別する」—この2段構成はRAG品質を上げる最も費用対効果の高い一手であることが多いです。
評価: 「なんとなく良くなった」を卒業する
RAGは工程が多く、感覚だけの改善はすぐ迷子になります。検索と生成を分けて測るのが原則です。
検索の評価(生成の前に測る)
- 質問と「正解チャンク」のペアを数十件作り、Recall@k(上位k件に正解が入っている率)を測る
- 生成品質がどれだけ高くても、正解情報が検索できていなければ原理的に正答できない。まず検索を単体で健全化する
生成の評価
- Faithfulness(忠実性): 回答が渡したコンテキストに根拠を持つか(幻覚していないか)
- Answer Relevance(回答関連性): 質問にちゃんと答えているか
- 人手評価が基本だが、LLM-as-a-judge(別のLLMに採点させる)で近似するのが実務の主流。RAGASなどの評価フレームワークはこの自動化を支援するツール
運用Tips
- 評価セットは本番の失敗ログから継続的に補充する(最初から完璧を狙わない)
- 変更は1工程ずつ。チャンクサイズと埋め込みモデルを同時に変えると、何が効いたか分からなくなる
- 「該当資料なし」のケースを評価セットに必ず入れる。答えられない質問に答えないこともRAGの品質
現場ではこう使う
RAGを実際に組む・運用するのは、社内文書QAボットや問い合わせ支援を作るバックエンド/MLエンジニアです。ゼロから作る場面よりも「動いてはいるが精度が出ないRAGを引き継いで改善する」場面のほうが多く、そのとき触るのは本文で見た各工程のパラメータです。
実際に触るもの: チャンク系では chunk_size と chunk_overlap(LangChainなら RecursiveCharacterTextSplitter の引数)。検索系では取得件数の top_k、ハイブリッド統合の重みやRRFの定数、メタデータフィルタの条件。ベクトルDBは FAISS・pgvector・Qdrant・Elasticsearch などから既存インフラとの相性で選ぶことが多く、リランカーは cross-encoder 系モデルを検索と生成の間に差し込むだけの構成が一般的です。
知らないと事故になる落とし穴:
- 埋め込みモデルを替えたら全チャンクの再インデックスが必須。新旧モデルのベクトルは同じ空間に住んでいないため、混在した瞬間に距離の比較が無意味になる
- 正規化と距離指標の不整合。コサイン類似度前提のモデルの出力を正規化せずに内積で検索すると、ノルムの大きいチャンクばかりが上位に来る
top_kを増やす=改善、ではない。無関係なチャンクがコンテキストに混ざるほど、生成が誤った根拠を拾うリスクは上がる。件数を増やすならリランキングとセットで- 権限の突き抜け。ベクトルインデックスは元文書のアクセス制御を知らない。検索段でユーザー権限によるフィルタを掛けないと、見てはいけない文書の内容が回答に混入する
面接・設計レビューで問われる問い: 定番は「検索精度が低いとき、まずどこを疑うか」。筋道は本文の通りで、プロンプトではなく検索を単体で測る(Recall@kを出す)→ ダメならチャンク境界と抽出前処理を見る → 次に埋め込みモデルの変更やハイブリッド化、の順で答えます。「RAGとファインチューニングの使い分けは」もよく問われます。知識の注入・更新はRAG、出力の形式・文体・振る舞いの矯正はファインチューニング、と役割の違いで答えるのが定石です。
まとめ
- RAGは「持ち込み可の試験」。知識更新は資料差し替えで済み、出典を示せる
- 品質の大半はチャンク設計と検索段で決まる。生成プロンプトの調整は最後
- ハイブリッド検索+cross-encoderリランキングの2段構成が費用対効果の定番
- Recall@kで検索を、Faithfulness/Relevanceで生成を分離評価し、失敗ログで評価セットを育てる
次回は、RAGの発展形(クエリ書き換え、HyDE、GraphRAG、エージェント型RAG)を設計パターンとして比較します。エージェントがツールとして検索を呼び出す構成の前提知識はLLMエージェントの基礎にまとめてあります。
コメント
コメントにはログインが必要です