第4章 RAG基礎
更新日:2025年12月16日
1. RAGの概念
RAGは、LLMの回答生成プロセスに外部知識の検索を組み合わせた手法である。LLMは学習データに基づいて応答を生成するため、学習後の最新情報や企業固有の情報を扱うことができない。RAGはこの制約を克服し、LLMに最新かつ正確な情報を提供する。
1.1 検索拡張生成とは
RAGの基本的な流れは以下の3ステップである。
Table 1. RAGの基本ステップ
| ステップ | 処理 | 説明 |
|---|---|---|
| 1. Retrieve | 検索 | ユーザーの質問に関連する文書を検索 |
| 2. Augment | 拡張 | 検索結果をプロンプトに追加 |
| 3. Generate | 生成 | 拡張されたプロンプトでLLMが回答生成 |
RAGを使用することで、以下のメリットが得られる。最新情報への対応(学習データの制約を超える)、ハルシネーションの軽減(根拠のある回答)、ドメイン知識の注入(企業固有の情報)、情報源の明示(回答の根拠を示せる)。
1.2 アーキテクチャ
RAGシステムは、インデックス作成フェーズとクエリフェーズの2つのフェーズから構成される。
Fig 1. RAGアーキテクチャ概要
【インデックス作成フェーズ】
文書 → チャンク分割 → 埋め込み生成 → ベクトルDB保存
【クエリフェーズ】
質問 → 埋め込み生成 → ベクトル検索 → 関連文書取得
↓
プロンプト作成 → LLM → 回答
インデックス作成フェーズでは、対象となる文書を読み込み、適切なサイズのチャンク(断片)に分割し、各チャンクを埋め込みベクトルに変換してベクトルDBに保存する。クエリフェーズでは、ユーザーの質問を埋め込みベクトルに変換し、ベクトルDBから類似度の高いチャンクを検索、それをコンテキストとしてLLMに渡して回答を生成する。
2. 埋め込み
埋め込み(Embedding)は、テキストを固定長の数値ベクトルに変換する処理である。意味的に類似したテキストは、ベクトル空間上で近い位置に配置される。この性質を利用して、類似文書の検索が可能になる。
2.1 Embeddings
LangChainでは、Embeddingsクラスを通じて様々な埋め込みモデルを利用できる。
Fig 2. OpenAI Embeddingsの使用例
from langchain_openai import OpenAIEmbeddings
# 埋め込みモデルの初期化
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 単一テキストの埋め込み
vector = embeddings.embed_query("LangChainとは何ですか?")
print(f"ベクトル次元: {len(vector)}") # 1536
# 複数テキストの埋め込み(ドキュメント用)
texts = ["Python入門", "機械学習の基礎", "深層学習とは"]
vectors = embeddings.embed_documents(texts)
print(f"ドキュメント数: {len(vectors)}") # 3
embed_query()は検索クエリ用、embed_documents()は文書インデックス用のメソッドである。一部のモデルでは、これらに異なる処理が適用される場合がある。
2.2 モデル選択
埋め込みモデルには様々な選択肢があり、精度、速度、コスト、言語対応などを考慮して選択する。
Table 2. 主要な埋め込みモデルの比較
| モデル | 提供元 | 次元数 | 特徴 |
|---|---|---|---|
| text-embedding-3-small | OpenAI | 1536 | コスト効率、多言語対応 |
| text-embedding-3-large | OpenAI | 3072 | 高精度、多言語対応 |
| multilingual-e5-large | Microsoft | 1024 | オープンソース、多言語 |
| all-MiniLM-L6-v2 | Sentence Transformers | 384 | 軽量、ローカル実行可 |
Fig 3. HuggingFace埋め込みの使用例
from langchain_community.embeddings import HuggingFaceEmbeddings
# ローカルモデルの使用
embeddings = HuggingFaceEmbeddings(
model_name="intfloat/multilingual-e5-large",
model_kwargs={"device": "cuda"} # GPU使用
)
3. ベクトルDB
ベクトルDB(Vector Database)は、埋め込みベクトルを効率的に保存・検索するためのデータベースである。通常のRDBMSとは異なり、高次元ベクトルの類似度検索に特化している。
3.1 Chroma
Chromaは、LangChainで最も手軽に使用できるベクトルDBである。インメモリまたはローカルファイルで動作し、小〜中規模のプロジェクトに適している。
Fig 4. Chromaの基本的な使用方法
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
# 埋め込みモデル
embeddings = OpenAIEmbeddings()
# ドキュメントの準備
from langchain_core.documents import Document
docs = [
Document(page_content="LangChainはLLMアプリ開発フレームワークです",
metadata={"source": "intro.txt"}),
Document(page_content="RAGは検索拡張生成の略称です",
metadata={"source": "rag.txt"}),
Document(page_content="ベクトルDBは埋め込みを保存します",
metadata={"source": "vectordb.txt"}),
]
# インメモリでベクトルストア作成
vectorstore = Chroma.from_documents(
documents=docs,
embedding=embeddings
)
# 類似度検索
results = vectorstore.similarity_search("LLMアプリケーション", k=2)
for doc in results:
print(doc.page_content)
Fig 5. Chromaの永続化
# 永続化ディレクトリを指定
vectorstore = Chroma.from_documents(
documents=docs,
embedding=embeddings,
persist_directory="./chroma_db"
)
# 既存のDBを読み込み
vectorstore = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
3.2 FAISS
FAISS(Facebook AI Similarity Search)は、Metaが開発した高速なベクトル検索ライブラリである。大規模データセットでの検索に優れており、本番環境での使用に適している。
Fig 6. FAISSの使用例
from langchain_community.vectorstores import FAISS
# ベクトルストア作成
vectorstore = FAISS.from_documents(
documents=docs,
embedding=embeddings
)
# ローカルに保存
vectorstore.save_local("./faiss_index")
# 読み込み
vectorstore = FAISS.load_local(
"./faiss_index",
embeddings,
allow_dangerous_deserialization=True
)
# 類似度スコア付き検索
results = vectorstore.similarity_search_with_score("RAGとは", k=3)
for doc, score in results:
print(f"スコア: {score:.4f}, 内容: {doc.page_content}")
Table 3. ベクトルDBの比較
| DB | 特徴 | 適したケース |
|---|---|---|
| Chroma | 簡単、Python native | 開発・プロトタイプ |
| FAISS | 高速、大規模対応 | 本番環境 |
| Pinecone | マネージド、スケーラブル | エンタープライズ |
| Weaviate | GraphQL、ハイブリッド検索 | 複雑な検索要件 |
4. Retrieverの実装
Retrieverは、ベクトルストアから関連文書を取得するためのインターフェースである。LangChainでは、ベクトルストアをRetrieverとして使用し、LCELチェーンに組み込むことができる。
Fig 7. 基本的なRAGチェーンの実装
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# コンポーネントの準備
model = ChatOpenAI(model="gpt-4o", temperature=0)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# RAGプロンプト
prompt = ChatPromptTemplate.from_template("""
以下のコンテキストに基づいて質問に回答してください。
コンテキスト:
{context}
質問: {question}
回答:
""")
# ドキュメントを文字列に変換する関数
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# RAGチェーンの構築
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
# 実行
answer = rag_chain.invoke("LangChainとは何ですか?")
print(answer)
このチェーンでは、retrieverが質問に関連する文書を検索し、format_docs関数で文字列に変換、プロンプトのcontextとして注入している。RunnablePassthroughは入力の質問をそのまま通過させる。
Fig 8. 検索パラメータのカスタマイズ
# 検索結果の数を指定
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
# 類似度しきい値を指定
retriever = vectorstore.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={"score_threshold": 0.8}
)
# MMR(Maximal Marginal Relevance)検索
# 多様性を考慮した検索結果を取得
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"k": 5, "fetch_k": 20}
)
MMR検索は、関連性が高いだけでなく、互いに異なる内容の文書を取得する。これにより、回答の多様性と網羅性が向上する。次章では、チャンク戦略、リランキング、評価手法など、RAGの精度を向上させるための発展的な手法を解説する。
本コンテンツは2025年12月時点の情報に基づいて作成されています。ベクトルDBやEmbeddingモデルは急速に進化しており、最新の選択肢については公式ドキュメントをご確認ください。