「RAGシステムを導入したのに、なぜかLLMが嘘をつく…」「ユーザーから『回答が間違っている』と指摘されたけど、どこから手をつければいいのかわからない」
多くのRAG開発者が直面するこの問題は、LLMのハルシネーション(幻覚)が原因かもしれません。特に、RAGはハルシネーションを減らすとされていますが、完全に防ぐことはできません。それどころか、関連文書があるにも関わらずLLMが矛盾する回答を生成する場合があり、通常のLLMのハルシネーションよりも深刻な信頼問題を引き起こす可能性があります。
この記事では、RAGシステムにおけるLLMのハルシネーション問題に対し、評価駆動開発のアプローチを取り入れ、自動評価ツールや指標を用いてハルシネーションを効率的に検出し、改善サイクルを自動化する具体的な手順と知見を提供します。実務で再現可能なコード例やフレームワークの活用方法を示し、より信頼性の高いLLMアプリケーション開発に貢献します。
RAGシステムにおけるLLMのハルシネーション問題とその危険性
このセクションでは、RAGシステムでハルシネーションが発生するメカニズムと、そのパターン、そしてなぜ危険なのかを解説します。
RAG(Retrieval-Augmented Generation)は、LLMが外部の知識ベースから関連文書を取得し、それをプロンプトに組み込むことで、より正確で最新の情報を基にした応答を生成する強力なアーキテクチャです。LLM単体での知識の陳腐化やハルシネーションの問題を軽減すると期待されています。しかし、RAGを導入したからといって、ハルシネーションが完全に解消されるわけではありません。
ハルシネーションの発生メカニズムとパターン
RAGシステムにおけるハルシネーションは、主に以下のパターンで発生します。
-
取得されたコンテキストの不備:
- Missing Content: ユーザーの質問に対する回答が知識ベースにそもそも存在しない場合、LLMは関連情報がないにも関わらず、もっともらしいが事実に基づかない回答を生成してしまうことがあります。
- Irrelevant Context: 関連性の低いドキュメントが取得され、LLMがノイズに惑わされて誤った結論を導き出すことがあります。
-
LLMによる回答抽出エラー:
- 関連するドキュメントがコンテキストとして与えられても、LLMがそこから正しい情報を抽出できなかったり、矛盾する情報やノイズに惑わされて不完全または誤解を招く回答を生成したりします。
- 数値の矛盾: コンテキスト内の数値を誤って読み取ったり、別の数値に置き換えたりする。
- 偽の引用: コンテキストに存在しない情報をあたかも引用であるかのように生成する。
- 否定の反転: コンテキストの内容を逆の意味で解釈してしまう。
- 回答のずれ: 質問の意図とは異なる、微妙にずれた回答を生成する。
- 根拠のない自信のある回答: コンテキストにない内容を、あたかも事実であるかのように自信満々に回答する。
- ハルシネーションの継続: 取得された情報が不完全であったり、わずかにずれていたりすると、LLMは既存の知識と提供されたコンテキストを混ぜ合わせて、もっともらしいが根拠のない詳細を作り出すことがあります。
RAGシステムにおけるハルシネーションの危険性
RAGシステムにおけるハルシネーションは、通常のLLMのハルシネーションよりも危険な場合があります。なぜなら、ユーザーは「RAGシステムは外部情報を参照しているから正確だろう」という期待を持っており、誤った情報でもあたかも事実に基づいているかのように提示されることで、より深く誤解を招く可能性があるためです。これはユーザーの信頼を著しく損ない、ビジネス上の損失にも繋がりかねません。
この問題に対処するためには、ハルシネーションを効率的に検出し、継続的に改善する自動評価ワークフローの構築が不可欠です。
LLMのハルシネーションを自動検出する主要な手法と評価指標
このセクションでは、ハルシネーションを自動で検出するための具体的な手法と、RAGシステムに特化した評価指標について解説します。
RAGアプリケーションの自動評価には、人間による評価に代わるものとして「LLM-as-a-Judge」アプローチが注目されています。
LLM-as-a-Judgeアプローチ
LLM-as-a-Judgeは、別の強力なLLMを「審査員」として使用し、生成された回答が提供されたコンテキストに忠実であるか(Faithfulness)を評価する手法です。
- 仕組み: 評価対象のLLMが生成した回答と、その回答の根拠となったコンテキストを「審査員LLM」に与え、回答がコンテキストに矛盾しないか、事実に基づいているかを評価させます。
-
メリット:
- 人間による評価と比較して、時間とコストを大幅に削減できます。
- 評価の客観性・一貫性を保ちやすくなります。
- 複雑なハルシネーションパターンも検出できる可能性があります。
-
トレードオフ:
- 審査員LLMの選定(精度 vs コスト/レイテンシ)が重要です。Databricksの研究では、GPT-3.5をLLMジャッジとして使用する際、各評価スコアの例を提供することで、GPT-4と比較してコストを10分の1に削減し、速度を3倍以上向上させる可能性が示されています。
RAG固有の自動評価指標
RAGシステムにおけるハルシネーション検出に特に重要なのが、以下の評価指標です。
-
Faithfulness (Groundedness):
- 定義: 生成された回答が、取得されたコンテキストによって事実上サポートされているかを測定する指標です。回答内の各主張がコンテキスト内に根拠があるかを評価します。
- 重要性: ハルシネーションを特定するための最も重要な指標であり、RAGシステムの信頼性を直接的に測ります。
-
Answer Relevancy:
- 定義: 生成された回答が、元の質問に対してどれだけ適切で関連性があるかを測定します。
- 重要性: 質問の意図を正しく理解し、的を射た回答を生成できているかを評価します。
-
Context Precision:
- 定義: 取得されたコンテキストが、質問に関連する情報のみを含んでいるかを測定します。関連性の低い情報(ノイズ)が多いとスコアが低くなります。
- 重要性: リトリーバーの精度を評価し、LLMがノイズに惑わされるリスクを低減する上で役立ちます。
-
Context Recall:
- 定義: 質問に対する回答を生成するために必要な情報が、取得されたコンテキストにどれだけ含まれているかを測定します。
- 重要性: 必要な情報が欠落していないか、リトリーバーが十分に機能しているかを評価します。
その他のハルシネーション検出アプローチ
- セマンティック類似性検出: 回答とコンテキストのセマンティックな類似性を評価し、乖離が大きい場合にハルシネーションと判断します。
- BERT確率的チェック、トークン類似性検出: 低コストで高速ですが、より複雑なハルシネーション(否定の反転など)の検出には限界があります。
- Vectara Hughes Hallucination Evaluation Model (HHEM): AI応答と取得されたコンテキスト間の事実の一貫性に焦点を当てた評価モデルです。
- AWSのハルシネーション検出アプローチ: LLMプロンプトベース検出、セマンティック類似性検出、BERT確率的チェック、トークン類似性検出の4つのアプローチを比較し、LLMプロンプトベース検出が精度とコストのバランスが良いとされています。
これらの手法と指標を組み合わせることで、RAGシステムのハルシネーションを多角的に、かつ効率的に検出することが可能になります。
RAG評価フレームワークを活用したハルシネーション検出の具体例
このセクションでは、DeepEvalとRAGASという2つの主要な評価フレームワークを使って、実際にハルシネーションを検出するコード例を示します。
DeepEval を用いたハルシネーション検出の例
DeepEvalは、LLMシステム(RAGパイプラインを含む)の品質をテストするためのオープンソース評価フレームワークです。Faithfulness、Contextual Precision、Contextual Recall、Contextual Relevancy、Answer Relevancy、そしてHallucinationなどのRAG固有のメトリクスを提供します。
以下のコードは、DeepEval v0.20.x を使用して、LLMが生成した回答が与えられたコンテキストに対してハルシネーションを起こしているかどうかを検出する例です。HallucinationMetricがLLM-as-a-Judgeとして機能し、回答の事実性を評価します。
# DeepEvalのインストール
# pip install deepeval
from deepeval.metrics import HallucinationMetric
from deepeval.test_case import LLMTestCase
from deepeval import evaluate # evaluate関数をインポート
import os
# OpenAI APIキーの設定 (環境変数または直接設定)
# DeepEvalはデフォルトでOpenAIのモデルをLLM-as-a-Judgeとして使用します
# os.environ["OPENAI_API_KEY"] = "YOUR_OPENAI_API_KEY"
# テストケースの定義
# context: LLMが回答を生成する際に参照すべき事実
# actual_output: LLMが生成した実際の回答
# ここでは意図的にハルシネーションを含む回答を設定
test_case = LLMTestCase(
context="The Great Wall of China is a series of fortifications made of stone, brick, tamped earth, wood, and other materials, generally built along an east-to-west line across the historical northern borders of China to protect the Chinese states and empires against the raids and invasions of various nomadic groups of the Eurasian Steppe.",
actual_output="The Great Wall of China was primarily built with concrete and steel to protect against alien invasions."
)
# HallucinationMetricの初期化
# thresholdはハルシネーションと判断するスコアのしきい値 (0-1)。
# スコアが高いほどハルシネーションの可能性が高いと解釈されます。
halu_metric = HallucinationMetric(threshold=0.5)
# ハルシネーションの測定
# DeepEval v0.20.x 以降では、evaluate関数を使ってメトリクスを評価するのが推奨されます。
# evaluate関数はリスト形式でテストケースを受け取り、評価結果を返します。
print("DeepEvalでハルシネーションを評価中...")
results = evaluate([test_case], metrics=[halu_metric])
# 結果の出力
# evaluate関数の戻り値はリストなので、最初のテストケースの結果を取得
if results and results[0].metrics:
# HallucinationMetricはresults[0].metricsリストの最初の要素として格納されます
evaluated_metric = results[0].metrics[0]
print("\nHallucination Metric:")
print(" Score: ", evaluated_metric.score) # スコア (0-1, 高いほどハルシネーションの可能性が高い)
print(" Reason: ", evaluated_metric.reason) # ハルシネーションと判断された理由
print(" Success: ", evaluated_metric.success) # スコアがthresholdを下回ればTrue
else:
print("評価結果が取得できませんでした。")
この例では、actual_outputがcontextと明らかに矛盾しているため、HallucinationMetricのスコアは高く、reasonにはハルシネーションと判断された具体的な理由が出力されます。
RAGAS を用いたRAGパイプラインの評価例
RAGASは、RAGシステムの評価に特化したフレームワークで、Faithfulness、Answer Relevancy、Context Precision、Context Recallなどのメトリクスを提供します。特に、自動でテストセットを生成する機能が強力で、これにより評価データ作成の手間を大幅に削減できます。
以下のコードは、RAGAS v0.1.x と LangChain v0.1.x を使用して、RAGパイプラインを評価する例です。
# RAGASのインストール
# pip install ragas langchain_openai pypdf python-dotenv chromadb datasets pandas
from dotenv import load_dotenv
from ragas.llms import LangchainLLM
from ragas.embeddings import LangchainEmbeddings
from ragas.testset import generator
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
)
from datasets import Dataset
import os
import pandas as pd
load_dotenv() # 環境変数からAPIキーをロード
# 1. ドキュメント処理
# 評価したいPDFドキュメントを準備 (例: "your_document.pdf")
# テスト用にダミーのPDFファイルを作成するか、既存の短いPDFを使用してください。
# 例: 'echo "This is a test document about the history of AI. AI started in the 1950s." > your_document.pdf'
# または、より複雑なPDFを準備
try:
loader = PyPDFLoader("your_document.pdf")
documents = loader.load()
if not documents:
print("警告: 'your_document.pdf' が空か、読み込めませんでした。ダミーデータで続行します。")
from langchain_core.documents import Document
documents = [Document(page_content="The capital of France is Paris. The Eiffel Tower is in Paris. Paris is known for its art and culture.")]
except Exception as e:
print(f"PDF読み込みエラー: {e}。ダミーデータで続行します。")
from langchain_core.documents import Document
documents = [Document(page_content="The capital of France is Paris. The Eiffel Tower is in Paris. Paris is known for its art and culture.")]
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = text_splitter.split_documents(documents)
# 2. RAGパイプラインの構築
embedding_model = OpenAIEmbeddings(model="text-embedding-ada-002") # モデル名を明示
vectorstore = Chroma(embedding_function=embedding_model, persist_directory="./chroma_db", collection_name="my_rag_collection")
vectorstore.add_documents(chunks)
retriever = vectorstore.as_retriever()
llm = ChatOpenAI(model_name="gpt-3.5-turbo-0125", temperature=0) # モデル名を明示, temperatureを0に設定して再現性を高める
# LangChain Expression Language (LCEL) を使用したRAGチェーン
# コンテキストと質問を明確に分離することで、LLMがコンテキストに基づいた回答を生成しやすくなります。
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| ChatPromptTemplate.from_template(
"Use the following context to answer the question:\n\nContext: {context}\n\nQuestion: {question}"
)
| llm
)
# 3. テストセットの自動生成 (RAGASの主要機能)
# RAGAS v0.1.x では LangchainLLM, LangchainEmbeddings を使用してテストセットを生成します。
generator_llm = LangchainLLM(llm=llm)
critic_llm = LangchainLLM(llm=llm) # 評価LLMとしても使用
embeddings = LangchainEmbeddings(embeddings=embedding_model)
# TestsetGeneratorのインスタンス化
testset_generator = generator.TestsetGenerator(
generator_llm=generator_llm,
critic_llm=critic_llm,
embeddings=embeddings
)
# ドキュメントからテストセットを生成
print("テストセットを生成中...")
# generate_with_documents は非推奨になる可能性があるので、generate_with_langchain_docs を使用
# 公式ドキュメントで最新の推奨APIを確認すること
testset = testset_generator.generate_with_langchain_docs(documents, test_size=5) # test_sizeを小さくして試行
testset_df = testset.to_pandas()
testset_df.to_csv("generated_testset.csv", index=False)
print("生成されたテストセット:")
print(testset_df)
# 4. RAGASによる評価 (生成されたテストセットを使用)
print("\nRAGパイプラインを評価中...")
# RAGASの評価には、質問、回答、コンテキスト、グラウンドトゥルース(オプション)を含むDatasetが必要
# 生成されたテストセットから必要な情報を抽出
# RAGASのevaluate関数は、Datasetオブジェクトを直接受け取る
# Datasetは 'question', 'answer', 'contexts', 'ground_truths' のカラムを持つ必要がある
# 'answer'と'contexts'はRAGパイプラインを実行して取得する必要がある
# RAGパイプラインの出力を収集するための関数
def get_rag_outputs(questions):
answers = []
contexts = []
for q in questions:
# RAGチェーンを実行して回答とコンテキストを取得
# LangChainのRunnablePassthroughとRunnableLambdaを使ってコンテキストを直接取得する
# RAGASの評価では、コンテキストはリスト形式で渡す必要がある
retrieved_docs = retriever.invoke(q)
# answer_outputはAIMessageオブジェクトなので、.contentで文字列を取得
answer_output = rag_chain.invoke(q)
answers.append(answer_output.content)
# コンテキストはリストのリストとして渡すため、page_contentを抽出
contexts.append([doc.page_content for doc in retrieved_docs])
return answers, contexts
# 生成されたテストセットの質問を使用
questions = testset_df["question"].tolist()
ground_truths = testset_df["ground_truth"].tolist() # ground_truthも使用
# RAGパイプラインを実行して回答とコンテキストを取得
rag_answers, rag_contexts = get_rag_outputs(questions)
# RAGAS評価用のデータセットを作成
data = {
"question": questions,
"answer": rag_answers,
"contexts": rag_contexts,
"ground_truths": ground_truths,
}
ragas_dataset = Dataset.from_dict(data)
# RAGASの評価を実行
result = evaluate(
ragas_dataset,
metrics=[
faithfulness,
answer_relevancy,
context_precision,
context_recall
],
llm=llm, # RAGASの評価LLMとして使用
embeddings=embedding_model # RAGASの評価埋め込みモデルとして使用
)
print("\nRAGAS 評価結果:")
print(result)
print(result.to_pandas())
# ChromaDBの永続化ディレクトリをクリーンアップ (オプション)
# import shutil
# if os.path.exists("./chroma_db"):
# shutil.rmtree("./chroma_db")
このコードを実行するには、your_document.pdfというファイルを作成し、OpenAI APIキーを環境変数に設定する必要があります。RAGASは、生成された質問とグラウンドトゥルース(正解)に基づいて、RAGパイプラインのFaithfulness、Answer Relevancy、Context Precision、Context Recallを自動で評価し、各メトリクスのスコアを出力します。特にFaithfulnessのスコアは、ハルシネーションの度合いを示す重要な指標となります。
RAGシステムにおけるハルシネーションのよくあるハマりどころと回避策
このセクションでは、RAG開発でエンジニアが陥りやすいハルシネーション関連の問題と、その具体的な解決策を解説します。
1. 取得されたコンテキストの不備(Missing Content / Irrelevant Context)
- ハマりどころ: ユーザーの質問に対する回答が知識ベースに存在しない場合、RAGシステムは「知らない」と答える代わりに、もっともらしいが事実に基づかない回答を生成してしまうことがあります。また、リトリーバーの精度が低いと、関連性の低いドキュメントが取得され、LLMがノイズに惑わされることもあります。
-
回避策:
- 包括的で最新の知識ベースの維持: 定期的にコンテンツを更新し、情報のギャップを監査しましょう。古い情報や誤った情報もハルシネーションの原因となります。
- チャンキング戦略の最適化: ドキュメントを適切なサイズに分割し、関連性の高い情報が確実に取得されるようにします。チャンクサイズが小さすぎるとコンテキストが失われ、大きすぎるとノイズが増えます。チャンクオーバーラップも考慮し、文脈の連続性を保ちましょう。
- リトリーバルアルゴリズムの改善: ベクトル検索だけでなく、メタデータ(タイムスタンプ、作成者、カテゴリなど)を組み込んで検索とランキングの精度を高めます。キーワード検索とベクトル検索を組み合わせたハイブリッド検索も非常に有効です。
- リランカーの導入: 取得されたドキュメントの関連性をさらに向上させるために、Cohere RerankやBGE-Rerankerなどのリランカーを使用することを検討しましょう。
- 「知らない」と答えるメカニズムの導入: 関連情報が見つからない場合に、LLMに「情報がありません」と明確に回答させるようにプロンプトを設計します(例: "If the context does not contain the answer, state that you don't know.")。
2. LLMによる回答抽出エラー(Answer Extraction Errors)
- ハマりどころ: 関連するドキュメントがコンテキストとして与えられても、LLMがそこから正しい情報を抽出できなかったり、矛盾する情報やノイズに惑わされて不完全または誤解を招く回答を生成したりします。
-
回避策:
- プロンプトデザインの改善: LLMに「提供されたドキュメントのみに依存する」ように、そして「特定の形式で出力する」ように明確な指示を与えます。コンテキストと質問をXMLタグやトリプルバッククォートなどの明示的な区切り文字で分離し、LLMがどこまでがコンテキストかを明確に認識できるようにします。
- 知識ベースのクリーンアップ: 矛盾する情報や重複する情報を排除し、ノイズを減らすことで、LLMが正しい情報を抽出しやすくなります。
- LLMのチューニング: 特定のタスクに合わせてLLMをファインチューニングすることで、抽出精度を向上させることができます(ただし、コストと労力がかかります)。
- Few-shot prompting: プロンプト内に正しい回答の例をいくつか含めることで、LLMの挙動を誘導し、望ましい形式での回答生成を促します。
3. ハルシネーションの継続(Persisting LLM Hallucinations)
- ハマりどころ: RAGはハルシネーションを減らすものの、完全に排除するわけではありません。取得された情報が不完全であったり、わずかにずれていたりすると、LLMは既存の知識と提供されたコンテキストを混ぜ合わせて、もっともらしいが根拠のない詳細を作り出すことがあります。
-
回避策:
- 厳密なグラウンディングと検証の追加: LLMに「取得されたソースのみを使用する」ように強く指示し、さらに「各主張に詳細な引用を要求する」ようにプロンプトで強制します。
- LLM-as-a-Judgeによる自動検出: 別の強力なLLMを「審査員」として使用し、生成された回答が提供されたコンテキストに忠実であるか(Faithfulness)を継続的に評価します。特に、回答を個々の主張に分解し、それぞれをコンテキストと照合して検証する「Claim-by-Claim Verification」が最も堅牢な方法です。
- 複数の検出手法の組み合わせ: トークン類似性検出で明らかなハルシネーションをフィルタリングし、LLMベースの検出器でより困難なハルシネーションを特定するなど、複数の手法を組み合わせることで検出精度を高めます。
- フィードバックループの導入: ユーザーからのフィードバックを継続的に収集し、リトリーバルや生成コンポーネントの改善に活用する運用体制を構築します。
これらの回避策を講じることで、RAGシステムにおけるハルシネーションのリスクを大幅に低減し、より信頼性の高いLLMアプリケーションを開発できます。
RAG評価ワークフローの構築とベストプラクティス
このセクションでは、RAGシステムの品質を継続的に維持・向上させるための評価ワークフローと、設計上のトレードオフ、そしてベストプラクティスについて解説します。
RAG評価ワークフローの構築
効果的なRAG評価ワークフローは、開発の初期段階から本番環境での運用まで、一貫して品質を監視し改善するための基盤となります。
-
評価指標の定義:
- RAG固有の指標(Faithfulness, Answer Relevancy, Context Precision, Context Recall)と、ビジネス要件に合わせたカスタム指標を明確に定義します。
-
テストセットの準備:
- 手動で作成したテストケースに加えて、RAGASなどのツールを使って合成データセットを生成し、多様なシナリオをカバーします。
- 合成データセットは、LLMを使って評価用の質問とグラウンドトゥルースの回答ペアを生成することで、手動作成の手間を省き、多様なテストケースを確保できます。
-
自動評価の実施:
- DeepEvalやRAGASのようなフレームワークを導入し、定義した指標に基づいて定期的に評価を実行します。
- 特にRAGアプリケーションに大きな変更(プロンプト、モデル更新、知識ベースの変更など)があった際には、必ず自動ハルシネーション検出を実行します。
-
結果の分析と問題特定:
- 評価スコアを分析し、どのメトリクスが低いか、どのテストケースで問題が発生しているかを特定します。
- リトリーバーとジェネレーターを個別に評価することで、問題の原因を特定しやすくなります。
-
改善策の適用:
- 問題の原因に基づいて、チャンキング戦略、リトリーバーアルゴリズム、プロンプトデザイン、LLMモデルの選択など、RAGシステムの各コンポーネントを改善します。
-
CI/CDパイプラインへの統合:
- 重要なアプリケーションでは、CI/CDパイプラインに評価を組み込み、品質しきい値(例: Faithfulness > 0.7)を下回る変更が本番環境にデプロイされるのを防ぎます。これにより、不正確な回答がユーザーに届くリスクを最小限に抑えます。
-
継続的な監視とフィードバック:
- 本番環境でのパフォーマンスを監視し、ユーザーからのフィードバックを収集して評価サイクルに組み込みます。テストスイートもアプリケーションの進化に合わせて定期的に更新します。
設計上のトレードオフ
RAGシステムの評価と改善には、いくつかのトレードオフが存在します。
-
精度 vs コスト/レイテンシ:
- LLM-as-a-Judgeのような高精度な評価方法は、追加の推論オーバーヘッドを発生させ、API料金やレイテンシを増加させます。
- GPT-4のような強力なLLMを評価に使うと高精度ですが高コストです。GPT-3.5に評価例をいくつか与えることで、コストを抑えつつ精度を維持できる場合があります。
- トークン類似性検出は低コストですが、精度が低く、複雑なハルシネーションを見逃す可能性があります。LLMプロンプトベース検出は、精度とコストのバランスが良い選択肢とされています。
-
チャンクサイズ:
- チャンクサイズが小さいと、より精密な検索が可能になりますが、コンテキストが断片化し、LLMが全体像を把握しにくくなる可能性があります。
- チャンクサイズが大きいと、より多くのコンテキストを保持できますが、関連性の低い情報が含まれる可能性が高まり、LLMがノイズに惑わされるリスクがあります。適切なチャンクサイズは、ドキュメントの種類や質問の特性によって異なります。
-
評価モデルの選択:
- 特定のLLMのエラーに特化して訓練されたカスタム評価モデルは、高い精度を発揮する可能性がありますが、将来的にLLMが異なる種類のエラーを生成するようになった場合に性能が不透明になる可能性があります。汎用的なLLM-as-a-Judgeの方が柔軟性が高い傾向があります。
ベストプラクティス
- RAG固有の評価指標の活用: Faithfulness (Groundedness)、Answer Relevancy、Context Precision、Context Recallなど、RAGシステムに特化した指標を積極的に使用し、多角的に評価します。
- LLM-as-a-Judgeアプローチの採用: ハルシネーション検出の最もスケーラブルな方法として、強力なLLMを評価者として使用します。特に「Claim-by-Claim Verification」は堅牢です。
- 自動評価の継続的な実施: RAGアプリケーションに大きな変更があった際には、必ず自動ハルシネーション検出を実行し、品質低下を早期に発見します。
- CI/CDパイプラインへの統合: 重要なアプリケーションでは、CI/CDパイプラインに評価を組み込み、品質ゲートとして機能させます。
- テストスイートの定期的な更新: アプリケーションの進化や新しいデータソースの出現に合わせて、新しいテストケースを追加し、評価の網羅性を高めます。
- リトリーバルと生成の分離評価: 問題の原因を特定しやすくするために、リトリーバーとジェネレーターを個別に評価します。
- カスタムメトリクスの利用: 標準メトリクスでカバーできない評価基準がある場合は、カスタムメトリクスを作成するか、G-Evalフレームワークを活用して独自の評価ルールを定義します。
- 合成データセットの活用: LLMを使用して評価用の質問とグラウンドトゥルースの回答ペアを生成することで、手動作成の手間を省き、多様なテストケースを確保します。
- 品質しきい値の設定と監視: Faithfulness > 0.7、Answer Relevancy > 0.8 のように品質しきい値を設定し、システムの更新に伴うメトリクスの変動を継続的に監視します。
まとめ
この記事では、RAGシステムにおけるLLMのハルシネーション問題に対し、評価駆動開発のアプローチを取り入れ、自動評価ツールや指標を用いてハルシネーションを効率的に検出し、改善サイクルを自動化する具体的な手順と知見を提供しました。
重要なポイントをまとめます。
- RAGシステムにおいてもLLMのハルシネーションは発生し、ユーザーの信頼を損なう深刻な問題となり得ます。
- ハルシネーションの自動検出には、LLM-as-a-Judgeアプローチと、Faithfulness (Groundedness) などのRAG固有の評価指標が非常に有効です。
- DeepEvalやRAGASといったフレームワークを活用することで、これらの評価を効率的に実装できます。特にRAGASはテストセットの自動生成機能が強力です。
- 取得コンテキストの不備、回答抽出エラー、ハルシネーションの継続といったハマりどころに対しては、チャンキング戦略の最適化、プロンプトデザインの改善、リランカーの導入、そして「知らない」と答えるメカニズムの導入などが有効な回避策です。
- CI/CDパイプラインへの自動評価の統合や、品質しきい値の設定と監視など、継続的な評価ワークフローを構築することが、信頼性の高いLLMアプリケーション開発には不可欠です。
RAGシステムの品質向上は、一度行えば終わりではなく、継続的な評価と改善が求められます。本記事で紹介した手法とフレームワークを参考に、ぜひご自身のRAGアプリケーションの信頼性向上に取り組んでみてください。
さらに深く学びたい方は、各評価フレームワークの公式ドキュメントや、RAGに関する最新の論文を参照することをお勧めします。