eval 設計 用語集+学習メモ — 評価系を「作る側」になる¶
LLM 出力の品質を定量化する評価系を設計するための写経メモ+用語集。 決定論チェッカー → golden dataset → LLM-as-a-Judge → judge のバイアス実測 → ハイブリッド合成 → 回帰ゲート、を ex01〜06 で一周する。 ロードマップ本体は
../../agent-design/STUDY_NOTES.md(STEP 3〜5)、サンプルの並びはREADME.mdを参照。
全体像¶
ファイル間の関係と学ぶ順序¶
| # | ファイル | 学ぶ概念 | LLM | この回の「背骨の一言」 |
|---|---|---|---|---|
| 01 | ex01_deterministic_checks.py |
決定論チェッカー(JSON / schema / regex / 長さ / 禁止語)を (passed, reason) に統一 |
❌ | 形式は決定論で測る |
| 02 | ex02_golden_dataset.py |
golden dataset 設計(代表性・難易度混在・エッジ・タグ)+正規化・EM・文字 F1・層別集計 | ✅ | 評価の質はデータ設計で決まる |
| 03 | ex03_llm_as_judge.py |
ルーブリック採点(観点別 1〜5)。reason→score の judge 版 CoT、JSON 固定+temperature=0 | ✅ | 意味は judge で測る |
| 04 | ex04_judge_bias.py |
position bias を swap consistency で、verbosity bias を同内容・長さ違いペアで実測 | ✅ | judge を信じる前に judge を測る |
| 05 | ex05_hybrid_pipeline.py |
決定論ゲート → judge の 2 段構え。「決定論で落とせるものに LLM を使わない」コスト設計 | ✅ | 安いゲートで先に落とす |
| 06 | ex06_regression_gate.py |
baseline vs candidate のケース単位勝敗。デグレ検知で exit 1(CI ゲート) |
✅ | 平均でなく win/loss を見る |
ex01(形式の検証器)と ex03(意味の採点器)が二本柱で、ex05 がそれを直列合成、ex06 が ex02 のデータセット+スコアラを使って変更前後を比較する、という依存になっている。ex01 → ex02 → ex03 → ex04 → ex05 → ex06 の順に読むと、部品が出てきた順に合成されていく。
評価フロー(決定論 / golden / judge / ハイブリッド / 回帰ゲート)¶
flowchart TD
OUT["LLM 出力 1 件"] --> KIND{"検証したいのは<br/>形式か 意味か"}
KIND -->|"形式(JSON・型・書式・長さ・禁止語)"| DET["決定論チェッカー<br/>ex01: check_json / check_schema /<br/>check_pattern / check_length / check_forbidden"]
DET --> DETR{"passed?"}
DETR -->|"No"| FAIL["fail(理由つき)<br/>= judge を呼ばずに確定(無料)"]
DETR -->|"Yes"| JUDGE
KIND -->|"意味(正確性・完全性・忠実性)"| JUDGE["LLM-as-a-Judge<br/>ex03: ルーブリックで観点別 1〜5<br/>reason → score の順で JSON 出力"]
JUDGE --> BIAS["judge の健全性チェック<br/>ex04: swap consistency / 長さ違いペア"]
JUDGE --> PASS["pass / fail(score 閾値で判定)"]
subgraph DATA["評価対象の供給源"]
GOLD["golden dataset<br/>ex02: (input, expected, tags)<br/>正規化 → EM / 文字 F1 → 層別集計"]
end
GOLD -.->|"既知の正解があるタスク"| KIND
DET -.->|"前段ゲートとして合成"| HYB["ハイブリッド評価<br/>ex05: 決定論ゲート → judge"]
JUDGE -.->|"後段として合成"| HYB
GOLD --> GATE["回帰ゲート<br/>ex06: baseline vs candidate を同一データで<br/>ケース単位 win/loss → デグレなら exit 1"]
GATE --> CI{"losses あり?"}
CI -->|"Yes"| RED["CI を赤く(マージ不可)"]
CI -->|"No"| GREEN["PASS"]
要するに 「形式 = 決定論(ex01)/意味 = judge(ex03)/正解付きの量産検証 = golden(ex02)」 の3部品があり、ex05 が縦に合成(コスト設計)、ex06 が横に比較(回帰検知)する構図。
サンプル別の要点¶
ex01 — 決定論チェッカー(LLM ゼロ呼び出しで白黒つく検査を先に全部やる)¶
中心概念: 決定論チェッカー(deterministic checker)。「機械的に passed/failed が一意に決まる」検査のこと。速い・無料・100% 再現可能の3拍子がそろう。LLM 出力でも「JSON としてパースできるか」「必須キーがあるか」「日付書式を含むか」「長さ制限内か」「禁止語が混じってないか」は決定論で測れる。逆に「内容が正しいか・役に立つか」は決定論では測れず、ex03 の judge の仕事になる。この線引きが eval 設計の出発点。
設計上の肝は、全チェッカーを (passed: bool, reason: str) のタプルに戻り値を統一していること(17〜18 行目の CheckResult = tuple[bool, str])。戻り値の形をそろえると、ex05 で複数チェッカーを直列のゲートとして並べられる(合成可能になる)。
# ex01_deterministic_checks.py
CheckResult = tuple[bool, str] # ① 戻り値の型を統一 → 合成可能にする土台
def check_json(output: str) -> CheckResult: # ② パースできるか(最頻出の事故を先に潰す)
try:
json.loads(output)
return True, "valid JSON"
except json.JSONDecodeError as e:
return False, f"JSON parse error: {e}"
def check_schema(output: str, required: dict[str, type]) -> CheckResult: # ③ キー有無+型
...
if not isinstance(data[key], expected_type):
return False, f"key {key} is {type(data[key]).__name__}, want {expected_type.__name__}"
| 行 | やってること | なぜそうする |
|---|---|---|
CheckResult = tuple[bool, str](18) |
戻り値の型を (合否, 理由) に固定 |
reason まで返すと、落ちた時に「何が」「どう」ダメかが集計できる。bool だけ返すと原因が消える |
check_json(23-28) |
まずパース可否だけ見る | 「```json フェンス混入」「前置きトーク混入」が JSON タスクの最頻出事故。意味検証の前にここで弾く |
check_schema(33-43) |
必須キー+型を確認 | パースできても amount が文字列「千二百」だと後段が壊れる。本格運用は pydantic / jsonschema に置換する最小版 |
| 実行部(68-84) | 「正常・フェンス混入・型違い」3 サンプルを全チェッカーにかける | 1 出力 × 複数観点のマトリクスを作ると、どの観点で落ちたかが一目で分かる |
末尾の「ここまで LLM ゼロ呼び出し・実行 0.01 秒」がこの回の主張。無料で落とせるものに金のかかる LLM judge を使うな。
ex02 — golden dataset 設計(評価の土台になる正解付き入力集合)¶
中心概念: golden dataset。(input, expected, tags) のレコード集合で、eval の品質はモデルでもプロンプトでもなくまずこのデータ設計で決まる。4 つの設計原則がコードに埋め込まれている(25〜33 行目)。
- 代表性: 本番で来る入力の分布を映す(きれいな例だけ集めない)
- 難易度の混在: 必ず解けるべき
easyと、改善を検知するhardを両方入れる - エッジケース: g04 のように「答えが本文にない」ケースを入れ、「わからない」と言えるか(= 幻覚チェック)を測る
- タグ: 集計を「全体 1 個の数字」でなく層別で見られるようにする
スコアラは2段構え。EM(Exact Match)= 正規化後の完全一致(厳しいが解釈の余地ゼロ)と、文字 F1 = 部分一致の度合い(EM=0 でも「惜しい」を拾う)。
# ex02_golden_dataset.py
def normalize(text: str) -> str: # ② 揺れを吸収(日本語 eval の生命線)
text = text.strip().lower()
return re.sub(r"[\s。、.,「」『』\"']", "", text)
def exact_match(pred: str, expected: str) -> bool: # ③ EM = 正規化後の完全一致
return normalize(pred) == normalize(expected)
def char_f1(pred: str, expected: str) -> float: # ④ 文字集合の precision/recall の調和平均
p, e = set(normalize(pred)), set(normalize(expected))
precision = len(p & e) / len(p)
recall = len(p & e) / len(e)
return 2 * precision * recall / (precision + recall)
| 行 | やってること | なぜそうする |
|---|---|---|
GOLDEN(25-33) |
easy / hard / edge をタグ付きで保持 | 「実務では JSONL で管理し、本番の失敗事例が出るたび 1 行足す」= データセットは育てるもの |
normalize(40-42) |
全角半角・大文字小文字・記号を除去 | 正規化が甘いと、内容は合っているのに記号差で EM が落ち、スコアが信用できなくなる |
char_f1(51-59) |
文字集合の積集合から precision・recall を出し調和平均 | EM は 0/1 で粗い。部分一致を連続値で拾えると改善の方向が見える |
| タグ別集計(91-96) | タグごとに EM 率を出す | 「全体 75%」より「edge だけ 0%」の方が次の行動につながる。集計は必ず層別で |
temperature=0(69 行目)も要点。eval では出力のばらつきを消すのが基本。
ex03 — LLM-as-a-Judge(決定論で測れない意味の品質をルーブリックで採点させる)¶
中心概念: LLM-as-a-Judge とルーブリック。要約・説明文のように正解が一意でないタスクは EM/F1 が使えない。そこで採点者役の LLM に点を付けさせる。鍵は ルーブリック(rubric)= 採点基準の明文化。「良い回答か?」と丸投げせず、観点(accuracy / completeness / conciseness)ごとに 1〜5 の各点の意味まで書く(24〜38 行目)。ここが曖昧だと judge のスコアは「雰囲気の数値化」にしかならない。
もう一つの肝が reason → score の順で出させる judge 版 CoT(34 行目の指示)。先に理由を言語化させてからスコアを決めさせると、採点の一貫性が上がる(思考の外部化)。出力は response_format={"type": "json_object"} で JSON 固定、temperature=0 でばらつきを抑える(52-53 行目)。
# ex03_llm_as_judge.py
RUBRIC = """...
必ず次の JSON だけを返してください(reason を先に書いてから score を決めること):
{"accuracy": {"reason": "...", "score": 1-5}, ...}""" # ① 観点・尺度・各点の意味を明文化
def judge(question, reference, answer) -> dict:
response = client.chat.completions.create(
model=JUDGE_MODEL,
messages=[{"role": "system", "content": RUBRIC},
{"role": "user", "content": f"質問: ...\n参照情報: ...\n採点対象の回答: ..."}],
temperature=0, # ② ばらつきを消す
response_format={"type": "json_object"}, # ③ 構造化を強制
)
return json.loads(response.choices[0].message.content)
実行部では「良い回答 / 捏造を含む不正確な回答 / 冗長な回答」の 3 つを採点させ、不正確な回答の accuracy・冗長な回答の conciseness がちゃんと下がるかを見る(83-84 行目)。これは「judge 自体の動作確認」= judge の eval の入り口でもある。下がらないならルーブリックの文言を直す。
ex04 — judge のバイアスを実測する(position bias と verbosity bias)¶
中心概念: judge のバイアス。LLM-as-a-Judge は採点者自身に系統的な癖を持つ。
- position bias(位置バイアス): ペア比較で「先に提示された方(A の席)」を選びがち。対策が swap consistency: 同じペアを
(a,b)と(b,a)の両順序で聞き、判定が一致した時だけ採用。順序で反転したら、それは中身でなく位置で勝った産物。 - verbosity bias(冗長性バイアス): 同じ内容なら長い方を高く採点しがち。対策はルーブリックに簡潔性を明記、または長さを揃えて比較。
# ex04_judge_bias.py
def swap_test(question, ans1, ans2) -> dict:
first = pairwise_judge(question, ans1, ans2) # ① ans1 を A の席に置く
second = pairwise_judge(question, ans2, ans1) # ② ans1 を B の席に置く(順序を入れ替え)
winner_run1 = "ans1" if first == "A" else "ans2"
winner_run2 = "ans1" if second == "B" else "ans2" # ③ B 視点に読み替え
return {
"consistent": winner_run1 == winner_run2, # ④ 両順序で同じ勝者なら信頼できる
"verdict": winner_run1 if winner_run1 == winner_run2 else "tie(順序依存)",
}
| 行 | やってること | なぜそうする |
|---|---|---|
first / second(48-49) |
同じペアを順序だけ替えて 2 回聞く | 1 回だけだと「位置で勝った」のか「中身で勝った」のか区別できない |
winner_run2(50) |
2 回目は ans1 が B の席なので、"B" を ans1 勝ちに読み替え |
席ではなく「どの回答が勝ったか」に正規化しないと一致判定できない |
consistent(52) |
両順序で同じ勝者か | 不一致なら position bias の影響下 → tie 扱いにして判定を捨てる |
実行部の設計が巧い。互角ペアでだけ position bias が表に出る(71-72 行目)。実力差が大きいペアでは中身の差が位置の癖に勝つので、バイアスは隠れる。だから「ほぼ互角」のペアでテストする。末尾に実務の定石3つ(両順序で聞く / judge と被採点モデルを分ける = self-preference 対策 / 人手ラベル 20〜30 件と一致率を測ってから本採用)が並ぶ。
ex05 — ハイブリッド評価パイプライン(決定論ゲート → LLM judge の 2 段構え)¶
中心概念: ハイブリッド評価とゲート方式。ex01 のチェッカーと ex03 の judge を直列合成する。原則は 「決定論で落とせるものに LLM を使わない」。形式不備は無料・ミリ秒で即落とし、合格したものだけを高価・低速な judge に回す。
# ex05_hybrid_pipeline.py
def evaluate(source: str, output: str) -> dict:
for gate in (check_json_schema, check_date_format): # ① 決定論ゲートを直列に
passed, reason = gate(output)
if not passed:
# 決定論で落ちた = judge 呼び出しなし(コスト 0 で不合格確定)
return {"verdict": "fail", "stage": gate.__name__, "reason": reason, "judged": False} # ②
result = judge_summary(source, json.loads(output)["summary"]) # ③ 通過分だけ judge へ
verdict = "pass" if result["score"] >= 4 else "fail"
return {"verdict": verdict, "stage": "judge", "reason": result["reason"], "judged": True}
| 行 | やってること | なぜそうする |
|---|---|---|
for gate in (...)(65) |
チェッカーを直列に並べ、1 つでも落ちたら即 return | ex01 で (passed, reason) に統一したから、こうやって並べられる |
"judged": False(69) |
「この件は judge を呼んでいない」を記録 | 後で「何件 judge を呼んだか」= コストを集計できる |
"stage": gate.__name__(69) |
どの段で落ちたかを残す | 層別集計で「形式不備が多い/意味不備が多い」= 直すべき場所が見える |
実行部では形式不備 2 件+意味不備 1 件+正常 1 件を流し、judge が呼ばれるのは後ろの 2 件だけ(4 件中 2 件 = コスト半減)。前段で 8 割落とせれば eval 全体のコストとレイテンシが 1/5 になる、という設計思想。eval のコストもレイテンシも設計対象。
ex06 — 回帰ゲート(プロンプト変更の前後をスコア差分で比較し、デグレなら落とす)¶
中心概念: 回帰ゲート(regression gate)。eval の最終形は「変更のたびに自動で回り、デグレを検知したら CI を赤くする」回帰スイート。ex02 の golden dataset+スコアラを使い、プロンプト 2 案(baseline = 現行版 / candidate = 変更案)を同一データで比較して勝敗を判定する。
# ex06_regression_gate.py
PROMPTS = {
"baseline": "...本文に答えがなければ「わからない」と答えてください。",
"candidate": "質問に単語または短いフレーズで答えてください。", # ① 「わからない」指示を削除(デグレを仕込む)
}
base = run_suite(PROMPTS["baseline"]) # ② 各案を golden 全件に回し id→正誤 の辞書に
cand = run_suite(PROMPTS["candidate"])
wins = [i for i in base if cand[i] and not base[i]] # ③ candidate で直ったケース
losses = [i for i in base if base[i] and not cand[i]] # candidate で壊れたケース
if losses or (cand_em - base_em) < DEGRADE_THRESHOLD: # ④ 1 ケースでも壊れたら CI を赤く
print("❌ REGRESSION: candidate はデグレを含む。マージ不可")
sys.exit(1)
| 行 | やってること | なぜそうする |
|---|---|---|
PROMPTS(34-37) |
candidate からわざと制約を 1 つ削る | edge ケース g04(「わからない」と答えるべき)が壊れる様子を再現する仕込み |
wins / losses(73-74) |
ケース単位で「直った/壊れた」を抽出 | 平均 EM が同じでも win/loss の中身が違えば別物。壊れたケース id まで出すから直せる |
if losses ... sys.exit(1)(86-88) |
壊れたケースがあれば終了コード 1 | 「平均は同じだから OK」を機械的に禁止。exit 1 が CI(GitHub Actions 等)を赤くするフック |
DEGRADE_THRESHOLD = 0.0(39 行目)は「ベースラインを 1 ケースでも下回ったら fail」の厳格運用。本格運用ではこの構造を promptfoo / inspect-ai に載せ替える。
用語集(最重要)¶
1. 一番混同する2語: 決定論チェッカー と LLM-as-a-Judge¶
eval の背骨。形式は決定論で、意味は judge で測る、という役割分担。
| 決定論チェッカー | LLM-as-a-Judge | |
|---|---|---|
| 測るもの | 形式(パースできるか・型・書式・長さ・禁止語) | 意味(正確か・役立つか・忠実か) |
| 判定 | 機械的に一意(再現 100%) | LLM が採点(バイアスあり・ばらつきあり) |
| コスト / 速度 | 無料 / ミリ秒 | 数円 / 数秒 |
| 具体例 | ex01 の check_json / check_schema / check_pattern |
ex03 の judge(ルーブリック採点) |
| 使う API | json.loads / re.search / isinstance |
chat.completions.create(response_format={"type":"json_object"}) |
判定基準(1文): その品質が「機械的に白黒つくか」で決める。つくなら決定論、つかない(人によって採点が割れる類)なら judge。ex05 はこの2つを直列に並べて両取りする。
よくある誤解: 「judge があれば決定論は要らない」→ 逆。無料で落とせる形式不備に judge を使うのは金とレイテンシの無駄(ex05 の主題)。決定論を前段ゲートにして judge の呼び出し数を減らすのが定石。
2. judge のバイアス2語: position bias と verbosity bias¶
どちらも judge の系統的な癖。混同しやすいので対比で。
| position bias | verbosity bias | |
|---|---|---|
| 癖の中身 | ペア比較で先に出た方(A の席)を選びがち | 長い方を高く採点しがち |
| 出やすい条件 | 品質が互角のペア(実力差があると隠れる) | 同内容で長さだけ違うペア |
| 対策 | swap consistency: 両順序で聞き、一致時だけ採用 | ルーブリックに簡潔性の観点を明記 / 長さを揃える |
| 具体例 | ex04 の swap_test(互角ペアで検査) |
ex04 の short vs long(水増し)ペア |
ほかに self-preference(judge が自分のモデルの生成文を好む)がある。対策は judge のモデルと被採点モデルを分けること。
3. golden dataset と 本番ログ(評価データの2系統)¶
| golden dataset | 本番ログ(production trace) | |
|---|---|---|
| 正解 | expected がある(採点が自動化できる) | 正解なし(オンライン judge かサンプリング人手) |
| いつ回すか | 変更前(オフライン)。CI で回帰検知 | 運用中(オンライン)。実トラフィックの監視 |
| 具体例 | ex02 / ex06 の GOLDEN |
../langfuse_basics/ の本番トレースへの score |
| 本メモの範囲 | ★ここ(ex02・ex06) | langfuse_basics ex05 のスコアと接続 |
育て方: 本番ログで見つけた失敗事例を golden に 1 行足す(ex02 末尾)。データセットは固定の試験問題ではなく、失敗のたびに育てるもの。
4. 評価指標: EM / 文字 F1 / precision / recall¶
| 指標 | 定義 | 性質 | 具体例 |
|---|---|---|---|
| EM(Exact Match) | 正規化後に完全一致なら 1 / それ以外 0 | 厳しい・解釈の余地ゼロ・粗い(0/1) | ex02 exact_match, ex06 |
| precision | 予測した文字のうち正解にも在った割合 = |p∩e|/|p| |
「無駄を出してないか」 | ex02 char_f1 の途中計算 |
| recall | 正解の文字のうち予測で拾えた割合 = |p∩e|/|e| |
「取りこぼしてないか」 | ex02 char_f1 の途中計算 |
| 文字 F1 | precision と recall の調和平均 | EM=0 でも「惜しい」を連続値で拾う | ex02 char_f1 |
EM か F1 か: 短答抽出(「ClickHouse」など答えが定まる)は EM。言い換えや部分一致を拾いたい(自由記述寄り)なら F1。ただし自由記述の「意味の正しさ」自体は F1 でも測りきれず judge へ(ex03)。 ※この回の F1 は文字単位。一般の QA で出る token-level F1(単語単位)とは粒度が違う点に注意。
5. pointwise judge と pairwise judge(judge の2方式)¶
| pointwise(点数式) | pairwise(ペア比較式) | |
|---|---|---|
| 何を出すか | 1 回答に絶対スコア(1〜5) | 2 回答のどちらが良いか(A/B) |
| 出てくる回 | ex03(ルーブリック採点) | ex04(pairwise_judge) |
| バイアス | verbosity 等 | position bias が出る(→ swap 必須) |
| 向く用途 | 単体の品質を数値化 | 2 案の優劣を決めたい(A/B 比較) |
6. 回帰ゲート と オフライン評価(運用での位置づけ)¶
| オフライン評価 | 回帰ゲート | |
|---|---|---|
| やること | golden を回して現状のスコアを知る | baseline と candidate を比べデグレを検知 |
| 判断 | 絶対値(「EM 80%」) | 差分(「前の版を下回ったか」) |
| 出力 | スコア表・層別集計 | win/loss + exit code(CI を赤/緑に) |
| 具体例 | ex02 | ex06 |
平均は罠: 平均 EM が同じでも「直った 2 件・壊れた 2 件」なら中身は別物。回帰ゲートは平均でなくケース単位の win/lossを見て、壊れた id まで出す(ex06)。
7. テスト と eval(最も根本の対比)¶
| テスト | eval | |
|---|---|---|
| 期待 | 毎回 100% pass | pass 率で測る(LLM は非決定的) |
| 失敗 1 件の意味 | バグ | 分布の 1 サンプル |
| 運用 | 落ちたらマージ不可 | 閾値・ベースライン比較で判断(ex06) |
決定論チェッカー(ex01)だけは「テスト」に近い(一意に白黒つく)。judge(ex03)が入った瞬間に「eval」の世界(率と分布)になる。
8. クイック早見表(困りごと → 見る/使うもの)¶
| 困りごと | 見る/使うもの |
|---|---|
| 出力が JSON / 型 / 書式どおりか確かめたい | 決定論チェッカー(ex01 check_json / check_schema / check_pattern) |
| 要約・説明文の「中身の良さ」を点数化したい | LLM-as-a-Judge + ルーブリック(ex03) |
| judge のスコアを信じてよいか不安 | swap consistency で position bias を実測(ex04) |
| judge が長い回答ばかり高評価する | verbosity bias。ルーブリックに簡潔性を明記(ex04) |
| eval のコスト・レイテンシを下げたい | 決定論ゲート → judge のハイブリッド(ex05) |
| プロンプト変更で性能が落ちてないか | 回帰ゲート。baseline vs candidate で win/loss(ex06) |
| 「全体は良いのに特定ケースが弱い」を見つけたい | タグ別の層別集計(ex02) |
| 短答が正解と一致しているか自動採点したい | 正規化 + EM(ex02 exact_match) |
| EM=0 でも「惜しい」を拾いたい | 文字 F1(ex02 char_f1) |
| 本番トレースを judge で採点したい(オンライン) | ../langfuse_basics/ ex05 の score と接続 |
学んだこと(要点)¶
- 形式は決定論、意味は judge。この役割分担が eval 設計の背骨。決定論で白黒つくものに LLM を使うのは無駄(ex01 ⇔ ex03 ⇔ ex05)。
- チェッカーの戻り値を
(passed, reason)に統一しておくと、後で直列ゲートとして合成できる(ex01 の設計が ex05 で効いてくる)。reason まで返すと落ちた原因が集計できる。 - eval の品質はデータ設計で決まる。代表性・難易度混在・エッジケース・タグの4原則を golden に埋め込む。集計は必ず層別で見る(「全体 75%」より「edge だけ 0%」が行動につながる)。
- judge を信じる前に judge を測る。position bias は swap consistency で、verbosity bias は同内容・長さ違いペアで実測できる。互角ペアでだけバイアスが表に出る点が巧い。
- judge は reason → score の順(judge 版 CoT)、JSON 固定、temperature=0、ルーブリック明文化、の4点セットでばらつきと曖昧さを抑える。
- 回帰ゲートは平均でなく win/loss。平均が同じでも壊れたケースがあれば別物。
exit 1で CI に繋ぐ。 - テストと eval は別物。テストは 100% pass・失敗=バグ、eval は pass 率・失敗=分布の1サンプル。
拡張アイデア¶
- golden dataset を JSONL ファイル化: ex02 の
GOLDENをハードコードからgolden.jsonlに出し、ex02 と ex06 で共有読み込みにする。本番の失敗事例を追記する運用(データセットを育てる)を実体験する。 - judge と人手ラベルの一致率を測る: 20〜30 件に人手で good/bad を付け、ex03 の judge スコアとの一致率(Cohen's κ など)を出す。「judge を本採用してよいか」をデータで判断する ex04 末尾の定石を実装する。
- ルーブリックなし版との比較: ex03 を「良い回答ですか? 1〜5 で」と丸投げする版に書き換え、ルーブリックあり版とスコアの説明力・一貫性を比較する。ルーブリックの効果を定量化。
- ハイブリッドのコスト計測を実数化: ex05 に judge 1 回あたりのトークン数・概算コストを記録し、「前段ゲートで N% 落とすとコストが何分の一になるか」を実測のグラフにする。
- promptfoo / inspect-ai への載せ替え: ex06 の自前回帰スイートを promptfoo の YAML、または inspect-ai の
Taskで書き直し、GitHub Actions の PR で自動実行する(STEP 5 の到達点)。 - pairwise の Bradley–Terry でランキング化: ex04 の pairwise 比較を 3 案以上に拡張し、勝敗行列から Bradley–Terry / Elo で総合ランキングを出す。多案比較を pointwise でなく pairwise で回す設計を学ぶ。
記事参照¶
- 連載との対応: Software Design 第28回(GEPA + LLM-as-a-Judge)。判定器としての LLM を最適化に組み込む回の前提知識。
- ロードマップ:
../../agent-design/STUDY_NOTES.md(STEP 3〜5) - オンライン評価(本番トレースへの judge):
../langfuse_basics/の ex05 スコアと接続する - サンプルの並び・観察ポイント:
README.md
作成: 2026-06-12 / 最終更新: 2026-06-12