← all writing

Evals: How to Actually Measure LLM Application Quality

Evals: How to Actually Measure LLM Application Quality

You cannot improve what you cannot measure, and it looks good does not scale. This is a deep, practical guide to building evaluations that catch regressions, settle debates with data, and drive real progress on LLM applications.

Why evals are the real moat

Teams obsess over prompts and models, but the thing that actually separates an LLM application that improves over time from one that thrashes is evaluation. Without evals, every change is a gamble. You tweak a prompt, it looks better on the one example you happened to check, you ship it, and you have no idea what you broke for the inputs you did not check. Evals turn it feels better into it scored higher on eighty cases, with two regressions here and here. They are tedious to build, unglamorous to maintain, and the single highest-leverage investment in the entire stack, because they are what let you move quickly without moving backward.

The deeper point is that in a world where everyone has access to the same models, your evals are a real competitive advantage. They encode your specific definition of quality, your particular failure modes, and the standards your users actually care about. A competitor can copy your prompt in an afternoon, but they cannot copy the accumulated knowledge embedded in a good evaluation suite, the hundreds of real cases that taught you exactly where your system tends to fail. That knowledge is what lets you improve faster than they can, and it compounds: every bug you turn into a test case is a mistake you will never silently make again.

The cost of flying blind

It is worth dwelling on what life without evals actually looks like, because many teams live there without naming it. Changes become frightening, because no one can predict their effect, so the team either stops changing things or changes them and hopes. Debates about whether a new prompt is better get settled by whoever argues most confidently, not by evidence. A model upgrade that should be a routine improvement becomes a risky migration no one wants to own. And worst of all, quality erodes invisibly: a change that fixed one thing quietly broke three others, and you only find out when a user complains, by which point the regression has been live for weeks. Flying blind is not just slow; it is a slow accumulation of unnoticed damage. Evals are the instrument panel that makes the damage visible while you can still fix it.

Evals turn subjective impressions into measurable signal, so changes become safe and progress becomes visible rather than hoped-for.

Start with a dataset, not a metric

The foundation of evaluation is not a clever scoring function; it is a set of representative inputs. Before you worry about how to score, collect what to score on. Gather real examples: the queries your users actually send, the documents you actually process, and especially the cases that have failed in the past. The instinct to start with the metric is backwards, because a metric measured on the wrong inputs tells you nothing useful, while even a crude metric measured on the right inputs is informative. Get the dataset right first and the scoring will follow.

Quality matters more than quantity, and by a wide margin. Twenty carefully chosen examples that cover your important scenarios and your known failure modes will teach you far more than a thousand random ones, because the random thousand are mostly easy cases that every version passes, while the curated twenty are the cases that actually discriminate between a good system and a bad one. Include the awkward inputs, the ambiguous ones, the adversarial ones, and the ones that have burned you before. Your evaluation set should be a concentrated sample of everything hard about your problem, not a representative sample of everything average about it.

Build the dataset as a living asset

An evaluation set is not built once; it grows. Every time you find a new failure in production, add it to the set, so that the same failure can never recur unnoticed. Over time this turns the dataset into the institutional memory of your application, a record of every kind of input your system needs to handle correctly, and it becomes the thing new team members can rely on to avoid repeating old mistakes. Seed it from real usage rather than imagination, because the inputs users actually send are reliably stranger and more varied than the ones you would invent at a desk. And keep it honest by holding some cases back: a portion of your data should be a set you do not look at while iterating, so you can check that improvements on your working set generalize rather than overfitting to it.

Three ways to score, in order of preference

Not every task needs the same kind of judgment, and the art is reaching for the cheapest, most reliable method the task allows. There are three broad approaches, and you should prefer them in this order:

  • Code-based checks for anything verifiable: is the JSON valid, does the answer contain the required value, is the computed number correct, does the generated code run and pass its tests? Fast, deterministic, free, and completely reliable. Use them wherever the task permits.

  • LLM-as-judge for qualities that resist exact matching: helpfulness, tone, coherence, faithfulness to a source. A model scores the output against a rubric. Powerful and scalable, but the judge itself must be validated, because a sloppy judge produces confident nonsense.

  • Human review for the highest-stakes or most subjective judgments. The most expensive and the most trustworthy. Use it to calibrate the cheaper methods and to spot-check, not to score every run.

The mistake to avoid is reaching for an expensive method where a cheap one would do. If you can check correctness with code, do not pay a model to judge it; code is faster, free, and never wrong about whether a string matches. Save the model judge for the genuinely fuzzy qualities, and save human review for the cases where even a model judge is not trustworthy enough. Matching the method to the task is what keeps evaluation affordable enough to run constantly, which is the whole point.

