Learning doc · from first principles

AI Evals

How to measure whether an AI system is doing what you think it's doing.
Author
James
Modules
2 of 7
Started
July 2026
The syllabus, in seven modules.
AI Evals · 2026
01.
Rubric Engineering
complete
02.
Judge Calibration
● current
03.
Pairwise Comparison
upcoming
04.
Golden Datasets
upcoming
05.
Production Monitoring
upcoming
06.
Reward Integrity
upcoming
07.
Build a Harness
capstone
Module 01 — Rubric Engineering
Designing judge rubrics that discriminate

The problem with vibes

Ask an LLM "rate this post 1–10" and you'll get a number. Run it again and you might get a different one. Ask a different model and you'll get a third. The number feels precise, but it's measuring the judge's general impression — not any specific property of the output.

This is the vibes problem: a single holistic score tells you almost nothing actionable. It went from 7 to 6 — why? Which part got worse? Was it the opening, the tone, the specificity? You can't debug what you didn't decompose.

A rubric fixes this by turning one vague question into several precise ones. Instead of "is this good?", you ask five binary questions, each targeting one concrete quality. Now when the score drops, you know exactly which dimension fell.

Why this matters

Every eval system rests on rubrics. Get them wrong and your judges are confident but incoherent — high scores for outputs your users hate, low scores for outputs they love. A well-designed rubric is the difference between "we have evals" and "our evals actually work."

Decomposing quality into dimensions

The first skill: taking a vague quality goal and breaking it into orthogonal, observable, discriminating dimensions. Each word earns its keep.

Worked example — decomposing "write a good LinkedIn post" into five dimensions:

D1
Hook
Does the first line create a specific reason to keep reading — a surprising claim, a concrete question, a tension?
D2
Voice
Does it sound like a specific person, or could any company have written it? Look for named experiences, specific opinions, distinctive phrasing.
D3
Specificity
Concrete details — names, numbers, examples — vs. abstract platitudes. "We improved performance" fails; "We cut p99 latency from 800ms to 120ms" passes.
D4
Structure
Readable flow. Paragraph breaks that aid scanning. Appropriate length for the platform. No wall of text, no single-sentence nothingness.
D5
CTA
Ends with a clear call to action that connects to the content above — not a generic "thoughts?" bolted on.

Notice: each dimension targets a different part of the text (opening, throughout, body, ending) and can fail independently. A post with a killer hook but no specificity scores PASS/FAIL/FAIL/PASS/PASS — immediately telling you where to focus the rewrite.

Binary vs. Likert — and why binary usually wins

Two scoring approaches for each dimension:

Likert scale

Rate 1–5 per dimension. Gives you a continuous signal. Sounds more precise.

Binary check

PASS or FAIL per dimension. Forces a crisp threshold. Sounds less precise.

In practice, binary almost always wins. Here's why:

In today's fast-paced business environment, it's more important than ever to invest in your team's growth. At our company, we believe that people are our greatest asset. We recently rolled out a new mentorship program and the results have been incredible. If you're thinking about leadership development, I'd love to connect and share what we've learned. What's your approach to developing talent? Drop a comment below!
7 / 10
"A solid post about leadership and team development. Well-structured with a clear call to action. Could use more specific details about the mentorship program results."

That's all you get. The score is confident, the reasoning is vague, and you have no idea which specific thing to fix. Run it again tomorrow and you might get a 6 or an 8.

In today's fast-paced business environment, it's more important than ever to invest in your team's growth. At our company, we believe that people are our greatest asset. We recently rolled out a new mentorship program and the results have been incredible. If you're thinking about leadership development, I'd love to connect and share what we've learned. What's your approach to developing talent? Drop a comment below!
Dimension
Score
Evidence
Hook
FAIL
"In today's fast-paced business environment" is a stock opener that could prefix any post about any topic. No specific event, no tension, no reason this post is worth reading now.
Voice
FAIL
No named personal experience. "At our company" — which company? "We believe people are our greatest asset" is a phrase every company uses. Nothing identifies a specific person or brand.
Specificity
FAIL
"The results have been incredible" — what results? No numbers, no names, no concrete examples. This is a claim without evidence.
Structure
PASS
Appropriate length for LinkedIn. Clear paragraph flow: context → initiative → invitation. Scannable without paragraph breaks because it's short enough.
CTA
PASS
"What's your approach to developing talent?" is a genuine question that connects to the post content. "Drop a comment below" is generic but the question earns the pass.

