第5章 Advanced RAG

更新日:2025年12月16日

本章では、RAGの精度を向上させるための発展的な手法について解説する。チャンク戦略の最適化、リランキングによる検索精度向上、ハイブリッド検索、そしてRagasやLangSmithを用いたRAGアプリケーションの評価手法を学ぶ。

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の評価手法は活発に研究が進んでおり、新しい指標やツールが登場する可能性があります。