Code-based checks: use them everywhere you can

The most underused evaluation technique is also the simplest: deterministic checks written in code. A surprising amount of what matters about LLM output is mechanically verifiable. Structured output can be validated against a schema. Extracted values can be compared against known answers. Generated code can be executed against a test suite, which is the gold standard, because passing tests is an unarguable signal of correctness. Even fuzzy-seeming requirements often have checkable components: an answer that must cite a source can be checked for the presence of a citation, a response that must stay under a length limit can be measured exactly. Pushing as much of your evaluation as possible onto deterministic checks makes the suite faster, cheaper, and more trustworthy, and it frees your expensive judgment methods to focus on the parts that genuinely need them.

Wherever output is verifiable, score it with deterministic code: schema validation, exact-value checks, executing generated code against tests. Fast, free, and never wrong.

LLM-as-judge: powerful and easy to misuse

For the qualities that code cannot check, using a model to judge output is the technique that makes evaluation scale. A judge model reads the output, and often the input and a reference, and scores it against criteria you define. This unlocks evaluation of helpfulness, tone, faithfulness, and the many other qualities that matter but resist exact matching. It is genuinely powerful, and it is also genuinely easy to misuse in ways that produce confident, wrong scores you then trust, which is worse than having no scores at all because it gives you false confidence.

A few practices keep a judge honest. Give it a concrete rubric with explicit criteria and a clear scale, not a vague instruction to rate from one to ten, because vague rubrics produce noisy, inconsistent scores. Prefer comparison over absolute scoring: models are far more consistent at judging whether answer A is better than answer B than at assigning an absolute number, so pairwise comparison against a baseline is often more reliable than a standalone grade. Validate the judge against human labels on a sample, and if it disagrees with people, fix the judge before you trust it on thousands of cases. And watch for known biases: judges tend to favor longer answers, answers that match their own style, and the first option presented, so control for position and length rather than letting them quietly skew your results.

The judge needs evaluating too

It is worth stating plainly, because it is so often skipped: a model judge is itself a model-based system, and it deserves the same scrutiny you would apply to any other. Before you rely on a judge to grade thousands of outputs, check that it agrees with human judgment on a sample where you know the right answer. Measure that agreement, and treat the judge as trustworthy only to the extent it tracks the humans. A judge that agrees with people ninety-five percent of the time is a fine instrument; a judge whose agreement you never measured is a guess wearing the costume of a measurement. The few hours it takes to validate a judge against human labels are among the best-spent hours in the whole evaluation effort, because every downstream decision rests on the judge being right.

Human review: expensive, essential, calibrating

Human review is the most expensive form of evaluation and the most trustworthy, and the trick is to use it where its cost is justified rather than spreading it thin. Its highest-value uses are calibration and spot-checking: humans label a sample that validates your automated methods, humans review the highest-stakes outputs where a mistake is unacceptable, and humans investigate the cases where the automated scores look suspicious. The goal is not to have humans grade every output, which does not scale, but to use human judgment as the anchor that keeps the scalable methods honest. When you design human review, give reviewers clear guidelines and the same rubric your judge uses, so their labels are consistent and directly comparable, and so disagreement between them surfaces ambiguity in the task rather than noise in the process.

Use human review where its cost is justified: calibrating automated judges, reviewing high-stakes outputs, and investigating suspicious scores, not grading every run.

Measure the whole system, not just the model

In any pipeline more complex than a single model call, an end-to-end score tells you that something is wrong but not where, and that is a recipe for slow debugging. The remedy is component-level evaluation: measure the parts as well as the whole. In a retrieval pipeline, evaluate whether retrieval returned the right documents, separately from whether the model used them well. In an agent, evaluate whether it chose the right tools in the right order, separately from whether the final answer was correct. When the end-to-end result is wrong, component-level metrics point you straight at the stage responsible, whether the retriever, the prompt, or the model, instead of leaving you to guess. This decomposition is what makes a complex system debuggable, and it is the difference between fixing the actual problem and randomly changing things until the symptom goes away.

Evaluating retrieval systems

Retrieval deserves its own evaluation because it fails in its own ways and because it is measurable independently of the generation that follows. For a set of queries with known relevant documents, you can measure whether the relevant material was retrieved at all and how highly it was ranked, which tells you directly whether the problem lives in chunking, embeddings, or ranking. You can also evaluate the generation step on its own by feeding it known-good context and checking whether it answers faithfully, which isolates hallucination and reasoning problems from retrieval problems. Separating these two axes, did we retrieve the right thing and did we use it well, turns a vague the answer was wrong into a specific, actionable diagnosis, and it is the key to improving a retrieval system without flailing.

