Skip to content

Evaluation Engineering Across Both Quadrants

Before you start

Prerequisite: Lesson 8, "Hardening the Stochastic Quadrant" — the security and cost disciplines that keep a system from being exploited or bankrupting its own team. After this lesson, you can: build a ten-test starting eval suite for either quadrant, name the five ways an LLM-as-judge setup fails and the fixes for each, distinguish offline, online, and regression eval loops, and explain why routing tasks across model tiers is an architectural decision rather than a benchmark contest.

Sarah's Layer C drafted a reply last week that was factually correct, well-written, and recommended a competitor's product by name. Nothing crashed. No error fired. The system did exactly what it was asked to do: draft a helpful reply. It just wasn't the reply anyone wanted, and nothing in Sarah's test suite caught it, because Layer A style tests ("did the right slot get filled") don't apply to freeform text, and Layer C had no test at all for "does this draft mention a competitor."

That gap is what this lesson is about. Lesson 8 hardened Sarah's system against being attacked and against quietly burning through budget. Neither discipline answers a more basic question: is the system doing its job? For a deterministic program, that's yes-or-no: the test passes or it doesn't. For a probabilistic system, "did it work?" stops being a yes/no question and becomes a distribution. Most of it will work most of the time. The engineering problem is knowing which part, how often, and finding out before a customer does.

That's evaluation engineering: the one craft that spans every quadrant in this course, not just the stochastic one. This course's own view is that the most distinctive skill an agent engineer has isn't prompt-writing. It's building the measurement systems that tell you whether the non-deterministic core of a system is behaving, before the bill, an incident, or the customer complaint tells you for you.

What "eval" means, layer by layer

Each of Sarah's four layers needs a different eval method, because each one fails in a different shape:

  • Layer A (CALM chat): conversation-level replay tests, slot assertions, flow completion rate per intent.
  • Layer B (extraction pipeline): schema validation rate, field-level precision and recall against a labeled set.
  • Layer C (research agent): LLM-as-judge on a held-out set, with regression suites of seed prompts and known-good outputs.
  • Layer D (Sarah in Cursor): Sarah's own judgment, informed by what the eval results from A, B, and C are telling her.

Notice the shape of that list: it gets less structured moving from A to D, the same order the trifecta risk got worse in lesson 8. That's not a coincidence. The less deterministic a layer is, the more its evaluation has to lean on judgment rather than exact-match assertions, and the more disciplined that judgment needs to be to stay honest.

A concrete starting point

"Build eval suites" is useless advice without a template, so here's the actual starting point: write ten representative inputs, write the correct output for each, run them on every deploy, and fail the deploy if any of them regress. That's it. Everything past that is refinement.

yaml
tests:
  - name: "enterprise_blocking_issue_pages_oncall"
    user_messages:
      - "my production is down and I'm losing money"
    slot_assertions:
      issue_category: "technical"
      urgency: "blocking"
      account_tier: "enterprise"
    flow_assertions:
      - action_page_oncall was called
      - utter_confirm_routing contained "on-call engineer"

  - name: "billing_question_non_blocking_routes_to_queue"
    user_messages:
      - "I think my invoice is wrong, no rush"
    slot_assertions:
      issue_category: "billing"
      urgency: "non_blocking"
    flow_assertions:
      - action_route_to_queue was called
  # ... 8 more

Ten tests like these give CI something concrete to check on every deploy: does an urgent enterprise outage still page on-call, does a low-priority billing question still route to the queue instead. Small, specific, and cheap to run.

Run these on every deploy. Not sometimes: every deploy. The eval suite is the only thing standing between a routine model update and a silent regression nobody notices until a customer does.

LLM-as-judge: the trap and the escape

Layer A's assertions check exact values: a slot, a called action. Layer C's output is free-form text: a draft reply, a summary, an explanation. You can't check that for equality against a known-good string, so the standard move is LLM-as-judge: ask a second model whether the output meets a set of criteria, and use its verdict as the test result.

The trap is that judges carry their own biases. They favor longer outputs over correct ones (verbosity bias). They favor outputs from their own model family (a GPT judge tends to prefer GPT-written text). They favor confident-sounding text over accurate text. And judge verdicts are themselves non-deterministic. The same output, scored against the same criteria, can get a different verdict on a different run.

