Detecting Drift: Quality Degradation and Prompt Sensitivity
~12 min read
LLM apps degrade silently — inputs shift, a model version changes under you, a prompt edit backfires. Drift detection watches output quality and input distributions over time to catch slow decay before users do.
A traditional bug crashes loudly. LLM quality problems are insidious: nothing errors, every request returns HTTP 200, and yet the answers slowly get worse. Drift detection is the practice of catching that silent decay. There are a few distinct kinds of drift, and they have different causes.
Input/data drift means the requests coming in have changed distribution from what your system was built and tested for. Users start asking about new topics, in new languages, or in longer/shorter forms than before. The model hasn't changed, but it's now operating outside its comfort zone. You detect this by monitoring the distribution of incoming requests over time — embedding queries and watching for clusters drifting or new clusters appearing, or tracking simpler signals like average input length, language mix, and topic distribution.
Output/quality drift means the quality of responses degrades even for similar inputs. Causes include a provider silently updating the model behind an API, a prompt or retrieval change that backfired, or a knowledge base that's gone stale. You detect it by continuously scoring a sample of production outputs — often with the LLM-as-judge and RAG metrics from this curriculum's evaluation topics — and watching those scores over time. A downward trend in faithfulness or a rising refusal rate is drift even if no single response looks alarming.
Prompt sensitivity is a related fragility: LLM outputs can swing on tiny prompt changes, so a seemingly innocent edit ('improve the system prompt') can quietly degrade a whole category of responses. The defense is to treat prompts like code — version them, and run a regression evaluation suite against a fixed test set before shipping any prompt change, so you catch a regression in CI rather than in production. Pinning model versions (rather than floating 'latest') protects against the provider changing the model under you.
The unifying idea: because degradation is gradual and quiet, you need a continuous baseline to compare against. Establish reference distributions (of inputs and of quality scores) when things are healthy, then watch for statistically meaningful movement away from that baseline — and alert on the movement, not on any single request. That's what turns silent decay into something you notice in time to fix.
💻 Code example
# Two simple drift signals: (1) a rolling quality-score baseline with
# a threshold, and (2) a population-stability-style input-drift check.
from collections import deque
import statistics
class QualityDriftMonitor:
"""Alerts when the rolling mean of judge scores drops meaningfully
below a healthy baseline established earlier."""
def __init__(self, baseline_mean: float, window: int = 200, drop: float = 0.1):
self.baseline = baseline_mean
self.scores = deque(maxlen=window)
self.drop = drop
def record(self, judge_score: float) -> bool:
self.scores.append(judge_score)
if len(self.scores) < self.scores.maxlen:
return False
current = statistics.mean(self.scores)
return current < self.baseline - self.drop # True => drift alert
def population_stability_index(expected: dict, actual: dict) -> float:
"""PSI over topic buckets: higher => input distribution has shifted.
Rule of thumb: <0.1 stable, 0.1-0.25 moderate shift, >0.25 major."""
import math
psi = 0.0
for bucket, e in expected.items():
a = actual.get(bucket, 1e-6)
e = max(e, 1e-6)
psi += (a - e) * math.log(a / e)
return psi
expected = {"billing": 0.5, "tech": 0.4, "other": 0.1}
actual = {"billing": 0.3, "tech": 0.3, "other": 0.4} # 'other' surged
print("input PSI:", round(population_stability_index(expected, actual), 3))
💬 Deep Dive with AI
Key points
- •LLM degradation is silent — no errors, HTTP 200 everywhere — so you need continuous drift detection, not just crash monitoring
- •Input drift: incoming requests shift distribution (new topics/languages/lengths); detect via embedding clusters or simple input-stat trends
- •Output/quality drift: responses worsen for similar inputs (silent model updates, backfired prompt/retrieval changes); detect by scoring sampled outputs over time
- •Prompt sensitivity: tiny prompt edits can swing outputs — version prompts and run a regression eval suite before shipping changes; pin model versions
- •Establish healthy baselines for inputs and quality scores, then alert on statistically meaningful movement away from baseline, not on single requests