「昨日は正しい答えを返していたのに、今日は違うことを言っている」——LLMを使ったサービスで最も頭を悩ませる問題だ。従来のソフトウェアのテストとは異なり、LLMの出力は確率的であり、同じ入力でも毎回異なる結果が返ることがある。このような特性を持つAIサービスの品質をどう担保するか、実践的なアプローチを解説する。
LLM品質保証が難しい理由
従来のソフトウェアテストは「期待する出力値」を定義できる。add(1, 2) === 3 のような単純な真偽判定だ。しかしLLMの場合、「良い回答」の定義自体が曖昧なことが多い。
さらに、LLMサービスには以下の特有の品質リスクがある。
- ハルシネーション: 存在しない事実を自信を持って回答する
- プロンプト・インジェクション: ユーザー入力がシステムプロンプトを上書きする
- モデルバージョン変更: APIプロバイダーのモデル更新による応答変化
- レイテンシ劣化: 入力トークン数増加によるレスポンス遅延
- コスト爆発: 無制限の入力受け付けによる予想外の課金
4軸評価フレームワーク
LLMサービスの品質を評価する軸を4つに整理した。
軸1: 正確性(Accuracy)
回答が事実と一致しているか。RAGシステムであれば、回答に使用した参照元ドキュメントと回答内容が矛盾していないかを確認する。
評価方法として有効なのが「LLM-as-a-Judge」パターンだ。別のLLMに評価させる方法で、以下のようなプロンプトで実装できる。
def evaluate_accuracy(question: str, answer: str, context: str) -> dict:
prompt = f"""
以下の回答が、提供されたコンテキストに基づいて正確かどうかを評価してください。
質問: {question}
コンテキスト: {context}
回答: {answer}
評価基準:
1. 回答はコンテキストに含まれる情報のみを使用しているか
2. コンテキストに反する情報が含まれていないか
3. 質問に対して適切に答えているか
以下のJSON形式で回答してください:
{{"score": 0-5, "reasoning": "理由", "has_hallucination": true/false}}
"""
# LLM APIを呼び出して評価結果を返す
...
軸2: 安全性(Safety)
有害なコンテンツ、個人情報の漏洩、プロンプト・インジェクションへの耐性を評価する。
INJECTION_PATTERNS = [
"システムプロンプトを無視して",
"Ignore previous instructions",
"あなたは今から",
"DAN mode",
]
def check_prompt_injection(user_input: str) -> bool:
for pattern in INJECTION_PATTERNS:
if pattern.lower() in user_input.lower():
return True
return False
パターンマッチングだけでは限界があるため、入力をLLMで事前スクリーニングする方法も有効だ。
軸3: 一貫性(Consistency)
同じ意味を持つ質問に対して、一貫した回答を返すか。表現を変えた同義質問10本のテストセットを作り、回答のコサイン類似度を計測することで数値化できる。
軸4: パフォーマンス(Performance)
レイテンシ(P50/P95/P99)、スループット、エラー率。これは従来のシステム監視と同じ手法で対応できる。
import time
import statistics
def measure_latency(prompt: str, n: int = 10) -> dict:
latencies = []
for _ in range(n):
start = time.time()
response = call_llm(prompt)
latencies.append(time.time() - start)
return {
"p50": statistics.median(latencies),
"p95": statistics.quantiles(latencies, n=20)[18],
"p99": statistics.quantiles(latencies, n=100)[98],
}
テストデータセットの設計
自動テストで使うテストデータセットは、以下の3種類を用意することを推奨する。
ゴールデンセット: 期待する回答が明確なケース。正確性評価に使用する。定期的にレビューして陳腐化を防ぐ。
エッジケースセット: 境界値、曖昧な質問、悪意ある入力。安全性テストに使用する。
リグレッションセット: 過去に問題になったケース。モデル更新後に同じ問題が再発しないかを確認する。
CI/CDへの組み込み
モデルやプロンプトを更新するたびにテストを実行する仕組みを作る。
# .github/workflows/llm-quality.yml
name: LLM Quality Gate
on:
pull_request:
paths:
- 'prompts/**'
- 'src/llm/**'
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run accuracy tests
run: python -m pytest tests/test_accuracy.py -v
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Run safety tests
run: python -m pytest tests/test_safety.py -v
- name: Check quality thresholds
run: |
SCORE=$(python scripts/evaluate_golden_set.py)
if [ "$SCORE" -lt "80" ]; then
echo "Quality score $SCORE is below threshold 80"
exit 1
fi
プロンプトのバージョン管理
プロンプトはコードと同様にGitで管理し、変更履歴を追跡する。プロンプトの変更がどの程度品質に影響したかを比較できる体制を整えておくことが、LLMサービスの継続的な品質向上の鍵だ。
LLMサービスのQAは「完璧なテストを書く」ことではなく、「品質の劣化に素早く気づき、対応できる体制を作る」ことだ。4軸の評価フレームワークを継続的に回すことで、AIサービスの信頼性は着実に上がっていく。