Module 5: Failure Modes and Resilience for AI
Drift: the silent degradation
Overview
Every failure you've seen so far happens in an instant: the model goes down now, hangs now, hallucinates in this response. There's a moment when you can say "it failed here". Drift is different and that's why it's treacherous: it doesn't happen at any one moment; it happens over weeks. The model or the data change little by little, and the system's quality degrades so gradually that there's never a "it broke" —today it gets 94% right, next week 93%, in a month 79%, and since each step is tiny, no one notices—. It doesn't throw an exception, it doesn't show up in an error log, it doesn't trip any of the alarms you've set. It's a hallucination distributed over time. This lesson installs the module's last failure mode and its only possible defense: because drift is silent and slow, the only way to detect it is to measure quality continuously —run the module 3 eval in production, week by week, and fire an alert when the score drops—.
In lesson 2 you classified drift as the temporal failure (silent, slow). Here you develop it. You'll see, executed, the eval of Mercado's semantic search drop from 0.94 to 0.75 over seven weeks —as queries from new product categories that the model handles worse arrive— and a monitor that detects the drop and fires an alert in week 4, two weeks before users start to complain. The difference between finding out from a metric or finding out from a complaint.
Connection with the module. This lesson closes the catalog of failure modes: together with availability (L4-L6, noisy) and hallucination (L3, silent and instantaneous), drift completes the map as the silent and slow failure. And it builds a bridge to module 7: monitoring drift is the first stitch of the data loop —observing quality in production to know when the system needs maintenance—. It directly reuses the module 3 eval: that eval was a gate that ran when you changed the prompt or the model; here the same eval runs continuously in production, as a health monitor. The boundary with AI Engineering: here drift as an architectural property to monitor; the statistical mechanics of detecting a shifting distribution, and how to retrain, belong to AI Engineering.
An analogy: the frog in the pot and the temperature gauge
There's an old metaphor about a frog in a pot of water: if the water heats up all at once, the frog jumps and saves itself; if it heats up very slowly, degree by degree, the frog never perceives the change —each instant feels almost the same as the previous one— and doesn't jump until it's too late. True of frogs or not, it precisely describes how a team misses drift: on no day is the system noticeably worse than the day before, so on no day does an alarm go off in anyone's head, and by the time the degradation is obvious, you've already been serving bad quality for weeks. The sudden failure (the boiling water all at once) makes you jump; the gradual failure (the water heating slowly) cooks you without your noticing.
What saves the frog? Not better intuition —intuition is exactly what fails with gradual changes—. A thermometer saves it: an instrument that measures the temperature objectively, number by number, and a clear rule ("if it goes above 40 degrees, jump"). The thermometer isn't fooled by the gradualness of the change, because it doesn't compare each instant to the previous one (where the change is imperceptible); it compares against a fixed reference (the 40 degrees, or the initial temperature). Degree 38, 39, 40 —and the alarm sounds— even though each individual step was a single degree.
Here's the point: drift cooks you like the frog, and the only defense is the thermometer —a continuous measurement of quality against a fixed reference, with a clear alert—. You can't detect drift by "paying attention" or "checking now and then", because the degradation is too gradual for intuition and too slow for an occasional review. You need to run the eval (your quality thermometer, from module 3) automatically and periodically in production, compare each measurement against the baseline (the quality the system launched with, your fixed reference), and fire an alert when the drop crosses a threshold. In Mercado, it's the difference between a dashboard that warns you "search dropped from 0.94 to 0.88, check it" and a ticket from an angry customer three weeks later asking why search "doesn't find anything anymore".
Worked example: the monitor that catches the drift
Let's simulate seven weeks of semantic search operation. Each week we run the eval in production and get a score. The score drops little by little —from 0.94 to 0.75— because something real is happening: more and more queries from new product categories arrive (Mercado added categories the model didn't handle well), and that fraction rises from 2% to 45%. That's the input drift that causes the output drift: the incoming data change, and the output quality degrades.
The monitor compares each score against two rules: an absolute one (alert if the score drops below 0.85) and a relative one (alert if it drops 5 points or more relative to the 0.94 baseline). It fires the alert the first week it crosses either of the two. We contrast with the "no monitoring" scenario, where no one notices anything until users complain (let's suppose, week 6).
# Lesson 7: DRIFT. The model or the data change over time and quality
# degrades SILENTLY (no exception, no outage: just a score that drops).
# The only defense is to MEASURE over time: run the M3 eval week by week
# in production and fire an alert when it drops.
# Drift / monitoring in depth: Chip Huyen, AI Engineering.
# Eval-gate score run every week in production (simulated). Drops little
# by little: NEW product categories arrive that the model handles worse.
WEEKLY_EVAL = [0.94, 0.93, 0.92, 0.88, 0.83, 0.79, 0.75]
# Fraction of queries in NEW categories (the cause of the drift): rises.
NEW_CATEGORY_SHARE = [0.02, 0.04, 0.08, 0.17, 0.28, 0.37, 0.45]
BASELINE = 0.94 # the score when the system went to production
ABS_THRESHOLD = 0.85 # alert if the score drops below this
REL_DROP = 0.05 # or if it drops >= 5 points vs baseline
# Without monitoring, no one notices anything until users complain; suppose
# the complaint arrives in week 6 (when the score is already at 0.79).
COMPLAINT_WEEK = 6
first_alert = None
print(f"{'week':<8}{'eval':<8}{'new(%)':<12}{'drop vs base':<15}monitor")
print("-" * 56)
for w, (score, share) in enumerate(zip(WEEKLY_EVAL, NEW_CATEGORY_SHARE), start=1):
drop = BASELINE - score
alert = score < ABS_THRESHOLD or drop >= REL_DROP
status = "ALERT" if alert else "ok"
if alert and first_alert is None:
first_alert = w
print(f"{w:<8}{score:<8.2f}{share * 100:<12.0f}{drop:<15.2f}{status}")
print("-" * 56)
print(f"With monitoring : the alert fires in week {first_alert} "
f"(drop of {BASELINE - WEEKLY_EVAL[first_alert - 1]:.2f} vs baseline).")
print(f"No monitoring : no one notices until the user complaint in week "
f"{COMPLAINT_WEEK}.")
print(f"Monitoring detected the drift {COMPLAINT_WEEK - first_alert} weeks earlier, "
f"with the score still at {WEEKLY_EVAL[first_alert - 1]:.2f} (not at "
f"{WEEKLY_EVAL[COMPLAINT_WEEK - 1]:.2f}).")
What to expect. When you run the file, the output is exactly this:
week eval new(%) drop vs base monitor
--------------------------------------------------------
1 0.94 2 0.00 ok
2 0.93 4 0.01 ok
3 0.92 8 0.02 ok
4 0.88 17 0.06 ALERT
5 0.83 28 0.11 ALERT
6 0.79 37 0.15 ALERT
7 0.75 45 0.19 ALERT
--------------------------------------------------------
With monitoring : the alert fires in week 4 (drop of 0.06 vs baseline).
No monitoring : no one notices until the user complaint in week 6.
Monitoring detected the drift 2 weeks earlier, with the score still at 0.88 (not at 0.79).
Read the table week by week, because it shows the drift happening.
No abrupt jump, just a descent. Look at the eval column: 0.94, 0.93, 0.92, 0.88, 0.83, 0.79, 0.75. In no pair of consecutive weeks is there a dramatic drop —the largest is from 0.92 to 0.88, barely 4 points—. If you compared each week only with the previous one, you'd never see anything alarming; each step is "a bit worse, nothing serious". That's the frog's trap: the week-to-week change is imperceptible. But look at the drop vs base column, which compares against the fixed reference (0.94): 0.00, 0.01, 0.02, 0.06, 0.11, 0.15, 0.19. Against the baseline, the degradation is undeniable —by week 7, the system lost almost 20 points of quality—. The thermometer's lesson: compare against a fixed reference, not against the previous step, because drift is only visible in the accumulated distance.
The cause is in plain sight: the input drift. The new(%) column tells you why the quality drops: the fraction of queries in new categories rises from 2% to 45%. The model didn't change (it's the same one), but the data reaching it changed —Mercado grew, added categories, and the queries moved toward terrain the model handles worse—. This is key: drift doesn't always come from "the model degrading"; it often comes from the world changing while the model stays fixed. The search that was excellent for the catalog of six months ago is mediocre for today's catalog, without anyone touching the model. That's why monitoring looks both at the output (the eval) and the input (the query distribution): a change in the input anticipates the drop in the output.
The monitor fires in week 4, the complaint arrives in week 6. Here's the measured value. The monitor crosses the relative threshold (drop of 0.06 ≥ 0.05) in week 4, with the score still at 0.88 —still decent—. Without monitoring, the team finds out from a user complaint in week 6, when the score is already at 0.79 —a severe degradation that already affected many customers—. Monitoring detected the problem 2 weeks earlier, and —more importantly— detected it while the quality was still recoverable, not after weeks of accumulated bad experience. Those two weeks are the window to react: investigate the cause (the new categories), adjust the system (better prompt, RAG with the new catalog, retrain —AI Engineering work—) before the damage is large.
The architectural implication: drift is the only failure mode you can't catch at the moment of the request; you only catch it by measuring the trend. Against an outage you put a fallback in the request; against a hallucination you put a verification in the request; but against drift there's nothing to put in the individual request —each response drifts a little, none is "broken"—. The defense lives in another dimension: in time, with a monitor that runs the eval periodically and compares against the baseline. Without that monitor, drift is invisible by design.
Going deeper: monitoring the health of an AI component
Two kinds of drift, one same defense. It's worth distinguishing where the degradation comes from, because it changes the response:
- Data drift: the input data change distribution. In the example, the queries move toward new categories. The model didn't change; the world did. It's the most common and the one the example simulates.
- Model drift: the model itself changes behavior. Watch out for a very real case of AI-native systems: you depend on a provider's model API, and the provider updates the model behind the same version or deprecates the one you were using. Your prompt, tuned for yesterday's model, performs differently with today's —without you changing a line—. This is a failure mode specific to depending on a model served by a third party, and it's only detected by measuring.
The defense is the same for both: measure quality over time with the eval. The cause differs (and that's why you also measure the input distribution, to know whether it's data drift), but the detector is the same thermometer.
The module 3 eval, now in production and continuous. This is the connection that closes the arc. In module 3, the eval was a gate that ran when you changed something (a new prompt, a new model) —a fitness function that blocked a deploy that lowered quality—. Here the same eval runs without you changing anything, continuously in production, because drift degrades quality even if you touch nothing. It's the same instrument with two uses: in CI, it catches the regression you introduce; in continuous production, it catches the regression time introduces. A good AI-native system runs its eval in both places.
How to set the threshold: absolute and relative. The example's monitor uses two rules, and it's worth understanding why both:
- Absolute threshold (score < 0.85): "below this quality, the system isn't acceptable, no matter where it comes from". It's a hard floor.
- Relative threshold / drop vs baseline (drop ≥ 0.05): "it dropped too much relative to how it launched, even if it's still above the floor". It catches drift early, while the absolute score is still decent. In the example, the relative rule fired in week 4 (0.88, still above the 0.85 floor); the absolute one wouldn't have fired until week 5 (0.83). The relative rule gives you the extra window.
Together: the relative one warns you early about a trend, the absolute one marks the "this is now unacceptable" point. Drift is caught better with the relative one, because it attacks the problem —the gradual degradation— on its own terrain: the accumulated distance against the reference.
What you monitor, beyond the score. The eval is the heart, but good monitoring of an AI component looks at several signals, and this builds the bridge to module 7 (observability for AI):
- Quality: the eval score (the core of this lesson).
- Input distribution: are the queries changing? (the example's
new(%)) —a change here anticipates the quality drop—. - Availability: rate of noisy failures, timeouts, 429 (from lessons 4-6).
- Degraded proportion: what fraction of responses was served by fallback (from lesson 5) —a sustained spike is a sign of trouble—.
- Cost and latency: tokens and ms per request (from module 2) —a cost drift also exists—.
Quality drift is the focus of this lesson, but all these signals live on the same dashboard, and module 7 integrates them into the complete data loop.
Common mistakes
Not monitoring quality in production. What happens: the team runs the eval once before launch, it comes out 0.94, declares it good, and never measures it in production again; six months later quality is 0.75 and no one knows until the complaints pile up. Why it happens: the eval is thought of as a launch test (is it ready?) and not as a continuous monitor (is it still healthy?). The system passed the test once and was assumed stable. How to detect it: you don't have a recent quality score for your AI component in production; the last eval is from launch day. How to fix it: run the eval periodically and automatically in production, save the series, and alert when it drops. The example measures it: the monitor caught the drift 2 weeks before the complaints.
Comparing only with the previous step (and not seeing the drift). What happens: the team does look at the weekly score, but only compares each week with the previous one —"it dropped from 0.92 to 0.88, barely 4 little points, normal"— and never against the baseline, so the accumulated degradation goes unnoticed week after week. Why it happens: the step-by-step comparison is the natural intuition, and it's exactly the one drift defeats (each step is small). How to detect it: your alert is based on the change relative to the previous measurement, not relative to a fixed reference. How to fix it: always compare against the baseline (the reference quality), not against the previous step —it's the thermometer that measures against the 40 degrees, not against the degree from a minute ago—. The example uses the relative-vs-baseline rule precisely for this.
Confusing a blip with drift (or vice versa). What happens: two symmetric errors. One: a one-day spot drop (a blip from a rare traffic spike) fires a drift alarm and the team chases a ghost. Two: a sustained drop is ignored on the belief that "it's surely noise" until it's too late. Why it happens: a one-off variation isn't distinguished from a trend. How to detect it: your monitor reacts to a single point, or ignores a sustained descending series. How to fix it: drift is a sustained trend, not a point —use a moving average or require the drop to persist for several measurements before alerting on drift, and reserve the "one bad point" alert for large drops—. The statistics of distinguishing signal from noise in a series is AI Engineering territory; for architecture, it's enough to retain that drift is a trend, and that the monitor should look at the series, not the point.
Exercises
Exercise 1 — Absolute vs relative. In the example, the alert fired in week 4 by the relative rule (drop of 0.06 ≥ 0.05), not by the absolute one (0.88 is still above the 0.85 floor). Explain what would have happened if the monitor had only the absolute rule, in which week it would have fired, and why having the relative rule is valuable for catching drift.
See solution
If the monitor had only the absolute rule (alert if score < 0.85), it would have fired in week 5, which is when the score (0.83) drops below the 0.85 floor for the first time —in week 4 the score is 0.88, still above, so the absolute rule doesn't fire—.
Having the relative rule is valuable for catching drift because it detects the trend before the score crosses the absolute floor. Drift is a gradual degradation; by the time the score drops below an "unacceptable" floor (0.85), you've already been degrading for weeks. The relative rule looks at the accumulated distance from the baseline (0.94), so it fires as soon as the drop is significant (0.06), even if the absolute value is still decent. That gives you the extra window —in the example, a week earlier; in a slower drift, it could be several— to investigate and react while quality is still good. The absolute rule tells you "it's already unacceptable"; the relative one tells you "you're heading in a bad direction, address it before it becomes unacceptable". For drift, the second is the one that matters.
Exercise 2 — The cause behind the score. The example shows two series: the eval (which drops) and new(%) (which rises). Explain the causal relationship between them, why the model "didn't change" but quality did drop, and what design action you'd take upon seeing this correlation (remember the boundary: the mechanics of the solution are AI Engineering, but the decision is architectural).
See solution
The causal relationship: the fraction of queries in new categories (new(%)) rises from 2% to 45%, and the model handles those new categories worse (they weren't well represented when the system was designed/tuned), so as more queries fall into terrain the model handles poorly, the average eval drops. The input drifts (data drift) and drags the output quality down.
The model "didn't change" —it's literally the same model with the same prompt— but quality dropped because the world changed around the model: Mercado grew, added categories, and users' queries moved toward that new terrain. The quality of an AI system isn't a property of the model alone; it's a property of the model against the data distribution that actually reaches it, and that distribution changes over time even if the model is frozen. A system excellent for the January catalog can be mediocre for the July one without anyone touching it.
The design action upon seeing this correlation (the architectural decision): recognize that the system needs to update to cover the new categories, and decide how at the design level —better prompt with examples from the new categories?, RAG that gives the model the context of the current catalog?, retrain/fine-tune with the new data?—. That choice between prompt/RAG/fine-tune is exactly the architectural decision of module 7. The mechanics of implementing it (how the RAG is built, how the fine-tune is done) is AI Engineering. What's architectural here is: (1) having the monitor that detects the drift, (2) looking at the input signal to diagnose the cause, and (3) deciding the update strategy. Drift isn't "fixed" once: it's monitored to know when the system needs maintenance, which is the module 7 loop.
Exercise 3 — Provider drift. A case of drift specific to depending on an external API: your model provider silently updates the model behind the version you use, or deprecates the one you were using and migrates you to another. Explain how this "model drift" would manifest in your monitor (gradual or all at once?), why your continuous eval would catch it even though you didn't change anything, and what design practice reduces the risk of a forced migration.
See solution
How it would manifest: unlike data drift (gradual), a provider's model change tends to manifest all at once —there's a day before and a day after—: the eval is stable at, say, 0.92 for weeks, and from one day to the next it jumps to 0.85 (or even rises, if the new model is better for your case, but it changes). It's a step, not a slope. Your prompt, tuned for the old model's behavior, performs differently with the new one.
Why the continuous eval would catch it even though you don't change anything: precisely because the eval measures the output quality in production, not "whether you deployed something". The monitor doesn't know or care why the quality changed; it detects that the score dropped (or changed) relative to the baseline and alerts. Since the change was the provider's and not yours, there would be no deploy of yours to give it away —without the continuous eval, it would be a completely invisible failure: nothing in your history changed—. The continuous eval is the only thing that looks at the real result and not just at your own changes.
Design practice that reduces the risk: pin the model version explicitly instead of using an alias that points to "the latest", and test a new version against your eval-set before migrating (the module 3 gate). That way, when the provider releases a new model or is going to deprecate yours, you control when you migrate and validate the migration against your eval before it reaches production —you turn a forced, silent migration into a planned, verified one—. Combined with the continuous eval (which catches what slips past you) and a provider deprecation notice, you reduce the risk of waking up one day with changed quality and not knowing why. It's the same discipline of "model-agnostic, version-controlled" that the guide uses throughout its code.
Summary and next step
In this lesson you installed the module's last failure mode, the most treacherous: drift —the silent, slow degradation— whose only defense is to measure quality continuously against a fixed reference. You saw it with the frog in the pot (that the gradual change cooks without its jumping) and the thermometer that would save it, and you measured it: the search eval dropped from 0.94 to 0.75 over seven weeks as queries from new categories rose from 2% to 45%, and the monitor fired the alert in week 4 —two weeks before users complained, with the score still at 0.88—. You retained the keys: compare against the baseline (not against the previous step), use a relative and absolute threshold (the relative one catches drift early), look at the input to diagnose the cause, and run the module 3 eval now continuously in production —the same thermometer, a new use—.
Before moving on you should be able to: explain why drift is invisible to the per-request defenses (fallback, verification) and is only caught by measuring the trend; distinguish data drift from model drift; set a relative threshold against baseline and explain why it catches drift better than an absolute one; and recognize the drift of a provider that updates the model. The fine statistics of drift detection is AI Engineering; here the decision to monitor and when to update is what's architectural.
With lesson 7 you completed the entire catalog of AI failure modes and their defenses. Lesson 8 is the capstone: you take Mercado's semantic search and build it the complete resilience shell —timeout + circuit breaker + cascading fallback + degradation— over the simulated model, and measure its availability with and without the shell (63.3% → 100%). You'll integrate everything from the module into an executed feature, with its diagram, its code, and an ADR that justifies why a model failure no longer takes the system down. The synthesis of everything you built.
Resources
- Chip Huyen, AI Engineering (O'Reilly, 2024) and Designing Machine Learning Systems (O'Reilly, 2022). The chapters on monitoring and observability and on data distribution shifts are the central reference of this lesson: types of drift (data, concept, model), how to detect them, and why continuous quality monitoring is part of designing a system with ML/AI. In English.
- Anthropic, Claude documentation — docs.anthropic.com. Check the model versions and deprecations pages to understand "provider model drift" —why pinning the version and validating before migrating reduces the risk—, at a conceptual level and without pinning a concrete version. In English.
architecture-for-ai-native-systems-guide, Module 3 (the eval as a fitness function) — the eval that here runs continuously in production was designed there as a CI gate; this lesson is its second use. And Module 7 (the data and feedback loop), toward which the monitoring points. In Spanish.- Martin Fowler and Bharani Subramaniam, "Emerging Patterns in Building GenAI Apps" — martinfowler.com/articles/gen-ai-patterns. Treats the continuous evaluation and monitoring of an AI component as operational patterns. In English.