promptfooでプロンプトをテストする

promptfooでプロンプトをテストする

2026.05.27

はじめに

LLM を組み込んだアプリケーションを開発していると、「システムプロンプトの正解がわからない」という悩みに突き当たります。プロンプトを少し変更しても、それで本当に良くなったのか、なんとなく良くなった気がするだけなのかがはっきりせず、評価がどうしても人の主観に依存しがちです。

さらに厄介なのが、モデルの新しいバージョンが出たときです。これまでと同じように正しく動くのかは、実際に試してみないとわかりません。とはいえ出力が自然言語で揺れる以上、入力に対して答えが一意に決まらないため、既存のユニットテストや E2E テストではうまく確認できない、というのが悩ましいところです。

この記事では、OSS のプロンプト評価ツール promptfoo を使って、こうしたプロンプトの良し悪しをコードのようにテストする方法を、Gemini APIと組み合わせて紹介します。

promptfoo とは

YAMLでプロンプト・モデル・テストケース・アサーションを定義し、promptfoo eval 一発で評価を回せる CLI ツールです。結果はターミナルにマトリクス表示されるほか、promptfoo view で Web UI から詳しく確認できます。複数モデルを横並びで比較したり、CI/CD に組み込んでプロンプトの回帰テストを回したりできます。

OpenAI / Anthropic / Google(Gemini) など主要プロバイダーに対応しており、今回は Google AI Studio の Gemini を使います。

なぜ promptfoo を選んだか

LLM評価ツールはもちろん promptfoo だけではありません。DeepEval、RAG評価に特化した Ragas、スコープを広げるならlangfuseなど...様々な選択肢があります。そのなかで今回 promptfoo を選んだのは、評価ツールに求めていた次の2点をOSS単体で満たせたからです。

1. 見やすい結果UIがあること

promptfoo view を実行するだけで、ローカルにWeb UIが立ち上がり、プロンプト・入力・出力・各アサーションの合否をブラウザで一覧できます。たとえば DeepEval はメトリクスが充実している一方、共有ダッシュボードや可視化は同社クラウドの Confident AI との連携が前提で、手元だけで完結する手軽なUIは持ちません。Ragas も基本はライブラリでUIはありません。

2. CIに組み込めること

プロンプトの品質を「変更のたびに自動で守る」には、CIに乗せられることが必要となります。
また手元で開発中の任意のタイミングで動かすことをメインのユースケースで考えているため、現状ではまだ試せてませんが、CIに組み込むことは想定されるため、対応が必須でした。

要するに「ローカルで手軽に結果が見えるUI」と「CIに素直に組み込めるCLI」を OSS単体で両立できたのが、今回の決め手です。

評価の構成要素

promptfoo の設定は、おおまかに次の4つの組み合わせでできています。

