AnyLearn
All lessons
AIintermediate

Features, Feature Stores, and Training-Serving Skew

The most common way a good model fails in production is that the features it is served differ from the ones it was trained on. This lesson covers where that divergence comes from, why point-in-time correctness is harder than it looks, what a feature store actually solves, and when you do not need one.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 9

The bug that only exists in production

A model scores well offline. It ships. Live accuracy is materially worse, and nothing in the code has changed.

Google's MLOps guidance names the cause: training-serving skew, which occurs when the features used for training are different from the ones used during serving.

What makes this the hardest class of ML bug is that every component is behaving correctly. The training code is right. The serving code is right. The model is right. They simply disagree about what a feature means, and no test that examines one component in isolation can see a disagreement between two.

It is also silent. The model does not error on a skewed feature, it just returns a worse answer, and worse answers do not page anyone.

Full lesson text

All 9 steps on one page, for reading, reference, and search.

Show

1. The bug that only exists in production

A model scores well offline. It ships. Live accuracy is materially worse, and nothing in the code has changed.

Google's MLOps guidance names the cause: training-serving skew, which occurs when the features used for training are different from the ones used during serving.

What makes this the hardest class of ML bug is that every component is behaving correctly. The training code is right. The serving code is right. The model is right. They simply disagree about what a feature means, and no test that examines one component in isolation can see a disagreement between two.

It is also silent. The model does not error on a skewed feature, it just returns a worse answer, and worse answers do not page anyone.

2. Two implementations of one idea

The classic source of skew is writing the same feature twice.

Training runs offline over historical data, usually in Python or SQL against a warehouse. Serving runs online with a latency budget, often in a different language, against a different store. So average_order_value_30d gets implemented once by the data scientist and once by the backend engineer.

# training, over a warehouse table
feat = (orders
        .filter(orders.ts > now - timedelta(days=30))
        .groupby("user_id")
        .agg(avg("amount")))
-- serving, against the transactional store
SELECT AVG(amount) FROM orders
WHERE user_id = ? AND ts > NOW() - INTERVAL '30 days';

These look identical. They disagree if the warehouse excludes cancelled orders and the transactional store does not, if one counts in UTC and the other in local time, or if the warehouse lags by six hours.

3. The differences that actually bite

Skew is rarely one dramatic mistake. It is an accumulation of small definitional gaps, and these are the recurring ones.

SourceHow it shows up
Filter mismatchOne side excludes refunds, test accounts or bots
Time zoneDaily aggregates cut at different hours
FreshnessWarehouse lags, so training sees complete windows and serving sees partial ones
Null handlingTraining imputes a mean, serving sends a zero
Type coercionA string category becomes an integer index in a different order

The null and type rows cause the most damage per incident. If training imputed the column mean for missing values and serving sends 0, the model reads a missing value as a genuine extreme, and does so confidently.

4. Point-in-time correctness

There is a second, subtler failure that is not a mismatch between two systems but a mistake inside one.

When you build a training set, each row pairs a label with the features as they were at the moment of the prediction. It is easy to instead join the feature values as they are today. A user who churned last March gets a total_lifetime_orders computed now, which includes everything up to the present.

That is label leakage. The feature carries information from after the label, and the model learns a relationship that cannot exist at serving time. Offline accuracy looks superb, because you handed the model the answer. Live accuracy collapses.

This is why correct feature retrieval requires an as-of join against a full history, not a lookup of the current value.

5. One definition, three readers

The structural fix is not better discipline across two implementations. It is having one implementation that all three consumers read from.

flowchart LR
A["Raw data sources"] --> B["Feature definition, written once"]
B --> C["Offline store, full history"]
B --> D["Online store, latest values"]
C --> E["Experimentation"]
C --> F["Continuous training"]
D --> G["Online prediction"]

6. What a feature store is

Google's guidance introduces the feature store at MLOps level 1, and describes its purpose directly: it avoids training-serving skew by acting as the data source for experimentation, continuous training and online serving alike.

The mechanism is that one feature definition materialises into two stores with different shapes.

  • The offline store holds full history and is optimised for large scans with an as-of join, which is what training and backfills need.
  • The online store holds only the latest value per entity and is optimised for a single-key lookup in single-digit milliseconds, which is what a prediction request needs.

Both are generated from the same definition, so the two cannot drift apart the way two hand-written implementations do. A secondary benefit is reuse: a feature built for one model becomes discoverable rather than being rebuilt slightly differently for the next.

7. Data validation as a gate

A feature store makes the two sides agree. It does not tell you when the input itself has gone wrong, and that is a separate gate.

Data validation compares incoming data against an expected schema: the columns present, their types, the categorical values allowed, and the plausible range or distribution of each numeric field. At MLOps level 1 this runs automatically before training, and it can halt the pipeline.

Halting is the point. Without it, an upstream team renaming a category or a sensor returning zeros produces a model trained on corrupted input, which then passes model validation if the corruption is present in the evaluation set too.

The schema is also a contract you can diff. When it changes, someone made a decision, and now there is a record of it.

8. When you do not need a feature store

Feature stores are infrastructure, and infrastructure has a running cost. Several situations do not justify one.

  • Batch-only prediction. If you score once a night with the same code that trains, there is no second implementation, so there is no skew to prevent.
  • One model, few features. The coordination problem a feature store solves is mostly a problem of many teams and many models sharing definitions.
  • Features computed entirely from the request. If everything the model needs arrives in the prediction call, there is nothing to look up.

The cheaper intervention that works at any scale is to write each feature transformation once, as a shared library imported by both the training job and the serving path. That removes the duplicate implementation, which is the actual disease. A feature store is the version of that idea with storage and history attached.

9. How to find skew you already have

If a model is live and you suspect skew, you do not need new infrastructure to check.

Log the exact feature vector the serving path constructs, for a sample of real requests. Then take those same entities and timestamps, run them through the training feature pipeline, and compare the two vectors field by field.

Compare distributions, not just individual rows. A single row matching proves little, whereas a per-feature comparison of mean, null rate and category frequency between the logged serving values and the training values will surface a mismatched filter or a null convention immediately.

This logged-vector comparison is worth building before a feature store, because it also tells you whether you have a skew problem at all, and therefore whether the larger investment is justified.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. What is training-serving skew?
    • The features used for training differ from the ones used during serving
    • The training set is drawn from a different time period than the test set
    • The model is trained on a GPU but served on a CPU
    • Training labels are imbalanced relative to production traffic
  2. Training imputes the column mean for a missing value; serving sends 0. What does the model see?
    • An error, because the type does not match the schema
    • Nothing, since most models ignore zero-valued features
    • A genuine extreme value that it treats with full confidence
    • A missing value, because 0 is the standard null encoding
  3. A training row for a user who churned in March uses their lifetime order count computed today. What has gone wrong?
    • A time zone mismatch between the two stores
    • Label leakage, because the feature contains information from after the label
    • A schema violation that data validation should have caught
    • The online store was queried instead of the offline store
  4. Why does a feature store keep an offline and an online store rather than one?
    • To keep a backup in case the primary store fails
    • Because regulations require training data to be stored separately
    • To let the data science and engineering teams own one each
    • They have different access patterns: history scans with as-of joins versus single-key lookups in milliseconds
  5. Which situation least justifies adopting a feature store?
    • A nightly batch job that scores using the same code that trains the model
    • Twenty models across four teams sharing overlapping feature definitions
    • A real-time service needing user aggregates within a few milliseconds
    • A team repeatedly finding mismatches between training and serving values

Related lessons