Your AI demo looks amazing. The CEO is impressed. The investor deck has a screenshot. Everyone agrees: ship it.
Then real users show up, and everything breaks.
This isn't a bug. It's a fundamental measurement problem. Demo prompts test the center of the distribution. Production traffic lives in the tails.
I've watched this play out enough times to predict it before launch. The team runs the same 15 prompts after every change. All 15 pass. Confidence goes up. Then real traffic arrives, and the metric that looked so good in the meeting room turns out to have measured almost nothing.
The Demo-Production Gap
I've tested GPT-5.1, Claude 4.5, Gemini 3 Pro, and several other frontier models across thousands of evaluation scenarios. Here's what I consistently see:
- Demo accuracy: 92-97% on curated, well-formed prompts
- Production accuracy: 61-78% on real user inputs with typos, ambiguity, and edge cases
That 20-30 point gap is where AI products go to die.
The important thing about that gap: it's roughly stable across models. Swapping GPT-5.1 for Claude 4.5 or Gemini 3 Pro moves both numbers a few points, but the gap itself stays. That tells you it isn't a model problem. It's a measurement problem. You can't close it by upgrading the model — only by upgrading what you test.
There's a name for the underlying phenomenon: distribution shift, and it's the core reason demos don't predict LLM production quality. Your evaluation set is drawn from one distribution — prompts written by insiders, about known use cases, in clean English. Your traffic is drawn from another: everything else. A 95% score on the wrong distribution isn't an approximation of the truth. It's a different question with a similar-looking answer.
Why Demos Deceive
1. Cherry-Picked Inputs
Demo prompts are written by the people who built the system. They unconsciously avoid the patterns that break it. They use correct terminology, clear intent, and reasonable scope.
Real users don't do this. They write "fix the thing from yesterday" and expect the AI to know what they mean.
This is a selection effect, and it compounds. Every time a prompt fails during development, someone tweaks it until it passes — and the tweaked version goes into the demo set. Six months in, your "test set" is a collection of prompts that have co-evolved with your system. It's the equivalent of training on your test data, done socially instead of computationally.
The tell is that nobody can explain why the demo prompts are phrased the way they are. "Summarize the following meeting notes into action items, one per line" isn't how anyone talks. It's how a prompt looks after it's been debugged.
2. Narrow Distribution
A demo set of 20 prompts covers maybe 5% of the input space. The other 95% includes:
- Multilingual inputs and code-switching
- Copy-pasted content with formatting artifacts
- Extremely long or extremely short queries
- Ambiguous requests that could mean 3 different things
- Requests that are slightly outside the agent's scope
Here's the part demos structurally can't cover: the tail is not a smaller version of the head. Failure modes in the tail are qualitatively different. A model that handles a clean 200-word email perfectly can lose the thread entirely on a 6,000-word forwarded chain with quoted replies, signatures, and a legal disclaimer pasted three times. Nothing in the head of the distribution predicts that.
3. No Adversarial Pressure
Demo prompts don't test what happens when the model is wrong but confident. They don't test what happens when the user pushes back. They don't test what happens at the boundary between "I can help with this" and "I can't help with this."
That boundary is where user trust is won or lost. A model that answers 95% of in-scope questions well but confidently fabricates on the 5% that are out of scope will feel worse to users than one that answers 85% well and clearly declines the rest. Demos never measure this, because demo authors don't ask out-of-scope questions.
4. Prompt Sensitivity
LLMs are far more sensitive to surface form than most teams expect. Reordering two sentences, switching "please summarize" to "give me a summary," or pasting the same content with different whitespace can flip an output from correct to wrong. Published work on prompt-format sensitivity has shown swings of several percentage points from formatting changes alone, and I see the same thing in my own evals.
A demo prompt is one point in that sensitivity landscape — usually a lucky one. Production sends you thousands of nearby points, and some fall off a cliff you never knew was there. If you haven't tested paraphrases of your core prompts, you don't know your accuracy. You know your accuracy at one phrasing.
How Demo and Production Diverge in Practice
When I compare an LLM demo vs production traffic for the same system, the same divergence patterns show up again and again:
The vocabulary cliff. Demos use the product team's vocabulary. Users use their own. A support agent tested with "I'd like to request a refund for order #4521" meets "hey i got charged twice??" — same intent, completely different surface form, very different outcome.
The context collapse. Demo prompts are self-contained. Real requests depend on context the model doesn't have: a previous ticket, an earlier conversation, a screenshot the user is looking at but didn't share. The model either asks (good) or guesses (common).
The compounding-turn problem. Demos are single-turn. Real conversations run five, ten, fifteen turns, and errors compound: a small misunderstanding at turn 2 quietly poisons everything after it. Per-turn accuracy of 95% over ten dependent turns is nowhere near 95% end-to-end.
The instruction-drift problem. Users ask for something slightly outside what the system prompt anticipated, and the model tries to be helpful anyway — leaving its guardrails behind in the process. Every scope boundary you didn't test is a boundary the model will improvise.
The format-artifact problem. Real inputs arrive with smart quotes, broken Unicode, Markdown pasted from one app into another, tables flattened into word soup. None of it appears in demo prompts. All of it appears in logs.
What to Do Instead
Build a Stratified Test Set
Don't test 100 prompts from the same distribution. Test 20 prompts from 5 different distributions:
- Happy path (what demos test)
- Edge cases (unusual but valid inputs)
- Boundary cases (at the limits of capability)
- Adversarial (actively trying to break it)
- Real user samples (messy, ambiguous, imperfect)
The methodology I use to build these sets:
- Mine real traffic first. If you have any production or beta logs, sample from them randomly — not the interesting ones, random ones. Random sampling is the only thing that shows you the actual distribution instead of the distribution you remember.
- Cluster and cover. Group sampled inputs by intent and by surface form. Cover every cluster that carries more than roughly 2% of traffic, weighted by frequency.
- Write perturbations, not just prompts. For each core case, add a paraphrase, a typo'd version, a version with pasted formatting junk, and a longer version buried in irrelevant context. This directly measures prompt sensitivity.
- Recruit outsiders for adversarial cases. The people who built the system are the worst at breaking it. Give someone uninvolved thirty minutes and log everything they try.
- Define grading before collecting outputs. Decide what "pass" means per case — exact match, rubric, or an LLM judge with a written rubric — before you see any model outputs. Otherwise you'll grade toward whatever the model happens to produce.
A Sample Eval Case Structure
Every case in my eval sets carries the same fields:
{
"id": "refund-typo-014",
"stratum": "real_user_sample",
"input": "hey i think i got charged 2x last week?? can u check",
"context": { "user_has_duplicate_charge": true },
"expected_behavior": "Acknowledge, confirm the duplicate charge, explain refund steps",
"must_not": ["invent order numbers", "promise a refund timeline not in policy"],
"grading": "rubric",
"source": "sampled from support logs",
"added": "2026-05-18"
}The two fields teams skip — and shouldn't — are must_not and source. must_not catches confident fabrication, which pass/fail grading on the happy answer misses entirely. source tells you whether your set is still anchored in reality or has drifted back into invented prompts.
At the set level, keep a simple coverage ledger:
| Stratum | Cases | What it catches |
|---|---|---|
| Happy path | 20 | Regressions on core flows |
| Edge cases | 20 | Format artifacts, length extremes, code-switching |
| Boundary cases | 20 | Scope limits, capability edges |
| Adversarial | 20 | Confident fabrication, guardrail drift, pushback |
| Real user samples | 20 | Everything you didn't think of |
A hundred well-stratified cases beats a thousand happy-path ones — and it's small enough to actually maintain.
Measure the Right Things
Accuracy on demo prompts is a vanity metric. Instead measure:
- Failure rate on real inputs: What percentage of real user queries produce wrong or unhelpful outputs?
- Confidence calibration: When the model says it's 90% sure, is it right 90% of the time?
- Graceful degradation: When it can't help, does it say so clearly?
And report results per stratum, never as one blended number. A blended score lets a strong happy path hide a broken tail — exactly the failure mode the stratified set exists to expose. "94% overall" is less useful than "99% happy path, 88% edge, 61% adversarial." The second version tells you where to work.
Test Continuously
One evaluation isn't enough. Models update. User behavior shifts. New edge cases emerge. Set up automated evaluation that runs daily against a growing test set.
Two habits make this sustainable. First, every production failure becomes an eval case within a day — that's how the set grows toward the true distribution instead of away from it. Second, pin and version everything: model version, system prompt, eval set version. When a score moves, you need to know whether the model changed, the prompt changed, or the test changed. Without versioning, a moving score is just noise you'll argue about in Slack.
FAQ
Isn't this just overfitting with extra steps? Essentially, yes — demo sets are overfitting done by humans. The prompts co-evolve with the system until they pass, which makes them a training set wearing a test set's badge. The fix is the same as in ML: keep a held-out slice of real, randomly sampled inputs that nobody tunes against.
I don't have production traffic yet. How do I build a realistic eval set? Use the closest proxy available: run a small beta, mine support tickets from the pre-AI version of the workflow, or have people outside the team attempt real tasks while you log everything. Treat your v1 set as provisional and rebuild it from real logs within the first month after launch. An imperfect sampled set still beats a polished invented one.
How big does the eval set need to be? Smaller than most teams fear. Around 100 stratified cases catches the majority of failure patterns and is cheap enough to run on every change. Coverage across strata and steady growth from real failures matter more than raw size. Scale up only when you need statistical confidence on small deltas between models or prompts.
Can I use an LLM to judge the outputs? Yes — at any real volume you'll have to — but calibrate it. Hand-grade a sample of 50-100 outputs, measure agreement between the judge and your own grades, and re-check whenever you change the judge's model or rubric. An unvalidated judge just moves the demo-prompt problem up one level: now your evaluator is the thing that looks right but was never tested.
The Bottom Line
If you're evaluating your AI with demo prompts, you're measuring the wrong thing. You're confirming it works in the lab. You need to know if it works in the wild.
The difference between a successful AI product and a failed one isn't model quality — it's evaluation quality.
---
*Running demo prompts and hoping for the best? Let's talk about building a real evaluation pipeline.*
