Vibe Engines
YouTube
AI System Design

Design a Synthetic Data Pipeline

Step 1 / 9

Learn AI system design by building a synthetic data generation pipeline that uses LLMs to create training and eval data step by step.

The numbers to beatspectask + schema + seedsstagesgenerate→diversify→filter→verifyoutputdiverse + validated

The whole design, in writing

Learn AI system design by building a synthetic data generation pipeline that uses LLMs to create training and eval data step by step. An interactive guide covering why naive generation is low-diversity and error-prone, generating with a strong teacher model, steering diversity to avoid mode collapse, quality filtering, verifying correctness, using the data for distillation/augmentation/evals, and the unhappy paths (model collapse, bias, contamination, licensing).

Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.

The big idea

What is a synthetic data pipeline?

Good models need lots of good data — but human labeling is slow, expensive, and often unavailable for a new task or a rare case. LLMs can generate training and eval data far faster and cheaper. The catch: a naive "generate 10,000 examples" gives you a repetitive, error-riddled pile that makes models worse. The value isn't generating data — it's generating diverse, correct, useful data.

Task Specseeds · schema
New in this step: Task Spec.

A synthetic data pipeline manufactures quality datasets with a strong teacher model, then earns their usefulness through diversity steering, quality filtering, and verification. The output feeds distillation (train a smaller model), augmentation (fill data gaps), and eval sets. Generate is easy; diversity + validity are the system.

What the new pieces do

Task Specclient
What data you need — the task, an output schema, a few seed examples, and constraints. Steers the whole pipeline.

Step 1 · Why "just generate" fails

Repetitive and wrong

The obvious approach: prompt an LLM "generate 10,000 training examples for task X" and use the output. Why is that dataset bad?

Task Specseeds · schema
The system as it stands at this step.

Prompt an LLM to "generate 10,000 examples" and use them directly. What's wrong?

  1. Fluency isn't the issue. Unsteered generation is low-diversity (the model repeats a few patterns — mode collapse) and error-prone (hallucinated facts, wrong labels, malformed outputs), so training on it teaches narrowness and mistakes.

  2. Generation is fast and cheap; that's the appeal. The problem is quality: without diversity control and filtering you get a repetitive, error-laden dataset that degrades models.

  3. Unsteered, the model clusters around a few templates (low diversity) and confidently produces some wrong or malformed examples (errors). A model trained on that learns a narrow slice with baked-in mistakes. The pipeline must add diversity and filter/verify quality.

Unsteered generation fails two ways. Low diversity: the model clusters around a few patterns (mode collapse), so the dataset covers a narrow slice of the real distribution. Errors: it confidently produces some hallucinated, wrong-label, or malformed examples. Train on that and the model learns narrowness and mistakes. The generation is the easy 10%; making the data diverse and correct is the system.

Why this piece earns its place

Both failures share a property that makes them dangerous in practice: neither one is visible in a sample. Read a handful of generations and every one looks fine — fluent, correctly formatted, plausible — because the diversity problem only exists at the level of the whole corpus, and the error rate is a fraction rather than a majority. Spot-checking, which is what everyone actually does, will happily certify a set that is neither varied nor correct. So the measurements have to be corpus-shaped, and they have to exist before you generate at scale: pairwise similarity across the set, counts of repeated openings and templates, a histogram over whatever axes you claim to cover. The other reason to build them early is the feedback loop. A bad dataset never announces itself as a bad dataset; it announces itself as a training run that came back slightly worse, days later, with no way to attribute the loss to anything in particular. That is the most expensive debugging loop in this design, and every check you can run before training is one you are not paying for in GPU hours and ambiguity.

Step 2 · Spec in, dataset out

The pipeline shape

Frame it as a pipeline. What does it take in, what stages does it run, and what does it guarantee about the output?

Task Specseeds · schemaPipelineorchestrate
New in this step: Pipeline.

The pipeline takes a task spec — the task, an output schema, a few seed examples, and constraints — and runs stages: generate (teacher model) → diversify (steer variety) → filter (reject bad) → verify (check correctness) → store. The guarantee isn't "lots of data" but "diverse, filtered, validated data fit for training/eval." The spec (especially the seeds and schema) steers everything; each stage removes a failure mode of raw generation.

Why this piece earns its place

