Chapter 3 of 8
Code-based graders
Not every grader needs a model. When there is one right answer, or a hard rule the output must obey, the best grader is plain deterministic code: fast, free, and never flaky. Two kinds do most of the work. An exact-match grader checks the output against the expected answer, ideal for classification, extraction, and anything with a canonical result. A constraint grader checks a format rule regardless of content: is the label uppercase and in the allowed set, does the JSON parse, is the number in range. In this lab you run a real sentiment classifier across the golden set, score it with an exact-match grader, and separately check the format constraint. The exact-match grader catches the one case the classifier gets wrong and scores four of five, which is exactly the honest signal a code grader is supposed to give.
The lab: read it, then run it
#!/usr/bin/env python3
"""
LAB EV3: Code-based graders.
The cheapest, most reliable grader is plain deterministic code. When there is one
right answer, or a hard format rule, you do not need a model to judge it: you need
an EXACT-MATCH grader and a CONSTRAINT grader. In this lab you run a real system
under test (a few-shot sentiment classifier) across a golden set, score it with an
exact-match grader, and separately check a format constraint (label must be an
uppercase member of the allowed set). The exact-match grader catches the one case
the classifier gets wrong, scoring 4 of 5, exactly as a code grader should.
Run: python3 modules/academy-content/labs/evals/ev3-code-graders.py
"""
import sys, os
_cands = [os.path.join(os.path.dirname(__file__), "..") if "__file__" in globals() else None,
os.path.join(os.getcwd(), "..", "labs"), os.path.join(os.getcwd(), "labs")]
for _c in _cands:
if _c and os.path.exists(os.path.join(_c, "academy_llm.py")):
sys.path.insert(0, os.path.abspath(_c)); break
from academy_llm import complete, chat, embed, cosine
LABELS = {"POSITIVE", "NEGATIVE", "NEUTRAL"}
# Golden set: five (review, gold label) cases. The negation case is deliberately
# hard, the kind of case a real classifier trips on.
GOLDEN = [
("I love this", "POSITIVE"),
("this is terrible and broken", "NEGATIVE"),
("the worst awful product", "NEGATIVE"),
("great and nice work", "POSITIVE"),
("not good at all", "NEGATIVE"), # hard: negation flips meaning
]
# The system under test: a few-shot sentiment classifier built on the mock LLM.
def system_under_test(review):
prompt = ("Classify the sentiment of this review.\n"
"love -> POSITIVE\n"
"hate -> NEGATIVE\n"
f"Input: {review}\nOutput:")
return complete(prompt)
# GRADER 1, exact match: is the output exactly the gold label? Deterministic, no model.
def exact_match_grader(output, gold):
return output == gold
# GRADER 2, constraint: is the output a valid uppercase label at all? Format check.
def constraint_grader(output):
return output in LABELS
correct = 0
format_ok = 0
print("STEP 1: run the classifier and grade each case with code")
for review, gold in GOLDEN:
out = system_under_test(review)
hit = exact_match_grader(out, gold)
fmt = constraint_grader(out)
correct += 1 if hit else 0
format_ok += 1 if fmt else 0
print(f" {out:8} gold={gold:8} match={str(hit):5} format_ok={fmt} <- {review!r}")
total = len(GOLDEN)
print("")
print("STEP 2: aggregate the two code graders")
print(f" exact-match score : {correct}/{total}")
print(f" format valid : {format_ok}/{total}")
# The exact-match grader must score 4/5: four correct, one negation case missed.
ok = (correct == 4) and (total == 5) and (format_ok == total)
print("")
print(f"EXACT-MATCH GRADER SCORED {correct}/{total} CORRECTLY: {'YES' if ok else 'NO'}")
if not ok:
sys.exit(1)
print("Deterministic graders are cheap and exact. Next: judging subjective output with a model.")
Runnable lab
ev3-code-graders.pyScore a classifier with an exact-match grader and a constraint grader, and prove it scores 4/5.
Proves: EXACT-MATCH GRADER SCORED 4/5 CORRECTLY
Runs in your browser via Pyodide. First run loads the runtime once; no install, no server.
The exact-match grader scored four of five and pointed straight at the miss: the negation case, where the classifier saw the word good and called it positive. That is a code grader doing its job, an exact number with no opinion involved. The constraint grader confirmed all five outputs were valid uppercase labels, a separate axis from correctness. Know the limit, though. Code graders only work where a right answer or a rule is well defined. The moment quality is subjective, tone, helpfulness, whether an answer is grounded, you need a different tool. That is the next chapter.
Check your understanding
1. When is a code-based grader the right choice?
2. What is the difference between the exact-match and constraint graders?
3. What is the limit of code-based graders?