FAQ

Benchmarks

Building a golden evaluation set

The highest-value artefact in your pipeline, and the one most teams skip. How to build a few hundred examples that make every later decision answerable.

Every dataset decision described anywhere on this site — which corpus, how much data, whether the fine-tune helped — is unanswerable without an evaluation set you trust. It is a few hundred examples and an afternoon, and almost nobody builds it first.

Build it before the training set

This ordering is the single most consequential process choice in a fine-tuning project, and the temptation to invert it is strong: training data feels like progress, evaluation feels like overhead.

But without a held-out set you cannot distinguish a better dataset from a luckier run. You cannot tell whether doubling your data helped. You cannot tell whether the model you shipped is better than the one before it. Every question becomes a matter of impression, and impressions on a handful of hand-typed prompts are reliably wrong.

Building it first has a second benefit: writing down what a correct output looks like forces you to define the task precisely, which usually changes what training data you decide to collect. Several teams discover at this point that they disagree internally about what the model should do.

Build the held-out set before the training set, shuffle whole sources rather than rows, and split by source. Random splits leak near-duplicates and inflate your metrics.

What goes in it

Coverage of your real input distribution matters far more than size. A few hundred items you have read every one of beats several thousand you have not.

Sample from real traffic if you have it. If you do not, write items that reflect what you expect — and revisit the set once you do have traffic, because the gap between expected and actual inputs is usually large and instructive.

Deliberately include the categories that break things:

  • Typical cases, in proportion to real frequency — the bulk of the set.
  • The long tail: unusual phrasings, rare formats, edge cases. Over-represent these relative to their frequency, because they are where failures concentrate.
  • Inputs that should be refused or escalated, if your application has any — otherwise you only ever measure compliance.
  • Adversarial and malformed inputs: empty, truncated, wrong language, prompt-injection attempts, inputs in the wrong format.
  • Cases where the correct answer is “I don't know” — the hardest thing to train and the easiest to forget to test.
  • Known past failures. Every production incident should end with an item added here. This is how the set earns its keep over time.
A lower-triangular grid with models on both axes, from gpt4, claude and chatgpt at the top to alpaca-7b, cohere and text_davinci_001 at the bottom. Each cell gives the number of samples needed for a paired t-test to separate that pair of models at p < 0.05: mostly 50, some 100 or 150, one 250 and one 450. Two grey cells mark pairs that cannot be separated on all 805 samples.
How many evaluation items it takes to tell two models apart: 50 for most pairs on this leaderboard, and 150 for 74 of the 78 pairs, according to the repository. A few hundred well-chosen items settles most comparisons; of the pairs left over, two were not separated even by all 805. Image: tatsu-lab/alpaca_eval · Apache-2.0 repository

Make the grading decidable

An evaluation set is only useful if two people grading it independently agree. If your expected output is a paragraph of prose, they will not.

Where you can, make correctness programmatically checkable — the same instinct that makes RLVR work. Does the output contain the right extracted value, parse as valid JSON against the schema, produce the right classification label, pass the test? Those graders run in milliseconds, give the same verdict on the same output every time, and can be used in CI — though, as below, they still need periodic spot-checks against what you actually intend.

Where output is genuinely open-ended, write a short rubric with explicit criteria rather than grading on overall impression, and validate that two people applying it agree before trusting it. A model judge can then apply the same rubric at scale — but check its agreement with human ratings on a slice first, and be aware it will tend to favour longer and more confident answers.

the useful shape for an eval item
{
  "id": "ext-0041",
  "category": "long_tail",
  "input": "Invoice attached. Total due?",
  "context": "...the document text...",
  "expected": {"total": 1284.50, "currency": "GBP"},
  "grader": "exact_match_json",
  "notes": "Total appears twice; the second is a subtotal. Added after incident 2026-08-14."
}

# category: typical | long_tail | refusal | adversarial
# grader names a function, not a judgement. Graders are ordinary functions,
# versioned with the set:
#   exact_match_json, contains_value, schema_valid, must_refuse, rubric_llm
A side-by-side comparison of two model checkpoints on the same DROP item. Both panels show the end of a passage of 2000 census figures for a county and the question 'How many in percent in the county from the census of 2000 weren't Irish?'. The left completion is '89.1%' and scores exact_match 0 and F1 0; the right completion is '89.1' and scores exact_match 1 and F1 1.
The same correct answer graded twice by DROP's exact-match metric: '89.1' scores 1 and '89.1%' scores 0. A deterministic grader is only as good as its normalisation, and spot-checking its failures is how you find out that the grader, not the model, was wrong. Image: allenai/open-instruct · Apache-2.0 repository; DROP item CC BY-SA 4.0 · DROP item: Dua et al. 2019, CC BY-SA 4.0