Evaluating agents

Agents are the hardest systems to evaluate, because they involve sequences of decisions rather than a single output, but the effort is essential precisely because there is so much that can go wrong across a multi-step run. Evaluate the final outcome, of course, but also evaluate the trajectory: did the agent take a sensible path, choose appropriate tools, avoid wasteful detours, and recover gracefully when something failed? A suite of representative tasks with known good outcomes, run whenever you change the agent, catches regressions that a few manual tries would miss. And the traces your agent emits for observability double as evaluation material, since real runs become the cases you replay. Evaluating the path as well as the destination is what lets you tell a lucky correct answer from a robustly correct process, and the difference matters when the next input is slightly different.

Run evals like tests

An evaluation suite only pays off if it is cheap enough to run constantly, so wire it into your workflow the way you would wire in automated tests. Run it on every meaningful change to a prompt, a model, or the pipeline, so you catch regressions at the moment you introduce them rather than weeks later in production. Track scores over time so you can see trends and catch slow erosion that any single run would miss. Make the suite fast and automated enough that running it is the default, not a special occasion, because an evaluation suite that is too slow or too manual to run routinely is one that will quietly stop being run, and an eval you do not run is no eval at all.

Wire evals into the workflow like tests: run them on every change, track scores over time, and make them fast enough that running them is the default.

Model upgrades are an eval problem

One of the most valuable things a good eval suite does is tell you whether a new model is actually better for your task. The benchmark numbers in a model announcement were measured on someone else problem, not yours, and a model that tops a public leaderboard can easily be worse for your specific application, your prompts, and your data. Your evaluation suite is the only authority that matters on this question. When a new model appears, run your suite against it and compare, holding everything else fixed, and let the results decide. This turns model upgrades from anxious migrations into routine, evidence-based decisions, and it occasionally saves you from a downgrade dressed up as an upgrade, which is exactly the kind of mistake that is invisible without evals.

Do not chase a single number

It is tempting to collapse quality into one headline score and optimize it, and it is a trap. A single metric hides trade-offs: you can raise the average while quietly regressing the cases that matter most, and the number will look like progress while the experience gets worse for the users you most need to keep. Keep a small dashboard instead of a single figure. Track the overall score, but also track performance on the critical sub-segments you care about, and track a separate count of hard failures, the outputs that are not merely worse but unacceptable. Optimizing one number is how you end up with a system that scores well and behaves badly, and a handful of complementary metrics is how you keep the trade-offs visible.

Hard failures deserve their own gate

Not all errors are equal, and averaging treats them as if they were. A response that is slightly less helpful than ideal is a minor ding; a response that is confidently wrong about something dangerous, or that violates a policy, or that exposes information it should not, is a different category entirely, and it can be averaged away on a leaderboard while remaining completely unacceptable to a real user. Track these hard failures separately and gate on them: a change that improves the average but introduces even one unacceptable failure should not ship until that failure is fixed. Separating the count of catastrophic failures from the average quality score is what keeps a metric-driven process from optimizing its way into something that looks good on paper and harms users in practice.

Online evaluation and production monitoring

Offline evaluation on a fixed dataset is essential but incomplete, because production sends inputs your dataset never anticipated. Online evaluation complements it by measuring quality on live traffic: implicit signals like whether users accept, edit, or retry the output; explicit signals like thumbs up and down; and automated checks run on a sample of real responses. These signals catch the distribution shift that offline evals miss, the new kinds of queries and the changing user behavior that no fixed dataset can predict. They also feed the loop, because the production cases that score poorly are exactly the ones to add to your offline dataset, closing the gap between what you test and what users actually do. The two forms of evaluation are partners: offline gives you fast, controlled iteration, and online keeps you honest about reality.

Ship changes behind comparison

When a change passes your offline suite, the safest way to confirm it in the real world is to compare it against the current version on live traffic rather than simply switching over. Running the new version in shadow, where it processes real inputs without its output being shown, lets you compare its behavior to production without risk. A controlled rollout to a fraction of traffic, with quality and outcome metrics watched closely, catches problems your offline suite missed before they reach everyone. These techniques are standard in software for a reason, and they apply just as well to LLM systems, where the gap between offline performance and live behavior can be large precisely because real inputs are so varied. Comparison-based rollout is how you get the benefit of a change while bounding the damage if it turns out to be worse than you thought.

