learn-ai-evals-with-phoebe / Builder session 2 of 10
Learn Evals with Phoebe · Builder track · Session 2 of 10

Building a golden set: the data your score depends on

Last session Recall got its first number. But a score is only as honest as the golden set behind it - feed it lazy questions and you get confident, meaningless numbers. This session is about building the eval dataset well: how big, how varied, how to cover the edge cases, and how to structure entries so a machine can grade them. You will write real golden entries for Recall, learn to generate candidates with an LLM (and why you must still curate them), and leave with a set you can actually trust.

🟢 Builder track · easy Practitioners · some Python Golden set craft Session 2 of 10
0-3 · Welcome 3-22 · Concepts 22-40 · Build a set 40-45 · Q&A
Part 0

Garbage golden set, garbage score

In b1 we trusted the twelve golden questions without asking where they came from. That trust is exactly what today interrogates. A golden set is the ground truth your whole eval stands on, and it is the single easiest thing to get quietly wrong. This session gives you the four qualities of a set worth trusting, shows you how to scale one with synthetic generation, and drills the discipline that keeps generation honest: a human curates before the numbers get believed.

Live - presented in session Self-study - full depth after class ★ Try it now Sources covered at the end
★ What you build today A clear standard for a trustworthy golden set (size, diversity, edge cases, gradeable structure), a working synthetic generator that drafts candidate question/answer pairs from your own docs, the habit of curating before trusting, and Recall's golden set upgraded from twelve seed questions to a real dataset.
Part 1 · covers what makes a golden set trustworthy

The four qualities of a golden set worth trusting 10 min live

A golden example is small: a question, the reference answer you would accept, and optionally the reference context (the chunk that should support it). The craft is not in any single row - it is in the shape of the whole set. Four qualities separate a set that measures reality from one that flatters your system.

One golden entry question "how do I get a refund?" reference answer "cancel within 14 days" reference context chunk C-refund A set of them is trustworthy when it is: 1 · Right size volume over per-item polish 2 · Diverse mirrors the real task mix 3 · Edge cases incl. ambiguous ones 4 · Gradeable structured for a machine Miss any one and the score lies: too small, skewed, soft on hard cases, or impossible to grade automatically. The set, not the row, is the artifact. Design the shape of the whole thing.
🔍 Click to zoom - one golden entry and the four qualities of a trustworthy set
LiveRight size: volume over per-item polish3 min

The instinct is to hand-craft a handful of perfect questions. The better instinct, at least once you are automating the grade, is more questions at slightly lower per-item polish.

  • Anthropic's guidance is blunt about this. Prioritize volume over quality: more questions with slightly lower-signal automated grading beats fewer, hand-graded ones. Coverage catches more regressions than polish does.
  • Statistics needs a denominator. A Hit Rate over twelve questions swings wildly when one flips. Over a hundred, one flip barely moves the number - and you can actually tell whether a change helped.
  • Automated grading is what makes volume affordable. If every item needs a human to grade, you cap out fast. Structure for machine grading (Part 2, quality 4) and volume stops being expensive.
LiveDiversity: mirror the real task distribution3 min

A set that over-represents easy questions gives a high score that means nothing in production. The mix of your golden set should look like the mix of questions your system actually gets.

  • Mirror the real-world task distribution. If a third of Recall's real traffic is Jira incident lookups (corpus B), roughly a third of the golden set should be too. Match topics, phrasings, and difficulty to reality.
  • Sample from real logs when you have them. The truest distribution is the one your users already produced. Pull real queries, strip anything sensitive, and let them seed the set.
  • Cover all three corpora. Recall spans personal notes (A), Jira incidents (B), and the company KB (C). A golden set that ignores one corpus cannot catch a regression that only hits that corpus.
LiveEdge cases, including the deliberately ambiguous4 min

The average question is not where systems break. Dedicate part of the set to the hard tail on purpose.

  • Reserve cases for edge behavior. Empty results, questions spanning two corpora, near-duplicate chunks, out-of-scope questions the system should decline - these are where scores should drop, and where you want to know.
  • Include ambiguous cases where even humans would struggle to reach consensus. Anthropic recommends this deliberately: a question with no single clean answer stress-tests how your system and your grader handle genuine uncertainty.
  • Label edge cases so you can slice. Tag them, so you can report the score on the hard tail separately from the easy body. A flat average hides a system that aces the easy and fails the hard.
Why ambiguous cases earn their keep An ambiguous golden question forces a decision you would otherwise never make: what is the right behavior when there is no clean right answer? Often the correct answer is that the system should ask a clarifying question or decline - and only an ambiguous case in the golden set will ever test that.
LiveStructure for automated grading3 min

