Claude for Developers

Lesson 21 of 14

Evaluating what you build

Here is the uncomfortable truth about LLM development: without measurement, you cannot tell an improvement from a regression. You change a prompt, the three examples you try look better, you ship — and quietly break two behaviours you didn't try. Every mature Claude team converges on the same discipline, and it is smaller than you fear: a set of real test cases, a grader, and the habit of running them before every change. This lesson is that discipline, minus the ceremony.

Start with twenty real cases

An evaluation set is inputs plus expectations, drawn from reality — actual tickets, actual documents, actual queries, including the ugly ones. Twenty cases beat zero by an enormous margin, and the set grows by the most valuable mechanism in this whole lesson: every production failure becomes a test case. The bug a user hit last Tuesday joins the suite, and no future prompt change can reintroduce it silently. That loop — fail, capture, never again — is regression testing, ported to model behaviour.

Store them as data, not code — a JSONL file with input, expected, and a note for why the case exists, so future-you knows what invariant each case guards.

Three graders, in order of preference

  • Exact checks — for classification, extraction, routing: compare output to the expected label or fields. Structured outputs make this trivial, which is an underrated argument for schemas everywhere: structured output is testable output.
  • Code checks — for constrained generation: does it parse, does the SQL run, do the tests pass, is every claimed citation actually present? Cheap, deterministic, and surprisingly comprehensive.
  • LLM-as-judge — for open-ended quality, where no string comparison works: a second Claude call grades each output against a rubric you write. This is the workhorse for summaries, support replies, and explanations — powerful, but it has failure modes you must design around.

A judge prompt that works is specific and decomposed — not "rate quality 1–10" (scores cluster and drift) but per-criterion pass/fail with a required justification:

text
Grade this support reply against each criterion. For each: PASS or FAIL plus one sentence of evidence.
1. Correctly identifies the customer's actual problem.
2. Every factual claim is supported by the provided documentation.
3. States the fix before the explanation.
4. No promises of refunds or timelines.
Return JSON: {"criteria": [{"id", "verdict", "evidence"}], "overall": "PASS"|"FAIL"}

Two judge pitfalls worth naming. Judges are lenient to themselves and swayed by fluency — so calibrate the judge once against a handful of human-graded outputs, and fix the rubric until they agree. And when the judge both finds and filters issues, recall silently drops; the sturdier pattern splits the roles — one pass reports everything with severity attached, a second pass (or a human) filters.

Evaluating agents, not just answers

Once you build the agents from the later lessons, add two evaluation lenses. Outcome checks stay primary — did the tests pass, was the PR mergeable, did the extracted data reconcile — because an agent is judged by its artifact. But trajectory checks catch what outcomes hide: how many turns and tokens the run took, whether tools were called when they should have been, whether the agent claimed successes its tool results don't support. And measure consistency, not single runs — an agent that succeeds four times in five has a 20% failure rate, which is a fact you want from your eval suite rather than from production. The same JSONL-plus-grader machinery covers all of it; the cases are just bigger.

Make it a gate, then measure the change

An evaluation set that runs ad hoc is a good intention; one that runs in CI is an engineering control. The shape is a normal test job: run the suite against the changed prompt or model, compare pass rates to the baseline, block the merge on regression. This transforms three conversations that are otherwise vibes into evidence: prompt changes ("did trimming the system prompt hurt anything?"), model migrations ("what actually breaks on the new model?" — run the suite, read the diff, fix, then switch), and cost work ("can this route really downshift from Opus to Sonnet?" — the question from the models lesson, now answerable in minutes).

Keep score on more than correctness while you're there: tokens and latency per case ride along for free in usage, so the suite doubles as your cost-regression alarm.

What to take into the next lesson

Twenty real cases in a file, the cheapest grader that works, failures captured as permanent tests, trajectory and consistency lenses for agents, the suite wired into CI as a gate. Evaluation is the enabling discipline for everything else this course promised — model downshifts, prompt iteration, safe migrations, earned autonomy — because it converts "we think it's fine" into "we checked." Two lessons remain on the production side: assembling the operational playbook, and securing all of it.

← Previous