Part 3 · Chapter 18

Evaluating a model

How anyone knows whether a model got better, and how often they are fooled. Capstone for Part 3.

Where we are

Part 3 has been about changing a model's behaviour: supervised fine-tuning (Chapter 14), preferences (15), reinforcement learning (16), and safety (17). Every one of those chapters ended with the same unanswered question: did it work? Loss on held-out text (Chapter 1) is the wrong instrument for that, because post-training is not trying to lower perplexity; it is trying to make the model more helpful, more correct, more terse, or safer, and those are measured differently. This chapter is the measuring instrument. Part 4 reuses it for applications (Chapter 23), where the same statistics apply and the same traps wait.

The question this chapter answers: what does it take to say, with evidence, that model B behaves differently from model A, and why are most such claims weaker than they look?

Picture this

A school district changes its maths curriculum and wants to know whether it worked. The obvious move is a test. But which test? If the new curriculum happened to include last year's exam questions as practice, scores go up and nothing was learned. If the test is multiple choice, a student who has learned to eliminate two wrong options looks like one who can do the maths. If the test is graded by teachers who know which students got the new curriculum, the grading drifts. If only twelve students took it, a three-point rise could be noise. And if the district compares its students against a neighbouring district's, the two groups had different students to begin with.

Every one of those failure modes has an exact counterpart in evaluating a language model, and each has a name: contamination, format sensitivity, judge bias, sample size, and unpaired comparison. The reason evaluation is a chapter and not a paragraph is that a frontier lab's decisions, which checkpoint to ship, which post-training recipe to keep, whether a safety intervention cost capability, are made on these numbers. Getting them wrong is expensive in both directions.

Map it
In the pictureIn the machineThe word we will use
The testA task, a dataset of items, a metric, and the code that runs themevaluation (eval); the code is the harness
A standardised test many schools takeA published dataset with a fixed metric that models are compared onbenchmark
Practising on last year's examTest items present in the training datacontamination
Guessing well on multiple choiceScores that depend on the answer format rather than the skillformat sensitivity
Teachers grading their own studentsA model scoring model outputs, with its own preferencesLLM-as-judge and judge bias
Same students, before and afterBoth models answer the same prompts; compare item by itempaired evaluation
Twelve students is not enoughHow many items are needed before a gap is not noisesample size, significance
Parents voting on which school is betterHumans choose between two anonymous answers; many votes become ratingsarena, Bradley–Terry / Elo

18.1What an eval is

An eval is four things, and confusion usually comes from leaving one implicit.

task       what the model is asked to do            "answer this grade-school word problem"
dataset    the items, with reference answers        8,500 problems, each with a numeric answer
metric     how one item is scored                   exact match of the final number
harness    the code: prompt template, few-shot      "Q: … A: Let's think step by step" ×8 examples,
           examples, decoding settings, parsing     greedy, parse the last number after "####"

Change any of the four and the number changes. The same model on the same dataset can score 60% or 80% depending on the harness: how many examples are shown, whether it is allowed to reason before answering, how the answer is extracted public (the Llama 3 report devotes a section to reporting its harness choices per benchmark precisely because of this). A benchmark score without its harness is a number without units.

Two scoring styles matter enough to name. Log-likelihood scoring shows the model a question and each candidate answer and asks which continuation it assigns the highest probability to. No generation; cheap; usable on base models that cannot follow instructions; and it is Chapter 1's next-token game applied to whole answers. Generative scoring lets the model write an answer and parses it. Closer to real use; sensitive to formatting, verbosity, and refusals; and the only option for tasks with free-form answers. The two can disagree by tens of points on the same model, and both are legitimate; they measure different things.

18.2The benchmark families

Benchmarks come in families, each measuring one slice of capability. The public reports for open models list dozens; here are the ones that appear in nearly every model card, with what each actually tests.

