What is What an eval is?
What an eval is is an AI engineering fundamental for people who work with LLMs. Tests for systems that never answer the same way twice, from unit case to benchmark.
The back office team has an invoice extractor that works well. One day, someone notices the prompt says: extract the total amount. And they change it to: extract the total amount, with two decimal places.
It looks harmless. The deploy goes out on a Friday.
On Monday, finance complains. Invoices with a discount are coming in at the gross amount. A one sentence change altered how the model read the field. And nobody could have known beforehand, because the only test was opening three files and looking at them.
With regular code, you'd have a unit test. With a model, the same input can produce different answers, and correct isn't always an exact match. The test built for that world is called an eval. In this first lesson of the evals and reliability trail, you'll learn what one is made of, how to grade it, and how to read its numbers without fooling yourself.
An eval is a test for model output. It has three parts.
A set of cases. Inputs, each with the expected result.
A way to run the system on all of them.
And a grading rule, that turns each output into a score.
The cases come from real data, anonymized, with the expected answer labeled.
The whole system runs, with the same prompt, model and tools as production.
Each case produces an output, stored together with the prompt version.
Grading compares the output with the expected result.
Each case gets a score. Pass or fail, or a value from zero to one.
And the report shows the overall rate, the rate per category, and the difference from the previous version.
Friday's three files failed at step one, and at step six. Three examples by eye aren't a set. And looking isn't a grading rule. On Monday, the team discovered a kind of invoice, one with a discount, that wasn't among the three.
There are three ways to grade. Exact match. Code compares field by field, or checks that the output fits a schema. Use it when there's a right answer, like a classification, an extraction, or a database query. On the invoice extractor, the total is an exact match against the labeled number.
A rule in code. Small functions in your code check properties of the output. Has a citation, stays under a hundred words, never names a competitor. Use it when the text varies, but there are objective criteria.
And a model as judge. Another model scores the output, with a written rubric. Use it for open-ended quality. Tone, helpfulness.
The rule is to start with the simplest one that does the job. Exact match is cheap, fast, and never wrong. A judge costs money, and it needs evaluating too. It inherits the model's variation, and it can agree with the mistake.
Here's a case where that matters. A tone eval for emails used only a model as judge. And the judge approved emails that promised a discount the store doesn't offer. A bigger judge wouldn't fix it. It can still find the promise helpful. Add rules in code first. Don't invent a price, don't name a competitor. Then use the judge on what remains.
Here's one for you. The extractor gets forty-eight of fifty cases right. Both misses are discounted invoices, the only two of that kind in the set. The team celebrates ninety-six percent. What is that number hiding?
It's hiding the rate per category. On the kind of invoice finance fears most, the rate is zero for two. The overall number diluted exactly the case that breaks the accounting system.
And calling it noise doesn't help. It might be noise overall, and it's still a hundred percent failure on discounts. You need more of those cases, not a pat on the back. Fill that slice, fix it, and only then look at the overall number.
There are three sizes of eval. A unit case. A bug seen in production becomes a case. It's the equivalent of a regression test.
An eval dataset. From fifty to a few hundred cases covering your product's categories. It runs on every change.
And a public benchmark. Well known sets that measure models in general. They help you pick a candidate model. They don't tell you whether your system works. If product wants to swap models because a public benchmark rose two points, and your internal eval dropped one point, your eval wins. You don't ship a benchmark. You ship your classifier.
And here's the beginner trap. Treating the dataset as a dead list. The best cases are born in production. The invoice finance sent back. The ticket the classifier routed to the wrong team. Each incident becomes one more line in the file. Six months later, that file is worth more than the prompt. You can rewrite a prompt in an afternoon. A good dataset takes months to gather.
Because output varies, a single run can mislead. For important cases, run three to five times, and look at the pass rate, not one round's result.
A drop from ninety-two to ninety percent on fifty cases is a single case. It may be noise.
And fifty typical cases won't cover a rare category. If discounted invoices are five percent of volume, and you sampled twenty files from the top of the folder, that kind may never get in. Stratify. Include some of every category the business fears, instead of only what shows up first.
On the page there's an eval that runs in a few seconds. Five customer messages, each labeled billing, order or other.
The model classifies each one, and code counts how many match the label exactly.
Now change the prompt to: answer with the category and a short justification. Run it again, and all five fail, even though the category at the front of the sentence is right.
That's not the model getting worse. Your grading is coupled to the old format. The eval and the prompt are the same contract. If the output gains a reason, grading reads the category field, not the sentence. That's the point. An eval turns I think it got better into a number, and shows you right away what a change broke.
So what changes? No prompt, model or tool change ships without running the eval first.
Trying five questions by hand before a deploy isn't an eval. That's a smell called vibe check eval.
And the eval has to run on its own, in your pipeline, or with a single command. That pattern is called an eval harness.
One last case. Your pipeline runs eighty cases on every pull request. Someone also tried four more questions in a chat on Friday, and shipped. The pipeline passed. And finance still came back with a complaint. Where did it leak? In those four questions. If they were different from the eighty, they should have become cases before the merge. If they weren't, the chat added nothing but false confidence.
So here's the idea to take with you. An eval is how you stop guessing. Real cases with the right answer, the real system running on them, and a grade that doesn't depend on anyone's mood. Read it per category, run it on every change, and feed it with every incident.
In the next lesson, we'll look at what happens when a team doesn't have one: the untested prompt. See you there.
O que é um eval
What an eval is is an AI engineering fundamental for people who work with LLMs. Tests for systems that never answer the same way twice, from unit case to benchmark.
The back-office team has an invoice extractor that works well. Someone notices the prompt says “extract the total amount” and changes it to “extract the total amount, with two decimal places”. It looks harmless. The deploy goes out on a Friday.
On Monday, finance complains: discounted invoices are coming in at the gross amount. A one-sentence change altered how the model read the field, and nobody could have known beforehand, because the only test was opening three PDFs and looking at them.
With regular code you would have a unit test. With a model, the same input can produce different answers, and “correct” is not always an exact match. The test built for that world is called an eval.
An eval is a test for model output. It has three parts: a set of cases (inputs with the expected result), a way to run the system on all of them, and a grading rule that turns each output into a score.
flowchart LR
D[("1. Test cases")]:::store --> R["2. Run the system"]:::tool
R --> S(["3. Model output"]):::llm
S --> G{"4. Grade"}
G --> N["5. Score per case"]:::tool
N --> A(["6. Report and comparison"]):::io
Friday’s three PDFs failed item 1 and item 6. Three examples by eye are not a set, and “looking” is not a grading rule. On Monday the team discovered a kind of invoice (with a discount) that was not among the three.
| Type | How it works | Use it when |
|---|---|---|
| Exact match | Code compares field by field, or checks that the output fits a schema | The output has a right answer: classification, extraction, SQL |
| Rule in code | Functions check properties: has a citation, stays under 100 words, never names a competitor | The text varies, but there are objective criteria |
| LLM-as-Judge | Another model scores the output with a written rubric | Open-ended text quality, tone, helpfulness |
Always start with the leftmost type that does the job. Exact match is cheap, fast, and never wrong. A judge costs money and needs evaluating too.
On a Brazilian NF-e invoice extractor, valor_total is an exact match against the labeled number. “Is the collection email polite?” has no equality. Then you add rules (stays under N words, contains the due date) and, if that still is not enough, a judge with a rubric. Do not start with the judge: it inherits the model’s variation and can agree with the mistake.
A public benchmark score does not replace your cases. A model that shines at math can still miss the discount field on your invoice. The cases that matter are your product’s, with your schema, in your language.
The beginner trap is treating the dataset as a dead list. The best cases are born in production: the invoice finance sent back, the ticket the classifier routed to the wrong team. Each incident becomes a line in the file. Six months later, that file is worth more than the prompt.
Because output varies, a single run can mislead. For important cases, run 3 to 5 times and look at the pass rate, not one round’s result. A drop from 92% to 90% on 50 cases is a single case, and it may be noise.
Fifty cases also fail to cover a rare category. If discounted invoices are 5% of volume and you sampled 20 “typical” PDFs, that kind may never enter. Stratify: some of every category the business fears, not only what shows up first in the folder.
This classification eval runs in a few seconds. It uses the Anthropic SDK (pip install anthropic and the ANTHROPIC_API_KEY variable).
import anthropic
client = anthropic.Anthropic()
PROMPT = "Classify the customer message in one word: billing, order, or other."
CASES = [
("I need a copy of my September invoice", "billing"),
("My order 4521 has not arrived yet", "order"),
("I was charged twice on my card", "billing"),
("Are you open on the holiday?", "other"),
("I want to swap the shirt for a bigger size", "order"),
]
def classify(message: str) -> str:
reply = client.messages.create(
model="claude-haiku-4-5",
max_tokens=20,
system=PROMPT,
messages=[{"role": "user", "content": message}],
)
return reply.content[0].text.strip().lower().rstrip(".")
passed = 0
for message, expected in CASES:
got = classify(message)
ok = got == expected
passed += ok
print(f"{'ok ' if ok else 'FAIL'} {expected:7} {got:10} {message}")
print(f"\n{passed}/{len(CASES)} cases passed")
Now change the prompt to “Answer with the category and a short justification” and run it again. Exact match will fail, and you will see right away what the change broke. That is the point: an eval turns “I think it got better” into a number.
Five cases are enough to feel the mechanism. They are not enough to ship. A real dataset starts when each category has examples, including the awkward ones: a bill about an order, a duplicate charge, a message in caps, a ticket with the national ID already masked.
Answer the 6 questions to complete this lesson. Watching alone does not complete it: the check is what counts toward the trail and the certificate.
What an eval is is an AI engineering fundamental for people who work with LLMs. Tests for systems that never answer the same way twice, from unit case to benchmark.