BXUP Track progress & test yourself — free
QA & Testing · Playbook · Advanced · ~4 min read
QA & TESTING · PLAYBOOK · ADVANCED

Calibrate an LLM Judge Before It Gates a Release

An uncalibrated judge is an uncalibrated gauge on a pressure vessel: it blocks good releases and waves through bad ones with equal confidence. Before any LLM-as-judge may fail a build, you measure its agreement against human labels on a gold slice — and you control the biases judges are known to have.

Tier: Advanced · Workflow area: Testing AI systems — judges, agents & robustness

This playbook takes you from "we wrote a judge prompt that looks reasonable" to "we have an agreement report that says this judge may gate releases." The judge is a measurement instrument, and QA's job is the same as with any instrument: calibrate it, document its error bars, and schedule re-calibration.

When to use

USE THIS WHEN

The judge has power

You are about to wire a model-graded assertion into CI where a fail blocks a merge or release. Faithfulness, tone, helpfulness or policy-compliance verdicts feed a dashboard leadership acts on. You inherited a judge someone else wrote and nobody can say how often it is wrong.

SKIP IT WHEN

Cheaper layers suffice

The property is checkable deterministically — schema validity, regex, PII absence, length. Semantic similarity against a reference answer covers it. The judge is only exploratory (labeling for triage, not gating) — calibrate before promotion, not before experimentation.

Prerequisites

  • A working eval harness: Promptfoo with model-graded asserts, or Langfuse evaluators, or DeepEval G-Eval.
  • 40–80 real outputs from the feature under test (production traces or staging runs — not synthetic).
  • Two humans willing to label them independently. One labeler measures nothing; disagreement between two is your noise floor.
  • A judge model at least as strong as the model under test, from a different family if possible.

The workflow

  1. Write the rubric before the judge prompt. Decide what "pass" means in words a new team member could apply. Prefer binary or 3-point scales — 1–10 scales collapse into noise around 6–8. Example rubric for a support-summary feature: Pass = every claim in the summary appears in the source ticket; no invented order numbers, dates or amounts; refund policy stated only if the ticket mentions it.

  2. Hand-label the gold slice. Sample 50 outputs stratified across easy, hard and known-failure cases. Both labelers apply the rubric independently, then reconcile. Record inter-human agreement first:

    Gold slice: 50 items
    Labeler A vs Labeler B raw agreement: 46/50 (92%)
    Reconciled labels: 34 pass, 16 fail
    

    If two humans cannot exceed ~85% agreement, the rubric is ambiguous — fix the rubric, not the judge.

  3. Write the judge prompt with structured output. Ask for the verdict last, after reasoning, and force JSON:

    You are evaluating a customer-support summary against its source ticket.
    
    Rubric:
    - FAIL if the summary contains any claim not present in the ticket.
    - FAIL if any number, date, or amount differs from the ticket.
    - FAIL if refund policy is mentioned but the ticket never raises refunds.
    - Otherwise PASS.
    
    Ticket: {{ticket}}
    Summary: {{summary}}
    
    Think through each rubric line, quoting the ticket. Then output JSON:
    {"reasoning": "...", "verdict": "PASS" | "FAIL"}
    Judge the content only. Length, style and formatting are irrelevant.
    
  4. Run the judge over the gold slice and compute agreement. A 20-line script is enough:

    promptfoo eval -c judge-calibration.yaml -o judge-run.json
    python compare_labels.py gold_labels.csv judge-run.json
    
    Judge vs reconciled human labels (n=50)
    Raw agreement:        44/50 (88%)
    Agreement on FAILs:   12/16 (75%)   <- the number that matters for a gate
    Cohen's kappa:        0.72
    False passes: 4  |  False fails: 2
    

    Weight agreement-on-fails over raw agreement: a gate exists to catch bad outputs, and a judge that passes everything scores 68% raw agreement here while being useless.

  5. Probe the known biases. Re-run the slice with two controls: swap the order of any paired comparisons (position bias), and check verdict correlation with output length (verbosity bias — judges reward longer answers). If verdicts flip on swap or correlate with token count, add explicit rubric lines ("length is irrelevant") and re-run.

  6. Read every disagreement. The 6 mismatches are the whole payoff. Typical findings: the judge misses subtle number changes (add an explicit "compare every number digit by digit" instruction), or humans mislabeled an item (fix the gold label). Iterate the judge prompt until agreement-on-fails clears your bar.

  7. Set the bar, then wire the gate. A defensible starting policy: kappa ≥ 0.7 and agreement-on-fails ≥ 80% before the judge may block anything. Below that, the judge may only flag for human review. Version the judge prompt, model and threshold in git next to the eval config.

  8. Schedule re-calibration. Re-run the gold slice whenever the judge model changes, the judge prompt changes, or quarterly — whichever comes first. Judges drift when providers silently update models; the gold slice is how you notice.

Warning

Never let the model under test judge itself with the same prompt family. Self-preference bias is well documented — use a different model family for the judge, or at minimum a different provider snapshot.

Variations

  • Promptfoo: encode the calibrated rubric as an llm-rubric assert with the judge model pinned in defaultTest.options.provider; keep the calibration run as a separate config you re-run on schedule.
  • Langfuse evaluators: attach the judge as an evaluator on production traces, and build the gold slice from the same trace table — annotation queues give you the two-labeler workflow for free.
  • DeepEval G-Eval: express the rubric as evaluation_steps; calibration is a pytest run over the gold slice comparing metric.score to your labels.

Quality check

  • Two-labeler gold slice existswith inter-human agreement recorded before any judge ran.
  • Agreement-on-fails reported separately from raw agreement, and it clears your written bar.
  • Position and verbosity bias probed with documented results, not assumed away.
  • Judge prompt, model, threshold and gold slice versioned in git; a reviewer can reproduce the agreement number.
  • Re-calibration trigger definedmodel change, prompt change, or a calendar date.

Pitfalls

  • Calibrating on synthetic outputs. A judge that agrees with humans on clean synthetic examples still fails on the weird outputs production actually produces. Build the slice from real traces.
  • One labeler. Agreement with a single human measures that human's mood. Two independent passes plus reconciliation, always.
  • A 1–10 scale. Score-9-vs-7 disagreements are noise wearing a costume. Binary or 3-point.
  • Gating on day one. Run the judge in flag-only mode for a week first; the disagreements it surfaces in live traffic are free calibration data.
Key Takeaway:

A judge earns gate power the way a new hire earns merge rights — by demonstrated agreement with people you trust, measured on work you already know the answer to, re-checked on a schedule. No agreement report, no gate.

This is the free reading view. Open BXUP to track your progress, run the hands-on labs, and prove it with original, exam-pattern assessments.
© Anvi Innovate · BXUP — Be Exponentially Upskilled · BXUP is an independent learning platform, not affiliated with or endorsed by AWS, Microsoft, Google, NVIDIA, IBM, Salesforce, Databricks, Oracle or Anthropic. All trademarks belong to their respective owners. · bxup.in