Result: 2/5 dimensions passed. The vibes judge gave this a 7/10 — the rubric reveals it fails on hook, voice, and specificity. Now you know exactly what to fix: open with the specific mentorship story, name the company, and cite the actual results.

When Likert earns its keep

Use Likert when you genuinely need degree, not just presence. "How technical is the language?" needs a spectrum because too technical and too simple are both failures. But only if your rubric anchors every level: 1 = "uses only abstract nouns"; 3 = "one concrete example per paragraph"; 5 = "three or more specific examples with names, dates, or data." Unanchored Likert is just vibes with extra steps.

Few-shot examples inside judge prompts

A judge prompt is a prompt — it responds to the same prompt engineering principles as any other LLM call. Few-shot examples are the single highest-leverage addition you can make to a rubric.

The pattern: for each dimension, show the judge 2–3 graded examples with reasoning. Include at least one PASS, one FAIL, and ideally one borderline case — the borderline is what teaches the judge where the line actually sits.

Example few-shot block for the HOOK dimension Here is the rubric for the HOOK dimension: A strong hook creates an immediate reason to keep reading — a surprising claim, a concrete question, or a tension that demands resolution. Example 1 (PASS): Post: "We lost our biggest customer last Tuesday. Here's what happened next." Reasoning: Opens with a concrete, high-stakes event and an implicit promise. The reader needs to know what happened. Score: PASS Example 2 (FAIL): Post: "In today's fast-paced business environment, it's more important than ever to focus on customer retention." Reasoning: Generic opener that could prefix any post about any topic. No specific event, no tension, no reason this post is worth reading right now. Score: FAIL Example 3 (BORDERLINE — FAIL): Post: "I've been thinking a lot about leadership lately." Reasoning: Personal but vague. "Thinking a lot" creates mild curiosity but no specific promise or tension. A scroll-past for most readers. Score: FAIL

Three principles for good few-shot examples:

Chain-of-thought grading

The order matters: quote first, reason second, score last. This is chain-of-thought grading, and it exists to prevent the judge from deciding the score before looking at the evidence.

Without CoT, the judge often anchors on a first impression and rationalizes backward — "this seems pretty good → 4/5 → let me find reasons it's a 4." With CoT, you force a different sequence:

Step 1
Quote
Extract the specific text that's relevant to this dimension. Forces grounding — the judge must find evidence, not generate an impression.
Step 2
Reason
Analyze whether the quoted evidence meets the criterion. Compare against the rubric definition and the few-shot examples.
Step 3
Score
Only now: output PASS or FAIL. The score follows from the reasoning, not the other way around.

This sequence reduces two common judge biases:

Judge prompt structure with CoT You are evaluating a LinkedIn post against the SPECIFICITY dimension. Definition: The post contains concrete details — names, numbers, dates, or specific examples — rather than abstract claims or platitudes. [few-shot examples here] Now evaluate this post: """ {post_text} """ Respond in exactly this format: EVIDENCE: [quote the specific phrases relevant to specificity] REASONING: [does the quoted evidence meet the criterion? compare to few-shot examples] SCORE: PASS or FAIL

The structured output format isn't just for readability — it's a forcing function. By requiring the judge to fill EVIDENCE before REASONING before SCORE, you physically prevent the anchor-then-rationalize failure mode.

Putting it together

Here's the anatomy of a complete rubric for one dimension, showing all the pieces assembled:

