Engineering Atlas › Building AI Systems

Evals: Testing Non-Deterministic Systems

13 min read · last reviewed 2026-10-17

Open in the interactive app: practice, quiz, mock interview →

In one minute

How it works

What goes in an eval set

Start from real inputs: logged production requests (anonymised), support tickets, user-reported failures, and hand-written cases for important edge cases. For each case, store what a good output must satisfy: an expected value, required facts, forbidden content, or a rubric. Tag cases by category and importance so you can report per-slice results, and mark critical cases that must always pass. Fifty good cases beat five hundred random ones at the start; grow the set from every failure you find. Husain suggests starting near 30 examples and adding until new ones stop revealing new failure modes, then about 100 labelled examples per failure mode when validating a judge; below roughly 60, he notes, the confidence intervals are usually too wide to conclude anything (Husain).

Three kinds of graders

Judges need calibration

Model judges have known biases (Zheng et al.): preferring longer answers, preferring their own model's style, being swayed by answer position when comparing two. The MT-Bench study (Zheng et al., 2023) found that strong judges such as GPT-4 reach over 80 percent agreement with human preferences, the same level humans reach with each other, and named position, verbosity and self-enhancement bias as the failure modes (Zheng et al.). The biases can be large: in studies Eugene Yan reviews, some judges preferred padded, longer answers more than 90 percent of the time, and swapping the order of the two answers and checking for a consistent verdict is the standard control for position bias (Yan). Measure your own judge: have humans label 100 to 200 outputs, run the judge on the same ones, and compute agreement and Cohen's kappa (agreement corrected for chance). Also report the judge's true positive rate and true negative rate separately, because raw agreement misleads when failures are rare: if 5 percent of cases fail, a judge that always says pass agrees 95 percent of the time and catches nothing (Husain). If kappa or the failure-catching rate is low, refine the rubric, split criteria, or use humans for that criterion. Keep some labelled data out of the judge prompt and test on it once, as you would with a model.

Statistics, briefly

A pass rate from n cases is an estimate. The Wilson score interval gives a sensible 95 percent range even for small n or rates near 0 or 1. On 100 cases, 85 percent passing has an interval of roughly 77 to 91 percent; on 1,000 cases, roughly 83 to 87 percent. Two versions whose intervals overlap heavily may not really differ. Practical rules: compare versions on the same cases (paired comparison), look at which cases changed rather than only the totals, run noisy cases several times, and size the set for the smallest difference you care about. Anthropic's research note recommends exactly this toolkit: report the standard error of the mean and a 95 percent interval of 1.96 standard errors, use paired differences because model scores on the same questions correlate (0.3 to 0.7 for frontier models, so pairing removes real noise), resample and average chain-of-thought answers per question, and run a power analysis to decide how many questions a given difference needs (Anthropic). One more trap from the same note: if questions share a unit, such as several questions about one document, cluster the standard errors on that unit, because naive errors can be over three times too small. The Wilson interval above is the better choice for small n and rates near 0 or 1 (Wikipedia).

Offline and online

Offline evals run in CI on every prompt, model or retrieval change and block releases that regress critical cases. Online evals score a sample of production traffic with the same graders, plus product signals: thumbs up or down, escalation to humans, task completion, follow-up questions that indicate confusion. Online failures become new offline cases, which is how the eval set stays representative. The need is real: Anthropic's 2025 postmortem found that offline evals alone missed three overlapping serving bugs, and the fix was continuous quality evaluation on production traffic (Anthropic).

The same shapes as any system

Evals are trust but verify, made quantitative. They play the role tests and monitoring play for deterministic software, with the extra step that the grader itself must be verified.

Down the stack

Layer 1The contract

An AI feature commits to target pass rates per slice on a versioned eval set, 100 percent on critical cases, judge agreement with humans above a threshold (for example kappa of at least 0.6) for model-graded criteria, and an online quality signal watched after every release.

Layer 2The mechanism

An eval harness loads cases, runs the system under test with fixed configuration, applies graders, and stores results per case and version so runs can be diffed. Judge prompts are versioned like code. Results feed a dashboard with per-slice pass rates and confidence intervals. Human labelling uses a simple tool showing input, output and rubric, with disagreements between labellers reviewed to sharpen the rubric. Online sampling takes, say, 1 percent of traffic, strips personal data, and runs graders asynchronously.

