LLMに社内文書について質問すると、的外れな回答や「ハルシネーション(幻覚)」が返ってくる——。この問題を解決するのがRAG(Retrieval-Augmented Generation=検索拡張生成)だ。
2026年現在、RAGはエンタープライズAI導入の最も一般的なアーキテクチャパターンとなった。しかし「RAGとは」で検索しても、概念の説明で終わる記事がほとんどだ。本記事はRAGの仕組みを図解するだけでなく、LangChainで実際にRAGパイプラインを構築し、ベクトルDBを選定し、RAGASで品質を評価するところまでカバーする。コピペで動くコード付きの実践ガイドだ。
RAGとは——LLMのハルシネーションを解決する検索拡張生成
RAGとは「Retrieval-Augmented Generation(検索拡張生成)」の略で、2020年にMeta AI(旧Facebook AI Research)の Patrick Lewis らが提唱した手法だ。LLMが回答を生成する前に、外部のデータベースやドキュメントから関連情報を検索(Retrieve)し、その情報を文脈としてプロンプトに含めてから生成(Generate)する。
なぜRAGが必要なのか
LLMには3つの根本的な限界がある。RAGはこれらすべてに対処する。
| LLMの限界 | 具体的な問題 | RAGによる解決 |
|---|---|---|
| 知識の鮮度 | 学習データのカットオフ以降の情報を知らない | 最新ドキュメントを検索して補完 |
| ハルシネーション | もっともらしいが事実と異なる回答を生成 | 参照元ドキュメントに基づいて回答 |
| 社内知識の欠如 | 非公開の社内文書・マニュアルを知らない | 社内DBを検索ソースに追加 |
RAGとファインチューニングの違い
LLMに新しい知識を与える手法として、RAGとファインチューニングがよく比較される。
| 観点 | RAG | ファインチューニング |
|---|---|---|
| 知識の更新 | 即時(ドキュメント追加のみ) | 再学習が必要(数時間〜数日) |
| コスト | 低い(検索インフラのみ) | 高い(GPUコンピュート) |
| 出典の提示 | 可能(参照チャンクを表示) | 不可能 |
| 応答スタイル変更 | 苦手 | 得意 |
| 推奨シーン | 社内FAQ、ドキュメント検索、最新情報 | 文体変更、専門用語対応 |
2026年の実務では、まずRAGを導入し、それでも不十分な場合にのみファインチューニングを検討するのが標準的なアプローチだ。
RAGパイプラインの仕組みを図解——チャンキングからレトリーバルまで
RAGパイプラインは大きく「インデックス構築(オフライン)」と「検索+生成(オンライン)」の2フェーズで構成される。
(PDF・HTML・MD)"] --> B["チャンキング
(テキスト分割)"] B --> C["埋め込みモデル
(Embedding)"] C --> D["ベクトルDB
に格納"] end subgraph online["検索+生成(オンライン)"] E["ユーザーの質問"] --> F["質問を
ベクトル化"] F --> G["類似度検索
(top-k取得)"] D --> G G --> H["検索結果を
プロンプトに挿入"] H --> I["LLMが
回答生成"] end style offline fill:#1e293b,color:#fff style online fill:#1e293b,color:#fff
Step 1: チャンキング(テキスト分割)
ドキュメントをそのまま埋め込むと、1つのベクトルに大量の情報が詰め込まれ、検索精度が下がる。そこでドキュメントを適切なサイズの「チャンク」に分割する。MinerUのようなPDF変換ツールで前処理すると精度が向上する。
| 分割戦略 | 特徴 | 推奨チャンクサイズ |
|---|---|---|
| 固定サイズ | 文字数で機械的に分割 | 500〜1000文字 |
| 再帰的分割 | 段落→文→文字の順で分割を試行 | 500〜1000文字 |
| セマンティック分割 | 意味の区切りで分割(埋め込みの類似度変化点) | 可変 |
| 親子分割 | 大きなチャンク内の小さなチャンクで検索 | 親: 2000、子: 500 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=200, # チャンク間の重複(文脈の断絶を防ぐ)
separators=["\n\n", "\n", "。", "、", " "], # 日本語対応
)
chunks = splitter.split_documents(documents)
Step 2: 埋め込み(Embedding)
チャンクを数値ベクトルに変換する。2026年時点の主要モデル比較は以下の通りだ。
| モデル | 次元数 | 日本語対応 | 価格($/1Mトークン) | 特徴 |
|---|---|---|---|---|
| OpenAI text-embedding-3-large | 3072 | ○ | $0.13 | 最も普及。次元削減可能 |
| Cohere embed-v4 | 1024 | ○ | $0.10 | 多言語、圧縮表現 |
| BGE-M3 | 1024 | ◎ | 無料(OSS) | 多言語に強い。ローカル実行可 |
| multilingual-e5-large | 1024 | ◎ | 無料(OSS) | Microsoft製。MTEB上位 |
日本語ドキュメント中心のRAGなら、BGE-M3(ローカル)またはtext-embedding-3-large(API)が実績豊富だ。
Step 3: ベクトル検索
質問文を同じ埋め込みモデルでベクトル化し、ベクトルDB内のチャンクとのコサイン類似度を計算して上位k件を取得する。
Step 4: LLM生成
検索されたチャンクをプロンプトの「コンテキスト」として挿入し、LLMに回答を生成させる。
prompt_template = """以下のコンテキストに基づいて質問に回答してください。
コンテキストに記載がない場合は「情報がありません」と回答してください。
コンテキスト:
{context}
質問: {question}
回答:"""
ベクトルデータベース比較2026——Pinecone・Qdrant・Chroma・pgvector
ベクトルDBはRAGのパフォーマンスと運用コストを左右する重要な選択だ。2026年時点の主要ベクトルDBを比較する。
| DB | 言語 | ホスティング | 無料枠 | 最大ベクトル数 | 特徴 |
|---|---|---|---|---|---|
| Pinecone | — | フルマネージド | 5GBまで無料 | 無制限(課金) | サーバーレス。セットアップ最速 |
| Qdrant | Rust | セルフホスト/Cloud | OSS無料 | 無制限 | 高性能フィルタリング、gRPC対応 |
| Chroma | Python | インメモリ/永続 | OSS無料 | メモリ依存 | 軽量。プロトタイプに最適 |
| pgvector | C | PostgreSQL拡張 | OSS無料 | テーブルサイズ依存 | 既存DBインフラを活用可能 |
| Weaviate | Go | セルフホスト/Cloud | OSS無料 | 無制限 | GraphQL API、モジュール型 |
| Milvus | Go/C++ | セルフホスト/Zilliz | OSS無料 | 10億ベクトル超 | 大規模特化。GPU対応 |
# Qdrantをローカルで起動(Docker)
docker run -p 6333:6333 qdrant/qdrant:latest
# pgvectorを既存PostgreSQLに追加
CREATE EXTENSION vector;
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(1536) -- OpenAI embedding次元数
);
RAG構築の実践——LangChainでゼロから作る
ここからが実装パートだ。LangChainの基本的な使い方を前提に、RAGパイプラインをゼロから構築する。RAG From Scratchシリーズも参考になる。
最小構成のRAG(30行)
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
# 1. ドキュメント読み込み
loader = DirectoryLoader("./docs", glob="**/*.md")
documents = loader.load()
# 2. チャンキング
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=200)
chunks = splitter.split_documents(documents)
# 3. ベクトルDB構築
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
vectorstore = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db")
# 4. RAGチェーン構築
llm = ChatOpenAI(model="gpt-4o", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={"k": 4}),
return_source_documents=True,
)
# 5. 質問
result = qa_chain.invoke({"query": "RAGの精度を向上させる方法は?"})
print(result["result"])
for doc in result["source_documents"]:
print(f" 出典: {doc.metadata['source']}")
このコードだけで、ローカルのMarkdownファイルに対するRAGチャットボットが動作する。Chromaはインメモリ動作するため、外部サービスの設定は不要だ。
LlamaIndex版(より簡潔)
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# 3行でRAG完成
documents = SimpleDirectoryReader("./docs").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("RAGの精度を向上させる方法は?")
print(response)
LlamaIndexは「データフレームワーク」としての設計思想で、LangChainより少ないコードでRAGを構築できる。一方、カスタマイズ性はLangChainが優る。
LangChain vs LlamaIndex——どちらを選ぶか
| 観点 | LangChain | LlamaIndex |
|---|---|---|
| GitHub Stars | 105k | 40.8k |
| 設計思想 | 汎用LLMアプリフレームワーク | データインデックス特化 |
| コード量 | やや多い(柔軟性のため) | 少ない(規約ベース) |
| カスタマイズ性 | 高い(各コンポーネント差替可能) | 中程度 |
| エージェント統合 | LangGraph(推奨) | LlamaIndex Agents |
| 推奨シーン | 複雑なRAG、マルチソース、エージェント | シンプルなRAG、高速プロトタイプ |
実務ではLlamaIndexでプロトタイプを素早く作り、要件が複雑化したらLangChainに移行するパターンが多い。
Advanced RAG——HyDE・Multi-Queryで検索精度を上げる
基本的なRAGパイプラインでは、ユーザーの質問文と関連ドキュメントの「言い回しの違い」によって検索精度が下がることがある。Advanced RAGはこの問題に対処する技術群だ。
HyDE(Hypothetical Document Embeddings)
ユーザーの質問に対して、LLMが「仮想的な回答ドキュメント」を生成し、そのドキュメントの埋め込みベクトルで検索する手法だ。質問文より回答文のほうがドキュメントとの類似度が高くなるという洞察に基づく。
ベクトル化"] C --> D["ベクトルDBで
類似度検索"] D --> E["取得した実文書で
LLMが最終回答"] style B fill:#f59e0b,color:#fff
Multi-Query Retriever
1つの質問を複数の異なる表現に言い換え、それぞれで検索して結果を統合する。「異なる視点からの検索」で網羅性を高める。
from langchain.retrievers.multi_query import MultiQueryRetriever
retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(),
llm=ChatOpenAI(model="gpt-4o-mini"),
)
# 1つの質問から3つのバリエーションを自動生成して検索
docs = retriever.invoke("RAGの精度向上方法")
Agentic RAG
LLMがエージェントとして動作し、「どのデータソースから検索すべきか」を自律的に判断する。単一のベクトルDBだけでなく、SQL DB、Web検索、API呼び出しを組み合わせる高度なアプローチだ。2026年はMCP(Model Context Protocol)との統合により、エージェントが外部ツールにアクセスするパターンが急速に普及している。
| 手法 | 改善対象 | 実装難易度 | 効果 |
|---|---|---|---|
| HyDE | 検索の質問-文書ギャップ | 中 | 高(+15-20%向上) |
| Multi-Query | 検索の網羅性 | 低 | 中(+10-15%向上) |
| Parent Document | チャンク断片化 | 中 | 高(文脈保持) |
| Contextual Compression | ノイズ除去 | 中 | 中(回答精度) |
| Agentic RAG | マルチソース対応 | 高 | 高(柔軟性) |
RAGの品質評価——RAGASフレームワークで定量化する
RAGパイプラインを構築したら、品質を定量的に評価する必要がある。RAGAS(Retrieval Augmented Generation Assessment)は、RAGパイプライン評価の業界標準フレームワークだ。
3つの評価指標
| 指標 | 測定対象 | 計算方法 | 目標値 |
|---|---|---|---|
| Faithfulness | 回答が検索結果に忠実か | 回答内の主張のうち、コンテキストで裏付けられる割合 | 0.8以上 |
| Answer Relevancy | 回答が質問に関連しているか | 回答から逆生成した質問と元の質問の類似度 | 0.8以上 |
| Context Recall | 必要な情報を検索できているか | Ground Truthに含まれる事実のうち、検索コンテキストでカバーされる割合 | 0.7以上 |
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_recall
from datasets import Dataset
# 評価データセット
eval_data = Dataset.from_dict({
"question": ["RAGとは何ですか?"],
"answer": ["RAGは検索拡張生成の手法で..."],
"contexts": [["RAGはRetrieval-Augmented Generationの略で..."]],
"ground_truth": ["RAGはLLMの回答精度を向上させる技術で..."],
})
result = evaluate(eval_data, metrics=[faithfulness, answer_relevancy, context_recall])
print(result)
# {'faithfulness': 0.92, 'answer_relevancy': 0.88, 'context_recall': 0.85}
RAG vs ロングコンテキスト——1Mトークン時代にRAGは不要か?
2026年、Claude Opus 4.6やGPT-5.4は100万トークン(約75万文字)のコンテキストウィンドウを持つ。「ドキュメントを全部コンテキストに入れれば、RAGは不要では?」という疑問が自然に浮かぶ。
| 観点 | RAG | ロングコンテキスト |
|---|---|---|
| ドキュメント量 | 数万件でもスケール | 数十ファイルが現実的上限 |
| レイテンシ | 検索 + 生成(1-3秒) | 全文読み込み(10-30秒) |
| コスト | 検索は安い(ベクトルDB) | 入力トークン全額課金(高額) |
| 精度(針を探す) | チャンク単位で高精度 | 長文だと「迷子」になりやすい |
| 更新の即時性 | ドキュメント追加のみ | 毎回全文を入力する必要あり |
| 出典の提示 | チャンク単位で出典表示可能 | 「どこに書いてあったか」の特定が曖昧 |
結論:RAGとロングコンテキストは「競合」ではなく「補完」の関係だ。数十ファイルの小規模プロジェクトならロングコンテキストで十分だが、数千〜数万件のドキュメントを扱うエンタープライズ用途ではRAGが不可欠だ。実際、2026年の多くのエンタープライズRAGシステムは「RAGで関連ドキュメントを絞り込み → ロングコンテキストで深く理解する」というハイブリッドアプローチを採用している。
コスト試算:1,000件のドキュメントを扱う場合
- ロングコンテキスト:1,000件 × 平均2,000トークン = 200万トークン入力。Claude Opus 4.6で$10/クエリ。月100クエリで$1,000/月
- RAG:検索で上位5件に絞り込み → 10,000トークン入力。Claude Opus 4.6で$0.05/クエリ。月100クエリで$5/月 + ベクトルDB費用
大量ドキュメントを扱う場合、RAGのコスト優位は200倍になる。
エンタープライズRAG——Dify・RAGFlow・Onyxの使い分け
コードを書かずにRAGを構築できるエンタープライズ向けツールも充実している。とくにDify、RAGFlow、Onyxが2026年の三大選択肢だ。
| ツール | 特徴 | 対応LLM | ドキュメント処理 | 価格 |
|---|---|---|---|---|
| Dify | ノーコードAIアプリビルダー | Claude, GPT, Gemini等 | 標準的なRAG | OSS無料 + Cloud有料 |
| RAGFlow | 深いドキュメント理解(DeepDoc) | 主要LLM全対応 | 表・図・レイアウト対応 | OSS無料 |
| Onyx | 社内ドキュメント検索特化 | 主要LLM全対応 | Slack/Confluence/Google Drive連携 | OSS無料 |
選定の指針
- 非エンジニアがRAGチャットボットを作りたい → Dify(GUIでフロー構築、最も直感的)
- PDF・表・複雑なドキュメントを扱う → RAGFlow(DeepDocエンジンが表やレイアウトを正確に抽出)
- 社内の既存ツール(Slack/Confluence等)と連携 → Onyx(コネクタが豊富、検索特化)
- フルカスタマイズが必要 → LangChain/LlamaIndex(コードベースで完全制御)
参照ソース
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks(RAG原論文, 2020)
- LangChain Documentation — RAG
- LlamaIndex Documentation
- RAGAS — Evaluation Framework for RAG
- Qdrant — Vector Search Engine(GitHub)
- Chroma — AI-native Embedding Database(GitHub)
- pgvector — Open-source Vector Similarity Search for Postgres
- RAGFlow — Deep Document Understanding RAG Engine(GitHub)
- Dify — Open-source LLM App Development Platform(GitHub)
- HyDE: Precise Zero-Shot Dense Retrieval without Relevance Labels(arXiv)