Keep it uncontaminated

The set is worthless the moment it enters training, and that usually happens by accident — a shared directory, a broad glob, a synthetic generator that saw it — rather than by anyone deciding to.

A bar chart titled Notable Models of the gap between GSM8k and GSM1k accuracy (percentage points) for about 40 models, sorted from Yi-6B-Chat at about -8 through Phi, Llama, CodeLlama, Mistral and Gemma models with negative gaps to GPT, Claude and Gemini models near zero or slightly positive, coloured by model family.
Each model's score on GSM1k, a fresh set of 1,205 school maths problems written to match GSM8k, minus its GSM8k score. Several open model families drop by up to 8 points on the new questions, while others hold steady. A private set written after the public one is how you see which scores were learned rather than earned. Image: Figure 1 of the paper · CC BY 4.0 · from Zhang et al. 2024, “A Careful Examination of Large Language Model Performance on Grade School Arithmetic”, arXiv:2405.00332

Hold it out explicitly and separately rather than relying on a random split — and shuffle before splitting, since data that arrived grouped by source will otherwise give you a split that is not representative. Unsloth's troubleshooting notes make this point directly: an unshuffled selection gives you a wrong evaluation.

Store it apart from training data so it cannot be swept into a glob. If you generate training data synthetically, check for near-duplicates of eval items. And if you ever use the eval set to tune hyperparameters, understand that you have partly spent it — which is why a separate validation split for tuning and a test set touched only at the end is worth the extra effort.

A scatter plot titled 'LCB-Easy vs HumanEval+': pass@1 on HumanEval+ against pass@1 on LiveCodeBench's easy problems for about 20 code models, with a legend below. A red-shaded band holds models such as DS-33B, DS-6.7B, WC-34B and DS-1.3B, high on HumanEval+ but lower on LCB-Easy; a green band holds GPT-4-Turbo, GPT-4, Claude-3-O, Gemini-Pro and the base models, whose two scores rise together.
Code models placed by their HumanEval+ score against LiveCodeBench's easy problems. The red group does well on HumanEval+ and poorly on the newer set, which the LiveCodeBench authors read as possible overfitting to HumanEval. A test that has been public, or tuned against, for long enough flatters exactly the models that saw it. Image: LiveCodeBench/LiveCodeBench · MIT repository · from “LiveCodeBench: Holistic and Contamination Free Evaluation of Large Language Models for Code”, arXiv:2403.07974

Treat it as a versioned asset

The set is code. Put it in version control, review changes to it, and record which version produced which reported number — otherwise an improvement may just be a changed set.

Add to it when you find failures, and resist the urge to remove items the model finds hard. A set pruned of difficult cases reports steadily improving numbers on a steadily easier test, which is the most comfortable way to deceive yourself available in machine learning.

Over a couple of years this becomes the most valuable artefact your team owns. Models, frameworks and base checkpoints will all be replaced. A well-curated evaluation set that encodes what your application actually has to do survives all of it, and makes every replacement decision answerable in an afternoon.

A split diagram. A full-width 'All Data' bar divides into 'Training data' and a separate 'Test data' block. The training portion is then drawn as five stacked rows of equal folds, each row using a different fold for validation and the rest for training, with a 'Final evaluation' arrow pointing from the untouched test block to the end of the process.
The block that is never trained on and never tuned against. A golden eval set has to be carved off before anything else happens — once you have tuned against it, it is a validation set and you no longer have a golden one. Image: scikit-learn/scikit-learn · BSD-3-Clause repository

Questions people ask

How many examples do I need?

A few hundred is a reasonable target: enough that differences are not pure noise, small enough to curate by hand. Weight toward coverage of distinct situations rather than volume — fifty items spanning fifty genuinely different cases tells you more than five hundred variations of three.

Can I reuse a public benchmark as my eval set?

As a supplement, not as the core. Public benchmarks measure general capability and may be contaminated into your base model's training data. They are useful for regression-checking general ability while your own set measures your task.

Should the eval set match my training data's distribution?

It should match your production input distribution, which is not always the same thing. If they differ, that is important information — it means your training data is unlike what the model will see, and the eval set is doing its job by revealing it.

How often should I re-grade manually?

Spot-check whenever you change the grader or add a category, and re-read a sample periodically even when nothing changed. Automated graders drift out of agreement with intent as the task evolves, and the failure is silent: the number keeps being produced.

Stop hunting. Start searching.

Tens of thousands of curated datasets, searchable in plain language — with the licence and size checked before you download anything.

Search Dataset Finder →