← Back to all posts

Closing the Loop: Why Evals Need to Talk to Embeddings

AI/MLNovember 1, 20258 min read
Closing the Loop: Why Evals Need to Talk to Embeddings

TL;DR: everybody's obsessing over eval frameworks, but almost none showing how models drift. evals don't remember context. embeddings do. when embeddings shift and evals stay static, silent regressions slip through. closing the loop converts eval results into actionable semantic signals.

everybody's been obsessing over eval frameworks. promptbench this, g-evals that. we got hundreds of dashboards telling us how models perform, but almost none showing how they drift. the whole thing's blind to the slow semantic decay that happens when embeddings move and evals stay still.

and that's weird because the signals are literally next to each other - same vectors, same distributions, just nobody's closing the loop.

the missing connection

right now, eval systems treat metrics like static scores. you run evals, get a table of numbers, maybe plot precision curves, then walk away. but embeddings - those are living systems. they shift with new data, retraining, even infrastructure updates.

the problem: evals don't remember context. embeddings do.

so when an embedding for cancel order starts drifting toward return item, your eval still says accuracy = 0.93. nothing in your monitoring stack screams "semantic drift." that's how silent regressions slip through in production.

a story from the field

a fintech team ran customer intent classification for their support channel. evals stayed at 94% accuracy for 6 months. then customers started complaining: refund requests were being routed to cancellations. charges weren't being reversed correctly. the team investigated, reran evals locally - still 94%.

what changed? their training data had shifted. more layoffs meant customers now used phrases like "halt my subscription" and "stop charging me" interchangeably with "cancel." the embeddings had learned a subtle cluster shift. the evals just... didn't know to check.

when they finally plotted embedding drift, the "refund" cluster had migrated 15% closer to "cancel" over 3 months. one number change. evals caught zero of it.

why drift stays invisible

embedding drift is sneaky. vector norms stay fine. cosine distances look small. and yet, clusters migrate just enough that your intent classifier starts misfiring.

Arize AI's embedding monitoring work nails the first half - tracking latent-space drift across time windows (Arize blog). what's still missing is the bridge from drift to evaluation signals.

today, drift metrics live in observability. eval metrics live in experimentation. no cross-talk.

where drift actually comes from

drift doesn't just happen one way. it comes from multiple angles, and evals miss all of them:

  • data drift - new user utterances, slang, context shifts. layoffs hit, "cancel order" now means something different
  • model drift - embedding model fine-tuned on new corpora, or refreshed from a newer pre-trained checkpoint
  • infrastructure drift - tokenizers change, batchnorm layers nudge vectors, quantization compresses clusters
  • semantic drift - word meanings evolve. on social platforms, meanings can shift within weeks

the scary part: the model still passes evals. your test set accuracy barely moves. but concept boundaries blur in subtle ways that only show up when live traffic hits edge cases. that's latent entropy - invisible until it breaks something.

how to spot if you have this problem

don't wait for production chaos. here's what to look for:

  • Evals stable, complaints rising: accuracy unchanged month-over-month, but support tickets for misclassifications climb
  • Unexplained performance gaps: eval benchmark at 92%, live traffic accuracy drops to 87% without visible code changes
  • Cluster creep: similar phrases that used to cluster together now scatter across different regions of embedding space
  • Cold models behave differently: a fine-tuned model from 2 months ago performs worse than yesterday's checkpoint on identical test data

closing the loop

imagine eval runs that automatically reindex spans of embeddings showing semantic drift from prior checkpoints.

you'd no longer treat evals as one-off scripts, but as feedback loops:

  1. eval executes on validation set
  2. embeddings for mispredicted samples are compared against previous snapshots
  3. spans with statistically significant drift are tagged as retraining candidates
  4. fine-tuning jobs kick off on those slices automatically

suddenly, eval isn't a dashboard - it's a retraining pipeline.

this loop converts eval results into actionable semantic signals. basically, model governance becomes continuous.

a working analogy

think of embeddings like a map, and evals like the GPS. we keep recalibrating the GPS without checking if the map shifted under it.

closing the eval–embedding loop means you align the map updates (embedding shifts) with the GPS recalibration (eval scores). if the terrain changes but your route doesn't, you'll still crash - even if the GPS says "on track."

