evalpair について
evalpairは、ローカルまたはホスト型モデルでLLM評価を実行・比較するCLI兼MCPサーバーです。項目ごとの結果を対応付け、不確実性と反復実行時のノイズを測り、変化が意味のあるものか判断できます。
主な機能
- 01単一モデルで評価スイートを実行
- 02応答をキャッシュして中断後に再開
- 03対応するスコアをブートストラップ区間で比較
- 04回答の変化とノイズフロアを測定
- 05決定的チェッカーでスイートを作成
活用シーン
- 01モデル、プロンプト、量子化の変更を比較
- 02スコア差が統計的ノイズを超えるか確認
- 03途中までの評価を再開
MCP 対応
評価スイートの一覧、評価実行、保存済み実行の確認と比較を行うツールをMCPクライアントに提供します。モデルを呼び出すのは評価実行時のみで、他のツールは保存結果を読み取ります。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx evalpairEVALPAIR_HOMEFolder for the call cache, saved runs and your own suites (default ~/.evalpair).EVALPAIR_API_KEYシークレットBearer token for an OpenAI-compatible server, if it needs one (OPENAI_API_KEY also works).ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
5掲載時のツール一覧 · 3 日前に更新
このツールにパラメーターはありません。
詳細
evalpair
LLM 評価スイートをモデルに対して実行し、すべての呼び出しをキャッシュして、2 回の実行を項目ごとに比較します。新しい モデル、プロンプト、量子化によって実際に何か変わったのか、それとも差はノイズなのかを確認できます。
多くの評価ツールは、2 つのスコアを並べて表示するだけです。160 問で 2 ポイントの差があれば結果が出たように見えますが、 実際にはそうでないことがほとんどです。evalpair は 2 回の実行を項目ごとに対応づけ、差のブートストラップ区間を示し、 悪化した項目と改善した項目の数を数え、ノイズフロアも測定できます。これは同じモデルに同じ質問を 2 回した場合の結果です。 私自身の調査では、温度 0 でも同じプロンプトを 2 回送ると回答の最大 3% が変わりました。そのため、回答変更率はそれを超えて初めて意味を持ちます。
これは CLI と MCP サーバーなので、エージェントは評価を実行して、その判定を自ら読み取れます。指定したモデルサーバーだけを呼び出し、 すべてのデータを 1 つのローカルフォルダーに保存します。
クイックスタート
uvx evalpair suites
uvx evalpair run gsm8k-160 -m llama3.1:8b --repeat --label llama
uvx evalpair run gsm8k-160 -m qwen3:8b --think off --label qwen3
uvx evalpair compare llama qwen3
run は 95% 区間付きのスコアと、最初の失敗例を表示します。解析できなかった返信と、切り詰められた返信が先に表示されます
(これらは通常、モデルではなくパーサーやトークン予算の問題です)。compare は両方のスコア、区間付きの対応あり差分、
悪化した項目と改善した項目の数、ノイズフロアを表示し、最後に平易な言葉で判定を示します。つまり、スコアの差がゼロと区別できるか、
また回答の変化が同じモデルに 2 回質問した場合を上回るかを示します。
実際の比較例:Ollama のデフォルトの 4 ビット Llama 3.1 8B と 2 ビット版を、M5 Pro ノート PC で比較します
(--num-ctx 4096。両方の実行に約 40 分かかります)。
$ evalpair compare llama-q4 llama-q2
A llama-q4: 84.4% [79.4%, 90.0%]
B llama-q2: 60.6% [53.1%, 68.1%]
B − A -23.8 pp [-31.9 pp, -16.2 pp]
changed 40.6% [33.1%, 48.1%] of 160 items (43 worse in B, 5 better)
floor (A) 0.0% [0.0%, 0.0%]; excess +40.6 pp [+33.1 pp, +48.1 pp]
B scores lower than A: -23.8 pp [-31.9 pp, -16.2 pp], paired over 160 items. Answers changed on 40.6% of
items (43 got worse, 5 better). The noise floor (the same model asked twice) is 0.0% for A, so the change
is beyond noise.
worse in B: gsm8k-0259 '168' → '52'
...
どちらのスコアも、量子化調査で同じ項目を使って各ビルドについて測定された値です。
実行を中断してから再度実行してください。すべての返信がキャッシュされるため、中断したところから再開できます。
MCP サーバーとして
claude mcp add evalpair -- uvx evalpair mcp
または、任意の MCP クライアントの設定に以下を指定します:{"command": "uvx", "args": ["evalpair", "mcp"]}。
| ツール | 説明 |
|---|---|
list_suites | 実行可能なスイート:名前、項目数、チェッカー、測定内容 |
run_eval | 1 つのモデルに対してスイートを実行し、結果を保存します(モデルを呼び出します。キャッシュ済みの返信は再利用されます) |
list_runs | 保存済みの実行。新しい順です |
show_run | 実行のスコアと区間、ノイズフロア、失敗した返信の末尾を表示します |
compare_runs | 2 回の実行を項目ごとに対応づけ、区間付きの差分、両方向への変化、ノイズフロアとの比較、例を表示します |
run_eval 以外はすべて、保存済みの実行結果を読み取るだけです。
バックエンド
- Ollama(デフォルト):
--backend ollama。サーバーはhttp://localhost:11434です。実行結果にはモデルの ダイジェストが記録されるため、後からテストしたビルドを正確に確認できます。思考するモデルでは--think on|off、 コンテキストウィンドウの設定には--num-ctxを指定します。 - OpenAI 互換サーバー:vLLM、
llama.cpp のサーバー、LM Studio、またはホスト型 API では、
--backend openai --base-url http://localhost:8000/v1を指定します。 ベアラートークンはEVALPAIR_API_KEY(またはOPENAI_API_KEY)から読み込まれ、ディスクには書き込まれません。
温度のデフォルトは 0、シードのデフォルトは 7 です。どちらもサーバー URL、モデル、メッセージ、トークン予算、思考設定とともにキャッシュキーの一部になります。
スイート
3つのスイートが同梱されています。私の「Measuring LLM Systems」研究で使用した項目セットで、プロンプトも研究で使用したものと一字一句同じです。そのため、実行結果を公開済みの数値と照合できます。
| スイート | 項目数 | チェッカー | 出典 |
|---|---|---|---|
gsm8k-160 | 160 | number | GSM8K test(MIT) |
mmlu-hs-160 | 160 | choice、科目ごとに層化 | MMLU、高校レベルの4科目(MIT) |
e2e-extract-150 | 150 | json_fields | E2E NLG のレストラン記録(CC BY-SA 4.0) |
独自のスイートを作成するには、~/.evalpair/suites/<name>/、またはパスで指定する任意の場所に、次の2つのファイルを含むフォルダーを作成します。
# suite.toml
description = "Capitals, answered in one word"
checker = "exact"
max_tokens = 64
system = "Answer in one word." # optional
user = "What is the capital of {country}?"
group = "region" # optional: stratify the bootstrap by this item field
{"id": "fr", "country": "France", "region": "Europe", "gold": "Paris"}
{"id": "pe", "country": "Peru", "region": "Americas", "gold": ["Lima", "Ciudad de los Reyes"]}
プロンプト内の{field}には項目の値が挿入されます。文字列のリストはアルファベット付きの選択肢(A. …)になり、それ以外はインデントされたJSONとして表示されます。中括弧をそのまま表示するには、{{と}}を使います。
| チェッカー | 採点方法 | 正解データ |
|---|---|---|
number | 「Answer:」の後にある数値、なければ\boxed{}、それもなければ最後の数値 | 数値 |
choice | 「Answer:」の後にある文字。見つからない場合はフォールバックを使用(文字はchecker_options.lettersで設定) | 文字 |
exact | 「Answer:」の後のテキスト、または最後の行を正規化 | 文字列または文字列のリスト |
contains | 正解の文字列が単語として含まれているか | 文字列またはリスト |
regex | checker_options.patternの最後の一致(最初のグループ) | 文字列またはリスト |
json_fields | 回答のJSONで正解できた正解オブジェクトのフィールドの割合(nullはnullでなければなりません) | オブジェクト |
チェッカーは決定的なコードであり、ここではLLMが別のLLMを採点することはありません。number、choice、json_fieldsのパーサーは研究で使われたものです。量子化研究のメイン実行で得られた9,870件すべての回答をこれらのパーサーで再採点すると、各回答について研究独自のスコアが再現されます(scripts/check_against_studies.py)。
数値の計算方法
- 再サンプリングの単位:項目。 2,000回のブートストラップ抽出を行い、パーセンタイル区間を算出します。シードを固定しているため、同じ実行では常に同じ区間になります。
groupがある場合、各グループ内で項目を再サンプリングします。 - 比較は、両方の実行で回答された項目を対象に、項目ごとに対応付けて行います。 各実行の1回目の回答を使います。2つの実行で異なるバージョンのスイートが使われていた場合(仕様と項目のハッシュが異なる場合)、比較結果にその旨が示されます。
- ノイズフロア:
--repeatを指定すると、各項目を別の呼び出しとしてもう一度送信します(独立したキャッシュエントリーを使用)。ノイズフロアは、解析後の回答が2回の間で変わった項目の割合です。比較では、各項目について、実行間での変化から各実行内の2回の回答間での変化を差し引いた値の区間が、ノイズフロアのあるすべての実行で0を上回る場合にのみ、変化を「ノイズを超える」と判定します。 - 項目はファイル内の順序で使われるため、
--limit 50では毎回同じ50項目が選ばれ、実行を制限しても項目どうしの対応付けは保たれます。
ファイルの保存場所
$EVALPAIR_HOME、または~/.evalpair:
cache.sqlite every reply, keyed by request
runs/<run>/meta.json suite and its hash, model, digest, backend, options, counts, timings
runs/<run>/rows.jsonl one line per item and pass: reply, parsed answer, score, tokens
suites/<name>/ your suites
制限事項
- 1回の実行につきモデルは1つで、チャット形式のプロンプトを1ターン使用します。ツールの使用、複数ターン、制約付きデコードにはまだ対応していません。
- チェッカーは決定的なものに限られるため、自由形式の回答には、コードで回答を検証できるスイートが必要です。
- ノイズフロアが測定するのは、同じサーバー上での実行間の変動です。別のマシンやサーバーの更新は対象外です。
ライセンス
コードはMITライセンスです。同梱のスイートにはそれぞれの出典のライセンスが適用されます(GSM8KとMMLUはMIT、E2E NLGはCC BY-SA 4.0)。各 suite.tomlにライセンスと出典が記載されています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。