Back to Blog
A computer screen showing a line graph, representing quality metrics tracked for drift in a production AI workflow

LLM Drift Monitoring: Detecting Quality Drift in Production

10 min read

LLM drift monitoring must catch failures that ordinary uptime dashboards miss. A workflow can return valid JSON in two seconds and still start routing refund requests incorrectly, omitting required evidence, or giving one customer segment worse answers. Offline tests cannot contain every production input, and one average score can hide a serious local failure. The fix is a production quality loop: sample completed runs by risk and segment, join delayed business outcomes, apply calibrated checks, confirm suspected drift with human labels, and connect every alert to a limited response. This guide shows how to build that loop without turning every request into an expensive second model call.

Define drift as a change in business quality

Start with the task, not a generic model score. A support triage workflow might need the correct queue, priority, and policy citation. An invoice workflow might need the correct supplier, totals, duplicate decision, and approval path. A document assistant might need a supported answer or an explicit refusal when evidence is missing.

Write each requirement as an observable outcome. Use exact checks where the system already knows the answer. A routing destination can be compared with the queue that ultimately resolved the ticket. A citation can be checked against the retrieved evidence. A proposed payment can be compared with the approved ledger entry. Reserve subjective graders for criteria such as completeness or clarity that deterministic code cannot express.

OpenAI's evaluation guide describes evals as repeatable tests built from task inputs, criteria, and graders. Production monitoring uses the same structure, but the dataset arrives over time and often receives its best label after the business process finishes.

Define drift as a sustained change in one or more task outcomes under a comparable slice of traffic. A rising average prompt length is an input change, not proof that answer quality fell. A lower global pass rate may come from a larger share of difficult cases rather than worse behavior within any case type.

For each metric, record:

  • the outcome and why it matters to the business;
  • the eligible population and exclusion rules;
  • the label source and expected delay;
  • the segments that must be measured separately;
  • the baseline window and minimum sample size;
  • the warning and action thresholds;
  • the owner and permitted response.

Keep availability, latency, token use, and exceptions on the same dashboard, but do not substitute them for semantic quality. Traces tell you what ran. Quality checks tell you whether the completed work was useful and correct.

Build a versioned quality event

Emit one quality event when a workflow reaches a terminal state. Do not evaluate directly from an application log line. The event needs stable identifiers and versioned context so a later label can be joined to the exact run.

{
  "quality_event_id": "qe_01842",
  "workflow_run_id": "run_7721",
  "workflow_version": "31",
  "prompt_version": "support_triage_12",
  "model_route": "standard_classifier",
  "tenant_tier": "enterprise",
  "language": "en",
  "task_type": "refund_request",
  "risk_tier": "medium",
  "input_fingerprint": "sha256:sample",
  "output_ref": "result_7721",
  "retrieval_snapshot": "kb_2026_09_02_04",
  "deterministic_checks": {
    "schema_valid": true,
    "policy_citation_present": true
  },
  "completed_at": "2026-09-02T10:05:00Z"
}

Store references to protected inputs and outputs rather than copying sensitive content into the monitoring system. Preserve the workflow, prompt, model route, retrieval snapshot, policy, and tool versions that can change behavior. Use trusted application metadata for tenant, language, task, and risk segments. Do not ask the model to label its own segment.

Add business outcomes as separate immutable label events. A support ticket may receive a final queue, agent correction, reopen flag, and resolution time several days later. An accounts payable item may receive an approval decision after a human checks the source documents. Joining these delayed labels is how the monitoring loop measures completed business work instead of surface plausibility.

NIST's AI Risk Management Framework treats measurement, management, and governance as continuing activities across the AI lifecycle. A versioned quality event gives those activities a concrete unit: one run, its context, its checks, its later outcome, and the response taken.

Sample by risk and segment

Uniform random sampling wastes review capacity on frequent, low-risk cases and may miss rare failures. Use a base random sample for an unbiased overall estimate, then add targeted samples for risk and diagnostic coverage.

A practical daily sampling plan can combine:

  1. A fixed random percentage of all eligible completed runs.
  2. Every high-risk run until the segment has enough evidence.
  3. Extra samples from new workflow, prompt, model, retrieval, and policy versions.
  4. Extra samples from low-volume languages, tenants, tools, and task types.
  5. Runs near a deterministic decision boundary.
  6. Runs attached to complaints, corrections, reopens, or downstream rejection.

Tag each sample with its selection reason and probability. Without that field, a quality dashboard can mistake an intentionally difficult review set for normal traffic. Report the unbiased base sample separately from targeted diagnostic samples. Use targeted samples to find and explain failures, not to estimate the global failure rate without weighting.

Deduplicate samples by workflow run. If the same run qualifies for three rules, review it once and preserve all three reasons. Freeze the sampled output and evidence before review so a later knowledge-base update cannot change what the grader sees.

Low-volume segments need an explicit policy. Do not calculate a volatile daily percentage from three examples and page someone when one fails. Accumulate a longer window, use exact counts beside rates, and route severe single cases through the exception process instead of calling them statistical drift.

Layer checks from cheap to expensive

Run deterministic checks first. They are reproducible, fast, and easy to debug. Useful checks include schema validity, required fields, allowed destinations, policy citations, numerical reconciliation, duplicate decisions, evidence presence, tool-result consistency, and whether the workflow abstained when required data was absent.

Next, apply business labels when available. These are often the strongest quality signal because they record what happened after the AI output entered the real process. Track label coverage and delay as first-class metrics. A stable pass rate based on only ten percent of expected labels can be a data-pipeline failure rather than good performance.