FamilyExamplesWhat it measuresWhat it misses
Knowledge, multiple choiceMMLU (57 subjects, 4 options) public, MMLU-Pro, GPQA (graduate-level science, expert-written, hard to Google) publicRecall and recognition across domainsAnything that needs writing; guessable from elimination; saturating at the top
MathsGSM8K (grade-school word problems) public, MATH (competition problems)Multi-step reasoning with a checkable answerHeavily contaminated; sensitive to whether the harness allows chain-of-thought
CodeHumanEval (164 Python functions with tests) public, MBPP, SWE-bench (real GitHub issues, run the repo's tests) publicWriting code that passes tests; SWE-bench adds navigating a codebaseHumanEval is tiny and memorised; SWE-bench depends on the agent scaffold as much as the model
Long contextNeedle-in-a-haystack, RULERWhether a fact placed deep in a long context can be retrievedRetrieval is easy; reasoning over the whole context is what users want and what these barely test
MultilingualMGSM, translated MMLU variantsWhether capability survives outside EnglishTranslated tests inherit translation quality; tokenizer costs (Chapter 6) confound
Instruction following and chatMT-Bench (80 multi-turn questions, judged) public, IFEval (verifiable constraints), AlpacaEval, Arena-HardDoing what was asked, in the way it was askedJudged by a model; measures the judge's taste as much as the answer
SafetyRefusal sets, jailbreak suites, dangerous-capability evals (Chapter 17)Whether the model declines what it should and helps with what it shouldAdversaries adapt; the eval measures yesterday's attacks

Two things to notice. Every family has a "what it misses" column, and none of them measure what a user experiences in a conversation. That is why the chat and arena rows exist, and why they are the noisiest. And the top rows saturate: when frontier models score in the high 80s or 90s on MMLU and GSM8K public (Llama 3.1 405B reports 87.3 and 96.8 respectively), the benchmark no longer separates them, and the field moves to harder ones. A benchmark has a useful life of a few years.

18.3Contamination

The training corpus (Chapter 9) is a crawl of the internet. Benchmarks are published on the internet, with their answers, and get copied into forums, tutorials, and GitHub repositories. So some fraction of any public test set is in the training data of any model trained after the test was released. The model has, in the language of Chapter 5, taken gradient steps on the answers.

Static view of the widget. True skill 60%, a third of the test set seen in training, 90% recall on seen items: reported accuracy 72%, an inflation of 12 points. The same model on a fresh rewrite of the benchmark scores 60%.

Detection works by comparison against held-out data. The cleanest demonstration is GSM1k, a fresh set of grade-school problems written to match GSM8K's distribution: several open models scored up to 13 points lower on the new set than on the old public, while frontier models showed little gap. Labs decontaminate by searching the training corpus for n-gram overlap with every benchmark they report and removing or flagging matches; the Llama 3 report describes exactly this and reports "clean" scores on the unaffected subsets public. It is imperfect: paraphrases slip through, and the detection is only as good as the list of benchmarks someone thought to check.

The Lab's rule for Beacon is the one every serious lab follows: any benchmark used to make a decision is treated as contaminated until the decontamination has been run, and any benchmark used to publish a number must have its harness and contamination check published with it. Internally, the numbers that drive decisions come from private evals that were never posted anywhere.

18.4Prompt sensitivity

The harness's prompt is part of the measurement. Published studies show the same model's MMLU score moving by several points when the answer options are relabelled from A/B/C/D to 1/2/3/4, when the few-shot examples are reordered, or when a trailing space is added public. Post-trained models add a second sensitivity: a chat model asked a raw multiple-choice question may refuse, hedge, or write a paragraph instead of a letter, and a harness that expects a letter scores that as wrong.

Three practices reduce the damage. Report the exact prompt. Evaluate with several prompt variants and report the spread, not just the best. And, when comparing two models, use the same harness for both, which is the paired design of §18.7. The last one is the most important: a five-point harness effect that hits both models equally cancels in the comparison; it only misleads when it hits them differently.

18.5A model as the judge

Most of what post-training changes has no reference answer. Is this reply more helpful? Better written? Did it follow the format? Humans can judge these, but a human judgment costs minutes and a lab wants a million of them a week. The standard substitute is a second model, given the question, one or two candidate answers, and a rubric, and asked for a verdict. This is LLM-as-judge, and it is the workhorse of every post-training pipeline described publicly public.

It works well enough to be useful: strong judges agree with human majority votes about as often as humans agree with each other, around 80% on chat-quality comparisons public (the MT-Bench study). It also has systematic biases, each of which has been measured:

Static view of the widget. True gap gives A a 60% win probability; a position bias of 0.8 toward the first slot makes the A-first verdicts say 77%. Judging each pair twice with positions swapped and keeping only consistent verdicts recovers about 60%, and reports that the judge contradicted itself on roughly 35% of pairs.

Two judging designs. Pairwise: show two answers, ask which is better. Robust to the judge's absolute scale, sensitive to position, and it directly answers "did the change help?". Pointwise: show one answer, ask for a score from 1 to 10. Cheaper (one call per answer, not per pair), comparable across many models, but judges compress toward the middle of the scale and their 7 is not stable across days or prompts. Pairwise for decisions; pointwise for dashboards.

Whatever the design, the judge must be calibrated: on a few hundred items, compare its verdicts to human verdicts, and report the agreement. A judge whose agreement with humans is unknown is a random number generator with good grammar.

18.6Humans, and arenas

Human evaluation remains the reference. Labs run it in two forms. Rated evals: trained raters score outputs against a guideline, slowly, expensively, and with inter-rater agreement measured and reported public. Arenas: anonymous users type a prompt, see two answers from two unnamed models, and vote. The Chatbot Arena collects millions of such votes and turns them into a leaderboard public.

Turning votes into ratings is a statistics problem with a standard answer. Assume each model has a strength sᵢ and that model i beats model j with probability 1 / (1 + e^{sⱼ − sᵢ}). That is the Bradley–Terry model; Elo is an online approximation to it. Fit the strengths to the observed votes by maximum likelihood, anchor one model at zero, and report the rest with confidence intervals. The arena's public methodology does exactly this public.

Static view of the widget. Five models with true log-strengths +1.6, +1.2, +0.9, +0.4, 0. After 50 random pairwise votes the fitted order is wrong (the second-best appears best). After 2,000 votes the fit is within about 0.1 of the truth for every model.
$ python code/ch18/arena_sim.py
   50 votes → A: +1.06 (true +1.60)  B: +2.02 (true +1.20)  C: +1.49 (true +0.90)  D: +0.75 (true +0.40)  E: +0.00 (true +0.00)
  500 votes → A: +1.61 (true +1.60)  B: +1.04 (true +1.20)  C: +0.94 (true +0.90)  D: +0.47 (true +0.40)  E: +0.00 (true +0.00)
 5000 votes → A: +1.48 (true +1.60)  B: +1.05 (true +1.20)  C: +0.84 (true +0.90)  D: +0.32 (true +0.40)  E: +0.00 (true +0.00)

Arenas have their own biases: the prompts are whatever users type (short, English, chat-like), the voters are self-selected, and models can be tuned for arena appeal (long, confident, formatted) without being better at anything else. Recent arena methodology adds style controls for exactly this reason public. An arena rating is the best single number for "which model do people prefer in chat"; it is not a measurement of any specific capability.

18.7Measuring a behaviour change

Now the question Part 3 kept asking. You ran a post-training step. Did the behaviour change? The design that answers it has three parts, and the arithmetic of each is small enough to do by hand.

Pair everything. Both models (or the model before and after) answer the same prompts. Comparing model A on one prompt set with model B on another is comparing the prompt sets. Comparing them on the same prompts, item by item, cancels everything about the prompts, and leaves only the difference between the models. Each prompt yields one of three outcomes: A better, B better, tie.

Count decisive pairs, test the count. Ties carry no information about direction; drop them. Under the hypothesis that the change did nothing, each decisive pair is a fair coin. The exact sign test asks how surprising the observed split is under a fair coin.

By hand

Fifty prompts. After the change, the judge (position-swapped, consistent verdicts only) says: after-better on 28, before-better on 12, tie or inconsistent on 10.

decisive pairs     n = 28 + 12 = 40
win rate           28 / 40 = 0.70
null hypothesis    p = 0.5, each decisive pair a coin flip
two-sided p-value  P(≤ 12 heads in 40 flips) × 2
                   = 2 × Σ_{i=0}^{12} C(40, i) / 2⁴⁰
                   = 2 × 0.0083
                   = 0.0166                                 ← below 0.05: the change did something

95% interval on the win rate (Wilson)     [0.55, 0.82]     ← wide: "70%" is really "somewhere above half"

same split with half the prompts (14 vs 6, n = 20)    p = 0.1153    ← not significant
same split with double (56 vs 24, n = 80)             p = 0.0005
a smaller effect at the same n (24 vs 16, n = 40)     p = 0.2682    ← 60/40 on 40 pairs is noise
$ python code/ch18/sign_test.py
wins  28  losses  12  ties  10  |  win rate 0.70  95% CI [0.55, 0.82]  two-sided p = 0.0166
wins  56  losses  24  ties  20  |  win rate 0.70  95% CI [0.59, 0.79]  two-sided p = 0.0005
wins  14  losses   6  ties   5  |  win rate 0.70  95% CI [0.48, 0.85]  two-sided p = 0.1153
wins  24  losses  16  ties  10  |  win rate 0.60  95% CI [0.45, 0.74]  two-sided p = 0.2682

true win rate 0.55 → about  782 decisive pairs for 80% power
true win rate 0.60 → about  194 decisive pairs for 80% power
true win rate 0.65 → about   85 decisive pairs for 80% power
true win rate 0.70 → about   47 decisive pairs for 80% power
true win rate 0.80 → about   20 decisive pairs for 80% power

The second block is the planning table. A change that wins 55% of pairs, which is a real and possibly valuable change, needs about 800 decisive pairs to detect reliably. Most internal "we tried X and it seemed better" decisions are made on far fewer, which is why they so often fail to replicate. The Lab sizes its decision evals from this table before running them.

Static view of the widget. At a true win rate of 0.65 and a 20% tie rate, 50 prompts give 40 decisive pairs, an expected 26 wins, and p ≈ 0.08: not yet significant. 100 prompts give p ≈ 0.007. The curve crosses p = 0.05 at about 70 prompts for this effect size and at about 1,000 for a 0.55 effect.

Report the size, not just the verdict. "p < 0.05" says the coin is not fair; it does not say how bent it is. The win rate with its interval says that. And the win rate is only interpretable with the rubric it was judged on: a 70% win rate on conciseness says nothing about correctness, and post-training changes that improve one often degrade another. The Lab's release gate for Beacon is not one number but a panel: every decision eval, paired, with intervals, on the dimensions the change was meant to move and on the ones it must not.

Evals during training and evals at release

Two different jobs. During a pretraining run (Chapter 13), evals are run on checkpoints every few thousand steps to catch divergence and to compare data mixtures; they must be fast and cheap (log-likelihood scoring on a few hundred items each) and their absolute values matter less than their trend. At release, evals are the evidence in the model card: full harnesses, decontaminated, with the prompts published, and the numbers compared against the previous model and against competitors on identical settings public. Confusing the two, by quoting a mid-training sanity check as a capability claim, is a common way to be wrong.

A model card's evidence has a hierarchy, and reading one is a skill. From strongest to weakest: paired human ratings with agreement statistics; arena ratings with intervals; paired judged evals with a calibrated judge and position swapping; decontaminated benchmark scores with the harness published; benchmark scores without the harness; and "we found it to be better". Beacon's card is expected to sit in the top three tiers for every claim it makes.

18.8Capstone 3: detect a behaviour change through the API

The design of §18.7, run for real, on a change you control. The behaviour: terseness. The change: a two-sentence system prompt. The claim to test: "the system prompt makes the model's answers more concise". Everything in Part 3 that changes a model's behaviour (SFT data, preference tuning, an RL reward) is evaluated the same way; the system prompt is just the cheapest change to make, so the mechanics of the eval stand alone.

arm A      model, no system prompt                                  "before"
arm B      same model, system prompt "Answer in at most two sentences."   "after"
prompts    the same 40+ questions, drawn from Dispatch's domain     paired
judge      a cheaper model, rubric on conciseness only, one character out
swap       every pair judged twice, positions swapped; keep consistent verdicts
statistic  exact sign test on decisive pairs; win rate with interval
# code/ch18/paired_eval.py (excerpt)
MODEL, JUDGE = "claude-opus-5", "claude-haiku-4-5"
TERSE = "Answer in at most two sentences. No preamble, no lists."

RUBRIC = """You are judging two answers to the same question for CONCISENESS ONLY: the better answer
is the one that is shorter while still answering the question. Ignore style and formatting.
Reply with exactly one character: A if answer A is more concise, B if answer B is, or T for a tie."""

def judge(question, a, b):
    r = client.messages.create(model=JUDGE, max_tokens=5, system=RUBRIC,
        messages=[{"role": "user", "content": f"Question: {question}\n\nAnswer A:\n{a}\n\nAnswer B:\n{b}"}])
    verdict = "".join(bl.text for bl in r.content if bl.type == "text").strip()[:1].upper()
    return verdict if verdict in "ABT" else "T"

for q in PROMPTS:
    base, terse = answer(q), answer(q, TERSE)
    v1 = judge(q, terse, base)             # terse shown first
    v2 = judge(q, base, terse)             # positions swapped
    # consistent "terse wins" / "base wins" / tie / judge flipped → counted as tie
    ...
p = 2 * sum(comb(n, i) for i in range(0, min(wins, losses) + 1)) / 2 ** n
(example output — 40 prompts; your judge's verdicts and the exact counts will differ)
terse wins                 base  142 words  terse   31 words  | Why does a push queue's depth grow even w
terse wins                 base  118 words  terse   28 words  | Explain what a KV cache stores and why it
tie                        base   41 words  terse   34 words  | What is the difference between prefill an
judge flipped with position base   96 words  terse   47 words  | How should I triage a pager alert about e
…
terse wins 31, base wins 3, ties 6 (of which position-inconsistent 4)
win rate 0.91 over 34 decisive pairs, exact sign test p = 0.0000

Three things to check when you run it, because they are where such evals go wrong. First, the word counts: if the "terse" arm is not actually shorter on most items, the judge's verdicts are measuring something else and the eval is broken before statistics enter. Second, the flip rate: a judge that contradicts itself on more than about a fifth of pairs is not a usable judge for this rubric, whatever its verdicts say. Third, the ties after swapping: the 40 prompts include a few whose base answer was already short, and those should tie. If none do, the judge is not reading.

Then the second half, which is the half people skip. A behaviour change is only worth shipping if it did not break something else. Run the same paired design with a correctness rubric on the same outputs. A terseness prompt that wins 91% on conciseness and loses 30% on correctness is a regression, and only the paired panel shows it. Dispatch's own release gate, built in Chapter 23, is this panel with more dimensions.

18.9Beacon's numbers

QuantityLlama 3.1 405B (as reported)Evidence
MMLU (5-shot) / GSM8K (8-shot, CoT) / HumanEval (0-shot)87.3 / 96.8 / 89.0public
Decontaminationn-gram overlap against every reported benchmark; clean-subset scores reported alongsidepublic
Human evaluationPaired comparisons against competitors across capability categories, with win/tie/loss rates and intervalspublic
Judge model useReward-model and LLM-judge scoring throughout post-training data selectionpublic
Closed frontier modelsModel cards report benchmark tables and some human-preference results; internal decision evals, judge calibration data, and contamination methods are mostly not disclosedunknown
Back of the envelope

What does a release-eval panel cost? Suppose the Lab's gate is 30 decision evals of 500 paired prompts each, judged twice (swapped) by a judge model, and each answer averages 400 output tokens with a 300-token prompt.

generation    30 evals × 500 prompts × 2 arms × 700 tokens               ≈ 21 M tokens through the candidate model
judging       30 × 500 × 2 orders × (300 + 2·400 + rubric 150) tokens     ≈ 38 M tokens through the judge
at list prices for a frontier candidate and a small judge                ≈ a few hundred to a few thousand dollars per gate
human rated slice    2,000 pairs × ~5 minutes × two raters                ≈ 330 rater-hours

The tokens are cheap next to a training run. The rater-hours are the bottleneck, which is why judge models exist and why their calibration against the rated slice is the number that makes the rest trustworthy.

Break it

Evaluate the two models on different prompt sets. The comparison now includes the difference between the sets, which can be larger than the difference between the models. A five-point gap can appear or vanish depending on which set got the harder questions. Pairing removes this entirely; nothing else does.

Skip the position swap. With a judge that leans 0.8 toward the first slot, a true 60/40 preference reads as 77/23 in one order and 41/59 in the other. Whichever order the harness happened to use decides the verdict. The swap costs 2× judge calls and is the difference between a measurement and a coin toss with a thumb on it.

Decide on 20 prompts. A 70/30 split on 20 decisive pairs has p = 0.115. Reasonable-looking splits at this size are consistent with no effect roughly one time in eight. Repeated across a lab's hundred small decisions per month, a dozen of them are noise, and the recipe drifts on ghosts.

Use the model under test as its own judge. Self-preference bias means the "after" model rates its own style higher. Published measurements put this at several points of win rate public, enough to turn a null result into a positive one. Judge with a different family.

Trust a benchmark whose prompts are on GitHub. The next model trained on a crawl has seen them. The score measures recall of the test set plus skill, in unknown proportion. A fresh rewrite of the benchmark, or a private set, is the only way to know which.

Optimise directly on the release benchmark. Every eval becomes a training signal once it is used to select checkpoints, choose data mixtures, or tune prompts. The number goes up; the capability it was a proxy for may not. This is Goodhart's law, and Chapter 15's reward over-optimisation is the same phenomenon with a different name. Hold out evals that are never used for selection, and report those.

Rebuild the model

Say it back. An eval is a task, a dataset, a metric, and a harness, and the number it produces is meaningless without all four. Benchmarks are public evals that measure one slice of capability each, saturate within a few years, and are contaminated by the crawl that trains the next model, so labs decontaminate, publish harnesses, and keep private sets for decisions. Free-form behaviour is judged by a model against a rubric, which works at about human-level agreement but carries position, verbosity, and self-preference biases, each of which has a specific fix: swap positions, control length, use a different family, calibrate against humans. Human votes in an arena become ratings through the Bradley–Terry model, the same logistic relation between strength gap and win probability that Elo approximates. To say a change worked, pair the prompts, drop the ties, run the exact sign test on the decisive pairs, report the win rate with an interval, and size the eval from the effect you hope to see: a 55% effect needs about 800 decisive pairs, a 70% effect about 50. Then run the same design on the dimensions the change must not have hurt. Beacon's release gate is that panel, and the capstone is one row of it, run through the API on a change you made yourself.

same promptspaired A and B answerbefore / after judge, swappedrubric, calibrated win / loss / tiedrop ties sign test + intervalsized in advance then repeat on every dimension the change must not have hurt · benchmarks decontaminated, harness published, private sets for decisions
What is the whole chapter in one line? Pair, judge both ways, count decisive outcomes, test and report the size, and do it for the things you did not mean to change too.
Exercises
  1. By hand. A change is judged on 30 prompts: 19 after-better, 7 before-better, 4 ties. Compute the win rate, the two-sided sign-test p-value (write out the binomial sum), and the Wilson interval. Then state how many more decisive pairs at the same win rate would bring the p-value under 0.01.
  2. Calculation. A judge has a position bias such that, with no true difference, it picks the first answer 65% of the time. Without swapping, what win rate would a harness that always shows the new model first report for a change that truly wins 50%? For one that truly loses (wins 40%)? Now suppose the harness randomises order per item: what does the expected reported win rate become in each case, and what is lost compared with swapping every pair?
  3. Code. Extend paired_eval.py with a second rubric for correctness (judge whether each answer is factually right about the question, independently, pointwise 0/1), run both rubrics on the same outputs, and print a two-row panel: conciseness win rate with interval, correctness rate per arm with interval. Then change TERSE to "Answer in one sentence" and report what happens to both rows.
Further reading