Layer 3The machine

Running evals costs model calls: 500 cases times 3 repetitions times (one system call plus one judge call) is 3,000 calls per run, which at a few cents each is tens of dollars, and minutes of wall time if run in parallel within rate limits. Batch APIs cut the cost of large or nightly runs. Caching system outputs keyed by input and configuration lets you re-grade with a new judge without re-running the system. These costs are small next to shipping a regression to millions of users, but they shape how often you can run the full suite versus a fast subset.

Why it's built this way

  1. AI outputs vary and fail silently, so behaviour must be measured, not assumed.
  2. Code checks are reliable but limited; model judges scale but can be biased; humans are accurate but slow.
  3. So graders are layered, and model judges are calibrated against humans.
  4. Every measurement has sampling error, so decisions need intervals and paired comparisons.
  5. Production is the best source of new failures, so online results feed the offline set.

Diagram

flowchart LR
  P["Production logs and failures"] --> S["Eval set: cases, tags, critical flags"]
  H["Hand-written edge cases"] --> S
  S --> R["Run system version"]
  R --> G1["Code graders"]
  R --> G2["Model judge with rubric"]
  HL["Human labels sample"] --> CAL["Judge calibration: agreement, kappa"]
  CAL --> G2
  G1 --> D["Per-slice pass rates with intervals"]
  G2 --> D
  D --> GATE{"Critical pass and no regression?"}
  GATE -->|yes| SHIP["Ship"]
  GATE -->|no| FIX["Fix"]

Worked example

A legal-tech company's contract-summary feature has an eval of 120 contracts with lawyer-written key points. Version A scores 82 percent of key points found; version B, a new prompt, scores 86 percent. The team is about to ship B.

Before deciding, they compute intervals: 82 percent of 1,440 key points is roughly 80 to 84 percent, and 86 percent roughly 84 to 88 percent. Those intervals treat key points as independent, but they cluster by contract, so the honest interval is wider; computed over 120 contracts, it is perhaps twice as wide, and the improvement is plausible rather than certain. But the per-slice view shows B dropping from 95 to 81 percent on indemnity clauses, a critical category, while improving on boilerplate. They also check the judge: lawyers had labelled 150 outputs, and the model judge agrees with them on 88 percent with kappa 0.71, acceptable overall, but only 70 percent on indemnity clauses, where the judge misses subtle carve-outs.

Decisions: fix the prompt's handling of indemnity before shipping; mark indemnity cases as critical; for that category, use a stricter rubric that asks the judge to quote the clause and list each carve-out, raising agreement to 86 percent; and add 40 more indemnity contracts to the set. B ships a week later with 87 percent overall and 96 percent on indemnity.

In the wild

Trade-offs

GraderStrengthsWeaknessesChoose when
Exact match and rulesCheap, deterministicOnly fits structured outputsClassification, extraction, format checks
Model judge with rubricScales to open-ended textBiases, needs calibrationSummaries, answers, tone
Pairwise model comparisonSensitive to small differencesPosition and length biasChoosing between two versions
Human expertsGround truthSlow, costlyCalibration, critical categories
Online product signalsReal-world impactNoisy, delayedMonitoring after release

Pitfalls in production

Leadership lens

Check yourself

  1. Why prefer code-based graders where possible?

    Show answer

    They are cheap, fast and deterministic, so they add no grader noise; model or human grading is only needed where code cannot judge.

  2. What does Cohen's kappa add over raw agreement?

    Show answer

    It corrects for agreement expected by chance, which matters when one label is much more common than the other.

  3. Two versions score 84 and 86 percent on 100 cases. Can you conclude the second is better?

    Show answer

    Not confidently; with 100 cases the intervals overlap heavily, so look at paired per-case differences or use more cases.

  4. Why should production failures be added to the eval set?

    Show answer

    They show real failure modes the set missed, keeping it representative and preventing the same failure from returning.

Sources and further study

Primary

Systems docs

Books

Other curricula

Free resources

Open in the interactive app: practice, quiz, mock interview →