ML Systems Lab Open interactive version →
Intermediate 29 min read training-serving skewproduction MLfeature drift

Training-Serving Skew

Definition, causes, detection, remediation

Your fraud model scored beautifully in offline testing. In production it is 15% worse. The features look right. No exception is thrown. The pipeline reports success every hour. So what broke?

One feature broke: "number of transactions in the last 7 days." At training time you computed it from a historical database — exact counts, every transaction, counted precisely. In production it comes from a real-time streaming service that counts *approximately* to stay fast (it uses a probabilistic sketch under the hood). The two numbers are close but not equal. For high-volume power users the gap is big enough to move the prediction — and those are exactly the users most likely to be committing fraud. The model learned from exact counts and is now judging approximate ones — the same kind of gap opens up when a scaler fit during training gets silently refit at serving time and lands on different numbers entirely. That mismatch has a name: training-serving skew.


Why this is so dangerous: it is completely silent

No alarm sounds when the database says 47 and the stream says 43. Nothing crashes. The model just quietly gets a little worse. And this is not some rare, big-company problem — it appears the moment your training code and your serving code are two different pieces of code. A two-person team with a scikit-learn model and a Flask endpoint has exactly the same exposure as a giant org. What matters is not infrastructure size; it is whether the feature is computed by *the same logic* in both places — not similar logic, the same logic.


The five ways skew sneaks in

*Different code:* training in Python, serving in Java — rounding and null-handling differ, and tiny differences compound. *Different freshness:* training reads a complete history offline; serving reads a real-time value that is slightly stale or approximate. Serving quietly reorders columns while the model expects a fixed layout — that's *schema drift*. *Preprocessing mismatch:* the scaler was fit on training data (mean 120, std 45) but serving refits it or loads defaults, so the numbers land in a totally different range. A training feature used information that won't exist at serving time, inflating the offline score against data the model will never actually see — that's *leakage*.


The fix is structural, not a patch

Build one feature-computation layer that both training and serving call — a feature store. The *same function* counts transactions whether you are assembling a training set or answering a live request, so four of the five root causes simply cannot occur. To catch anything left over: record the exact features every production request saw alongside its prediction, then re-score those logged features offline and compare to real production results — the same check as re-running last week's fraud-flagged requests through today's model to see if the scores still line up. Any gap is skew, measured directly. That technique — record in production, replay offline — is called *log-and-replay*. The core idea: a model cannot fix bad inputs — the only durable defense is making the two codepaths *the same code.*

Key points

Takeaway

Training-serving skew is an infrastructure problem, not a modeling problem. A model cannot compensate for receiving different feature values than it was trained on. Two separately maintained codepaths will always drift. The only reliable fix is a single shared computation function with serialized preprocessing parameters — anything else is relying on discipline that will eventually fail at the worst moment.

Recap

Check your understanding

Q1. Your model predicts churn well offline but performs randomly in production, though aggregate feature distributions look similar. Select the two mechanisms most likely to explain this.

Q2. You find that a "user_7d_purchase_count" feature has PSI=0.35 between training and production. What is the investigation and remediation process?

Q3. A model is trained with a StandardScaler fit on training data. How do you ensure the scaler is applied correctly at serving, and what goes wrong if it is not?

Q4. A model trained on historical data uses a "days_since_last_login" feature. At training time, this was computed relative to today's date. Explain the skew this creates and how to fix it.

Try it interactively

ML Systems Lab is a free interview-prep platform for ML engineers — work through the full interactive module, quizzes, and drills.

Open ML Systems Lab →