Complete rubric — VOICE dimension DIMENSION: Voice SCORE TYPE: Binary (PASS / FAIL) DEFINITION: The post sounds like it was written by a specific person with identifiable opinions — not a generic corporate account. Evidence includes: named personal experiences, first-person stories with concrete details, distinctive phrasing or sentence rhythm, specific opinions the author owns. PASS EXAMPLE: Post: "I spent three years telling my team that 'move fast and break things' was our motto. Then we broke our billing system on a Friday afternoon and I spent the weekend explaining to 200 customers why their invoices were wrong. We don't say that anymore." Reasoning: Named time period (three years), specific incident (billing system, Friday, 200 customers), personal confession with a clear opinion shift. This could only have been written by this person. Score: PASS FAIL EXAMPLE: Post: "At our company, we believe in moving fast while maintaining quality. Our team has learned important lessons about balancing speed and reliability." Reasoning: "Our company" (unnamed), "our team" (unnamed), "important lessons" (unnamed). Every phrase is interchangeable with any company. No personal voice, no identifiable author. Score: FAIL BORDERLINE EXAMPLE (FAIL): Post: "I've always believed that the best leaders are the ones who listen more than they talk." Reasoning: First-person, which is better than corporate "we." But the opinion is a widely shared platitude, not a distinctive stance. No specific story or experience grounds it. A hundred people could have written this sentence. Score: FAIL INSTRUCTIONS: Evaluate the post below against this dimension. Quote the evidence, reason about it, then score. Post: """ {post_text} """ EVIDENCE: REASONING: SCORE:

This is a production-grade rubric dimension. It has: a precise definition, a PASS example with reasoning, a FAIL example with reasoning, a borderline case that teaches the threshold, and a structured output format that enforces CoT grading.

A full rubric repeats this pattern for each dimension. Five dimensions, each with this level of specification, is a complete judge prompt.

Check your understanding
Click to reveal
Why is "Does the post have good tone?" a bad rubric dimension? reveal →

"Good" is not observable — two judges will disagree on what it means, and the same judge may score it differently on consecutive runs. It fails the observability test: no one can point to specific text and say "this is where the tone becomes good." Replace it with something concrete: "Does the post avoid passive voice and hedge words like 'perhaps' and 'somewhat'?" or "Does the post use second-person 'you' at least twice?" — these are observable, binary, and a human could check them with a highlighter.

Your "Completeness" dimension always scores PASS. What should you do? reveal →

A dimension that never discriminates is either too easy (the bar is too low) or too vague (the judge is defaulting to PASS when uncertain). Two fixes: raise the bar — "Are all parameters documented?" is tighter than "Is the documentation complete?" — or split it into sub-dimensions that can independently fail. If it still never fails after tightening, drop it. A rubric dimension that's always PASS is consuming judge tokens for zero signal.

Your rubric has 12 dimensions. A colleague says "cut it to 5." Are they right? reveal →

Probably. More dimensions means more judge calls, more cost, and more noise. But the real argument is signal quality: if three dimensions are always correlated (they rise and fall together across your dataset), they're measuring the same underlying quality — merge them. Run your rubric on 50 outputs and check: which dimensions actually vary independently? Keep those. The goal is the minimum set of dimensions that captures meaningful quality differences. Five is a good target for most content domains.

You're writing few-shot examples for a SPECIFICITY dimension. All three examples are PASS. What's wrong? reveal →

All-PASS examples train a lenient judge. The judge learns: "this is what PASS looks like" but never learns: "this is where the line is." Include at least one FAIL — ideally a borderline FAIL where the text almost passes but doesn't quite have enough concrete detail. The borderline case is the most important example in the set because it defines the threshold. Without it, the judge has to guess where PASS ends and FAIL begins.

Module 02 — Judge Calibration
Evaluating your evaluator

The bootstrap problem

You built a rubric in Module 1. You wired it into a judge prompt. The judge is scoring outputs and the scores look reasonable. Five dimensions, binary checks, chain-of-thought grading — everything by the book.

