RAG(検索拡張生成)の実践ガイド:仕組みから実装まで徹底解説
公開日: 2026年4月10日
はじめに
近年、ChatGPTをはじめとする大規模言語モデル(LLM)の普及により、AIを活用したシステム開発が急速に広まっています。しかしLLMには「学習データのカットオフ以降の情報を知らない」「社内固有のデータには対応できない」「ハルシネーション(もっともらしい嘘をつく)」といった課題があります。
そこで注目されているのが**RAG(Retrieval-Augmented Generation:検索拡張生成)**です。RAGはこれらの課題を解決する強力な手法として、企業の実務システムから個人の開発プロジェクトまで幅広く活用されています。
本記事では、RAGの基本概念から実際の実装手順、さらには現場で使える実践的なTipsまでを体系的に解説します。
RAGとは何か?基本概念をわかりやすく解説
RAGの定義
RAG(Retrieval-Augmented Generation)とは、外部の知識ベースから関連情報を検索(Retrieve)し、その情報をもとにLLMがテキストを生成(Generate)する手法です。2020年にMeta AI(当時Facebook AI Research)の研究チームが発表した論文で提唱されました。
簡単に言えば、「試験本番に教科書の参照が許可された状態」に近いイメージです。LLM単体では記憶していない情報でも、外部データベースから必要な情報を取り出して回答を生成できるようになります。
RAGが解決する3つの課題
| 課題 | 概要 | RAGによる解決策 |
|---|---|---|
| 知識のカットオフ | LLMは学習完了後の情報を知らない | 最新情報を外部DBに追加するだけでOK |
| ドメイン特化データ | 社内文書や専門知識への対応が難しい | 独自データをベクトルDBに格納して参照 |
| ハルシネーション | 事実と異なる情報を生成することがある | 根拠となる文書を明示し信頼性を向上 |
RAGの仕組み:3つのフェーズ
RAGは大きくインデックス作成フェーズとクエリ(検索+生成)フェーズの2段階に分かれます。
フェーズ1:ドキュメントのインデックス作成
まず、知識ベースとなるドキュメントを検索可能な形式に変換します。
- ドキュメントの収集:PDF、Word、Webページ、データベースなど様々な形式のデータを収集
- チャンキング(分割):長いドキュメントを適切なサイズの断片(チャンク)に分割
- 埋め込み(Embedding):各チャンクをベクトル(数値の配列)に変換
- ベクトルDBへの格納:変換したベクトルをベクトルデータベースに保存
フェーズ2:検索(Retrieval)
ユーザーから質問が来たとき、以下の手順で関連ドキュメントを取得します。
- ユーザーの質問もベクトルに変換
- ベクトルDB内のデータとコサイン類似度などで比較
- 類似度が高い上位N件のチャンクを取得
フェーズ3:生成(Generation)
取得したチャンクをコンテキストとしてLLMに渡し、回答を生成します。
プロンプト例:
以下のコンテキスト情報を参考に、ユーザーの質問に回答してください。
【コンテキスト】
{検索で取得した関連文書}
【質問】
{ユーザーの質問}
【回答】
RAGの実装:Pythonによる実践コード
必要なライブラリ
RAGを実装するためのPythonエコシステムは充実しています。代表的なライブラリは以下の通りです。
- LangChain / LlamaIndex:RAGパイプライン構築フレームワーク
- OpenAI API:LLMおよびEmbeddingモデル
- ChromaDB / FAISS / Pinecone:ベクトルデータベース
シンプルなRAGパイプラインの実装例
以下はLangChainとChromaDBを使った基本的なRAGの実装例です。
from langchain.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
# ステップ1: ドキュメントの読み込み
loader = TextLoader("company_docs.txt", encoding="utf-8")
documents = loader.load()
# ステップ2: チャンキング(分割)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 1チャンクの最大文字数
chunk_overlap=50 # チャンク間のオーバーラップ
)
chunks = text_splitter.split_documents(documents)
# ステップ3: ベクトル化&DBへの格納
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
# ステップ4: RAGチェーンの構築
llm = ChatOpenAI(model_name="gpt-4o", temperature=0)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True # 参照元文書も返す
)
# ステップ5: 質問してみる
result = qa_chain({"query": "製品の返品ポリシーを教えてください"})
print(result["result"])
print("参照元:", result["source_documents"])
このコードだけで、社内ドキュメントに基づいた質問応答システムが構築できます。
RAGの精度を高める実践的なTips
チャンキング戦略の最適化
チャンクのサイズは精度に大きく影響します。
- 小さすぎる(100文字以下):文脈が失われて意味が通らなくなる
- 大きすぎる(2000文字以上):関連しない情報が混入しノイズになる
- 推奨値:日本語の場合は200〜600文字が一般的に良好
また、Semantic Chunking(意味的な区切りでチャンクを作る手法)を使うと、単純な文字数分割より高品質なチャンクが得られます。
ハイブリッド検索の活用
ベクトル検索(意味的類似性)だけでなく、BM25などのキーワード検索と組み合わせるハイブリッド検索が効果的です。
- ベクトル検索:意味的に近い文書を取得(例:「車」で「自動車」もヒット)
- キーワード検索:完全一致・部分一致で取得(型番や固有名詞に強い)
両者を組み合わせることで、幅広いクエリに対応できます。
リランキング(再順位付け)
検索で取得した文書をさらに精密に並び替えるリランキングも重要なテク