Evaluation & Test Sets
Scenario
You tweak your system prompt to make the bot more concise. It works on your three test queries. You deploy it. The bot now refuses all complex questions, replying 'I must be concise.' Before you read on, predict: how many test queries would you need to catch this?
Think about coverage — then read on to understand how golden datasets and automated evals prevent silent regressions.
Mental model
Evaluation is unit testing for vibes. It turns 'this looks good to me' into a repeatable number you can track across every prompt change.
Standard code either works or crashes. LLM outputs exist on a spectrum of quality. Evaluation is the process of building a golden dataset of (input, expected behavior) pairs, running every pipeline change against it, and scoring the results. Since you cannot do exact string matching on natural language, you use a strong LLM as a judge to grade whether the output contains the expected facts or behavior.
Deep dive
When you build an AI app, your first instinct is to 'vibe check' — run a few queries manually and eyeball the outputs. This does not scale. A change that fixes one edge case almost always breaks another. You need automated, repeatable measurement. Every prompt or model change must be validated against the same standard test suite before it ships.
Manual vibe checks miss silent regressions. Automated evals catch them before deployment.
The foundation of evaluation is the **golden dataset** — a static list of 50–200 diverse inputs and the expected behaviors or key facts you want to see in the output. It must cover easy questions, hard multi-step reasoning, adversarial inputs ('ignore all instructions'), and edge cases. Without this dataset, you have nothing to measure against and no way to prove improvement.
A golden dataset of inputs and expected facts is your evaluation ground truth.
You cannot use exact string matching to grade LLM outputs. If the expected answer is 'Paris' and the model outputs 'The capital is Paris, France', the string match fails even though the answer is correct. Instead, use **LLM-as-a-judge**: a meta-prompt asks a stronger model to determine whether the output contains the expected fact or satisfies the grading criterion.
LLM-as-a-judge grades semantic meaning, not exact characters — essential for natural language output.
An eval run loops over your golden dataset, generates the output with your current system, passes both the output and the expected answer to the judge model, and collects a score (0 or 1). Average these scores to get a metric like '87% factual accuracy'. If the score drops after a change, you revert.
Eval run = generate outputs → grade with judge → average score → ship or revert.
You can write judges for multiple dimensions: tone ('is this polite?'), hallucination ('is every claim in the retrieved context?'), safety ('did it refuse this harmful query?'). Run the eval suite on every prompt change, model swap, or chunking change. Treat it like CI/CD unit tests — a score drop blocks the deploy.
Write separate judges for accuracy, tone, safety. Run on every pipeline change.
Code examples
Define the golden dataset
test_set = [
{
'input': 'What is the refund policy?',
'expected_fact': 'Refunds are allowed within 30 days of purchase.'
},
{
'input': 'Can I buy a car?',
'expected_fact': 'The system must refuse — we only sell software.'
},
]
The expected value is the core fact or behavior, not a rigid string. The judge will check whether the model's actual output contains or satisfies this expected fact.
LLM-as-a-judge grading function
from openai import OpenAI
client = OpenAI()
def grade_output(question: str, expected: str, actual: str) -> int:
prompt = f"""You are an impartial judge.
Question: {question}
Expected Fact: {expected}
Actual Model Answer: {actual}
Does the Actual Answer contain the Expected Fact?
Respond with exactly 1 for Yes, or 0 for No."""
resp = client.chat.completions.create(
model='gpt-4o', # judge must be capable — don't use a small model
messages=[{'role': 'user', 'content': prompt}],
temperature=0.0 # deterministic grading
)
return int(resp.choices[0].message.content.strip())
The judge evaluates semantic meaning, not exact characters. temperature=0 makes grading deterministic. Always use the most capable model available as the judge — a weak judge produces unreliable scores.
The eval loop
def run_evals(test_set: list[dict], agent_func) -> float:
scores = []
for item in test_set:
actual = agent_func(item['input']) # run the system under test
score = grade_output(item['input'], # grade the output
item['expected_fact'],
actual)
scores.append(score)
accuracy = sum(scores) / len(scores)
print(f'Eval result: {accuracy * 100:.1f}% accuracy')
return accuracy
This loop is the heartbeat of AI engineering. Run it before shipping any prompt change. If accuracy drops from 95% to 80%, you don't ship. Over time, add more test cases as you discover edge cases in production.
Key points
- Vibes don't scale: Manual testing misses regressions. You need automated, repeatable measurements to ship safely.
- Golden dataset: A curated, static list of inputs and expected behaviors. Never change the dataset and the system at the same time — you cannot tell what caused the score change.
- LLM-as-a-judge: Use a strong model (GPT-4o) to grade outputs semantically — because exact string matching fails on natural language.
- Continuous evaluation: Run the full eval suite on every prompt or pipeline change, treating it like CI/CD unit tests.
Common mistakes
- Using exact string matching for evaluation: asserting output == 'Yes' fails if the model says 'Yes, I can help' or 'Absolutely'. Exact matches mark correct answers as failures. Use an LLM judge to evaluate semantic meaning.
- Using a weak model as the judge: If your system runs on GPT-4o-mini and your judge is also GPT-4o-mini, the judge cannot reliably detect complex reasoning failures or subtle hallucinations. The judge must always be a more capable model than the one being evaluated.
- Changing the test set and the system at the same time: If you update the golden dataset and the system prompt in the same commit, you cannot tell whether the score changed because the system improved or the test got easier. Change only one at a time.
Glossary
- golden dataset
- A curated, static list of test inputs and the expected correct behavior — used as a measuring stick to score your system before each deployment.
- LLM-as-a-judge
- A technique where a powerful LLM grades the outputs of another model using a structured grading prompt, replacing slow human grading.
- regression
- When a change meant to improve the AI causes it to fail at tasks it previously handled correctly — often invisible without an automated eval suite.
Recall questions
- Explain what a golden dataset is and why it is needed, as if to a classmate.
- Why can't we use exact string matching to grade LLM outputs?
- Why should the judge model be set to temperature=0?
- Your eval suite produces flaky results — the same model output gets 'pass' on one run and 'fail' on another. Predict two likely causes.
Questions & answers
Your team's LLM evaluation pipeline produces flaky results: the same model output gets a pass on one run and a fail on the next. What are two likely causes and how would you fix them?
First: the judge LLM's temperature is greater than 0, causing non-deterministic grading. Fix: set temperature=0. Second: the judge prompt is ambiguous, causing the judge to apply inconsistent criteria. Fix: simplify to strict binary output (1 or 0) with clear, specific grading rubrics.
Approach: Identify that flakiness comes from non-determinism in the judge. Temperature and prompt clarity are the two primary levers.
You are building an eval to check if your RAG bot is hallucinating. How would you structure the LLM-as-a-judge prompt?
Pass the retrieved context chunks and the model's generated answer to the judge. Ask: 'Is every claim in the Generated Answer fully supported by the Retrieved Context? Answer 1 for Yes, 0 for No.' This evaluates faithfulness — no golden expected answer is needed, only the context-answer pair.
Approach: Show that hallucination evaluation compares the retrieved context against the generated output — not against a pre-written expected answer.
Continue learning
Previous: RAG Evaluation