第4章 RAG基礎

更新日:2025年12月16日

本章では、RAG(Retrieval-Augmented Generation:検索拡張生成)の基礎について解説する。RAGはLLMが学習していない知識を外部データから取得して回答を生成する手法であり、企業内文書検索やFAQシステムなど実用的なLLMアプリケーションの基盤となる。

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モデルは急速に進化しており、最新の選択肢については公式ドキュメントをご確認ください。