But "looks reasonable" is exactly the vibes problem we just spent a module escaping. The judge says PASS on Voice and FAIL on Hook — is it right? You don't know, because you haven't checked it against anything. You're trusting the judge on faith.

Meta-evaluation is the practice of evaluating your evaluator. The idea sounds recursive but the implementation is concrete: get humans to grade the same outputs, then measure how often the judge and humans agree — and more importantly, how they disagree.

Why this matters

Without calibration, you can't distinguish between "the model got worse" and "the judge got stricter." Every time you change a rubric, swap a model, or update few-shot examples, the judge's behavior shifts. Calibration is the only way to detect drift and separate signal from noise.

Building a calibration set

The foundation of meta-evaluation: a set of outputs graded by humans using the same rubric the judge uses. This is your ground truth — the thing you compare the judge against.

Rule 1
Same rubric
Give humans the exact rubric text you give the judge — same definitions, same examples. If the human and judge see different instructions, disagreement measures rubric differences, not judge quality.
Rule 2
50–100 items
Enough to detect systematic bias with confidence. Below 30, random variation dominates. Above 200, you're spending labeling budget for marginal precision gains.
Rule 3
Double-label
Have 2+ humans label independently. This gives you human–human agreement — the ceiling your judge can realistically hit. If humans disagree 30% of the time, expecting 95% judge–human agreement is fantasy.
Rule 4
Represent the distribution
Sample outputs from the same pipeline the judge will see in production. A calibration set of cherry-picked examples will overestimate performance on messy real-world outputs.

The calibration set is not a one-time artifact. Rebuild or extend it whenever the content distribution shifts — new product features, different user demographics, or a changed generation prompt all change what the judge needs to handle.

Percent agreement — and why it lies

The naive metric: count how often the judge and human give the same score, divide by total items. Simple, intuitive, and dangerously misleading.

The problem is base rate inflation. If 90% of outputs genuinely pass a dimension, a judge that always says PASS achieves 90% agreement. It looks great. It's useless — it has zero discriminative power, agreeing only because it never risks a FAIL.

The always-pass trap Calibration set: 100 outputs Human labels: 92 PASS, 8 FAIL Judge A (always PASS): Agrees on 92 PASS ✓ Disagrees on 8 FAIL ✗ Percent agreement: 92% Judge B (actually tries): Agrees on 85 PASS ✓, 6 FAIL ✓ Disagrees on 7 PASS ✗, 2 FAIL ✗ Percent agreement: 91% Judge A "wins" — but Judge B is the only one actually detecting failures.

Percent agreement rewards judges that follow the base rate. In any skewed distribution — and most eval distributions are skewed — it's nearly meaningless as a quality signal.

Cohen's kappa — adjusting for chance

Cohen's kappa asks a sharper question: how much better is this judge than random guessing? It computes how often two raters would agree by chance (given their individual tendencies), then measures how much the actual agreement exceeds that baseline.

The formula κ = (Pₒ − Pₑ) / (1 − Pₑ) Pₒ = observed agreement (same as percent agreement) Pₑ = expected agreement by chance If the judge says PASS 95% of the time and the human says PASS 90% of the time: Pₑ = (0.95 × 0.90) + (0.05 × 0.10) = 0.86 Even 90% observed agreement gives: κ = (0.90 − 0.86) / (1 − 0.86) = 0.29 That's "fair" — barely better than chance.

The interpretation scale:

κ < 0.20
Poor
Barely better than flipping a coin. The rubric or judge is broken.
0.20 – 0.40
Fair
Some signal, but noisy. The dimension needs work.
0.40 – 0.60
Moderate
Decent agreement. Acceptable for early-stage evals; keep refining.
0.60 – 0.80
Substantial
Strong agreement. This is the target for production rubrics.
κ > 0.80
Near-perfect
Excellent. The judge and human are aligned. Rare for subjective dimensions.

The key insight: kappa penalizes the easy agreement that comes from skewed distributions. A judge that always says PASS on a 90%-PASS dataset gets 92% percent agreement but κ ≈ 0.15 — exposed as barely above chance.

