Human-in-the-Loop Spot Checks
Introduction
You've built a judge, written its rubric (L168 (Writing Judge Prompts & Rubrics)), and measured and calibrated away its biases (L169 (Judge Biases & How to Calibrate)). It agrees with your humans ~85% of the time. So you're done — fire the humans, automate everything? No. This final lesson of the section is the discipline that keeps the whole thing honest: humans stay in the loop.
The reason is simple and permanent: a judge is calibrated, not ground truth. It drifts the moment your rubric, model, or traffic changes; it meets cases nobody anticipated; and it's overconfident, reporting more certainty than it earns. Humans remain the anchor. But you also can't put a human on every output at production scale — so the real skill isn't “review or automate,” it's spending a limited human budget where it catches the most errors. This lesson is that skill: which samples to send to people, how much and how often, and how to turn every human correction into a better judge.

The Judge Is Calibrated, Not Ground Truth
It's tempting to treat a calibrated judge as done — a κ of 0.7 against humans feels like permission to walk away. It isn't, for three reasons you already met:
- It drifts. Calibration is a snapshot. A new model version, a one-line rubric tweak, or a shift in what users ask can quietly move the judge's behavior — and yesterday's agreement number no longer holds (L165 (Statistical Rigor: Sample Size & Confidence) — that number was a noisy estimate to begin with).
- It meets the unanticipated. Your rubric was written against the cases you'd seen. Production serves cases you haven't — the long tail where “good” is genuinely unclear and the judge is just guessing confidently.
- It's overconfident. As L169 (Judge Biases & How to Calibrate) showed, judges report higher certainty than their accuracy supports — so a lone confident verdict is not self-validating.
Humans are the ground-truth anchor that catches all three: the periodic check that says “the judge is still right,” and the source of new labels when it isn't. The question is never whether to keep humans — it's how to use a few of them well.
Three Modes: In-the-Loop, On-the-Loop, Automated
There are three ways a human can relate to an evaluation, and mature systems use all three at once, layered by risk:
- Human-in-the-loop — a person is in the decision path, before action. Used for high-stakes or irreversible outputs (a medical summary, a legal answer, a large refund): the AI proposes, a human approves or corrects.
- Human-on-the-loop — a person monitors and audits a sample, ready to step in. This is the spot check: most traffic flows through automatically, and humans watch a slice to keep it honest.
- Fully automated — the judge decides, no human in the moment.
The practical architecture is a layered oversight stack, cheapest first: deterministic checks on every request (format, schema — L160 (Functional Correctness & Exact Match)) → an LLM judge for scalable scoring (L166 (The Idea: Models Grading Models)) handling 80–90% → human review of the flagged, uncertain, and high-risk cases → expert adjudication for high-stakes calls and ties. Each tier is more expensive and rarer than the one below it. Your job is to make sure the cases that need a human actually reach one — and the rest don't waste anybody's time.
What to Review: Don't Sample Randomly
Here's the mistake almost everyone makes first: reviewing a random sample. Random tells you an aggregate quality number, which is useful — but it spends most of your scarce human attention on easy cases the judge already got right. The errors hide in the corners, and random rarely visits the corners.
The high-leverage move is targeted sampling — surface the uncertain, risky, novel, and high-impact cases:
- Uncertainty sampling — review where the judge's confidence is lowest (near its decision boundary). These are, by definition, the cases the judge is most likely to be wrong about; uncertainty quantification finds a disproportionate share of errors per review.
- Disagreement sampling — review where a diverse panel of judges split (L169). Disagreement is the signal that a case is hard.
- Priority / stratified sampling — by segment, by low score, by user-reported issue, by stakes. Make sure every important slice gets eyes.
- A small random baseline — keep a little pure-random review too, to catch blind spots your proxies don't flag (like the confidently-wrong case).
The combination — uncertainty + disagreement + high-stakes, plus a random trickle — catches most of the errors with a fraction of the reviews. That's the whole game: point the humans at the judge's blind spots, not at random.
See It: Spend Your Human Eyes
Here's a stream of 24 judge-scored outputs that hides 6 errors you can't see — you only get the observable signals: the judge's confidence, whether a panel disagreed, and whether it's high-stakes. Pick a sampling strategy and a review budget, then reveal how many of the 6 errors your humans actually caught.