Read pipeline as a batch job rather than a service, because that inverts most of the usual instincts. Nothing here has a latency budget or an uptime target. What matters is that a long, rate-limited run survives being interrupted, and that any one stage can be re-run without paying for the stages before it. The cheap build is a single script that generates, filters and verifies in memory and writes out the survivors. The expensive consequence arrives the first time someone asks what the dataset would look like at a stricter gate: with nothing materialized between the stages, answering costs a full regeneration — the one stage that costs real money — so in practice nobody asks twice. Write each stage's output to its own place and the same question becomes a re-filter you can run over lunch. Give generation a deterministic unit of work too, one attribute cell or one template at a time, so a resumed run knows what it already produced instead of sweeping the space again. And treat the schema in the spec as a contract: the rule checks, the dedup key and the training format all read it, so changing it mid-run leaves you with two halves that do not belong to the same dataset.

  • spectask + schema + seeds
  • stagesgenerate→diversify→filter→verify
  • outputdiverse + validated

What the new pieces do

Pipelinegateway
Runs generate → diversify → filter → verify → store, producing a clean, diverse, validated dataset from the spec.

Step 3 · The teacher

Generation with a strong model

Candidates have to come from somewhere. What generates them, and how do you steer what gets generated?

PipelineorchestrateTeacher Modelgenerate
New in this step: Teacher Model.

Use a strong teacher model prompted with templates, the seed examples, and often personas or roles to shape style and content. You can generate inputs, outputs, or both (e.g. a question and its answer), and use techniques like self-instruct (bootstrap new tasks from seeds) or having the teacher produce step-by-step reasoning. The teacher is usually a bigger/better model than the one you'll train — you're transferring its capability into data.

Why this piece earns its place

Two consequences of the teacher choice that only surface later. The first is correlation. If the judge downstream is the same model, or the same family, then its blind spots are the generator's blind spots — it approves exactly the errors it was most likely to make, and the filter measures nothing while reporting a healthy acceptance rate. Score with a different family where you can, and prefer a check that is not a model at all. The second is where the teacher's weakness actually lands. On anything checkable, selection does the work, and a corpus assembled by keeping only what passes can be better than the teacher's average output — that is the whole reason over-generating pays. On the part of the task you cannot check there is no selection pressure at all: a judge that shares the teacher's understanding cannot lift the data above it, so the corpus inherits those weak spots at roughly the rate the teacher has them, confidently and in the right format. That flips the selection criterion. Choose the teacher on the slice you have no checker for, because that is the only slice where its quality passes straight through to the student.

  • teacherstrong model
  • seeds + templatessteer content
  • personasstyle + variety

What the new pieces do

Teacher Modelservice
A strong "teacher" LLM that produces candidate examples from prompts/templates seeded for the task.

Step 4 · Cover the space

Steering diversity

Left alone, the teacher repeats itself — the number-one failure of synthetic data. How do you force it to cover the breadth of the real distribution instead of echoing a few templates?

PipelineorchestrateDiversityseeds · attributesTeacher Modelseeded · diverse
New in this step: Diversity.

The teacher keeps producing similar examples (mode collapse). How do you get real diversity?

  1. Instead of one prompt repeated, you sweep a space of attributes — topics, difficulty, style, personas, edge cases — so each generation targets a different region; raise sampling temperature for variety; and deduplicate near-identical outputs (by embedding similarity). This forces coverage of the distribution rather than clustering around a few modes.

  2. More of the same prompt gives more of the same output — it deepens mode collapse rather than fixing it. You must vary the generation systematically and dedup.

  3. Lower temperature makes generations MORE similar, worsening collapse. You want controlled diversity: attribute sampling + higher temperature + dedup, not more determinism.

Steer diversity explicitly. Sweep a space of attributes — topics, difficulty, style, personas, edge cases — so each generation targets a different region of the distribution (attribute/topic sampling); raise sampling temperature for variety; and de-duplicate near-identical outputs (e.g. by embedding similarity). This turns "the model's favorite ten patterns" into broad coverage. Diversity is engineered, not hoped for — it's the difference between data that generalizes and data that collapses.

Why this piece earns its place