Use a model grader only for remaining semantic criteria. Microsoft's general-purpose evaluator documentation separates criteria such as coherence and fluency and specifies the inputs each evaluator needs. Follow that discipline for custom graders. Give one grader one defined criterion, a compact rubric, the relevant evidence, and an explicit score or label schema.

Calibrate each grader against a human-labeled set before using it for alerts. Measure agreement by segment, not only in aggregate. A grader that agrees on English support replies may fail on short Japanese messages or technical incident notes. Keep the judge model, prompt, rubric, and threshold version in every evaluation record.

Phoenix documents deterministic and model-based evaluations over datasets, experiments, and production traces, along with traces of the evaluator itself. Regardless of tool choice, retain the evaluator input, version, output, and timing. The grader is another production component. It can drift, time out, or change after a model update.

A simple execution policy looks like this:

def evaluate(run, label=None):
    exact = run_deterministic_checks(run)
    if exact.has_blocking_failure:
        return QualityResult("fail", source="deterministic", reasons=exact.reasons)

    if label is not None:
        return compare_with_business_outcome(run, label)

    if run.sample_reason in {"high_risk", "new_version", "boundary"}:
        return run_versioned_semantic_grader(run)

    return QualityResult("pending_label", source="none")

The code leaves a run pending when evidence is unavailable. It does not turn missing labels into passes or ask a grader to invent a business outcome.

Separate mix change from quality change

Compare like with like before declaring drift. Build a baseline by workflow version and the segments that materially affect difficulty. For a support workflow, those might be task type, language, channel, and customer tier. For document extraction, document family, source system, scan quality, and page-count band may matter more.

Monitor three views together:

  • traffic share by segment;
  • quality within each segment;
  • the weighted overall quality result.

Suppose the overall pass rate falls from 92 percent to 86 percent. If every segment is stable but the share of complex refund cases doubled, the workflow may not have degraded. Capacity planning, product scope, or routing needs attention. If English requests remain stable while French refund requests fall sharply after a prompt release, the release is a plausible cause and the response can stay narrow.

Use distributions where a mean hides the failure. Track the share below a task threshold, the count of severe failures, and quantiles for continuous scores. Keep the baseline versioned and visible. A moving baseline that updates every day can absorb a slow decline until the bad state looks normal.

Do not alert on a threshold alone. Require a minimum sample, persistence across more than one evaluation batch when risk permits, and a meaningful effect size. High-severity deterministic violations can bypass those statistical gates because one unauthorized payment recommendation may warrant immediate containment.

Turn alerts into bounded decisions

Every alert needs an evidence packet and a small response menu. Include the affected metric and segment, current and baseline windows, sample counts, workflow and evaluator versions, representative failures, label coverage, recent releases, and traffic-mix changes.

The owner should choose among defined actions:

  • collect a larger confirmed sample;
  • send the affected segment to human review;
  • disable one tool or model route;
  • roll back a prompt, workflow, retrieval, or policy version;
  • reduce automation scope;
  • open an incident for a severe control failure;
  • close the alert as a grader or data-pipeline defect.

Do not let the monitoring service rewrite prompts or switch models automatically from a noisy semantic score. It may automate safe containment that policy already permits, such as routing a specific segment to review. Changes to decision logic should follow the normal tested release path.

Record the decision, actor, evidence, and result. After mitigation, compare the affected segment with the frozen pre-alert window. Closing the alert requires evidence that quality recovered or that the suspected change was not real.

Test the monitor before trusting it

Exercise the quality loop with synthetic mutations and replayed production-derived fixtures. A monitoring system that has never detected a controlled failure has not proved its alert path.

Use at least these tests:

  1. Change one prompt version so a required field disappears and confirm the exact check catches it.
  2. Lower quality only for one language and confirm the segment alert fires while the global result may remain stable.
  3. Double the share of difficult inputs without changing within-segment quality and confirm the system reports mix change rather than model drift.
  4. Delay business labels and confirm coverage drops without converting unlabeled runs into passes.
  5. Change the grader version and confirm old and new results remain distinguishable.
  6. Feed the grader examples where human reviewers disagree and confirm those cases do not create an automatic rollback.
  7. Re-submit the same sampled run and confirm it receives one review record.
  8. Corrupt the quality-event join key and confirm the monitor exposes unmatched labels.
  9. Trigger an alert below the minimum sample and confirm it remains informational unless severity policy overrides it.
  10. Route an affected segment to human review, then confirm the action is logged and reversible.

Also watch the monitor itself: event delivery, sample selection, label joins, evaluator error rate, evaluator latency, review backlog, and alert age. Phoenix's active work on online-evaluation input handling shows that production evaluation has its own data mapping and execution lifecycle.

Start with one workflow decision that already produces a reliable downstream label. Define the quality event, choose one base sample and two risk samples, calibrate one semantic grader only if deterministic checks and business labels are insufficient, and run the ten failure tests before connecting alerts to operational action.

References

  1. OpenAI working with evals supports repeatable datasets, criteria, graders, and evaluation runs.
  2. NIST AI Risk Management Framework supports ongoing AI risk measurement, management, and governance.
  3. Microsoft general-purpose evaluators supports criterion-specific output evaluation and explicit evaluator inputs.
  4. Phoenix evaluations supports deterministic and model-based evaluation over production traces, datasets, and experiments.
  5. Phoenix online-evaluation pull request 15459 supports the operational need to map production trace data into online evaluator inputs.

About Fire In Belly: Independent senior engineering from Tallinn, Estonia. We design and build AI workflow automation, internal tools, and custom software with the drift monitoring and response rules described above, at published fixed prices. Schedule a call to discuss your next project.