Slide the budget and switch strategies with reveal on. At a quarter of the stream reviewed, uncertainty and disagreement sampling catch ~5 of 6 errors; random catches about 1. Notice the one sneaky error the proxies miss — the confidently-wrong, low-stakes case — which is exactly why you keep a small random trickle on top of the targeted sampling. Same human budget, wildly different bug-catching power, decided entirely by where you point it.
How Much, How Often, and Catching Drift
Targeting solves which cases; you still need a budget and a cadence. The working defaults:
- A small, continuous slice — e.g. a few percent of traffic reviewed every week, not a one-time audit at launch. Quality erodes silently; continuous review is how you notice.
- Always review the flagged + high-stakes — anything low-confidence, panel-split, user-reported, or irreversible gets a human regardless of the random budget.
- QA-sample the auto-approved — review a slice of what the judge passed (not just what it flagged), to catch systematic errors the judge is blind to.
The number that ties it together is judge↔human agreement, tracked over time. It's your drift alarm: when it slips below ~80%, the judge — not the humans — needs rework. The routing in code is just the triage rule:
# You can't review everything, so route the human budget to where the judge is weakest:
# low confidence, judges disagree, or high stakes. (Uncertainty + disagreement sampling.)
def route(item, panel_labels, conf_threshold=0.85):
agree = len(set(panel_labels)) == 1 # do the diverse judges agree? (L169)
confident = item["judge_confidence"] >= conf_threshold
high_stakes = item["stakes"] == "high" # refund · medical · safety · legal
if high_stakes or not agree or not confident:
return "human" # uncertain / disagreed / risky -> a person looks
return "auto" # easy + agreed + confident -> trust the judge
# Uncertainty sampling finds a DISPROPORTIONATE share of the errors per review — far more
# than random. Still review a small RANDOM % too, to catch blind spots the proxies miss.That route() is uncertainty + disagreement + stakes sampling in five lines: trust the judge on the easy, agreed, confident cases, and send everything risky to a person. Tune conf_threshold and your random rate to hit the human budget you can actually staff — and watch the agreement number to know when the threshold needs to move.
Close the Loop: Corrections Are Signal
The reviews aren't the point — the corrections are. Every time a human overrides the judge, you've been handed a labeled hard case, and it should feed three places at once:
# A human correction isn't just a fix — it's signal. Each one feeds three places, and a
# running judge↔human agreement number tells you when the judge has drifted.
def review(item, human_label, store):
matched = (human_label == item["judge_label"])
store["agreement"].append(matched)
if not matched: # a disagreement = gold
store["eval_set"].append({**item, "label": human_label}) # 1) grow the eval set (L158)
store["to_triage"].append(item) # 2) read these -> fix the
# rubric (L168) / recalibrate (L169)
rate = sum(store["agreement"][-200:]) / len(store["agreement"][-200:]) # 3) track over time
if rate < 0.80: # the drift alarm
alert(f"judge↔human agreement {rate:.0%} < 80% — recalibrate before you trust it")
# production -> human spot-checks -> dataset -> a better judge & rubric. The loop compounds.Each disagreement (1) grows your eval set with a real, gold-labeled case (L158 (Building Your First Eval Set)), (2) goes into a pile you read to refine the rubric (L168) or recalibrate the judge (L169), and (3) updates the agreement number that triggers the drift alarm. That's the flywheel: production → human spot-checks → a better dataset → a better judge → back to production, compounding with every cycle (and it's the through-line to L183 (Closing the Loop: Production → Dataset)).
Two notes on the humans themselves. Annotation quality is its own discipline — clear guidelines, calibration sessions where reviewers grade shared examples and argue out disagreements, inter-rater agreement > 0.80, and a senior adjudicator for ties and high-stakes calls (your Tier-3). And the meta-lesson that opens the next section: the single most valuable thing you do here isn't computing a score — it's looking at your data (L171 (Look at Your Data (The #1 Rule))). Spot-checking is how the looking gets built into the system.
🧪 Try It Yourself
Stand up the smallest real spot-check loop on something you ship — an afternoon, and it pays for itself the first week:
- Route by uncertainty. Take a batch of judge-scored outputs. Sort by the judge's confidence (or, if you run a 2-judge panel, pull the disagreements). Hand-review the bottom 10–20% — the least-confident — instead of a random 10–20%.
- Add the non-negotiables. Also review every high-stakes output (refunds, anything user-facing-irreversible), no matter its score.
- Log the corrections. For each one you override, write down the corrected label and one line of why. That why is a rubric fix waiting to happen.
- Track the number. Compute judge↔human agreement on what you reviewed. Set a threshold (say 80%); if you dip under it after a change, recalibrate before trusting the judge again.
Do this for two weeks and you'll have three things you didn't before: a growing gold eval set, a list of rubric fixes, and an early-warning number for when your judge goes off the rails.
Mental-Model Corrections
- “A calibrated judge means I can drop the humans.” Calibration is a snapshot that drifts; the judge is overconfident and meets novel cases. Humans stay as the ground-truth anchor — just a strategic few.
- “Review a random sample.” Random spends your budget on easy cases. Target uncertainty, disagreement, and high-stakes to catch a disproportionate share of errors — plus a small random trickle for blind spots.
- “Spot-checking is just QA overhead.” Each correction is signal: a gold eval case (L158), a rubric fix (L168), and a data point for the drift alarm. It's how the judge gets better.
- “Check it once at launch.” Quality erodes silently. Review a continuous slice and track agreement over time — < 80% is your cue to recalibrate.
- “One reviewer is fine.” Use guidelines, calibration sessions, inter-rater agreement (> 0.80), and an adjudicator — humans disagree too, and an uncalibrated human process is no anchor at all.
- “In-the-loop vs automated is a binary.” It's a layered stack: deterministic → judge → human-on-the-loop spot checks → human-in-the-loop on high-stakes. Match the tier to the risk.
Key Takeaways
- A judge is calibrated, not ground truth — it drifts, meets novel cases, and is overconfident. Keep humans as the anchor, but you can't review everything, so spend a few humans well.
- Three modes, layered by risk: deterministic checks → LLM judge (80–90%) → human-on-the-loop spot checks of the flagged/uncertain → human-in-the-loop on high-stakes, with expert adjudication for ties.
- Don't sample randomly. Target uncertainty (lowest judge confidence), disagreement (panel split — L169), and high-stakes, plus a small random baseline — it catches a disproportionate share of errors per review (~5/6 vs ~1/6 at the same budget).
- Set a budget + cadence: a continuous few-percent slice, always-review the flagged + high-stakes, QA-sample the auto-approved, and track judge↔human agreement — < 80% is the drift alarm.
- Close the loop: every human correction grows the eval set (L158), refines the rubric (L168) / recalibrates the judge (L169), and feeds the agreement number — the flywheel from production → review → dataset → better judge (L183 (Closing the Loop: Production → Dataset)).
- The through-line: the highest-value act in evaluation is looking at your data — and spot-checking is how you build that looking into the system (L171 (Look at Your Data (The #1 Rule))).