The attribute grid is authored content, and that has a consequence people skip past: you can only cover the axes you thought to name. Whatever you left off is absent from the dataset and absent from your report of what the dataset covers, so the blind spot gets frozen in and looks like coverage. Where any real data exists — production logs, support tickets, a handful of genuine requests — derive the axes from it rather than brainstorming them at a desk. The subtler point is that a grid only buys diversity between cells. Inside one cell the teacher still has a favorite shape, and that is where collapse hides once the sweep is in place: same skeleton, same argument order, different nouns. Embedding dedup will not catch those, because they are not near-identical text — they are near-identical structure. Varying temperature, seeds and persona within a cell is the separate lever for that, and it needs its own decision. Last, weight the cells deliberately. A flat sweep asserts a flat world, and produces as many exotic edge cases as ordinary ones, which teaches a prior that is wrong in a quieter way than collapse is.

  • attribute samplingsweep the space
  • temperaturemore variety
  • dedupdrop near-duplicates

What the new pieces do

Diversityservice
Steers variety: samples topics/attributes/personas and de-duplicates so generations cover the space, not one template.

Step 5 · Reject the bad ones

Quality filtering

Even from a good teacher, some generations are malformed, off-task, low-quality, or mislabeled. Letting those into the dataset poisons training. How do you keep only the good ones?

Teacher Modelseeded · diverseQuality Filterjudge · rulesDatasetclean · diverse
New in this step: Quality Filter, Dataset.

Filter every candidate before it enters the dataset. Cheap rule/format checks first (schema valid? right length? on-task?), then a model-as-judge to score quality/correctness and reject low-scoring examples — and often generate extra so you can afford to throw many away. This is generate-and-select: over-produce, then keep only the high-quality subset. Filtering is what makes synthetic data trustworthy — without it, the teacher's confident mistakes become the student's learned mistakes.

Why this piece earns its place

Filtering is a second, unannounced diversity filter, and that is the failure to watch for. Rejection is not uniform across the space you just worked to cover: the hard attribute cells — the rare topics, the difficult examples, the awkward personas — are exactly where the teacher is weakest, so they fail the checks at a higher rate and quietly drain out. An overall acceptance rate tells you nothing about this. Track survival per attribute cell, and when a cell empties, the fix is usually to generate more into it rather than to loosen the gate. There is a related bias in the judge itself: it tends to prefer long, fluent, confident answers, so hard filtering shifts the style of the corpus toward the judge's taste and the student inherits it. And do not throw the rejected candidates away. A pile of rejects is the cheapest diagnostic here: it shows which templates are broken rather than merely unlucky, it is the negative half of any set you use to check the judge against a human, and it is gone the moment the run ends, because getting it back means paying for the whole generation a second time.

  • rulesschema/format/on-task
  • judgescore + reject
  • over-generateafford to discard

What the new pieces do

Quality Filterservice
Rejects bad candidates — malformed, off-task, low-quality, wrong-label — via rules and a model-as-judge.
Datasetdata
The curated output — diverse, filtered, verified examples ready for training, augmentation or evals.

Step 6 · Prove it where you can

Verification & grounding

Filtering catches obvious junk, but for factual or code data you can often do better than a judge's opinion — you can check correctness. How, and why does it matter so much?

Diversityseeds · attributesTeacher Modelseeded · diverseQuality Filterjudge · rulesVerifyexecute · checkDatasetclean · diverse
New in this step: Verify.

You generated 1,000 synthetic coding examples with solutions. A judge model rates each one 1-10 for correctness. Is that enough?

  1. A judge is another model guessing whether code is right by reading it, which is fallible even for a strong model — subtle bugs read as plausible. For code specifically, you have a much stronger signal available: does it actually run and pass tests?

  2. Execution is objective evidence, not an opinion: code either passes the tests or it doesn't. Reserve judge-scoring for the genuinely uncheckable cases (subjective quality, style) and verify anything with a ground truth directly.

  3. Human review of 1,000 examples defeats the economics that make synthetic data worth generating in the first place. Execution-based verification gets you objective correctness without that cost.

Verify correctness whenever the task allows a ground truth. Generated code? Execute it against tests and keep only what passes. Factual claims? Check against a source (retrieval/grounding) or require citations. Math? Verify the answer. This is far stronger than a judge guessing, and it's how you get reliable synthetic data for domains where wrong labels are poison. Verification turns "the teacher says it's right" into "we proved it's right."

Why this piece earns its place

