Eval-Driven Development — You Can't Ship What You Can't Measure

The single practice that separates teams who improve their LLM apps from teams who just change them is evaluation. Without a trustworthy way to measure quality, every prompt tweak is a gamble — you fix one case, break two others, and never know. Eval-driven development makes the eval set the center of gravity: you build it before you optimize, you gate every change on it, and you treat it as the most valuable asset the project owns. This post is about building evaluation you can actually trust.

Post 2 made offline evaluation the gate between develop and deploy. This post is how to build that gate. The hard truth underneath it: LLM output quality is fuzzy and non-deterministic (post 1), so “it looks good to me” doesn’t scale and doesn’t survive. Eval-driven development replaces vibes with a repeatable, graded measurement that tells you whether a change is actually an improvement.

The eval set is the asset

The foundation of everything is a curated evaluation set: a collection of representative inputs paired with what good output looks like. This is the ground truth your whole loop runs on, and building a good one is the highest-leverage work in LLMOps: - Representative — it should cover the real distribution of inputs: the common cases, the important edge cases, and crucially the failure cases you’ve already hit in production (post 2’s backward flow). An eval set that only has easy cases tells you nothing. - Graded by difficulty and importance — some cases are “must never get wrong” (safety, core use case); others are nice-to-have. Knowing which is which keeps you from trading a critical regression for a cosmetic win. - Living — every real-world failure becomes a new eval case, so the set grows to encode everything the system has ever gotten wrong. This is what makes the loop have memory: a bug fixed and added to evals can’t silently return.

A team’s eval set is more valuable than any individual prompt, because prompts are cheap to change and the eval set is what tells you which change is better. Guard it, grow it, and version it like the asset it is.

How to evaluate open-ended output

The awkward part: how do you score an open-ended answer when there’s no single right string? There’s a toolbox, and mature teams layer several:

The practical pattern is a pyramid: cheap deterministic checks on everything, reference/judge metrics for quality, human review for calibration and high stakes. No single method is enough — rules miss nuance, judges have biases, humans don’t scale — so you combine them.

Making it drive development

Having evals is necessary; using them as the driver is the discipline: - Gate changes on the eval set. Every prompt, model, or config change runs against the evals before it ships, and a change that regresses the must-pass cases doesn’t merge. This is the mechanism that lets you iterate quickly without fear — you can try an aggressive prompt rewrite because the eval set will catch what it breaks. - Track scores over time, per version. Tie eval results to the prompt configuration version (post 3) so you can see quality trending up or down across releases and attribute changes to specific versions. - Compare, don’t just score. The useful question is rarely “is this good?” but “is version B better than version A?” Run both against the same set and compare — relative comparison is more reliable than absolute scores and is exactly what you need to decide whether to ship. - Beware overfitting to the eval set. If you only ever optimize against the same frozen set, you can tune to it while real quality stalls — the same trap as overfitting in ML. Keep growing the set with fresh production cases so it stays an honest proxy for reality.

The mindset shift is to treat quality as something you measure and move, not something you hope for. Teams that evaluate can answer “did this change help?” with evidence; teams that don’t are editing a non-deterministic system in the dark, and it shows up as the mysterious quality drift that plagues unmeasured LLM apps.

The takeaway: evaluation is the practice that separates improving an LLM app from merely changing it, because quality is fuzzy and non-deterministic and “looks good to me” doesn’t scale. The center of gravity is a curated eval set — representative (including real production failures), graded by importance, and living — which is more valuable than any prompt because it tells you which change is better and gives the loop memory. Score open-ended output with a layered toolbox: cheap deterministic checks wherever correctness can be exact, reference-based metrics, LLM-as-judge (calibrated against humans, watched for bias), and human review spent on calibration and high stakes. Then drive development with it: gate every change on the evals, track scores per version, compare B vs A rather than scoring in the abstract, and keep growing the set to avoid overfitting.

Key takeaways

Further reading

Sources & References