Why vibes fail: the case for evaluation
Why trying a few prompts by hand misleads you, with a worked example of fixing one case and silently breaking others, the shape of an evaluation pipeline that replaces vibes, offline versus online evaluation and a first-week plan.
You changed the prompt, switched to a smaller quantization or upgraded the model. Is the system better or worse? If your answer is "seems fine", you are running on vibes. Vibes are how most LLM projects start, and why so many get worse in ways nobody notices until users complain.
#A story in numbers
A team has a support assistant. A customer reports a wrong refund answer, so they tweak the prompt, retry that one question, and it is now correct. They ship it.
What they did not see:
| Category | Before | After |
|---|---|---|
| Refund questions (20 cases) | 14 correct | 17 correct (+3) |
| Shipping questions (20 cases) | 18 correct | 15 correct (โ3) |
| Account questions (20 cases) | 17 correct | 15 correct (โ2) |
| Overall | 49 of 60 | 47 of 60 |
The change fixed the case they looked at and three more, and quietly broke five others. The overall system is slightly worse, and they will learn it from support tickets in two weeks. A 60-case test set that takes a minute to run would have shown the drop immediately. This kind of trade-off is the rule, not the exception: prompts, models and quantizations all shift behaviour across the board.
#Why vibes fail
- Tiny samples. Five examples cannot distinguish a real change from luck. One flipped result moves the score by 20 points.
- Cherry-picking. You test the cases you remember, usually the easy or the recently failed ones.
- Recency bias. The last bad answer dominates your impression, and the last good one makes you feel finished.
- Non-determinism. Sampling makes the same prompt succeed and fail on different runs, so a single try proves little.
- Hidden regressions. Fixing one case quietly breaks others you did not re-check.
- Confirmation bias. You want the change to work, so you read ambiguous outputs charitably.
- Nobody else can reproduce it. Opinions do not transfer between teammates, and they do not survive staff turnover.
- Drift. Hosted models, data and user behaviour change underneath you with no deploy at all.
None of this means you are careless. It means that outputs from a statistical system need statistics.
#Five prompts is not evidence
Suppose version A truly succeeds on 70 percent of your real traffic and version B on 60 percent, so B is really worse. You try each on five random prompts. The chance that B scores at least as well as A is about 50 percent: a coin flip. And if A truly were better by 10 points, five prompts would usually fail to show it. To distinguish a 10-point difference you need on the order of a hundred or more examples, or paired comparisons (metrics and statistics).
Dataset
inputs + expected
Run
prompt + model
Score
rules or judge
Report
score ยฑ error
Gate
vs baseline
Pass rate 75% (3 of 4) ยท tiny n, so wide error bars!
1. Dataset
Representative inputs with expected answers or grading criteria, tagged by category. This is the asset that makes everything else possible.
Start with 50 to 100 cases and a 100-line script. Everything else in this course makes this loop more trustworthy.
#The pipeline that replaces vibes
- Dataset: representative inputs, with expected answers or grading criteria (golden datasets).
- Run: your whole system (prompt + model + retrieval + tools + settings) produces outputs.
- Score: metrics, rules or a judge turn outputs into numbers (metrics, LLM-as-judge).
- Report: aggregate scores with uncertainty, broken down by tag, and a list of failures to inspect.
- Gate: compare to a baseline and block changes that get worse (regression testing in CI).
A skeleton makes it concrete:
import json
def evaluate(system, path="golden.jsonl"):
cases = [json.loads(l) for l in open(path)]
results = []
for c in cases:
output = system(c["input"]) # your prompt + model + retrieval
results.append({"id": c["id"], "tags": c["tags"], "pass": score(c, output), "output": output})
rate = sum(r["pass"] for r in results) / len(results)
print(f"pass rate {rate:.1%} on {len(results)} cases")
for r in results:
if not r["pass"]:
print("FAIL", r["id"], r["output"][:100])
return resultsEverything in this course elaborates one of those lines.
#Offline and online evaluation
| Offline | Online | |
|---|---|---|
| Data | Fixed dataset | Real traffic |
| When | Before release, in CI | After release, continuously |
| Strength | Repeatable, cheap, safe | Reflects real users |
| Weakness | May not match reality | Slower, noisier, risk to users |
| Example | Golden set pass rate | Sampled judging, thumbs, A/B tests |
You need both. Offline catches regressions early; online finds what you did not think of and feeds new cases back into the offline set (online evaluation).
#Three kinds of question evals answer
- Is this version better than that one? (model, prompt, quantization comparisons, choosing a model)
- Is it good enough to ship? (a threshold such as "at least 90 percent of the golden set passes, and zero critical failures")
- Did anything get worse? (regression detection)
Notice that none of these needs a perfect metric. They need a consistent one.
#Eval-driven development
The loop that works:
write failing cases โ change prompt/model/retrieval โ run evals โ read failures โ repeat
โฒ โ
โโโโโโโโโโโโโ add every new real-world failure as a case โโโโโโโโโโโโโโโโThis is test-driven development adapted to statistical systems. You write down what "good" means before you tinker, you change one thing at a time, and you keep the cases that taught you something. Teams that work this way iterate faster, not slower, because they stop arguing about opinions and stop shipping regressions.
#Start small
You do not need a platform. A first useful evaluation is:
- 50 to 100 real or realistic examples in a JSONL file,
- a Python script that runs them and scores each pass or fail,
- a printed pass rate and a list of failures.
You will build exactly this in the lab. Everything else in this course makes that script more trustworthy and more useful.
#Objections you will hear
| Objection | Response |
|---|---|
| "Evals are slow." | A 100-case run against a local model takes minutes, and catches regressions that cost days |
| "Our task is subjective." | Subjective tasks are evaluated with rubrics and pairwise comparison; the numbers are less precise, not meaningless |
| "We do not have labelled data." | Start with 30 real inputs and your own judgement of what good looks like; label as you go |
| "The model is too variable." | Measure the variability (run twice, compare); it is information, not an excuse |
| "We tested it manually." | Write those manual tests down; that is a dataset |
| "Benchmarks already say it is good." | Public scores measure other tasks (benchmarks) |
#What to evaluate
Not just "accuracy". Typical dimensions: correctness, faithfulness to sources, format validity, safety, refusal behaviour, tone, latency and cost. Choose a few that matter for your product and measure each separately. A change that raises accuracy two points but doubles latency may be a loss.
#Your first week
| Day | Task |
|---|---|
| 1 | Collect 30 real inputs (anonymised) and write what a good output looks like for each |
| 2 | Turn them into a JSONL file with ids, tags and checkable criteria |
| 3 | Write the runner and scorer; get a baseline pass rate |
| 4 | Read all failures; fix labels that are wrong; add 20 more cases covering the gaps |
| 5 | Make one change to your prompt or model; compare; decide with the numbers |
By Friday you will have a number you can defend and a process you can repeat.
#Common mistakes
- Treating a handful of examples as evidence.
- Never writing the examples down.
- Changing several things at once, so you cannot tell what mattered.
- Measuring only the average, hiding a collapsed segment.
- Building an elaborate platform before a simple script.
- Evaluating once, then never again.
#Exercise
You compare two prompts on 10 hand-picked questions: prompt A gets 8 right, prompt B gets 9. Your colleague says "B is better, ship it".
- Why is that weak evidence?
- What would you do?
Answers:
- Ten hand-picked questions give very wide uncertainty: 8 of 10 and 9 of 10 are easily the same underlying rate, the difference is one question, and nothing shows whether B broke other cases.
- Build a golden set of at least 50 to 100 real questions, run both prompts on the whole set (temperature 0), compare pass rates with intervals and the paired list of cases that changed, and decide on that, also checking per-tag results.
Quick quiz
+10 XP per correct answer, +25 XP for a perfect score
1. Why is 'it worked on my 5 test prompts' weak evidence?
2. What is a golden dataset?
3. You fix a prompt so that 3 failing cases now pass, but 5 previously passing cases now fail. Without a test set you would see...
4. Which is the best description of offline evaluation?
5. A first useful evaluation needs roughly...