この記事をシェア
ハルシネーションを定量的に検知し、回答精度を継続的に計測する。テストフェーズの「勘頼み」から卒業するための実践ハンドブック。
はじめに:大企業でAIエージェント導入が失敗する本当の理由
AIチャットボットやエージェントの開発でテストフェーズに入ると、必ずぶつかる壁がある。
「この回答、正しいのか?」
従来のソフトウェアテストなら、期待値と実際の出力を比較すれば済む。しかしLLMの出力は自然言語であり、同じ意味でも表現が無数にある。しかも最も厄介な問題——ハルシネーション(もっともらしい嘘)——は、人間が一件一件チェックしなければ見逃すリスクがある。
コンサルタントとして大企業のAI導入に関わっていると、こんな場面によく出くわす。技術的な検証は十分できている。精度もそこそこ出ている。なのに、最終的な意思決定者から「導入見送り」の結論が下される。
理由を聞くと、決まってこう返ってくる。
「AIが間違えたとき、誰が責任を取るんですか?」
これは一見、責任論の問題に見える。しかし本質は違う。大企業が本当に恐れているのは「AIが間違えること」ではなく、「AIが間違えているのに気づけないこと」だ。
人間でも間違いは起きる。だが人間の場合、上司がレビューする、同僚がダブルチェックする、という仕組みが自然とある。AIの場合は? 無数の回答がシステムから流れ出ていき、どれが正しくてどれが誤りなのか、誰も把握できていない——それが恐怖の正体だ。
この「見えない恐怖」を解消する手段が、AI出力の定量的スコアリングである。回答に点数をつけ、低スコアの回答だけ人間がレビューする仕組みを作れば、「間違いに気づけない」問題は構造的に解決できる。
このガイドでは以下の2ツールを使い、定量的・自動的にAI出力を評価する方法を解説する。
| ツール | 得意領域 |
|---|---|
| RAGAS | RAGシステムのハルシネーション・精度評価 |
| DeepEval | 汎用LLMの多角的品質評価・CI組み込み |
Part 1: RAGAS
概要
RAGAS(Retrieval Augmented Generation Assessment) は、RAG(検索拡張生成)システムに特化した評価フレームワーク。2023年にES Dingらが発表した論文をベースに開発され、現在はOSSとして活発にメンテナンスされている。
GitHubスター数:8,000以上(2025年時点)
仕組み
RAGASの核心は「LLM-as-Judge」パターンにある。GPT-4やClaudeなどの高性能モデルを「審査員」として使い、評価対象の出力を採点させる。
評価は以下の4つの主要メトリクスで構成される:
質問 (Question)
↓
検索コンテキスト (Context) ←── ベクターDB検索結果
↓
LLMが生成した回答 (Answer)
↓
正解(グラウンドトゥルース)(Ground Truth) ←── あれば
| メトリクス | 計測内容 | スコア範囲 |
|---|---|---|
| Faithfulness | 回答がコンテキストに忠実か(ハルシネーション逆指標) | 0〜1 |
| Answer Relevancy | 回答が質問に対して的確か | 0〜1 |
| Context Precision | 検索されたコンテキストの中で関連箇所の割合 | 0〜1 |
| Context Recall | 正解の情報をコンテキストがカバーできているか | 0〜1 |
Faithfulnessの計算ロジック
1. 回答を複数の「クレーム(主張)」に分解する
例:「東京の人口は1,400万人で、日本最大の都市です」
→ クレームA: 東京の人口は1,400万人
→ クレームB: 東京は日本最大の都市
2. 各クレームがコンテキスト内に根拠があるかを判定
コンテキスト内に根拠あり → 1
コンテキスト内に根拠なし → 0(ハルシネーション)
3. Faithfulness = 根拠ありクレーム数 ÷ 総クレーム数
このスコアが低い=コンテキストにない情報を回答に含めている=ハルシネーション。
インストール
pip install ragas
評価バックエンドにOpenAIを使う場合(デフォルト):
pip install ragas openai
export OPENAI_API_KEY="sk-..."
Claudeをバックエンドに使う場合(後述):
pip install ragas anthropic
export ANTHROPIC_API_KEY="sk-ant-..."
基本的な使い方
① データセットの準備
RAGASには以下の4フィールドが必要(ground_truthは任意):
from datasets import Dataset
# 評価データの作成
data = {
"question": [
"返品ポリシーはどうなっていますか?",
"配送にはどのくらいかかりますか?",
],
"answer": [
"商品到着後30日以内であれば返品可能です。レシートが必要です。",
"通常3〜5営業日でお届けします。離島は別途7〜10日かかります。",
],
"contexts": [
# RAGが検索してきたドキュメントチャンク(リスト形式)
["当社の返品ポリシー:購入後30日以内に限り返品を受け付けます。返品の際は必ずレシートをご持参ください。"],
["配送について:標準配送は3〜5営業日。沖縄・離島は10〜14営業日となります。"],
],
"ground_truth": [
# 正解(任意。Context Recallの計算に使用)
"到着後30日以内、レシート持参で返品可能です。",
"3〜5営業日。離島は7〜10日。",
]
}
dataset = Dataset.from_dict(data)
② 評価の実行
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
)
result = evaluate(
dataset,
metrics=[
faithfulness,
answer_relevancy,
context_precision,
context_recall,
],
)
print(result)
③ 結果の確認
# DataFrameとして確認
df = result.to_pandas()
print(df)
# 出力例:
# faithfulness answer_relevancy context_precision context_recall
# 0 1.00 0.92 1.00 0.85
# 1 0.75 0.88 0.80 0.90
faithfulnessが0.75の行に注目。コンテキストには「沖縄・離島は10〜14営業日」とあるが、回答は「7〜10日」と書いており、ここがハルシネーションとして検知されている。
ClaudeをバックエンドにするRAGAS設定
RAGASはデフォルトでOpenAIを使うが、Claudeに変更可能:
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy
from langchain_anthropic import ChatAnthropic
from langchain_anthropic import AnthropicEmbeddings
# Claudeモデルを審査員に設定
llm = ChatAnthropic(model="claude-haiku-4-5-20251001") # コスト抑制にHaikuが有効
# 埋め込みモデルの設定(Answer Relevancyに必要)
embeddings = AnthropicEmbeddings(model="voyage-3")
result = evaluate(
dataset,
metrics=[faithfulness, answer_relevancy],
llm=llm,
embeddings=embeddings,
)
コスト注意:GPT-4oで評価すると100件で数百〜数千円かかる場合がある。Claude Haikuは大幅に安価。
実践的な活用:閾値ベースのアラート
import pandas as pd
def evaluate_and_alert(dataset, threshold_faithfulness=0.85):
result = evaluate(
dataset,
metrics=[faithfulness, answer_relevancy],
)
df = result.to_pandas()
# ハルシネーションの疑いがある行を抽出
hallucination_risk = df[df["faithfulness"] < threshold_faithfulness]
if len(hallucination_risk) > 0:
print(f"⚠ ハルシネーションリスク検知: {len(hallucination_risk)}件")
print(hallucination_risk[["question", "answer", "faithfulness"]])
else:
print("✅ ハルシネーションリスクなし")
return df
evaluate_and_alert(dataset)
Part 2: DeepEval
概要
DeepEval はConfident AI社が開発する、LLM評価に特化したOSSフレームワーク。RAGASと異なり、RAGに限らず汎用のチャットボット・LLMアプリケーション全般に対応している。
最大の特徴はpytestと統合できること。既存のCIパイプラインにそのまま組み込める。
GitHubスター数:9,000以上(2025年時点)
仕組み
DeepEvalのメトリクスは大きく3種類に分類される:
┌─────────────────────────────────────────────────────┐
│ DeepEvalのメトリクス │
├─────────────────┬───────────────────────────────────┤
│ RAG系 │ Faithfulness, Answer Relevancy, │
│ │ Contextual Precision/Recall │
├─────────────────┼───────────────────────────────────┤
│ 汎用品質系 │ G-Eval, Hallucination, │
│ │ Bias, Toxicity │
├─────────────────┼───────────────────────────────────┤
│ エージェント系 │ Task Completion, Tool Correctness │
└─────────────────┴───────────────────────────────────┘
G-Evalとは
G-EvalはDeepEvalの中核メトリクスで、評価基準を自然言語で定義できるのが最大の強み。
評価基準(自然言語)→ LLMが評価ステップを生成 → Chain-of-Thoughtで採点
業務要件をそのまま評価基準に書けるため、ドメイン固有の品質定義に強い。
インストール
pip install deepeval
初回セットアップ(任意:Confident AIのダッシュボードと連携する場合):
deepeval login
export OPENAI_API_KEY="sk-..."
基本的な使い方
① テストケースの定義
from deepeval.test_case import LLMTestCase
test_case = LLMTestCase(
input="返品ポリシーを教えてください",
actual_output="商品到着後30日以内であれば返品可能です。レシートが必要です。",
expected_output="到着後30日以内、レシート持参で返品可能です。", # 任意
retrieval_context=[ # RAGのコンテキスト(任意)
"当社の返品ポリシー:購入後30日以内に限り返品を受け付けます。返品の際は必ずレシートをご持参ください。"
],
)
② ハルシネーション検知
from deepeval.metrics import HallucinationMetric
from deepeval import evaluate
metric = HallucinationMetric(
threshold=0.8, # スコアがこれを下回ると失敗
model="gpt-4o",
include_reason=True, # 判定理由を含める
)
evaluate([test_case], [metric])
③ G-Eval(カスタム評価基準)
from deepeval.metrics import GEval
from deepeval.test_case import LLMTestCaseParams
# 業務要件を直接評価基準として定義
correctness_metric = GEval(
name="Correctness",
criteria="""
回答が以下の基準を満たしているか評価してください:
1. 質問に対して直接的に答えている
2. 事実として誤った情報を含んでいない
3. 重要な情報を省略していない
4. 丁寧で適切なトーンである
""",
evaluation_params=[
LLMTestCaseParams.INPUT,
LLMTestCaseParams.ACTUAL_OUTPUT,
LLMTestCaseParams.EXPECTED_OUTPUT,
],
threshold=0.7,
)
evaluate([test_case], [correctness_metric])
④ 結果の取得と解釈
from deepeval.metrics import HallucinationMetric, GEval
from deepeval.test_case import LLMTestCaseParams
from deepeval import evaluate
# 複数メトリクスを同時評価
metrics = [
HallucinationMetric(threshold=0.8, include_reason=True),
GEval(
name="Correctness",
criteria="回答が質問に対して正確で完全であること",
evaluation_params=[
LLMTestCaseParams.INPUT,
LLMTestCaseParams.ACTUAL_OUTPUT,
],
threshold=0.7,
),
]
results = evaluate([test_case], metrics)
# 個別スコアの取得
for metric in metrics:
print(f"{metric.__class__.__name__}")
print(f" スコア: {metric.score:.2f}")
print(f" 合否: {'✅ PASS' if metric.is_successful() else '❌ FAIL'}")
if hasattr(metric, 'reason'):
print(f" 理由: {metric.reason}")
出力例:
HallucinationMetric
スコア: 0.92
合否: ✅ PASS
理由: The actual output is consistent with the provided context. All claims are supported.
Correctness
スコア: 0.85
合否: ✅ PASS
理由: The answer directly addresses the question and contains no factual errors.
pytestへの統合(CI/CD連携)
DeepEvalの最大の強みはここにある。
# test_chatbot.py
import pytest
from deepeval import assert_test
from deepeval.test_case import LLMTestCase
from deepeval.metrics import HallucinationMetric, GEval
from deepeval.test_case import LLMTestCaseParams
# 実際のチャットボットAPIを呼ぶ関数(任意に実装)
def call_chatbot(question: str) -> str:
# ここにチャットボットAPIの呼び出しを実装
return "..."
@pytest.mark.parametrize("question,context,expected", [
(
"返品ポリシーを教えてください",
["購入後30日以内に限り返品を受け付けます。レシート必須。"],
"30日以内、レシート持参で返品可能",
),
(
"配送日数を教えてください",
["標準配送3〜5営業日。離島は10〜14営業日。"],
"3〜5営業日(離島は10〜14日)",
),
])
def test_chatbot_quality(question, context, expected):
actual_output = call_chatbot(question)
test_case = LLMTestCase(
input=question,
actual_output=actual_output,
expected_output=expected,
retrieval_context=context,
)
assert_test(test_case, [
HallucinationMetric(threshold=0.85),
GEval(
name="Correctness",
criteria="回答が質問に正確に答えており、重要な情報を省略していないこと",
evaluation_params=[
LLMTestCaseParams.INPUT,
LLMTestCaseParams.ACTUAL_OUTPUT,
LLMTestCaseParams.EXPECTED_OUTPUT,
],
threshold=0.7,
),
])
実行:
deepeval test run test_chatbot.py
# または
pytest test_chatbot.py -v
GitHub Actionsへの組み込み例:
# .github/workflows/llm-eval.yml
name: LLM Quality Gate
on:
pull_request:
branches: [main]
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install dependencies
run: pip install deepeval openai
- name: Run LLM evaluation
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: deepeval test run tests/test_chatbot.py
これでPRマージ前にLLM品質ゲートが走る。
Part 3: RAGAS vs DeepEval 使い分けガイド
判断フローチャート
あなたのシステムは?
│
├─ RAG構成(ベクターDB+検索あり)
│ │
│ └─ まずRAGASから始める
│ Faithfulness / Context Precision / Recall
│ ↓
│ ハルシネーション以外の品質も見たい?
│ → DeepEvalも追加(G-Eval)
│
└─ 汎用チャットボット(RAGなし)
│
└─ DeepEvalから始める
HallucinationMetric + G-Eval
↓
CIに組み込みたい?
→ pytest統合を活用
組み合わせ構成(推奨)
# 最強の評価パイプライン
# RAGAS → ハルシネーション・RAG精度
# DeepEval → カスタム品質基準・CI統合
# Step 1: RAGASでRAG品質の基礎評価
ragas_result = evaluate(dataset, metrics=[faithfulness, answer_relevancy])
# Step 2: スコアが低いケースをDeepEvalで詳細分析
low_quality_cases = ragas_result.to_pandas()[
ragas_result.to_pandas()["faithfulness"] < 0.85
]
for _, row in low_quality_cases.iterrows():
test_case = LLMTestCase(
input=row["question"],
actual_output=row["answer"],
retrieval_context=row["contexts"],
)
# DeepEvalのHallucinationMetricで詳細な理由を取得
metric = HallucinationMetric(threshold=0.8, include_reason=True)
metric.measure(test_case)
print(f"Q: {row['question']}")
print(f"判定理由: {metric.reason}\n")
Part 4: スコアリングと「人間のダブルチェック」を組み合わせる
ここが大企業導入の鍵になるポイントだ。スコアリングは「全件自動判定」のためだけにあるのではない。「低スコアの回答だけ人間がレビューする」というハイブリッド体制を作るためのものでもある。
大企業が「AIが間違いに気づけない」ことを恐れているなら、答えはシンプルだ。
- 全回答をスコアリングする(自動)
- スコアが閾値を下回ったものだけを人間にエスカレーションする
- 人間のレビューを通過したものだけを公式回答として扱う
たとえば、faithfulnessが0.85を下回る回答が全体の3%だとしよう。月1,000件のクエリなら、人間がレビューすべきは30件だけ。これなら「すべてを人間がチェックする」という旧来の方式と比べてもコストは大幅に削減できる上に、「間違いを見逃さない」という保証も維持できる。
def route_to_human_review(df, threshold_faithfulness=0.85):
"""スコアが低い回答をエスカレーションキューに積む"""
needs_review = df[df["faithfulness"] < threshold_faithfulness].copy()
auto_approved = df[df["faithfulness"] >= threshold_faithfulness].copy()
needs_review["status"] = "human_review_required"
auto_approved["status"] = "auto_approved"
print(f"自動承認: {len(auto_approved)}件 ({len(auto_approved)/len(df)*100:.1f}%)")
print(f"要人間確認: {len(needs_review)}件 ({len(needs_review)/len(df)*100:.1f}%)")
# Slackやチケットシステムへの通知処理をここに実装
for _, row in needs_review.iterrows():
notify_reviewer(row["question"], row["answer"], row["faithfulness"])
return auto_approved, needs_review
このアーキテクチャは「AIが自律的にすべてを決める」のではなく、「AIが仕分けをして、怪しいものだけ人間の目を通す」という設計だ。大企業の内部統制の観点でも受け入れやすく、責任の所在も明確になる。
Part 5: 他のソリューションとの比較
RAGAS・DeepEval以外にも、AI出力の品質管理に使えるツールやサービスはある。それぞれ特性が異なるので、目的に応じて使い分けを検討したい。
LangSmith(LangChain社)
LangSmith はLangChain社が提供するLLMアプリのオブザーバビリティ・評価プラットフォームだ。OSSのRAGAS/DeepEvalと異なり、SaaS型のダッシュボードが充実している。
- 強み:本番トラフィックのトレース・サンプリング収集、A/Bテスト、チームでの評価レビューワークフロー
- 弱み:クラウドへのデータ送信が必要(機密データの扱いに注意が必要)、有料プランが前提になるケースも
- 向いているケース:LangChain/LangGraphを既に使っている、本番モニタリングをしたい
Guardrails AI
Guardrails AI は評価よりも「ガードレール(制約)」に特化したフレームワークだ。LLMの出力を構造化・検証し、ポリシー違反や有害コンテンツを検知・遮断する。
- 強み:PII(個人情報)検出、有害コンテンツフィルタ、出力スキーマ検証など、コンプライアンス要件に強い
- 弱み:ハルシネーションの意味的な評価はRAGASの方が得意
- 向いているケース:金融・医療・法務など、規制の厳しい業界での利用
どれを選ぶか?
| ツール | 評価の深さ | 本番監視 | コンプライアンス | CI統合 |
|---|---|---|---|---|
| RAGAS | RAG特化◎ | △ | △ | ○ |
| DeepEval | 汎用◎ | △ | ○ | ◎ |
| LangSmith | ○ | ◎ | ○ | ○ |
| Guardrails AI | △ | ○ | ◎ | ○ |
開発・テストフェーズはRAGAS/DeepEval、本番モニタリングはLangSmith、規制対応はGuardrails AIという使い分けが現実的だ。
Part 6: テストセット設計のベストプラクティス
評価ツールはあっても、テストセット(評価用の質問と正解)がなければ意味がない。
最低限のテストセット構成
| カテゴリ | 件数 | 内容 |
|---|---|---|
| 正常系(ドキュメントに答えあり) | 30件 | RAGが正確に答えられるべき質問 |
| 境界系(曖昧・部分的に答えあり) | 10件 | コンテキストに部分的にしか情報がない |
| 異常系(ドキュメントに答えなし) | 10件 | 「わかりません」と答えるべき質問 |
合計50件でまず始める。
テストデータの自動生成(RAGAS)
RAGASには既存ドキュメントからテストデータを自動生成する機能がある:
from ragas.testset import TestsetGenerator
from langchain_community.document_loaders import DirectoryLoader
# ドキュメントを読み込む
loader = DirectoryLoader("./docs/", glob="**/*.txt")
documents = loader.load()
# テストセットを自動生成
generator = TestsetGenerator.from_langchain(
generator_llm=ChatOpenAI(model="gpt-4o"),
critic_llm=ChatOpenAI(model="gpt-4o"),
embeddings=OpenAIEmbeddings(),
)
testset = generator.generate_with_langchain_docs(
documents,
test_size=50,
distributions={
"simple": 0.6, # 単純な質問
"reasoning": 0.2, # 推論が必要な質問
"multi_context": 0.2, # 複数ドキュメントにまたがる質問
},
)
testset.to_pandas().to_csv("testset.csv", index=False)
まとめ:実装ロードマップ
Phase 1(1〜2週間):計測を始める
pip install ragas deepeval
- テストセット50件を手動or自動生成で作成
- RAGASのFaithfulnessを週次でバッチ実行
- スコアをCSVに保存して推移を追う
Phase 2(2〜4週間):品質ゲートを設ける
- DeepEvalをpytestに統合
- GitHub ActionsのPRチェックに組み込む
- Faithfulness < 0.85のケースを自動でSlack通知
- スコア閾値ベースの人間エスカレーション機能を実装
Phase 3(継続運用):本番監視
- LangSmithで本番トラフィックをサンプリング収集
- 週次バッチ評価でスコア推移ダッシュボード化
- スコア低下のアラートで問題の早期発見
- 月次レポートで経営層・コンプライアンス担当への説明責任を果たす
最後の点が重要だ。このロードマップを実装すると、「AIが何をどれくらいの精度で答えているか」を定量的に示せるようになる。導入を躊躇していた経営層に対して、「ハルシネーション率0.3%、低スコア回答は全件人間レビュー済み」と言えるようになったとき、初めて大企業のAI導入は現実的な選択肢になる。
参考リンク
このガイドを参考に、AIチャットボットの品質評価を「感覚」から「数値」へ移行しよう。最初の50件のテストセット作成が一番大変だが、そこを乗り越えれば評価の自動化は一気に加速する。そしてそのスコアが、大企業の意思決定者を動かす「証拠」になる。