Verification is the one stage that needs infrastructure the rest of the pipeline does not. Executing model-generated code means a sandbox, a wall-clock timeout, a memory cap and no network, because you are running untrusted output at volume and some fraction of it will loop forever or try to reach the internet. Budget for that before promising execution-based filtering. The subtler problem is where the tests come from. If the teacher writes the solution and its tests in the same breath, a wrong solution with agreeable tests sails through — a check is only as independent as the thing doing the checking, and self-marked homework is weak evidence. Derive the tests from the spec separately, or from a different model, and treat passing your own tests as a lower grade of proof than passing tests you did not write. It also changes the economics wherever it applies: a test run costs a fraction of a judge call, so on checkable tasks you can afford to over-produce far harder than elsewhere. The finished dataset then holds two tiers of evidence — rows a machine proved and rows a model merely liked — and those should never be reported as one quality number.

  • executerun code vs tests
  • groundcheck facts vs source
  • provennot just plausible

What the new pieces do

Verifyservice
Checks correctness where it can be checked: run generated code, validate against a source, confirm labels.

Step 7 · What it's for

Distillation, augmentation & evals

You have a clean, diverse, verified dataset. What do you actually do with synthetic data?

Task SpecPipelineDiversityTeacher ModelQuality FilterVerifyDataset
The system as it stands at this step. · swipe to pan the diagram

Three main uses. Distillation: train a smaller, cheaper student model on the strong teacher's outputs — capturing much of its capability at a fraction of the cost. Augmentation: fill gaps in real data (rare classes, edge cases, new tasks) or expand scarce datasets. Eval sets: generate test cases to measure a model (with care about contamination). Done well, this is a flywheel: a strong model generates data that trains/improves models, cheaper than human labeling.

Why this piece earns its place

Augmentation is the use that goes wrong quietly. Rows generated to fill a gap sit beside real rows in the same training set, so they have to be indistinguishable from their neighbors — same length distribution, same formatting habits, same messiness — because if they are not, the student learns the tell instead of the task. Contamination is the second trap, and it is not a duplicated row. Generate training data and eval data from the same seeds and the same templates and you get near-duplicates across the split with no literal overlap, so a text-match check finds nothing and the score comes back better than it should. Split by lineage — seed, template, source document — before either set is generated, rather than by shuffling finished rows. And one inheritance worth naming out loud: a distilled student copies the teacher's manner along with its ability, the hedging, the refusals, the formatting habits and the length it likes to write at. Nobody decides that, it arrives with the data, and it is a product decision somebody should have made on purpose.

  • distillteacher → smaller student
  • augmentfill data gaps
  • evalgenerate test sets

Step 8 · The sharp edges

Collapse, bias, contamination & rights

Synthetic data has serious traps: model collapse (training on synthetic degrades over generations), bias amplification, test-set contamination, and licensing of teacher outputs.

Task SpecPipelineDiversityTeacher ModelQuality FilterVerifyDataset
The system as it stands at this step. · swipe to pan the diagram

