Anatomy of AI Observability
Traces, metrics, evals, drift detection, and regression alarms.

Traces, metrics, evaluations, drift detection, and regression alarms β turning your AI system from a black box into something you can trust, scale, and continuously improve.
TL;DRβ
- AI observability has 5 pillars: Logs Β· Traces Β· Metrics Β· Evaluations Β· Alerts.
- Trace every user request end-to-end with a single
trace_idso you can debug across model calls, tools, and subagents. - Track performance, usage, cost, quality, and adoption metrics β at least one from each category.
- Run evaluations continuously β a living eval suite is your regression net.
- Drift is silent: detect it with rolling averages, canaries, and shadow traffic before users do.
- Alert on impact, not noise. Tie every alert to an action.
Why this mattersβ
You can't improve what you can't see. AI systems fail in subtle, drifty, expensive ways β a quiet 5% accuracy drop, a 10Γ cost spike from a chatty prompt, a hallucination in production. Observability is what turns those silent failures into actionable signals.
Bottom line: Observability isn't about data. It's about understanding β and understanding is what lets you ship AI with confidence.
The Big Picture β Full-Stack AI Observabilityβ
Bottom line: Logs, Traces, Metrics, Evaluations, Events all flow through one
trace_idand end up stored, correlated, visualized, and alerted on.
The 5 Observability Pillarsβ
| Pillar | Purpose | Examples |
|---|---|---|
| π Logs | Raw events & structured logs | Everything important that happened |
| π Traces | End-to-end request flow | Services, models, tools, timing, dependencies |
| π Metrics | Aggregated numbers over time | Latency, tokens, cost, errors, quality |
| β Evaluations | Quality measured continuously | Correctness, factuality, safety, coherence |
| π¨ Alerts | Notify on issues & regressions | Thresholds, anomalies, drift, SLA breaches |
Properties every pillar must have:
- β Everything important is captured
- β Immutable
- β Searchable
- β Auditable
π‘ Tip: Start with traces + cost/latency metrics + a small eval suite. Add the rest as you mature.
End-to-End Trace Exampleβ
One user request through an agentic workflow:
| Span | Service / step | Latency | Tokens (in / out) |
|---|---|---|---|
| π’ Total Request | User: "How do I add SSO?" | 8.21s | 5,420 / 1,842 |
| βΈ Orchestrator (planner) | Plan steps, choose tools | 420 ms | 812 / 98 |
βΈ Model call (claude-sonnet-4) | Reasoning & planning | 1.82 s | 1,120 / 256 |
| βΈ Tool: codebase search | Search docs & code | 680 ms | 0 / 312 |
βΈ Model call (claude-sonnet-4) | Synthesis | 2.11 s | 1,340 / 612 |
βΈ Tool: read file (auth/README.md) | Read integration guide | 230 ms | 0 / 128 |
βΈ Tool: git diff (mainβ¦HEAD) | Inspect recent changes | 310 ms | 0 / 156 |
βΈ Model call (claude-sonnet-4) | Final answer | 2.47 s | 1,980 / 456 |
| βΈ Response delivered | To user | 200 ms | β |
π‘ Tip: Use trace IDs to jump from metrics β traces β logs for root cause.
Instrumentation β Log Schemaβ
A consistent schema is half the battle. Use this as your baseline:
{
"ts": "2025-05-20T10:30:00.123Z",
"trace_id": "c7f3wabu2",
"span_id": "a1b2-d-sonnet-4",
"parent_id": null,
"user_id": "u_123",
"session_id": "abc123",
"model": "claude-sonnet-4",
"input_tokens": 21000,
"output_tokens": 832,
"cost_usd": 0.0187,
"cache_hit": false,
"status": "success",
"task": "code_review",
"latency_ms": 8214,
"tool_calls": [
{ "tool": "git.diff", "ms": 310, "ok": true },
{ "tool": "fs.read", "ms": 230, "ok": true }
],
"tags": { "tier": "prod", "files_changed": 8 }
}
Required fields (the "irreducible minimum"):
ts,trace_id,span_id,parent_idmodel,input_tokens,output_tokens,cost_usdlatency_ms,statustask,user_id,session_id
π‘ Tip: Standardize this schema across all services. It's the single highest-leverage thing you can do for AI observability.
Key Metrics β What to Measureβ
Start with one metric from each category. Add more as the system matures.
| Category | Metric | Why it matters | Example target |
|---|---|---|---|
| β‘ Performance | Latency (P50 / P95) | User experience | P95 < 5 s |
| β‘ Performance | Time to First Token | Perceived speed | P95 < 2 s |
| β‘ Performance | Throughput (RPS) | Capacity planning | As needed |
| β‘ Performance | Error rate | Reliability | < 1% |
| π Usage | Input tokens | Cost driver | Track trend |
| π Usage | Output tokens | Cost driver | Track trend |
| π Usage | Context window % | Risk of truncation | < 80% |
| π Usage | Cache hit rate | Cost optimization | > 60% |
| π° Cost | Cost per request | Unit economics | < $0.02 |
| π° Cost | Cost per user / day | Budget control | Set budget |
| π° Cost | Total daily / monthly | Total spend | Within budget |
| β Quality | Correctness (eval score) | Are we right? | > 0.85 |
| β Quality | Hallucination rate | Factuality | < 1% |
| β Quality | Safety / policy violations | Guardrails | 0 tolerance |
| β Quality | User satisfaction (CSAT) | Happy users | > 4.5/5 |
| π Adoption | Acceptance rate | AI output used | > 50% |
| π Adoption | Re-ask / rework rate | Friction | < 15% |
π‘ Tip: Start with a small set. Add more as you mature. Tracking everything tracks nothing.
Evaluations & Testingβ
Build a living eval suite and run it continuously β every change to prompts, models, or tools.
Eval typesβ
| Type | Question it answers |
|---|---|
| β Correctness | Is it factually right? |
| π Factuality | Are claims grounded in source? |
| π‘οΈ Safety | Clear & consistent boundaries? |
| π¬ Helpfulness | Does it solve the task? |
| π§· Groundedness | Does it use provided context? |
Example eval case (YAML)β
id: sso_setup_basic
description: Explain how to add SSO
tags: [docs, auth]
input:
- "How do I configure SSO with Okta?"
expected:
must_contain:
- "Okta"
- "redirect_uri"
- "clientId"
- "claims"
must_not_contain:
- "hardcoded secrets"
- "outdated endpoints"
rubric:
- name: correctness weight: 0.4
- name: groundedness weight: 0.3
- name: safety weight: 0.2
- name: adverse weight: 0.1
Running evals β recommended cadenceβ
- On every PR that touches prompts, agents, or skills (CI gate).
- Nightly against a representative sample of production traffic.
- Weekly full sweep across your "canary set".
- Before any model bump (Sonnet β Opus, version rollover, etc.).
π‘ Tip: Run evals on every change to prompts, models, or tools. It's your AI regression test suite.
Drift Detection β Catching Silent Failuresβ
Drift = quality degrading slowly over time. By the time users complain, you've lost trust.
Drift signals to watchβ
- π Eval score drop
- π€ Increase in hallucinations
- π Spike in user re-asks
- β±οΈ Change in latency
- π Change in token usage
- β Higher error rates
- π‘οΈ New safety violations
Detection methodsβ
| Method | What it does | When to use |
|---|---|---|
| Statistical β rolling average & control charts | Trend over time | Always |
| Anomaly detection (z-score, EWMA) | Outlier spikes | Production at scale |
| Canary evals with fixed test set | "Did anything change?" | Every deploy |
| Shadow traffic comparison | Old vs new in parallel | Major prompt/model changes |
| Distribution shift (KL divergence) | Input or output distribution changed | Mature monitoring |
Visualizing driftβ
A simple rolling chart of your eval score with a threshold line is enough to start:
Eval Score over time
1.0 β€ββββββββ
0.9 β€ βββββ
0.8 β€- - - - - - - - threshold - - - - -
0.7 β€ βββββ
0.6 β€ ββββ β drift!
ββββββββββββββββββββββββββββββ
Apr 20 May 4 May 18
π¨ Alert example: "Eval score fell below 0.85 for 3 consecutive days."
Alerting & Auto-Responseβ
Notify the right people, take action automatically where safe.
Alert examplesβ
| Severity | Trigger |
|---|---|
| π΄ Critical | Eval score < 0.80 |
| π΄ Critical | Safety violation detected |
| π‘ Warning | Error rate > 2% |
| π‘ Warning | Latency P95 > 10 s |
| π΅ Info | New model deployed |
| π΅ Info | Daily cost > $100 |
Auto-response playbookβ
- Page on-call (critical only).
- Rollback to last known good prompt / model.
- Switch to fallback model.
- Reduce context / enable cache.
- Throttle traffic if needed.
- Open incident + notify team.
π‘ Tip: Alert on impact, not noise. Every alert needs a runbook.
Dashboards to Buildβ
A small set of dashboards is enough for 80% of value:
- π Requests / Day β traffic shape
- β±οΈ P95 Latency β user experience
- π° Total Cost (USD) β money
- β Eval Score (avg) β quality
- β Error Rate (%) β reliability
- πΎ Cache Hit Rate (%) β efficiency
- π₯§ Top Routes by Cost β where the money goes
- π’ Tokens In / Out β usage trend
π‘ Tip: One glance should tell you if the system is healthy.
Step-by-Step Setupβ
1. Pick a backendβ
- OpenTelemetry β Grafana / Tempo / Loki (open, portable).
- Datadog / Honeycomb / New Relic (managed).
- LangSmith / Langfuse / Helicone / Phoenix (AI-native).
2. Standardize the log schemaβ
Put the JSON schema above in a shared library (@org/ai-logger) and use it everywhere.
3. Add a tracing wrapperβ
Instrument every model call, tool call, and subagent invocation with the same trace_id.
// pseudo-TS
const traceId = uuid();
await withSpan(traceId, "model.call", { model, input_tokens }, async () => {
const res = await client.complete(prompt);
log({ ts, trace_id: traceId, model, input_tokens, output_tokens: res.tokens, cost_usd: priceOf(res) });
return res;
});
4. Emit metricsβ
Use Prometheus / StatsD / OTel meters for the metrics table above.
5. Build the eval suiteβ
Start with 20 hand-picked test cases. Grow as you find real failures.
6. Wire CI evalsβ
Run the eval suite on every PR that touches prompts, agents, or models. Fail the build below threshold.
7. Configure drift & alertsβ
Rolling average over 7 days; alert when N consecutive days breach threshold.
8. Document runbooksβ
Every alert links to a runbook with: symptom β likely cause β first action.
Variants for Different Team Settingsβ
π€ Solo developerβ
- One JSONL log file, daily rotation.
- 5-case eval set, run before every prompt change.
- Email alert on cost > daily budget.
π₯ Small team (2β10)β
- OTel + Grafana (or Honeycomb free tier).
- 20β50 case eval suite in CI.
- Slack alerts: cost + safety only.
- Weekly review of the eval-score chart.
π’ Enterprise / regulatedβ
- Full audit trail + immutable storage (S3 + Object Lock).
- PII redaction in logs at write time.
- SIEM integration for safety + auth events.
- Eval suite versioned, peer-reviewed, signed.
- On-call rotation for AI quality, not just uptime.
π Open-source / communityβ
- Public dashboards (with PII stripped).
- Anonymized eval results published.
- Community-contributed eval cases.
Bottom line: Same pillars, escalating discipline.
Common Patterns & Recipesβ
Pattern 1 β Universal trace IDβ
const traceId = req.headers["x-trace-id"] ?? uuid();
// Pass to every model call, tool call, and subagent.
Pattern 2 β Sampled deep loggingβ
1% of requests β full prompt + response logged
Everyone β metrics + trace skeleton only
Pattern 3 β Canary evals on deployβ
# .github/workflows/eval.yml
on: [push]
jobs:
eval:
steps:
- run: npm run eval:canary
- if: failure()
run: ./scripts/rollback.sh
Pattern 4 β Shadow comparisonβ
On 1% of prod traffic:
- Call current model AND candidate model
- Compare eval scores
- Block promotion if delta > threshold
Pattern 5 β Cost anomaly detectionβ
-- alert if today's cost > 2Γ 7-day average
SELECT day, sum(cost_usd) AS spend
FROM ai_events
GROUP BY day
HAVING spend > 2 * avg_7d
Pattern 6 β Hallucination spike detectorβ
window: 1 hour
threshold: hallucination_rate > 1.5Γ7d_avg
action: page + auto-switch to deterministic fallback
Pattern 7 β Eval-driven prompt PRsβ
PR template:
- [ ] Eval suite ran
- [ ] Score change: Β±__%
- [ ] No regression on safety set
- [ ] Cost change: Β±__%
Best Practices β β
- π Measure everything with context (trace IDs, tags).
- π Use consistent trace IDs across the stack.
- π·οΈ Version prompts & models (always know what produced what).
- π§ͺ Maintain a living eval suite.
- π°οΈ Detect drift early.
- π― Alert on impact, not noise.
- π Keep dashboards simple & actionable.
- π Document runbooks for every alert.
Anti-Patterns ββ
- π« No instrumentation ("we'll add it later").
- π« Only alerting on errors β miss quality drift entirely.
- π« Eval suite is stale or tiny.
- π« Ignoring small degradations.
- π« No rollback strategy.
- π« Dashboards nobody looks at.
- π« Ad-hoc experiments in prod without logging.
- π« Blindly trusting outputs.
Troubleshootingβ
| Symptom | Likely cause | Fix |
|---|---|---|
| "It got worse last week" | No drift detection | Add rolling-avg alert |
| Cost spike, no idea why | No per-task cost log | Add task tag + log cost_usd |
| Can't reproduce a bad answer | No prompt/version logged | Log prompt hash + model version |
| Eval suite always green | Suite too narrow | Add adversarial + edge cases |
| Alerts ignored | Too many, no runbooks | Cut 80%; write runbooks for the rest |
| Trace gaps | trace_id not propagated | Enforce via wrapper / middleware |
| PII in logs | No redaction at write | Add PII scrubber before persist |
Quick-Start Checklistβ
- β Standard log schema deployed
- β Trace IDs propagated end-to-end
- β 4 metrics live (latency, cost, error, quality)
- β Eval suite (β₯ 20 cases) running in CI
- β Drift alert on eval score
- β Cost alert at 80% of daily budget
- β One unified dashboard
- β Runbook for every alert
π§ Mantra: Prevent Β· Detect Β· Fix Β· Learn.
Starter Configsβ
Minimal log emitter (TypeScript)β
import { performance } from "node:perf_hooks";
export function logAIEvent(e: AIEvent) {
console.log(JSON.stringify({
ts: new Date().toISOString(),
trace_id: e.traceId,
span_id: e.spanId,
parent_id: e.parentId ?? null,
model: e.model,
input_tokens: e.inputTokens,
output_tokens: e.outputTokens,
cost_usd: e.costUsd,
latency_ms: e.latencyMs,
status: e.status,
task: e.task,
user_id: e.userId,
session_id: e.sessionId,
cache_hit: e.cacheHit ?? false,
tags: e.tags ?? {}
}));
}
Eval runner (skeleton)β
for (const c of cases) {
const out = await runAgent(c.input);
const score = grade(out, c.rubric);
results.push({ id: c.id, score });
}
report({
avg: avg(results.map(r => r.score)),
failing: results.filter(r => r.score < 0.8)
});
Alert rule (Prometheus / Grafana)β
- alert: AIEvalScoreLow
expr: avg_over_time(ai_eval_score[3d]) < 0.85
for: 1d
labels: { severity: critical }
annotations:
summary: "AI eval score dropped"
runbook: "https://runbooks/ai-eval-score"
Glossaryβ
- Span β One unit of work in a trace (a model call, a tool call).
- Trace β All spans for one user request, linked by
trace_id. - Eval (evaluation) β Scored test of model output against a rubric.
- Drift β Slow change in model behavior or input distribution.
- Canary β Small, controlled test against a fixed set.
- Shadow traffic β Calling a new model in parallel for comparison without affecting users.
- Rubric β Weighted set of criteria used to score outputs.
- Runbook β Documented response for an alert.
- CSAT β Customer Satisfaction score.
- TTFT β Time to First Token.
Further Readingβ
- Search: "OpenTelemetry semantic conventions for GenAI"
- Search: "LLM evaluation harness HumanEval MMLU"
- Search: "drift detection statistical methods EWMA"
- Search: "AI observability platforms 2026 comparison"
πͺ Goal & Pillarsβ
- π― The goal: Ship high-quality AI-powered features with predictable cost and zero surprises.
- π‘οΈ Prevent β Catch issues early with smart gates.
- π Detect β See what's going on in real time.
- π§ Fix β Resolve fast with context and automation.
- π§ Learn β Continuously improve models, prompts, and workflows.
"Observability is not about data. It's about understanding." β Charity Majors