要素 役割
prompts テストしたいプロンプト({{var}} でテンプレート化できる)
providers 実行するモデル(例: google:gemini-3.5-flash
tests 入力変数(vars)と期待(assert)のセット
assert 出力をどう判定するか(アサーション)

評価はprompts × providers × tests の直積で実行されます。プロンプト1つ・モデル2つ・テスト3つなら、計6回の評価が走る、というイメージです。

環境

プロジェクトを作り、promptfoo をインストールします。

mkdir prompt-test && cd prompt-test
export GOOGLE_API_KEY="your-api-key"

pnpm add promptfoo
# npm install promptfoo でも可

pnpm 10 だと bindings file エラーになる

promptfoo は評価結果の保存に SQLite(better-sqlite3 というネイティブモジュール)を使います。pnpm はセキュリティのため、依存パッケージのライフサイクルスクリプトをデフォルトで実行しません。そのままだと、インストール時、実行時に次のエラーで落ちます。

Error: Could not locate the bindings file.

今回はpackage.json にビルド許可を足してから pnpm add(または pnpm install)すれば解決します。

{
  "pnpm": {
    "onlyBuiltDependencies": ["better-sqlite3", "esbuild"]
  }
}

つづけて雛形を生成しておきます。

pnpm exec promptfoo init --no-interactive
# npx promptfoo@latest init --no-interactive

promptfooconfig.yaml が生成されます。以降はこのファイルを書き換えていきます。

実際に動かしてみる

まずシンプルなお題として、「文章を1文で要約する」プロンプトをテストしてみます。

# promptfooconfig.yaml
description: 要約プロンプト

prompts:
  - "次の文章を1文で要約してください。\n\n{{text}}"

providers:
  - google:gemini-3.5-flash

tests:
  - vars:
      text: |
        クラスメソッドはAWSなどのクラウド活用を支援するクラウドインテグレーション企業です。
        技術メディア「DevelopersIO」の運営でも知られています。
    assert:
      - type: contains
        value: クラスメソッド
      - type: llm-rubric
        value: 1文で要約されている

contains は「出力に クラスメソッド という文字列が含まれるか」という決定的なチェック、llm-rubric は「1文で要約されているか」を LLM に採点させる主観的なチェックです。
曖昧な自然言語でアサーションを指示できるのが面白いですね。

実行します。

pnpm exec promptfoo eval # npx promptfoo@latest eval

ターミナルにマトリクス形式で結果が出ます。

Starting evaluation eval-i4D-2026-05-27T10:28:27
Running 1 test cases (up to 4 at a time)...
Evaluating [████████████████████████████████████████] 100% | 1/1 

┌──────────────────────┬──────────────────────────────┐
│ text                 │ [google:gemini-3.5-flash]    │
│                      │ 次の文章を1文で要約...       │
│                      │ {{text}}                     │
├──────────────────────┼──────────────────────────────┤
│ クラスメソッドは...  │ [PASS]                       │
│                      │ クラスメソッドはAWS...       │
└──────────────────────┴──────────────────────────────┘
✓ Eval complete (ID: eval-i4D-2026-05-27T10:28:27)

» View results: promptfoo view
» Share with your team: https://promptfoo.app
» Feedback: https://promptfoo.dev/feedback

Total Tokens: 1,315
  Eval: 354 (43 prompt, 30 completion, 281 reasoning)
  Grading: 961 (216 prompt, 52 completion)

Results:
  ✓ 1 passed (100%)
  0 failed (0%)
  0 errors (0%)
Duration: 11s (concurrency: 4)

Web UI でも確認できます。

pnpm exec promptfoo view # npx promptfoo@latest view

ブラウザが開き、プロンプト・入力・出力・各アサーションの合否が一覧できます。
その評価の詳細(実際の出力や、アサーションごとの判定理由)が確認できます。

promptfoo1

モデルを横並びで比較する

providers を複数並べると、同じプロンプト・同じテストを別モデルで実行して比較できます。ここでは現行の gemini-3.5-flash と、ひとつ前の世代の gemini-2.5-flash を並べて、世代が上がって出力品質がどう変わるかを見てみます。

providers:
  - google:gemini-3.5-flash
  - google:gemini-2.5-flash

# 採点係はgemini-3.5-flashにお願いする
defaultTest:
  options:
    provider: google:gemini-3.5-flash

eval を実行すると、モデルごとの合格率・レイテンシ・トークン数(コスト)が並びます。

Starting evaluation eval-vjp-2026-05-27T10:34:27
Running 2 test cases (up to 4 at a time)...
Evaluating [████████████████████████████████████████] 100% | 2/2 

┌──────────────────────┬───────────────────────────┬───────────────────────────┐
│ text                 │ [google:gemini-3.5-flash] │ [google:gemini-2.5-flash] │
│                      │ 次の文章を1文で要約...    │ 次の文章を1文で要約...    │
│                      │ {{text}}                  │ {{text}}                  │
├──────────────────────┼───────────────────────────┼───────────────────────────┤
│ クラスメソッドは...  │ [PASS]                    │ [PASS]                    │
│                      │ クラスメソッドはAWS...    │ クラスメソッドはAWS...    │
└──────────────────────┴───────────────────────────┴───────────────────────────┘
✓ Eval complete (ID: eval-vjp-2026-05-27T10:34:27)

» View results: promptfoo view
» Share with your team: https://promptfoo.app
» Feedback: https://promptfoo.dev/feedback

Total Tokens: 1,751
  Eval: 836 (43 prompt, 31 completion, 354 cached, 689 reasoning)
  Grading: 915 (433 prompt, 115 completion)

Providers:
  google:gemini-2.5-flash: 482 (1 requests; 43 prompt, 31 completion, 408 reasoning)
  google:gemini-3.5-flash: 354 (0 requests; cached, 281 reasoning)

Results:
  ✓ 2 passed (100%)
  0 failed (0%)
  0 errors (0%)
Duration: 6s (concurrency: 4)

Web UI で見ると、モデルが列で横並びになり、どのケースで差が出たかが一目で分かります。
(今回のケースだと単純なテストだったため、結果に大きな違いはありませんでした。)

promptfoo2

このように同一のプロンプトで別々のモデルを比較し、最適なモデルを選ぶためのデータを収集することができます。

まとめ

  • promptfoo を使うと、YAMLでプロンプトテストを宣言的に書ける
  • わかりやすいWEB UIで結果を参照できて便利!!
  • providers を並べるだけでモデルの横並び比較ができ、CI連携で回帰テストも現実的になる

簡単にローカルでプロンプトの検証を始められるのでぜひお試しください!

参考

この記事をシェアする

関連記事