Do not overfit to your evals

An evaluation suite is a proxy for quality, not quality itself, and like any proxy it can be gamed, including by you, unintentionally. If you tune relentlessly against a fixed set of cases, you will eventually improve on those specific cases without improving the underlying system, the same way a student who memorizes a practice test learns the answers rather than the material. The defenses are to hold out cases you do not iterate against, to refresh the dataset with new real inputs over time, and to treat a suspiciously high score with the skepticism it deserves. The eval exists to tell you the truth about your system, and the moment you start optimizing the eval rather than the system, it stops doing its job. Keep the suite honest and it will keep you honest.

The payoff

Good evals change how a team works, and the change is profound. Changes stop being scary, because you can see their effect before they reach users. Debates about whether a prompt or a model is better get settled by data instead of by whoever is most persuasive. New team members can contribute without fear, because the suite catches their mistakes before those mistakes ship. Model upgrades become routine. Quality stops eroding invisibly, because every regression shows up as a number going the wrong way. The upfront cost is real, and building the dataset and the harness is unglamorous work that competes with more exciting things, but it is the difference between an application that compounds improvements over time and one that lurches sideways forever, fixing one thing while breaking another.

So build the evals first, or at least early, and treat them as the core asset they are rather than an afterthought. Start with a small set of real, hard cases. Score with code where you can, a validated judge where you must, and humans where it counts. Run the suite on every change, track a handful of complementary metrics, gate on the failures that are unacceptable, and feed production reality back into the dataset. Do that, and you will have built the thing that lets everything else in your LLM application get reliably better instead of merely different. Evaluation is not the glamorous part of building with language models, but it is the part that determines whether you are actually improving, and that, in the end, is the only question that matters.

Choosing metrics that fit the task

There is no universal quality score, and trying to force every task into the same metric produces measurements that miss what matters. A classification task wants accuracy and a confusion matrix that shows which categories get confused. A summarization task wants faithfulness to the source and coverage of the key points, not surface similarity to a reference. A retrieval task wants metrics about whether the right documents came back and how highly they ranked. A code-generation task wants the pass rate of executed tests. An extraction task wants field-level precision and recall. The work of designing an evaluation is partly the work of articulating what good actually means for your specific task, and then finding the most direct measurement of that. A metric borrowed from a different task because it was convenient will reliably tell you about the wrong thing, and a metric you designed to capture your real definition of quality will tell you about the right one.

Synthetic data has a place, with caveats

Building an evaluation set from real usage is ideal, but early on you may not have enough real data, and waiting is not always an option. Synthetic data, cases generated by a model to exercise scenarios you expect, can bootstrap a suite and fill gaps in coverage where real examples are scarce. It is genuinely useful for that, and it lets you test edge cases that are rare in real traffic but important when they occur. The caveat is that synthetic data reflects what a model imagines your inputs look like, not what they actually look like, and real users are reliably stranger, messier, and more creative than any generator anticipates. Use synthetic data to start and to supplement, but treat real cases as the gold standard and migrate toward them as they accumulate. A suite built entirely on synthetic data measures your performance on an imagined version of your problem, which is a different and easier thing than the real one.

The cost of evaluation itself

Evaluation is not free, and a suite that uses model judges on a large dataset and runs on every change has a real cost in money and time that is easy to overlook until the bill arrives. This is a feature to manage, not a reason to skip evaluation. Manage it by tiering: run a fast, cheap subset of code-based checks on every change for immediate feedback, and reserve the expensive judge-based and human evaluations for less frequent, higher-stakes checkpoints like a release candidate or a model upgrade. Sample rather than scoring every production response. Cache judge results for outputs that have not changed. The goal is a suite that is cheap enough to run as often as you need without being so expensive that you start skipping it, because an evaluation process that is too costly to run routinely degrades into one that is not run at all, and you are back to flying blind.

Evaluation across the lifecycle

Evaluation is not a single activity but a set of practices that show up at every stage of building with language models, and recognizing where each fits keeps the effort proportionate. During development, fast offline evals on a curated set give you the tight feedback loop that lets you iterate on prompts and pipelines without guessing. Before a release, a fuller evaluation including judge-based and human review on a release candidate confirms that the change is genuinely an improvement and introduces no unacceptable failures. After release, online evaluation and production monitoring keep watch on live quality and surface the cases your offline set never anticipated. And continuously, the failures you find in production flow back into the offline dataset, so the whole system gets a little harder to fool over time. These stages reinforce one another, and a mature practice runs all of them rather than treating evaluation as a one-time gate.