The final quality is mechanical but decisive: the set has to be gradeable by a machine, or volume and CI are both off the table.

  • Pick a grading mode per item. Multiple-choice (exact option match), string match (expected substring or id), code-graded (a function checks the output), or LLM-graded (a model judges against a rubric). Retrieval golden sets are usually string/id match - cheap and deterministic.
  • Make the expected field unambiguous. For Recall's retriever the expected field is a chunk id (like C-refund), not free text - so grading is a set membership check, not a fuzzy comparison.
  • Save the hardest grading for last. LLM-graded items are powerful but pricey and need their own validation (that is b5 and b6). Start with the cheap deterministic modes wherever the task allows.
Part 2 · covers synthetic vs curated sets

Synthetic vs curated: generate, then curate 8 min live

Writing a hundred golden questions by hand is slow. The modern move is to let an LLM draft candidates from your own documents, then have a human curate: keep the good, fix the salvageable, cut the rest. Generation gives you volume; curation gives you trust. You need both.

Source chunk a doc from corpus A/B/C LLM / RAGAS generate triples: Q / answer / context Human curates keep · fix · cut before trusting Golden set survivors only, now trusted Never ship a generated set unvalidated. Generation scales the draft; humans license the trust.
🔍 Click to zoom - generate candidate triples, then curate down to a trusted set
Self-studyA simple prompt-based generator4 min read

The core idea is small: hand the model a chunk, ask it for questions a real user would ask that this chunk answers, and get back the expected answer and the source id along with each question. Here is a minimal generator over Recall's corpora.

Python · generate candidate Q/A pairs from a chunkimport json from anthropic import Anthropic client = Anthropic() GEN_PROMPT = """You are helping build an evaluation set for a RAG assistant. Read the SOURCE chunk below. Write {n} questions a real user might ask that this chunk - and only this chunk - answers well. For each, give the short reference answer grounded in the chunk. Return JSON: a list of objects with keys "question" and "reference_answer". SOURCE (id={chunk_id}): {chunk_text} """ def generate_candidates(chunk_id, chunk_text, n=3): msg = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, messages=[{ "role": "user", "content": GEN_PROMPT.format(n=n, chunk_id=chunk_id, chunk_text=chunk_text), }], ) pairs = json.loads(msg.content[0].text) # attach the source id as the reference context / expected id for p in pairs: p["reference_context"] = chunk_id p["expected"] = chunk_id return pairs candidates = [] for cid, text in recall_chunks.items(): # your corpus A/B/C chunks candidates += generate_candidates(cid, text, n=3) print(len(candidates), "candidates drafted - now curate")
Do not skip the curation pass The output above is a draft, not a golden set. Read every candidate: cut leading or trivial questions, fix answers that drift from the chunk, drop near-duplicates, and hand-write the ambiguous edge cases the model will not think to produce. The generator saves typing, not judgment.
Self-studyRAGAS testset generation3 min read

When you want more than a per-chunk prompt, RAGAS automates the whole thing. It builds a knowledge graph from your documents, then generates a mix of question types so the set is not all one shape.

Python · RAGAS TestsetGeneratorfrom ragas.testset import TestsetGenerator from langchain_anthropic import ChatAnthropic from langchain_community.document_loaders import DirectoryLoader # load Recall's docs (corpus A/B/C on disk) docs = DirectoryLoader("recall_corpora/").load() generator = TestsetGenerator.from_langchain( llm=ChatAnthropic(model="claude-sonnet-4-5"), ) # builds a knowledge graph, then a mix of single-hop and multi-hop queries dataset = generator.generate_with_langchain_docs( docs, testset_size=60, # how many golden examples to draft ) df = dataset.to_pandas() # question / reference / contexts columns df.head()
  • Knowledge graph first. RAGAS builds a graph from your docs and uses it to write questions that need one chunk (single-hop) or several (multi-hop).
  • A deliberate mix. The default query distribution is roughly half single-hop and half multi-hop, split between abstract and specific multi-hop questions - so your set exercises both simple lookups and reasoning across chunks.
  • testset_size is yours to set. Ask for 60 or 600. Then - same rule - curate before you trust the numbers it produces.
Self-studyValidate the generator against humans2 min read

