Evals are the unit tests of prompts
Every prompt change ships against a golden set. Every incident becomes a case. And the LLM judging the outputs is treated as the biased witness it is.
Prompt changes used to ship on vibes: run three examples, looks better, merge. Then a "small wording improvement" quietly broke number formatting in a pipeline for four days. Now a prompt is code, and code does not merge without tests.
The golden set grows out of scars
Each pipeline carries a labeled set of input/expected pairs. Nobody sat down to author it; it accreted, one case per incident, each test a way the system once embarrassed itself. Our largest text pipeline currently runs about 3,900 cases on every change with an expected failure count of exactly zero. The zero is non-negotiable. A suite that tolerates a few failures is a suite nobody reads.
LLM-as-judge, with handcuffs
Half our cases have no single right answer, so a model judges them. A model judge is a biased witness, and we treat it like one:
Verdict rules:
- Compare A and B for the stated criteria only. Do not reward length.
- TIE is a valid verdict. Prefer TIE over a coin flip.
- Output exactly one line: WINNER: A | B | TIE, then one reason.
(Runner: every pair is judged twice with A and B swapped.
Only a verdict that survives the swap is recorded. ~11% do not.)
- Position bias is real. Judges favor the first answer. The swap-and-agree protocol deletes that class of noise, at the cost of doubling judge calls. Worth it.
- Length bias is real. Unconstrained judges reward word count. The rubric says so explicitly, and outputs are capped before judging.
- Self-preference is real. A model grades its own family generously, so the judge is a different family than the generator wherever the stakes are high.
Agents get a harder bar
For agent tasks we do not measure pass@k, whether one of k attempts succeeds. We measure the opposite: run the same task k times and require every run to succeed before the agent earns autonomy on that task class. A workflow that succeeds four times out of five is not 80% done. It is a pager duty rotation you have not scheduled yet.
The payoff is boring in the best way: prompt refactors, model swaps and provider migrations became routine changes with a red/green answer, instead of leaps of faith followed by a week of watching logs.