Try it: the kappa calculator

Edit the confusion matrix below and watch percent agreement and kappa diverge. Try the presets to build intuition for when percent agreement lies.

Human: PASS
Human: FAIL
Judge: PASS
Judge: FAIL
Percent agreement
87%
Looks good — but check kappa →
Cohen's kappa (κ)
0.74
Substantial agreement
Chance agreement (Pₑ)
50%
The baseline kappa adjusts for
What to notice

Click "Always-PASS judge" — percent agreement stays high (it matches the base rate), but kappa collapses to near zero. Then click "Balanced" — percent agreement is lower but kappa is much higher. Kappa rewards discriminative agreement, not just following the crowd.

Finding disagreement patterns

A kappa score tells you how much your judge disagrees with humans. But to fix the judge, you need to know how it disagrees. Four patterns to look for:

The diagnostic procedure: for every disagreement, read the judge's chain-of-thought reasoning. Is it quoting the right evidence? Is it reasoning correctly from evidence to score? The CoT format from Module 1 makes this forensic analysis possible — without it, you'd just see a bare score with no way to trace why it went wrong.

When to retrain or retire a judge

Calibration isn't a one-time exercise. Judges drift — the content distribution changes, the underlying model updates, or your quality standards evolve. Here's when to act:

Retrain (fix the rubric)
  • κ between 0.2–0.6 on a dimension — there's signal but it's noisy. Tighten definitions, add few-shots from the disagreement cases.
  • Systematic leniency or severity — the bias is consistent and correctable.
  • New content types appearing — the judge needs examples it hasn't seen.
Retire (rethink the dimension)
  • κ below 0.2 after two rounds of rubric fixes — the dimension may not be measurable by an LLM judge at this level of specificity.
  • Human–human agreement is also low — the dimension is inherently subjective. Consider splitting it into more concrete sub-dimensions.
  • The dimension no longer discriminates — all outputs pass because the generator improved. Drop it and add a harder check.
The recalibration loop

Every rubric change restarts the calibration cycle. Changed the Voice definition? Re-label 50 outputs with the new rubric, re-run the judge, re-compute kappa. This feels tedious but it's the only way to know whether your "improvement" actually improved anything. Ship a rubric change without recalibrating and you're back to vibes.

Check your understanding
Click to reveal
Your judge gets 94% agreement with humans. Your colleague says the judge is great. What question should you ask? reveal →

What's the base rate? If 92% of outputs are PASS, a judge that always says PASS would get 92% agreement. The 94% could mean the judge is barely above chance. Compute Cohen's kappa — it adjusts for the base rate and tells you how much agreement exceeds random guessing.

You compute κ = 0.72 for Hook but κ = 0.31 for Voice. What do you do? reveal →

Fix Voice, don't touch Hook. A 0.31 is fair — there's some signal but the rubric needs work. Look at the disagreement cases: is the judge being too lenient or too strict? Add borderline examples from the actual disagreements. Then re-label and re-measure. Don't retrain dimensions that are already working.

Two humans label 100 outputs and agree only 70% on Voice. Your judge–human κ is 0.45. Is the judge bad? reveal →

Not necessarily — human–human agreement sets the ceiling. If humans agree only 70%, that's roughly κ ≈ 0.4 between humans (depending on base rates). A judge at κ = 0.45 is performing at or slightly above human-level agreement. The problem isn't the judge — it's the dimension. Consider splitting Voice into more concrete sub-dimensions that humans agree on consistently.

You changed three few-shot examples in the Specificity rubric and reran the judge. Scores improved. Are you done? reveal →

No — you need to recalibrate. "Scores improved" means the judge's behavior changed, but you don't know if it changed in the right direction without re-measuring against human labels. Re-label a fresh sample with the updated rubric, recompute kappa, and compare. Without this step, you're optimizing for the judge's confidence, not its accuracy.

Author
James · learning in public
Template
Cobalt Grid · cream + cobalt risograph
Progress
Module 2 of 7 complete
Updated
July 2026