第5章 Advanced RAG
更新日:2025年12月16日
1. チャンク戦略
チャンキング(Chunking)は、文書を適切なサイズの断片に分割する処理である。チャンクのサイズや分割方法は、RAGの検索精度に大きく影響する。適切なチャンク戦略の選択は、RAGアプリケーションの品質を左右する重要な要素である。
1.1 分割手法
LangChainは複数のテキスト分割手法を提供している。
Table 1. 主要なText Splitterの比較
| Splitter | 分割基準 | 適したケース |
|---|---|---|
| CharacterTextSplitter | 文字数 | シンプルな分割 |
| RecursiveCharacterTextSplitter | 階層的区切り文字 | 汎用(推奨) |
| TokenTextSplitter | トークン数 | トークン制限管理 |
| MarkdownHeaderTextSplitter | Markdownヘッダー | Markdown文書 |
| HTMLHeaderTextSplitter | HTMLヘッダー | HTML文書 |
Fig 1. RecursiveCharacterTextSplitterの使用例
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # チャンクの最大文字数
chunk_overlap=200, # オーバーラップ文字数
length_function=len,
separators=["\n\n", "\n", "。", "、", " ", ""]
)
# テキストを分割
chunks = text_splitter.split_text(long_text)
# Documentオブジェクトとして分割
documents = text_splitter.split_documents(docs)
RecursiveCharacterTextSplitterは、separatorsリストの順序で区切り文字を試行する。まず段落(\n\n)で分割を試み、チャンクが大きすぎる場合は改行(\n)、句点(。)と順次細かい区切りで分割する。
1.2 オーバーラップ
chunk_overlapパラメータは、隣接するチャンク間で共有する文字数を指定する。オーバーラップを設定することで、文脈の分断を軽減できる。
Fig 2. オーバーラップの効果
# オーバーラップなし
[チャンク1: "...文の終わり"] [チャンク2: "新しい文の始まり..."]
↑ 文脈が途切れる
# オーバーラップあり(200文字)
[チャンク1: "...文の終わり。新しい文の"]
[チャンク2: "文の終わり。新しい文の始まり..."]
↑ 文脈が保持される
Table 2. チャンクサイズとオーバーラップの目安
| 文書タイプ | チャンクサイズ | オーバーラップ |
|---|---|---|
| 一般的な文書 | 500〜1000 | 100〜200 |
| 技術文書 | 1000〜2000 | 200〜400 |
| Q&A・FAQ | 200〜500 | 50〜100 |
| コード | 1500〜3000 | 0(関数単位) |
最適なチャンクサイズは、文書の性質、質問のタイプ、LLMのコンテキストウィンドウによって異なる。実験と評価を通じて最適値を見つけることが重要である。
2. リランキング
リランキング(Reranking)は、ベクトル検索で取得した候補文書を、より高精度なモデルで再順位付けする手法である。ベクトル検索は高速だが、クエリと文書の意味的な関連性を完全には捉えられない場合がある。リランキングモデルは、クエリと文書のペアを直接評価し、より正確な関連度スコアを算出する。
Fig 3. リランキングの処理フロー
質問 → ベクトル検索(上位20件取得)→ リランカー(上位5件に絞込)→ LLM
Fig 4. Cohereリランカーの使用例
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
# リランカーの初期化
reranker = CohereRerank(model="rerank-multilingual-v3.0", top_n=5)
# 圧縮リトリーバーでラップ
compression_retriever = ContextualCompressionRetriever(
base_compressor=reranker,
base_retriever=vectorstore.as_retriever(search_kwargs={"k": 20})
)
# 検索実行(20件取得→5件にリランク)
docs = compression_retriever.invoke("LangChainの特徴は?")
Table 3. 主要なリランキングモデル
| モデル | 提供元 | 特徴 |
|---|---|---|
| rerank-multilingual-v3.0 | Cohere | 多言語対応、API |
| bge-reranker-v2-m3 | BAAI | オープンソース、多言語 |
| cross-encoder/ms-marco | Sentence Transformers | オープンソース、英語 |
3. ハイブリッド検索
ハイブリッド検索は、ベクトル検索(密ベクトル)とキーワード検索(疎ベクトル/BM25)を組み合わせた検索手法である。両者の長所を活かすことで、検索精度を向上させる。
Table 4. 検索手法の比較
| 手法 | 長所 | 短所 |
|---|---|---|
| ベクトル検索 | 意味的類似性を捉える | 特定キーワードに弱い |
| キーワード検索 | 完全一致に強い | 同義語に弱い |
| ハイブリッド | 両方の長所を活用 | 実装が複雑 |
Fig 5. EnsembleRetrieverによるハイブリッド検索
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
# BM25リトリーバー(キーワード検索)
bm25_retriever = BM25Retriever.from_documents(docs)
bm25_retriever.k = 5
# ベクトルリトリーバー
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
# アンサンブル(重み付け)
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6] # BM25: 40%, Vector: 60%
)
# 検索実行
docs = ensemble_retriever.invoke("Python asyncio の使い方")
weightsパラメータで各リトリーバーの重みを調整できる。技術文書では固有名詞やコード要素が多いため、BM25の重みを高めると効果的な場合がある。
4. RAG評価
RAGアプリケーションの品質を客観的に評価することは、改善サイクルを回すために不可欠である。評価には、検索の精度(Retrieval)と生成の品質(Generation)の両面を考慮する必要がある。
4.1 Ragas
Ragas(RAG Assessment)は、RAGパイプラインを評価するためのフレームワークである。複数の評価指標を提供し、参照データなしでも評価可能な指標がある点が特徴的である。
Table 5. Ragasの主要な評価指標
| 指標 | 評価対象 | 説明 |
|---|---|---|
| Context Precision | 検索 | 検索結果の関連性 |
| Context Recall | 検索 | 必要な情報の網羅性 |
| Faithfulness | 生成 | 回答がコンテキストに忠実か |
| Answer Relevancy | 生成 | 回答が質問に適切か |
Fig 6. Ragasによる評価の実装例
from ragas import evaluate
from ragas.metrics import (
context_precision,
context_recall,
faithfulness,
answer_relevancy
)
from datasets import Dataset
# 評価データの準備
eval_data = {
"question": ["LangChainとは?", "RAGの利点は?"],
"answer": ["LangChainは...", "RAGの利点は..."],
"contexts": [["context1", "context2"], ["context3"]],
"ground_truth": ["正解1", "正解2"]
}
dataset = Dataset.from_dict(eval_data)
# 評価実行
result = evaluate(
dataset,
metrics=[
context_precision,
context_recall,
faithfulness,
answer_relevancy
]
)
print(result)
4.2 LangSmith
LangSmithは、LangChainが提供する観測・評価プラットフォームである。RAGパイプラインの各ステップをトレースし、レイテンシ、トークン使用量、入出力を可視化できる。
Fig 7. LangSmithの設定
# 環境変数の設定
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY="ls__..."
export LANGCHAIN_PROJECT="my-rag-project"
Fig 8. LangSmithでのデータセット評価
from langsmith import Client
from langsmith.evaluation import evaluate
client = Client()
# データセットの作成
dataset = client.create_dataset("rag-eval-dataset")
# 評価の実行
results = evaluate(
lambda x: rag_chain.invoke(x["question"]),
data=dataset,
evaluators=[
"qa", # 質問応答の正確性
"context_qa", # コンテキストを考慮した評価
],
experiment_prefix="rag-v1"
)
LangSmithのダッシュボードでは、実験結果の比較、エラー分析、回帰テストが可能である。本番環境でのモニタリングにも使用でき、RAGアプリケーションの継続的な改善に役立つ。
本コンテンツは2025年12月時点の情報に基づいて作成されています。RAGの評価手法は活発に研究が進んでおり、新しい指標やツールが登場する可能性があります。