
RAG / embedding / vector DB
モデルが知らないことは、調べてから答えさせればいい。RAGを支えるチャンキング、embedding、ベクトルDB、ハイブリッド検索、リランカー、そして評価の方法までをひと続きで見ていきます。
このページの内容(11項目)
「うちの会社の経費精算の締め日は?」と聞くと、AIが自信満々に間違える。なぜ?
LLMは学習したデータの範囲でしか物事を知りません。社内規程や先週決まったことは、そもそも学習データに入っていません。それでも「それらしい答え」を作れてしまうのがLLMの怖いところです。では、答える前に社内の資料を調べさせたらどうでしょう。これがRAGの出発点です。
RAGとは:調べてから答える
ひとことで言うと
RAG(Retrieval-Augmented Generation、検索拡張生成)は、質問に関係しそうな文書を検索して取り出し、それをプロンプトに添えてからLLMに答えさせる仕組みです。モデル自体は学習し直しません。
RAGは「持ち込み可の試験」です。LLMは暗記に頼らず、図書館の司書(検索システム)が探してきた資料のページを見ながら答案を書きます。司書が的外れな本を持ってくれば、答案も外れます。RAGの品質の大半は、この司書の腕で決まります。
名前は2020年のLewisらの論文に由来します。現在では、論文の手法そのものよりも「検索結果を文脈として渡して生成させる」設計全般を指す言葉として使われています。
flowchart TD
subgraph prep["事前準備"]
D["社内文書など"] --> C["チャンクに分割"]
C --> V["embeddingに変換"]
V --> DB["ベクトルDBに保存"]
end
Q["ユーザーの質問"] --> S["検索"]
DB --> S
S --> P["質問と検索結果で
プロンプトを作る"]
P --> L["LLMが回答"]
RAGの利点は、知識を「モデルの外」に置けることです。文書を差し替えればすぐ最新になり、回答に「どの文書を根拠にしたか」を示せます。アクセス権に応じて検索対象を絞る、といった制御もしやすくなります。LoRAなどの微調整(第13章)で知識を覚えさせるより、更新や削除がずっと簡単です。
チャンキング:資料をどう切るか
長い文書をそのまま検索対象にすると、「どこに答えがあるか」がぼやけます。そこで文書を数百トークン程度の断片(チャンク、chunk)に切ってから保存します。これを チャンキング(chunking) と呼びます。
- 固定長で切る: 一定のトークン数ごとに切る、いちばん単純な方法。前後を少し重ねる(オーバーラップ)と、文の途中で切れて意味が失われるのを和らげられます。
- 構造に沿って切る: 見出し・段落・表・コードの関数単位など、文書の構造で切る方法。人間が読む単位に近いので、多くの場合こちらが扱いやすくなります。
- 文脈を足す: チャンクだけを読むと「この会社」「前述の条件」が何を指すかわからないことがあります。文書名や章見出しをチャンクの先頭に付けておくと、検索でも生成でも迷いが減ります。
最後の工夫を発展させたのが、Anthropicが紹介した Contextual Retrieval です。LLMに「このチャンクは文書全体の中でどんな位置づけか」という短い説明を書かせ、チャンクに付け加えてから索引を作ります。同社の実験では、検索失敗(上位20件に正解チャンクが入らない割合)が、後述のBM25との併用で49%、さらにリランキングを加えると67%減ったと報告されています。
ためしてみよう
チャンクの大きさに唯一の正解はありません。手元の文書と、実際に聞かれそうな質問を10〜20個用意し、チャンクの長さや切り方を変えて「正解の入ったチャンクが上位に来るか」を比べるのがいちばんの近道です。
embedding:意味を座標にする
ひとことで言うと
embedding(埋め込み)は、文章を数百〜数千個の数字の並び(ベクトル)に変えたものです。意味が近い文章ほど、ベクトル同士も近くなるように作られています。
たとえば「経費の締め日」と「精算の期限」は、使っている単語は違っても意味は近い。embeddingモデルはこの2つを近い位置に置きます。逆に「締め日」と「締め切りのサッカー試合」は離れた場所に置かれるはずです。
embeddingは「意味の地図の住所」です。似た話題の文章は同じ町内に住んでいて、質問の住所を調べれば、近所に住んでいる文書をすぐ見つけられます。
近さは、ベクトル同士の向きの近さ(コサイン類似度、cosine similarity)や内積で測るのが一般的です。押さえておきたい実務上の注意点は3つあります。
- 文書と質問は同じembeddingモデルで変換する。モデルが違えば地図も違い、住所を比べられません。モデルを替えたら全文書を変換し直します。
- モデルごとに得意不得意がある。日本語の文書なら、日本語を含む多言語の評価で確かめる。比較にはMTEB(Massive Text Embedding Benchmark)などのベンチマークが参考になります。
- embeddingは「話題の近さ」には強い一方、型番・人名・エラーコードのような文字列の完全一致は苦手なことがある。これが次のハイブリッド検索の動機です。
ベクトルDB:近い住所をすばやく探す
文書が数百万チャンクあると、質問のたびに全部と距離を計算するのは大変です。そこで 近似最近傍探索(ANN、Approximate Nearest Neighbor) という索引を使い、「完全に正確ではないが、ほぼ正しい近所」を高速に見つけます。この索引を持ち、ベクトルの保存と検索を得意とするのがベクトルDB(vector database)です。
| 索引の方式 | 仕組みのイメージ | 特徴 |
|---|---|---|
| HNSW | 近いもの同士をつないだ多層のグラフをたどる | 検索が速く精度も高いが、構築が遅くメモリを食う |
| IVFFlat(IVF系) | ベクトルをグループに分け、近いグループだけ調べる | 構築が速く省メモリだが、速さと精度のバランスはHNSWに劣る |
専用のベクトルDB(Qdrant、Milvus、Weaviate、Pineconeなど)のほかに、既存のデータベースにベクトル検索を足す選択肢もあります。代表例が PostgreSQL の拡張機能 pgvector です。いつものテーブルにベクトル列を追加し、SQLで近い順に並べられます。HNSWとIVFFlatの両方の索引に対応し、PostgreSQLの全文検索と組み合わせたハイブリッド検索の例もREADMEに載っています(リリースは v0.8.7 2026年10月時点)。
CREATE EXTENSION vector;
CREATE TABLE chunks (id bigserial PRIMARY KEY, body text, embedding vector(1024));
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops);
-- 質問のベクトルに近い順に5件(<=> はコサイン距離)
SELECT body FROM chunks ORDER BY embedding <=> $1 LIMIT 5;
pgvectorの vector 型は、索引を張れる次元数が2,000までという制限があります(halfvec 型なら4,000まで)。次元の大きいembeddingモデルを使うときは事前に確認しましょう。社内の文書量が中規模までなら、「まずは使い慣れたPostgreSQLで」という判断は十分に現実的です。
ハイブリッド検索とBM25
embeddingによる検索(ベクトル検索、密な検索)は言い換えに強く、昔ながらのキーワード検索は完全一致に強い。両方の長所を取るのが ハイブリッド検索(hybrid search) です。
キーワード検索の定番が BM25 です。「質問の単語が文書に何回出てくるか」と「その単語がどれだけ珍しいか」をもとに点数を付けます。「の」「です」のようにどこにでもある語は軽く、「ERR-4031」のような珍しい語は重く扱われます。日本語では単語の区切りが空白でないので、形態素解析やn-gramで分割してから使うのが普通です。
2つの検索結果を1つの順位にまとめる方法としてよく使われるのが RRF(Reciprocal Rank Fusion) です。点数そのものではなく「何位だったか」だけを使い、各リストでの順位rに対して 1/(k+r) を足し合わせます(kは定数)。点数の尺度が違う検索同士でも、素直に混ぜられるのが利点です。
flowchart TD Q["質問"] --> A["ベクトル検索
意味が近い"] Q --> B["BM25
単語が一致"] A --> F["RRFで順位を統合"] B --> F F --> R["リランカーで
上位を並べ直す"] R --> L["上位数件を
LLMへ渡す"]
リランカー:最後に目利きが並べ直す
ベクトル検索では、質問と文書を別々にベクトルにしてから比べます(bi-encoder)。事前に文書を変換しておけるので速い反面、細かい関係は見落としがちです。
リランカー(reranker) は、質問と候補文書をペアでモデルに読ませ、「この文書はこの質問の答えになっているか」を直接採点します(cross-encoder)。精度は高いものの、候補ごとにモデルを動かすので遅く、全文書には使えません。そこで「速い検索で50〜100件を集め、リランカーで上位数件に絞る」という二段構えが定番になっています。
一次検索は「書庫から関係ありそうな本を台車で運んでくる係」、リランカーは「1冊ずつ中身を確かめて、本当に使える数冊を机に並べる係」です。
両者の中間として、トークン単位のベクトルを持っておき細かく照合するColBERTのような「後期相互作用(late interaction)」型の手法もあります。
長いコンテキストがあればRAGは不要?
最近のモデルは数十万〜100万トークンを一度に読めるものもあります(たとえばDeepSeek-V4は100万トークンのコンテキストに対応 2026年10月時点)。それなら全部プロンプトに入れればいいのでは、という疑問は自然です。
実際、資料が少ないなら全部入れるのは有力な選択肢です。Anthropicは、知識ベースが20万トークン(約500ページ)より小さければ、RAGを組まずにすべてプロンプトに含めてしまう方法も挙げています。プロンプトキャッシュ(第28章)を使えば、同じ資料を何度も読ませるコストも抑えられます。
一方で、RAGが有利な場面もはっきりあります。
- 量: 社内文書全体のように、どんな長いコンテキストにも収まらない規模。
- コストと速度: 入力トークンは課金と待ち時間に直結する。毎回100万トークン読ませるのは高くつく。
- 埋もれ: 長い入力の途中にある情報は見落とされやすい、という報告があります(「Lost in the Middle」論文)。モデルの改良で改善は進んでいますが、無関係な文章を大量に混ぜないに越したことはありません。
- 権限と鮮度: 利用者ごとに見てよい文書を絞り、更新をすぐ反映できる。
現実には「RAGで絞り込んでから、長いコンテキストにたっぷり渡す」という組み合わせが多く使われます。
一歩進んだRAG:GraphRAGとエージェント型RAG
普通のRAGは「質問に似たチャンクを数件持ってくる」のが基本なので、「この文書群全体で議論されている主要なテーマは?」のような全体を俯瞰する質問は苦手です。似たチャンクを数件読んでも全体像は見えません。
Microsoftの研究者らが提案した GraphRAG は、事前にLLMで文書から人物・組織・概念などの実体と関係を抜き出して知識グラフを作り、まとまりごとの要約まで用意しておく手法です。俯瞰的な質問に強くなる代わりに、索引作りにLLMを大量に使うのでコストがかかります。実装はMicrosoftがGitHubで公開しています。
もうひとつの流れが エージェント型RAG(agentic RAG) です。検索を1回で終わらせず、LLM自身が「まず規程を検索、足りなければ改定履歴も検索」と検索語を考え、結果を見て次の行動を決めます。検索をツールの1つとして使うエージェント(第20章)の一種と考えると整理しやすいでしょう。柔軟になる反面、手順が増える分だけ遅く、高く、挙動の確認も難しくなります。
RAGをどう評価するか
RAGがうまくいかないとき、原因は「検索が外れた」のか「検索は合っていたのに生成で間違えた」のかで、直す場所がまったく違います。だから評価も2段に分けます。
| 段階 | 問うこと | 指標の例 |
|---|---|---|
| 検索 | 正解の入ったチャンクを取ってこれたか | Recall@k、MRR、Context Precision / Recall |
| 生成 | 取ってきた資料に忠実に答えたか | Faithfulness(忠実性)、回答の関連性 |
| 全体 | 利用者の役に立ったか | 正答率、引用の正しさ、人による評価 |
出発点として、実際の質問と「正解が書いてある文書の場所」の組を数十件作っておくと、チャンクの切り方やembeddingモデル、リランカーを変えたときの効果をすぐ比べられます。RAGASのように、LLMを採点者として使い忠実性などを自動で測るツールもあります。ただしLLM採点にも癖があるので、ときどき人の目で突き合わせることが大切です(評価全般は第30章)。
よくある誤解
RAGを入れればハルシネーションはなくなる
検索が外れれば外れた資料をもとに答えるし、資料を読み違えることもある。減らす手段であって、なくす手段ではない
RAGにはベクトルDBが必須
キーワード検索だけのRAGも、既存DB+pgvectorのRAGもある。必要なのは「よい資料を取ってくる仕組み」
RAGはモデルに知識を学習させる方法だ
モデルの重みは変わらない。毎回プロンプトに資料を添えているだけ
確認クイズ
Q2. リランカーを全文書に直接使わないのはなぜ?
質問と文書のペアごとにモデルを動かすため遅いからです。速い一次検索で候補を数十件に絞ってから使います。
Q3. embeddingモデルを新しいものに替えたら、何が必要?
保存済みの全チャンクを新しいモデルで変換し直すことです。モデルが違うとベクトルの「地図」が違うので、古いベクトルとは比べられません。
Q4. RAGの回答が間違っていた。最初に確かめるべきことは?
検索結果に正解の資料が入っていたかどうかです。入っていなければ検索側(チャンキング、embedding、ハイブリッド検索、リランカー)、入っていたなら生成側(プロンプトやモデル)を直します。
この章のまとめ
- RAGは「検索してから答える」仕組み。モデルを学習し直さずに、最新の知識や社内の知識を使える。
- 品質の大半は検索で決まる。チャンキング、embedding、ハイブリッド検索(BM25+ベクトル)、リランカーを組み合わせる。
- ベクトルDBは近似最近傍探索で近いベクトルを速く探す。PostgreSQLならpgvectorで始められる。
- 長いコンテキストとRAGは競合ではなく補完。量・コスト・権限で使い分ける。
- 評価は「検索」と「生成」に分けて測ると、直す場所がわかる。
さらに深く学ぶ
この章の内容をもう一歩掘り下げるための原典です。
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks検索した文書を生成モデルに渡して答えさせる「RAG」という名前と枠組みを提案した論文。
- Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks文全体の意味を1本のベクトルにする実用的な方法を示し、意味検索や埋め込みモデルの普及につながった論文。
- Lost in the Middle: How Language Models Use Long Contexts長い入力の真ん中にある情報ほど使われにくいことを示した論文。「全部入れればよい」とは限らない理由です。
出典・参考
- Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks(arXiv:2005.11401)
- Anthropic: Introducing Contextual Retrieval — 検索失敗率49%・67%減、20万トークン未満なら全文投入の選択肢
- pgvector/pgvector(GitHub) — HNSW・IVFFlat、次元の上限、ハイブリッド検索、v0.8.7(2026年10月確認)
- Cormack et al., Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods(SIGIR 2009, PDF)
- Muennighoff et al., MTEB: Massive Text Embedding Benchmark(arXiv:2210.07316)
- Khattab and Zaharia, ColBERT(arXiv:2004.12832)
- Liu et al., Lost in the Middle: How Language Models Use Long Contexts(arXiv:2307.03172)
- deepseek-ai/DeepSeek-V4-Pro(Hugging Face) — 100万トークンのコンテキスト(2026年10月確認)
- Edge et al., From Local to Global: A Graph RAG Approach to Query-Focused Summarization(arXiv:2404.16130)、microsoft/graphrag(GitHub)
- Es et al., Ragas: Automated Evaluation of Retrieval Augmented Generation(arXiv:2309.15217)、Ragas: Available metrics