Pin the judge model and version

Never run against "latest." A judge model change is a test-suite change, whether or not anyone intended it to be one.

Use rubrics, not yes/no

"Rate groundedness 1 to 5 against this rubric" produces more reliable, more reviewable verdicts than "is this grounded?"

Use a different judge family than the generator

If the system under test wrote its output with one model family, judge it with another. Cross-family judging cuts the self-preference bias measurably.

Calibrate against humans

Label 50 outputs yourself, then measure how often the judge agrees with you. This course's own working threshold: below 85% agreement, treat the judge as not yet reliable enough to trust for that task. Adjust the threshold up for higher-stakes tasks; it isn't a universal constant, just a reasonable starting bar.

Use multiple judges for high-stakes tests

Take a majority vote across judges rather than trusting a single verdict when the cost of a wrong pass is high.

The most valuable test in any suite is still the one where a human labeled the ground truth. Judge-based tests are a scaling mechanism for extending that human judgment across volume, not a substitute for having made it in the first place.

Three eval loops, not one

Offline, online, and regression eval answer different questions, and conflating them is how teams end up with a false sense of coverage.

Offline eval runs a fixed test set on every deploy: deterministic inputs, known-good outputs, a pass/fail verdict. It's the gatekeeper between a dev branch and main. For Sarah, that's the ten representative tickets per layer, run in CI.

Online eval scores a sample of real production traffic in the background, with no customer impact, to catch drift: are outputs getting worse on tickets that look like X. For Sarah, every hundredth ticket gets its Layer C draft scored by an LLM judge against the rubric, with an alert if the average score drops more than 10%.

Regression eval turns every production incident into a permanent test case. When something goes wrong, the failing input joins a regression set that runs on every deploy forever. This is how a suite earns its keep over time rather than staying frozen at day-one coverage. For Sarah, the first time Layer C drafts a reply recommending a competitor's product, that exact ticket goes into the regression set with the assertion that output must never mention a competitor again. Every deploy checks it, permanently.

Most teams build offline eval and call the job done. The teams that don't get burned are the ones running all three, with a standing discipline of adding to the regression set after every incident rather than treating the incident as a one-off.

Three eval loops, each answering a different question

Model selection as an architectural decision

A common anti-pattern once a team has working evals: pick one frontier model and run it for every task. It's expensive, slower than it needs to be, and above a certain volume stops being commercially viable at all.

Mature teams route tasks to model tiers instead of routing everything to the biggest model available:

Task typeModel tierWhy
Planner / reasoner (Layer C orchestration)FrontierLong-horizon coherence matters; cost is tolerable at low volume
Worker / executor (individual tool calls)Mid-tierFast, cheap, reliable for bounded tasks
Classifier / router (Layer A intent detection)SmallSub-second latency, cheap, fine-tunable on your own data
Extractor (Layer B nightly pipeline)Small, fine-tunedStructured output, fixed schema, high volume
Judge (eval loops)Mid-tier, different family from the generatorCross-family judging reduces the bias covered above
Guardrail (input/output safety)SpecializedPurpose-built, fast, cheap

The economics are the reason this is worth doing rather than a nice-to-have: in this course's own worked example, routing Sarah's triage system across six model tiers instead of running one frontier model everywhere cuts her monthly bill by 60 to 80 percent without reducing quality on any single task, because each task runs on a model sized for what it actually needs. Treat that range as a directional estimate from this specific worked system, not a guarantee for yours — the real number depends on your own task mix and current model choice.

Model selection, seen this way, is not a benchmark-chasing exercise. It's an architectural decision made per layer, measured per task, and revisited every quarter as new models release, which is a very different activity from picking "the best model" once and leaving it wired into everything.

Quick check — A colleague says building an eval suite for a new agent is too abstract to start on without a dedicated ML background. What's the concrete counter to that, from this lesson?

Hardening keeps a system from being exploited. Evaluation tells you whether it's doing its job. Neither one, on its own, answers who in the organization is accountable for either, which is where the next lesson turns.

Continue to Lesson 10

The organizational axis: who owns a system built this way, and how that ownership question changes across the four quadrants.

Have a question about this lesson?

Reply here and it goes straight to Rod. Same as replying to one of his emails.