4 min readMachine learningMLOpsProduction

Why ML prototypes stall before production: seven failure modes

A demo that works is not a system that works. The gap between the two is filled with problems that have nothing to do with model architecture, and teams keep discovering them one sprint at a time.

There is a familiar shape to stalled machine learning work. The notebook produces good numbers. The demo lands well. Then the launch date moves, and moves again, and nobody can point at a single blocking problem — because there isn't one. There are seven, and they surface in roughly the same order every time.

None of them are about model architecture. That is the part most teams get right, because it is the part they enjoy and the part the literature covers. What follows is everything else.

1. There is no evaluation set, only a vibe

The prototype was judged by looking at outputs. That works for twenty examples and collapses at two hundred. Without a held-out set with agreed labels, nobody can answer the only question that matters before launch: is this version better than the last one? Teams end up relitigating the same disagreement every review, because there is no shared instrument to settle it.

The fix is unglamorous and cheap relative to its value: build the evaluation set before tuning anything. Two hundred labelled examples that reflect real traffic beat twenty thousand scraped ones. Version it alongside the model, and treat a change to the evaluation set as a change requiring the same scrutiny as a change to the code.

2. The prototype's data pipeline does not exist in production

In the notebook, the features came from a CSV that someone assembled by hand over two days. In production they have to be computed live, from systems that are sometimes slow, occasionally down, and rarely in the shape the notebook assumed. This is training-serving skew, and it is the single most common reason a model that scored well offline behaves badly in front of users.

3. Latency was never a requirement, so it was never measured

A model that takes 900ms is fine in a notebook and unusable inside a checkout flow. Latency budgets are rarely stated up front, so they get discovered during integration, at which point the options are all expensive: a smaller model, a caching layer, an asynchronous redesign of the surrounding feature, or shipping something slow.

Stating the budget early changes which model you pick, which is exactly why it belongs at the start rather than the end.

4. Nobody owns what happens when the model is wrong

Every model is wrong sometimes. The design question is what the product does about it, and it is a product question rather than a modelling one. Silent failure is the default when nobody decides, and silent failure in a system users trust is how a technical problem becomes a support problem.

  • Low-confidence predictions route to a human queue rather than through to the user
  • Irreversible actions require confirmation regardless of confidence
  • The user can see that a decision was automated, and can contest it
  • Every override is logged, because overrides are the highest-signal training data you will ever get

5. Inference cost is discovered on the invoice

This one arrived with large language models and has not left. Cost per request is trivial to measure and almost never measured, so it compounds quietly until it appears as a line item somebody has to explain. By then the architecture assumes the expensive path.

Measuring cost per request from the first week changes design decisions while they are still cheap to change: routing simple requests to smaller models, caching aggressively at the semantic level, and setting a hard spend alert that fires before the finance conversation does.

6. There is no path to the next version

The first deployment gets all the attention. The second one reveals that shipping a model version is a manual, half-documented ritual involving one person's laptop. So it does not happen, the model ages, and performance decays in a way nobody is watching for.

Deployment should be boring before it is needed: versioned artefacts, a rollback that has actually been tested, and a shadow or canary path so a new version can be compared against the live one on real traffic rather than on faith.

7. Monitoring watches the servers, not the model

Infrastructure monitoring is usually in place — CPU, memory, error rates, uptime. All of it can be green while the model quietly degrades, because a model does not crash when it becomes wrong. It keeps answering, confidently, with worse answers.

  • Input distribution drift against the training baseline
  • Prediction distribution shift, which often moves before accuracy does
  • Delayed accuracy, measured once ground truth arrives
  • Human override rate, the cheapest early warning most teams already have and do not track

The pattern underneath all seven

Every item on this list is operational, not scientific. That is the actual lesson: the hard part of machine learning in production is production. A team that treats the model as the deliverable will keep rediscovering these one sprint at a time, and each rediscovery costs a release date.

A useful discipline is to write the runbook before the model is finished. If you cannot describe how a new version ships, how a bad prediction is caught, and who is paged when quality drops, the system is not ready — regardless of what the offline metrics say.

Related services

Ready when you are

Have a project in mind? Let's talk about it.

Send us a short description of what you're building or what's broken. We'll reply within a day with honest thoughts on scope, approach, and whether we're the right fit.