Common pitfalls

A handful of recurring mistakes undermine evaluation efforts, and naming them helps you avoid them. The tiny unrepresentative dataset gives confident scores that do not generalize because it does not cover the cases that matter. The unvalidated judge produces grades nobody checked against human judgment, so the whole suite rests on an unexamined assumption. The single-number obsession optimizes an average while regressing the cases users care about most. The happy-path-only suite tests the inputs that work and learns nothing about the failures that actually hurt. The frozen dataset never grows, so the suite stops reflecting how the system is really used. And the overfit suite gets gamed by relentless tuning until the score improves but the system does not. Each of these has a remedy described throughout this guide, and the meta-lesson is that an evaluation process needs its own quality control, because a bad eval is worse than none: it gives you confidence you have not earned.

Making evaluation a habit

The teams that get the most from evaluation are not the ones with the most sophisticated metrics; they are the ones for whom checking is reflexive. They do not ship a prompt change without running the suite, the way a disciplined engineer does not merge code without running the tests. They add a case to the dataset the moment they find a new failure, while the failure is fresh and the fix is in hand. They look at the dashboard before they argue about whether something is better. This reflexive habit, more than any particular technique, is what turns evaluation from a project into a practice, and it is what compounds into a system that reliably improves. Build the habit deliberately: make the suite easy to run, make adding cases frictionless, and make looking at the numbers the normal first step rather than an afterthought, and the discipline will become second nature.

Who owns evaluation

A practical question that quietly determines whether evaluation actually happens is who owns it. When evaluation is nobody specific job, it tends to be everybody good intention and nobody actual work, and the suite slowly decays. The healthiest arrangement treats the evaluation set as shared, owned infrastructure that the whole team contributes to and depends on, with clear responsibility for keeping it current and trustworthy. Domain experts, the people who actually understand what a good answer looks like for your application, are essential here, because they are the ones who can write the rubric, label the calibration set, and judge whether a borderline output is acceptable. Evaluation is not purely an engineering task; it is the place where domain knowledge about quality gets encoded into something measurable, and that encoding only happens well when the people who hold the knowledge are involved in building the suite rather than handing requirements over a wall.

This is also why evaluation pays dividends beyond the numbers. The act of building an eval set forces a team to articulate, concretely and by example, what they actually mean by quality, and that conversation is valuable in itself. Disagreements about how to score a case are usually disagreements about what the product should do, surfaced early and cheaply. A team that has built a good evaluation suite has, as a side effect, built a shared, precise understanding of its own standards, and that alignment is worth nearly as much as the measurements the suite produces.

Start small and grow

If all of this sounds like a large undertaking, the encouraging truth is that you do not need to build it all at once, and trying to would likely mean never starting. The highest-leverage first step is small: collect ten or twenty real cases that matter, write down what a good answer looks like for each, and set up the simplest possible way to run your system against them and check the results. Even that crude beginning is transformative, because it replaces does this seem better with did this pass the cases I care about. From there you grow the dataset as you find failures, add code-based checks as you identify verifiable properties, introduce a validated judge when you need to score fuzzy qualities, and wire the whole thing into your workflow so it runs automatically. Each increment makes the next change a little safer and the next debate a little more grounded. The perfect evaluation suite is the enemy of the useful one; start with the useful one and let it earn its growth.

The bottom line

Evaluation is the discipline that turns building with language models from guesswork into engineering. Everything else in the stack, the prompts, the context, the agents, the loops, depends on being able to tell whether a change made things better or worse, and that is precisely what evals provide. Without them you are optimizing in the dark, shipping on vibes, and accumulating regressions you cannot see. With them you can move quickly and confidently, settle questions with data, adopt new models on evidence, and improve relentlessly without sliding backward. Build the dataset from real, hard cases. Score with code where you can, a validated judge where you must, and humans where it counts. Track complementary metrics, gate on the failures that are unacceptable, and feed reality back in. It is the least glamorous work in the field and the most decisive, because in the end the only question that matters is whether your system is actually getting better, and evaluation is the only thing that can answer it.

One last reframing to carry away: evaluation is not a gate you pass through once on the way to shipping, it is the lens through which you see your own system clearly. Without it, you are guessing about the thing that matters most, whether your work is actually helping, and guessing is a luxury that erodes quietly into regression. With it, every decision becomes evidence-based, every change becomes reversible in judgment if not in code, and the whole team shares a single honest picture of where quality stands. That clarity is the real product of an evaluation practice, and it is worth far more than any individual score it ever produces.