Avoid model collapse — recursively training models on their own synthetic output degrades quality/diversity over generations — by mixing in real data, enforcing diversity, and verifying quality (don't train blindly on unfiltered self-generated data). Watch bias: the teacher's biases get amplified in the data, so measure and rebalance. Prevent contamination: never let synthetic eval data leak into training, and don't generate evals from the same distribution you'll test on naively. Respect licensing/terms of the teacher model's outputs. And always evaluate the downstream model on real held-out data — synthetic data is a means, real-world performance is the judge.

Why this piece earns its place

The word real in "mix in real data" is carrying more weight than it looks. A corpus scraped or bought today is not cleanly human any more — a growing share of any open pool was itself written by a model — so an anchor chosen for convenience can be partly the thing it is supposed to anchor against, and the protection weakens without anyone touching the ratio. Define what counts as real for this dataset, prefer sources you collected yourself and can date, and treat a bought corpus as unknown until you can say where it came from. The ratio needs an owner rather than a principle: synthetic rows are cheap and real ones are not, so the mix drifts toward synthetic release by release unless it is a number somebody is accountable for and reports. And the licensing question belongs at teacher selection, on day one, because it is the only decision here that is genuinely expensive to reverse. A threshold is a config change that takes effect on the next run; discovering that the teacher's terms forbid your use taints every row already generated, and the remedy is regenerating the corpus and retraining whatever learned from it.

You did it

You just designed a synthetic data pipeline.

Task SpecPipelineDiversityTeacher ModelQuality FilterVerifyDataset
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • Naive "generate N examples" gives low-diversity, error-prone data that degrades models.
  • The value is diverse + correct data; frame it as generate → diversify → filter → verify → store.
  • A strong teacher model generates candidates, steered by seeds, templates and personas.
  • Engineer diversity: attribute/topic/persona sampling + temperature + dedup to avoid mode collapse.
  • Over-generate and aggressively filter (rules + model-as-judge) so only good examples enter.
  • Verify correctness where checkable — execute code against tests, ground facts — beats judge-opinion.
  • Use it for distillation, augmentation and evals; guard against collapse, bias, contamination and licensing.

Where an interviewer pokes next

Getting the boxes right is the easy half. These are the questions that separate a candidate who drew the diagram from one who has run the thing. Answer each one out loud before you open it.

  1. Why does naively asking an LLM to "generate 10,000 examples" produce a bad dataset?

    It fails on the two properties that actually make training data valuable: diversity and correctness. On diversity, an unsteered model repeatedly prompted the same way clusters around a small number of its favorite patterns and phrasings — mode collapse — so the resulting dataset covers only a narrow slice of the real distribution, and a model trained on it learns that sliver and generalizes poorly to everything else. On correctness, the teacher, however fluent, will confidently produce some hallucinated facts, wrong labels, malformed outputs, and off-task examples, and because they read plausibly they slip in unnoticed; a model trained on them learns those very mistakes. The generation step itself is the easy, cheap part — LLMs write fluent examples effortlessly — but that fluency masks the lack of breadth and the presence of errors. So the actual engineering of a synthetic data pipeline is almost entirely the machinery that fixes these two problems: deliberately steering variety so the data covers the space, and filtering plus verifying so only correct examples survive. Without that machinery, more generated data makes the trained model worse, not better.

  2. How do you engineer diversity instead of hoping for it?

    You treat coverage as an explicit design task rather than a side effect of prompting. The core technique is attribute sampling: instead of repeating one prompt, you define a space of attributes relevant to the task — topics, difficulty levels, styles, personas, formats, edge cases — and systematically sweep it so each generation is conditioned to target a different region of the distribution, which forces the teacher out of its default handful of modes and across the whole space you care about. You pair this with raised sampling temperature to increase variety within each region (lowering temperature would do the opposite, making outputs more similar and worsening collapse), and with deduplication that removes near-identical generations, typically by comparing embedding similarity and dropping duplicates. Together these convert "the model's ten favorite patterns repeated a thousand times" into genuine breadth. The reason this matters is that a model trained on diverse synthetic data learns to generalize across the real distribution, whereas one trained on collapsed data effectively memorizes a narrow region and performs poorly outside it — so diversity is engineered deliberately through parameterized generation and dedup, not assumed.

  3. Why is filtering (over-generate then select) the highest-leverage stage?

    Because quality in synthetic data comes primarily from selection, not from the teacher being flawless. Even a strong teacher produces a meaningful fraction of malformed, off-task, low-quality, or mislabeled examples, and those confident mistakes become the student model's learned mistakes if they enter the dataset — so the dataset's usefulness hinges on removing them. The efficient way to do this is generate-and-select: deliberately over-produce candidates (more than you need), then apply a cascade of checks and keep only the good subset. Cheap rule and format checks run first — is the output schema-valid, the right length, actually on-task? — cheaply discarding obvious junk, followed by a model-as-judge that scores quality and correctness and rejects low-scoring examples. Because you generated a surplus, you can afford to throw many away and still end up with enough clean data, and a smaller, cleaner dataset trains a better model than a larger, dirtier one. This is why filtering is the highest-leverage stage: the teacher just supplies raw candidates, but aggressive selection is what determines whether the final data improves or degrades the model, so investing in good filters (and generating enough surplus to filter hard) pays off more than almost anything else in the pipeline.

  4. When and why is verification stronger than a model-as-judge filter?

    Verification is stronger whenever the task has a checkable ground truth, because it grounds the dataset in objective correctness rather than another model's opinion, which can itself be wrong or biased. A model-as-judge is essentially one model guessing whether another model's output is good — useful and general, but fallible, especially on subtle correctness. When you can actually check, you should: for generated code, execute it against tests and keep only the examples that pass, which is a gold-standard technique because passing tests is objective evidence of correctness rather than a plausibility judgment; for math, compute and verify the answer; for factual claims, check them against an authoritative source via retrieval or require citations you can validate. This execution- or grounding-based filtering turns "the teacher says it's right" into "we proved it's right," which matters enormously in domains like code, math, or facts where a wrong label is poison to training. So the hierarchy is: use cheap rules to catch format errors, use a judge for subjective or uncheckable quality, and wherever correctness is verifiable, verify it directly — because proven-correct data is far more reliable than judge-approved data, and it's what lets synthetic data be trusted in high-stakes domains.

  5. What is model collapse and how do you guard against the main risks of synthetic data?

    Model collapse is the degradation that happens when models are trained recursively on their own (or other models') synthetic output over successive generations: each round, the data loses a bit of the diversity and tail behavior of the true distribution and amplifies the model's quirks, so quality and variety progressively decay if you keep feeding synthetic data back in without correction. The primary guard is to anchor training in real data — mix genuine human data with synthetic rather than training purely on generated output — and to enforce the diversity steering and quality verification described earlier so you're not blindly amplifying a narrow, error-laden distribution. Beyond collapse, three other risks need explicit handling. Bias amplification: the teacher's biases get baked into and often magnified in the generated data, so you measure the distribution and rebalance rather than assume neutrality. Contamination: synthetic evaluation data must never leak into training, and you must be careful not to generate test sets from the same distribution you'll naively test on, or you'll overstate performance. Licensing and terms: the outputs of a teacher model may carry usage restrictions, so you respect the relevant terms. And underlying all of it, you always evaluate the downstream model on real, held-out data, because synthetic data is only a means — real-world performance is the actual judge of whether the pipeline worked.

Check yourself — the answers, and why

Nine steps in, these are the calls you should be able to make cold. Pick one, then read why.

  1. Naive "generate N examples" produces bad data because…

    Training on narrow, error-laden data teaches narrowness and mistakes; diversity + validity are the system.

  2. Diversity is achieved by…

    Sweep an attribute space and dedup to cover the distribution instead of collapsing to a few modes.

  3. Quality filtering works by…

    Selection, not a perfect teacher, produces quality — over-produce and discard aggressively.

  4. Verification (vs a judge) is stronger when…

    Execution/grounding proves correctness objectively instead of a model guessing.

  5. To avoid model collapse you…

    Recursively training on unfiltered self-generated data degrades quality/diversity over generations.

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

What it must do

Agree on these before drawing a single box.

  • Generate: use a strong teacher model to produce candidate examples from a task spec, schema and seeds.
  • Diversify: steer variety across attributes/personas so the data covers the space, not one template.
  • Filter: over-generate, then reject malformed, off-task, low-quality or mislabeled candidates.
  • Verify: where a ground truth exists — run code against tests, ground facts — keep only what checks out.
  • Serve the data: feed distillation (train a student), augmentation (fill gaps), and eval sets.

The qualities that shape everything

Each one names the mechanism that buys it.

A capable candidate source
A strong teacher model, prompted with templates, seed examples and personas, generates inputs, outputs or reasoning traces — transferring its capability into data.
Data that covers the real distribution
Diversity steering sweeps an attribute grid — topics, difficulty, style, personas, edge cases — raises temperature, and de-dupes near-identical outputs to defeat mode collapse.
Only good examples enter the dataset
A Quality Filter runs cheap rule/format checks then a model-as-judge, over-generating so you can discard aggressively — the teacher’s confident mistakes never become the student’s.
Proven-correct, not just plausible
Verify where a ground truth exists — execute generated code against tests, check facts against a source, verify math — far stronger than a judge guessing.
Transfer teacher capability cheaply
Use the clean dataset for distillation (train a smaller student on the teacher’s outputs), augmentation of scarce/rare data, and generated eval sets.
Don’t quietly degrade over generations
Guard against model collapse by mixing in real data, enforcing diversity and verifying quality, and always evaluate the downstream model on real held-out data.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

Treat diversity + validity as the system over using raw “generate N examples” output directly

Unsteered generation clusters around a few patterns (mode collapse) and confidently produces wrong or malformed examples. Train on that and the model learns narrowness and mistakes — the generation is the easy 10%, curation is the system.

Attribute sampling + higher temperature + dedup over generating more with the same prompt

More of the same prompt deepens mode collapse rather than fixing it. Sweeping an attribute space targets different regions of the distribution and dedup drops near-duplicates — coverage is engineered, not hoped for.

Over-generate then aggressively select over trusting the teacher to be perfect

Quality comes from selection, not a flawless teacher. Generate a surplus, apply rule checks + an LLM judge, and discard hard — a smaller, cleaner dataset beats a larger, dirtier one for training.

Execute against tests where checkable over trusting a model-as-judge score for correctness

A judge is another model guessing whether code is right by reading it — subtle bugs read as plausible. Execution is objective evidence: code passes tests or it doesn’t. Reserve the judge for genuinely uncheckable quality.

Anchor training in real data over training recursively on unfiltered self-generated output

Recursively training on a model’s own synthetic output degrades quality and diversity over generations (model collapse). Mixing in real data, enforcing diversity, and verifying quality keeps the distribution honest.

The answer, out loud

What a strong answer to “Design a Synthetic Data Pipeline” sounds like, first question to last trade-off. It is about 7 minutes of talking; the whiteboard and the interviewer fill the rest of the 45. Read it aloud once, then close the page and give it yourself.

  1. 0–3 min

    Name what we actually want

    I'd start by saying what the deliverable actually is, because it isn't data. Human labeling is slow and expensive, and for a new task or a rare case there may be nobody to label at all — that is the reason we are here. But if I just prompt a model for ten thousand examples and hand that over, I have made things worse: the set is repetitive, it has wrong labels in it, and a model trained on it learns the narrowness and the mistakes. So the thing I am designing for isn't volume. It is diverse and correct examples. Generating is the easy part; everything after it is the system.

    Built in step 1: Repetitive and wrong
  2. 3–7 min

    The pipeline shape

    So I'd draw it as a pipeline with a spec at the front. The spec is the task, an output schema, a few seed examples and the constraints, and it steers everything downstream. Then the stages: generate, diversify, filter, verify, store. What I'd promise isn't volume — it is that whatever comes out is diverse, filtered and validated. The shape I keep in my head is generate-and-curate: over-produce cheaply, then select hard. Every stage after generation exists to remove one specific failure of raw output, so I can point at any box and say which failure it is there to kill.

    Built in step 2: The pipeline shape
  3. 7–12 min

    Pick a teacher, and seed it well

    For candidates I'd use a strong teacher model, usually bigger than whatever I am going to train, prompted with templates, the seed examples, and personas or roles to shape style and content. I can generate inputs, outputs, or both — a question and its answer — and if I want the data to teach reasoning I have the teacher produce the steps, not just the result. The part I'd spend real human time on is the seeds. There are few enough of them that I can read every one, and each gets copied into thousands of generations, so an hour spent fixing seeds buys more than a week spent reading what they produced.

    Built in step 3: Generation with a strong model
  4. 12–18 min

    Engineer the coverage

    Left alone the teacher repeats itself, and that is the number-one failure here. I wouldn't fix it by generating more from the same prompt — that deepens the collapse rather than curing it. I'd sweep an attribute space: topics, difficulty, style, personas, edge cases, so each call is aimed at a different region of the distribution. I'd raise the sampling temperature for variety inside a region, and de-duplicate near-identical outputs by embedding similarity. Lowering temperature would be exactly backwards. The point I'd want to land is that coverage here is engineered — it is a grid somebody authored — not something you hope falls out of a good prompt.

    Built in step 4: Steering diversity
  5. 18–24 min

    Over-generate, then select

    Even a good teacher produces malformed, off-task and mislabeled examples, and they read plausibly, so they slip in. My filter is a cost ladder. Rules and format checks run first because they are nearly free — schema valid, right length, on task. Then a model-as-judge scores whatever survives, and that is a model call on every candidate, including all the ones I am about to reject. So the number I'd size up front is the surplus: how many I generate for each one I keep is what sets the bill, not the size of the dataset I hand over at the end.

    Built in step 5: Quality filtering
  6. 24–30 min

    Prove it where proof exists

    Wherever there is a ground truth I'd stop asking a model's opinion and check. Generated code: run it against tests and keep what passes. Math: compute the answer. Factual claims: check them against a source, or require citations. A judge is another model guessing by reading, and a subtle bug reads as plausible — execution is evidence. So I'd reserve the judge for the genuinely uncheckable things, quality and style, and verify everything else directly. That is the difference between plausible and proven, and in code or math a wrong label is poison.

    Built in step 6: Verification & grounding
  7. 30–36 min

    What the data is for

    Three uses, and I'd rank them by how far I'd trust them. Distillation is the headline: train a smaller student on the teacher's outputs and capture much of the capability at a fraction of the cost. Augmentation is where I'd actually start if a real dataset already exists and only has holes in it — rare classes, edge cases, a task nobody has data for yet. Generated eval sets I'd be slowest to trust, and I'd say that out loud: a number produced by the same machinery it is measuring is not independent evidence. I'd keep that set small enough that a person reads every row before it scores anything.

    Built in step 7: Distillation, augmentation & evals
  8. 36–40 min

    The trade-off, and what is left

    The honest trade-off is that every gate I have added costs generations I throw away, and every one I drop shows up later as a model that is quietly worse. Filtering and verification are where the compute goes, and they are also the only reason the data is worth training on. The risks I'd name unprompted are model collapse — training recursively on self-generated output degrades quality and diversity, so I mix in real data and keep verifying — plus bias amplification, contamination, and the licensing terms on the teacher's outputs. And whatever the pipeline reports, I'd judge the student on real held-out data. With more time I'd close the loop: take the cells the student still fails on and aim the next round of generation at those, rather than producing more of what it already handles. I'd also make the case for not generating at all, because where real data exists and is cheap this pipeline is the expensive way to end up with a worse dataset.

What this teaches

Learn AI system design by building a synthetic data generation pipeline that uses LLMs to create training and eval data step by step. An interactive guide covering why naive generation is low-diversity and error-prone, generating with a strong teacher model, steering diversity to avoid mode collapse, quality filtering, verifying correctness, using the data for distillation/augmentation/evals, and the unhappy paths (model collapse, bias, contamination, licensing).

Key takeaways

  • Naive "generate N examples" gives low-diversity, error-prone data that degrades models.
  • The value is diverse + correct data; frame it as generate → diversify → filter → verify → store.
  • A strong teacher model generates candidates, steered by seeds, templates and personas.
  • Engineer diversity: attribute/topic/persona sampling + temperature + dedup to avoid mode collapse.
  • Over-generate and aggressively filter (rules + model-as-judge) so only good examples enter.
  • Verify correctness where checkable — execute code against tests, ground facts — beats judge-opinion.
  • Use it for distillation, augmentation and evals; guard against collapse, bias, contamination and licensing.

Concepts covered

  • What is a synthetic data pipeline?
  • Repetitive and wrong
  • The pipeline shape
  • Generation with a strong model
  • Steering diversity
  • Quality filtering
  • Verification & grounding
  • Distillation, augmentation & evals
  • Collapse, bias, contamination & rights
RUN IT YOURSELF

The coverage that four times the data does not buy back

Six generations of a generator trained on the previous generation's output, run two ways: one feeding purely on itself, one with a fixed share of fresh real data mixed into every generation. It prints the two numbers a team keeps on a dashboard beside the two that actually moved — then reruns the same loop at a quarter and four times the corpus, and again with truncation switched off, so you can see which one is doing the damage. Change REAL_SHARE, hit Run, and watch the tail come back.

HOW TO READ THE CODE — 5 IDEAS
  1. By generation 6 the pure arm holds 4 of 16 rare categories, and 8.5% of real traffic falls in categories it can no longer produce at all — not rarely, at all. The anchored arm holds 16/16 and 0.0% (step 8).
  2. Over those same six generations the mean score and the sd each move by under 2%, and that much is sampling noise. Every aggregate on the dashboard reads normal in both arms; only the two coverage columns separate them.
  3. It is not that the corpus is small. The last line reruns the pure arm at 2,000 / 8,000 / 32,000 rows per generation and the loss lands at 10.0% / 8.5% / 8.7% — nucleus truncation drops a fixed fraction of the mass every generation, so more data never dilutes it (step 4).
  4. Switch truncation off (top_p=1.0) and at this corpus size the pure arm loses nothing — 16/16, 0.0% blind. Sampling drift is the small-corpus story; the sampler is the one that survives scale.
  5. The loss is one-way: zero weight in, zero rows out, so support only ever falls. Mixing real data does not filter, judge or verify anything (steps 5–6) — it re-injects tail mass every generation, and that alone is the difference between the two halves of the table.
CPython · WebAssembly
built to manufacture good training data, not a million copies of the same example — make the calls, drop the filter, run the gauntlet.
Finished this one? 0 / 65 AI System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More AI System Designs