AI評価パイプラインの構築:データセットからCI/CDでのLLMテスト自動化まで

Dev.to / 2026/4/30

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical UsageModels & Research

要点

  • この記事では、「AI評価パイプライン」としてテストケースをLLMシステムに通し、指標(メトリクス)でスコアリングし、結果を保存・分析していく実践的な流れを説明しています。
  • パイプラインの信頼性は主に高品質なデータセット作成に左右され、理想としては本番ログを中心にしつつ、合成例やエッジケース/失敗シナリオで補うべきだと強調しています。
  • このパイプラインは「システム品質の唯一の真実(source of truth)」として位置づけられ、単発のテストではなく継続的な品質測定を可能にします。
  • input(入力)、expected(期待)、RAG向けのcontext(任意)、typeやdifficultyなどのmetadataを含むデータセット例のスキーマを示し、評価しやすいテストケースの構造を具体化しています。
  • データセット作成をStep 1としており、データ品質の重要性を過小評価しがちな落とし穴にも触れています。

本番環境でAIシステムをテストするための連載の第2部

第1部では、AIシステムのテストが従来のソフトウェアと本質的にどう違うのかを掘り下げました。

非決定性、プロンプトへの感度、そしてユニットテストだけでは不十分な理由について話しました。

ここからは、理論を実践へ移します。

AIを確実にテストする仕組みを、実際にどう構築するのでしょうか?

この記事では、AI評価パイプラインの構築に向けた実践的なアプローチを、データセット作成からCI/CD統合まで順を追って説明します。

AI評価パイプラインとは?

高いレベルで見ると、評価パイプラインは次のような形になります:

Dataset → System → Evaluation → Metrics → Analysis

より具体的には:

  • テストケースのデータセットを定義する
  • それらをAIシステムに通す
  • 定義した指標を使って出力を評価する
  • 結果を時系列で保存し、分析する

これが、システム品質のための「唯一の真実(source of truth)」になります。

ステップ1:高品質な評価データセットを構築する

評価パイプラインの良さは、データセットの質にしかりです。

データはどこから来るか:

  • 本番ログ(最も価値が高い)
  • 合成例(カバレッジのため)
  • エッジケースと失敗シナリオ

例となる構造:

{
  "input": "払い戻しの方針は何ですか?",
  "expected": "30日間の返金期間に言及すべき",
  "context": "任意(RAGシステムの場合)",
  "metadata": {
    "type": "faq",
    "difficulty": "easy"
  }
}

良いデータセットの条件:

  • 実際のユーザー行動を表している
  • エッジケースを含む
  • 既知の失敗モードをカバーしている

インサイト: 多くのチームがこのステップを過小評価しています。多くの場合、モデルの選択よりもデータセットの品質のほうが重要です。

ステップ2:評価指標を定義する

従来のシステムと違って、正しさが常に2値(正/誤)で表せるとは限りません。

複数の評価戦略を組み合わせる必要があります。

よくあるアプローチ:

1. 完全一致(構造化されたタスク向け)

  • 分類やJSON出力に有用

2. セマンティック類似度

  • 厳密な文言ではなく意味を測る

3. LLMをジャッジとして使う

  • モデルを使って出力の品質を評価する

4. タスク成功(エージェント向け)

  • システムは目的を達成できたか?

トレードオフ:

  • 完全一致 → 正確だが脆い
  • セマンティック → 柔軟だが曖昧
  • LLMジャッジ → スケールしやすいが完璧ではない

重要なのは、複数のシグナルを組み合わせることです。

ステップ3:評価を実行する

この段階では、データセットに対してシステムを実行します。

シンプルな評価ループは次のようになります:

results = []

for sample in dataset:
    output = system.run(sample["input"])

    score = evaluator(
        output=output,
        expected=sample.get("expected"),
        context=sample.get("context")
    )

    results.append({
        "input": sample["input"],
        "output": output,
        "score": score
    })

まずはシンプルにしておきましょう。複雑さは後から加えられます。

ステップ4:結果を保存し、デバッグを可能にする

生のスコアだけでは不十分です。可視性が必要です。

保存するもの:

  • 入力
  • 出力
  • スコア
  • メタデータ

追加するもの:

  • 失敗のタグ付け
  • エラーのカテゴリ(幻覚、フォーマットなど)
  • トレースログ(特にエージェントの場合)

これにより、次の問いに答えられるようになります:

なぜシステムは失敗したのか?

この層がなければ、デバッグは当て推量になってしまいます。

ステップ5:時間経過による変化を追跡する

評価パイプラインは一度きりの作業ではありません。

次のような問いに答えられるべきです:

  • 最新の変更によってパフォーマンスは向上したか?
  • 幻覚の発生率は増えたか?
  • プロンプトの微調整がエッジケースを壊したか?

次の指標を追跡する:

  • 精度
  • 幻覚率
  • タスク成功率

データセットにバージョンを付け、実行ごとの差分を比較します。

ステップ6:CI/CDに統合する

ここで評価が、エンジニアリングの規律(ディシプリン)の一部になります。

次のときに評価を実行します:

  • プロンプトが変更されたとき
  • モデルが更新されたとき
  • リトリーバルのロジックが変更されたとき

例となるワークフロー:

コード変更 → 評価を実行 → 指標を比較 → 合否(パス/フェイル)

次のような閾値を定義できます:

  • 精度がX%を下回ったら失敗にする
  • 幻覚率が増えたら失敗にする
返却形式: {"translated": "翻訳されたHTML"}

これはサイレントな退行を防ぎます。

エンドツーエンドのフロー

すべてをまとめると:

Dataset
   ↓
Run System
   ↓
Evaluate Outputs
   ↓
Store Results
   ↓
Compare with Previous Runs
   ↓
Trigger Alerts / Decisions

これがあなたのAI品質管理ループです。

実世界の例

たとえば、あなたがサポート用チャットボットをテストしているとします。

パイプライン導入前:

  • 手動テスト
  • 結果が一貫しない
  • 改善を追跡しにくい

パイプライン導入後:

  • データセットとして約200件の実際の問い合わせ
  • 更新のたびに自動評価
  • 明確な指標(正確性、根拠)

結果:

  • より速い反復
  • 幻覚の減少
  • リリースへの確信が向上

よくある落とし穴

パイプラインがあっても、チームは次のような問題に直面します:

  • 評価データセットへの過剰適合
  • LLMを「裁判官」として盲信する
  • 実際の利用に応じてデータセットを更新しない
  • データセットのバージョン管理がない

評価(eval)を静的なものとして扱うのは避けてください。evalはシステムの変化に合わせて進化させるべきです。

次に何をする?

この連載の次のパートでは、次の内容をさらに深掘りします:

  • RAGシステムの評価(検索+生成)
  • 文脈の関連性と忠実性の測定
  • 検索パイプラインにおけるよくある失敗パターン

最後に

AIシステムは大きな失敗としては現れません。むしろ、じわじわとずれていきます。

評価パイプラインは、そのずれを検出し、測定し、制御するための手段を提供します。

一度テストするだけの話ではありません。
重要なのは、あなたに対して継続的に次を知らせるシステムを作ることです:

私のAIは、まだ期待どおりに動いていますか?