OpenAI's guidance on evals is consistent on one point: an LLM can generate synthetic eval data and even grade it, but you validate that generated set (or model-graded eval) against human judgment before you trust it at scale.

  • Sample and check. Have a human review a random slice of the generated set. If the answers or expected ids are wrong too often, the whole set is suspect - fix the prompt or the source, do not paper over it with volume.
  • Agreement is the gate. Only once a human agrees with the generator on a good sample should you scale generation up and lean on the numbers. Trust is earned per set, not assumed.
  • This applies double to LLM graders. The same validate-against-humans rule governs the model-graded metrics in b5 and b6, where the model is not just writing questions but scoring answers.
Part 3 · covers the b1 set, scored

The seed set, scored again ★ 5 min live

Here is Recall's original twelve-question seed set from b1, scored live. As you read the table, treat it as the set under review: which questions are too easy, which corpus is thin, where is the ambiguous case that should be here and is not? That reading is the work of this session.

Live★ Review the seed set as data4 min

Change k and watch the score, but keep your eye on the questions this time, not the metric. A trustworthy set would spread evenly across corpora A, B, and C, include a couple of genuinely hard cases, and have at least one ambiguous entry. Judge this seed set against that bar.

Honesty note - what this scorecard really does Retrieval here uses the same simplified lexical embedder as the RAG course playground, so it runs with zero network. But the evaluation math - Hit Rate@k, MRR, Precision@1 over a golden set - is exactly what you compute in production. You are watching the real metric mechanic with a toy retriever.

Notice how few questions there are: with twelve, a single flip moves Hit Rate by more than eight points. That volatility is the b1 set telling you it is a seed, not a finished golden set. Growing and diversifying it is your homework.

Build-along · take it further

Turn 3 real questions into golden entries ★ 12 min · your own system

The fastest way to internalize this is to build three real entries for a system you actually run - Recall, or your own.

Pull three real questions. Take three questions your system genuinely receives (from logs, from memory, from a teammate). Real phrasing, not tidy paraphrases.

Write the reference answer and context. For each, write the short answer you would accept as correct, and name the chunk or doc id that should support it. That id is your gradeable expected field.

Add one deliberately ambiguous case. Write a fourth entry where even you and a colleague would disagree on the single right answer. Note what the right behavior is - answer, decline, or ask to clarify.

Tag and file. Label the corpus and mark the ambiguous one as an edge case, so you can slice its score separately later. You now have four rows of a real golden set.

★ Recall's golden set after b2 Recall's golden set is no longer a twelve-question seed you inherited - it is a set you can defend: sized for stable numbers, spread across all three corpora, salted with edge and ambiguous cases, and structured so a machine can grade every row. The score from b1 finally means something. In b3 we go deep on the retrieval metrics that read this set.
Homework

Before session b3 ◐ 45 min total

Source material

Official sources covered

Taught from official docs. This page covers ~80% of their working content on golden-set construction - the rest (full RAGAS metric suites, hosted grading) lands in later sessions.

Anthropic · developing tests (empirical evals)Part 1 · volume over quality · mirror the task distribution · structure for auto-grading · ambiguous edge cases
RAGAS · testset generationPart 2 · knowledge graph · single-hop + multi-hop mix · testset_size
OpenAI · evals (synthetic data + validation)Part 2 · generate then validate against humans before scaling
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · Anthropic's guidance on golden-set size is best summarized as...

Anthropic advises prioritizing volume over per-item polish, because coverage catches more regressions and automated grading makes volume affordable.

2 · Why deliberately include ambiguous cases where even humans disagree?

Ambiguous entries force a decision you would otherwise skip: what is correct when there is no clean answer. Often that is a clarifying question or a decline, and only an ambiguous case tests it.

3 · You used an LLM to generate a golden set. Before trusting its scores at scale you should...

OpenAI's guidance: LLMs can generate synthetic eval data, but you validate that data (and model-graded evals) against human judgment before relying on it at scale. Trust is earned per set.

Builder session 2 cheat sheet · pin this

Golden entryquestion + reference answer + (optional) reference context. The set, not the row, is the artifact.
Right sizeVolume over per-item polish (Anthropic). More auto-graded questions beats fewer hand-graded ones.
DiversityMirror the real task distribution - topics, phrasings, difficulty, and all three corpora.
Edge casesDedicate entries to the hard tail, including ambiguous cases where humans disagree.
GradeableStructure for automated grading: multiple-choice, string/id match, code-graded, or LLM-graded.
Generate then curateLLM or RAGAS drafts triples; a human keeps, fixes, or cuts before the set is trusted.
RAGAS testsetKnowledge graph → single-hop + multi-hop mix; testset_size configurable.
Validate vs humansOpenAI: validate any generated set or model grader against human judgment before scaling.