what this saves you

the fintech team above lost ~$18K in reversed charges before fixing the issue. a gaming company had their toxicity filter start classifying friendly banter as harassment (embedding shift toward aggression, evals asleep). an e-commerce platform misrouted urgent refunds because their intent model silently degraded.

connecting evals to embedding drift catches these in days, not months.

implementation sketch

this isn't sci-fi. a prototype could be built from what already exists:

  • store historical embedding snapshots in vector DBs like Weaviate or LanceDB
  • hook eval pipeline outputs to drift detectors (Gupta et al., 2023)
  • compute semantic shift metrics (EmergentMind 2023)
  • stream drift spans into retraining queues
  • fine-tune small adapters to realign embeddings in those zones

the technical flow:

  1. baseline snapshot - store embeddings for validation/test sets at each model checkpoint
  2. eval execution - run standard evals, log mispredicted samples
  3. semantic delta - compare embeddings for those samples across checkpoints. use cosine shift (Δcosine), centroid displacement per cluster, or Procrustes distance for global alignment
  4. drift segmentation - group high-drift spans (same concept, different cluster topology)
  5. retraining trigger - pipe those spans into fine-tune queues or adapter updates
  6. continuous loop - every eval run refreshes reference embeddings before scoring

start small: begin by logging embedding snapshots weekly alongside eval runs. compute pairwise distances to previous week. calculate cosine shift and centroid displacement per cluster. flag anything moving >5% per week. that's your drift signal baseline. then feed high-drift samples into a lightweight LoRA or adapter retraining job.

Arize could literally own this space - turning evals into self-healing feedback systems.

why it matters

every org today runs evals and drift monitors separately. the moment those two start talking, we'll finally have model reliability at runtime, not just model explainability after failure.

evals become dynamic truth, not static judgment. and embedding drift stops being an afterthought - it becomes the retraining signal.

once evals can read embedding drift directly, you start seeing semantic failures before they hit production metrics. a cluster drifts. evals notice. retraining triggers automatically. the feedback loop stays tight.

that's the difference between reactive model governance ("oops, we broke something") and continuous model alignment ("we caught it before users noticed").

the cost of staying disconnected

here's what happens if you don't close the loop:

evals become fossilized. they'll keep showing stable numbers while your model quietly drifts into a different language space. meaning collapses slowly - intents overlap, boundaries blur, and retraining happens too late, if at all.

you end up with that weird mismatch where the model "tests fine" but production feedback says otherwise. like a compass that points north, but the magnetic field already moved.

the result isn't catastrophic failure - it's gradual incoherence. models start losing alignment with user reality. responses that were once precise become fuzzy. similar intents start bleeding into each other. and once that gap widens past a threshold, no retrospective metric can fix it.

the longer you wait, the more retraining you'll need. by the time you notice, semantic drift has already compounded across dozens of samples. at that point, you're not fine-tuning - you're rewinding.

that's why evals need to move with embeddings. static evals only work in a static world. but embeddings are living systems. if evals don't evolve with them, they'll stop measuring anything real.

what Arize (or anyone) could do

Arize AI already nailed half the stack - embedding visualization, time-window drift tracking, slice analytics. what's missing is the "semantic response layer" that links those drifts to eval results and retraining.

they could easily extend their eval pipelines to add:

  • drift-aware sampling for eval datasets - don't sample randomly. bias eval sets toward high-drift regions where semantic shift is happening
  • automatic checkpoint comparison for embeddings - snapshot embeddings at each model version, automatically compute alignment deltas (Procrustes, CKA) and flag shifts
  • trigger-based fine-tuning tasks - when drift exceeds threshold, pipe mispredicted samples into retraining queues automatically
  • continuous reindexing of embeddings used for eval queries - don't evaluate once. refresh embedding context with each drift checkpoint

that's the missing flywheel:

eval → drift detect → re-align → new eval → new drift

at that point, "evals" stop being static dashboards. they become self-healing semantic systems. the system watches itself, detects when meaning drifts, and automatically corrects course.

that's the product that wins.

references

Note: This approach requires infrastructure to version embeddings alongside models. Start by simply logging embedding snapshots at each model checkpoint, then build drift comparison tooling on top.