Evaluating outputs
A model's answers vary, so a changed prompt cannot be judged by trying it once. Keep an evaluation set: inputs with what a good answer must contain. Score every case, report the pass rate, and compare prompt versions on the same set.
Scorers range from strict to loose. Exact match suits labels such as positive or negative, after trimming and lower-casing. Free text is scored by required words or by a second model as a judge. A crash is a failed case, not a reason to stop the run.
cases = [("I love it", "positive"),
("Awful", "negative")]
model = lambda text: "positive"
passed = sum(model(t) == want
for t, want in cases)
print(passed, "of", len(cases))Read the failures, not just the rate: they show which kind of input the prompt still gets wrong.
Your task
Write exact(output, expected) comparing after strip() and lower(), and contains_all(output, words), true when every word appears in the output ignoring case. Write evaluate(model, cases, scorer) for (input, expected) pairs, returning {"passed", "total", "rate", "failures"} (rate 0.0 when empty, failures the failed inputs, a raising model fails the case). Write compare(model_a, model_b, cases, scorer) returning "a", "b" or "tie" by passed count.
The explanation opens here once every check passes.