Lesson 31 · Slide 1
LLM Observability in Production
You cannot improve what you cannot measure. Observability turns your LLM application from a black box into a system you can understand, debug, and optimise under real-world load.
Learning Objectives
- Implement structured request/response logging with token counts and latency
- Integrate distributed tracing with Langfuse, LangSmith, or Phoenix/Arize
- Define and track key metrics: latency percentiles, throughput, error rates, cost
- Build alerts and dashboards for anomaly detection
- Set up feedback loops to close the gap between monitoring and improvement
Lesson 31 · Slide 2
Logging: The Foundation
Every LLM call should produce a structured log entry. Unstructured print() statements do not scale. Structured JSON logs let you query, filter, and aggregate.
What to Log
Per-Request Fields
- request_id — unique correlation ID
- model — exact model version
- prompt_hash — hash of the system + user prompt
- input_tokens / output_tokens
- latency_ms — wall-clock time
- status — success, error, timeout
Context Fields
- user_id / session_id
- environment — staging vs production
- prompt_version — which template was used
- temperature and other generation params
- timestamp — ISO 8601 with timezone
import json, time, hashlib, logging
logger = logging.getLogger("llm")
def log_llm_call(request_id, model, prompt, response, start_time):
entry = {
"request_id": request_id,
"model": model,
"prompt_hash": hashlib.sha256(prompt.encode()).hexdigest()[:12],
"input_tokens": response.usage.input_tokens,
"output_tokens": response.usage.output_tokens,
"latency_ms": round((time.time() - start_time) * 1000),
"status": "success",
}
logger.info(json.dumps(entry))
Notes: Emphasise that raw prompts/responses may contain PII. Log hashes or redacted versions in production. Store full payloads only in a secure, access-controlled trace store.
Lesson 31 · Slide 3
Tracing: Following the Thread
A single user action may trigger multiple LLM calls, retrieval steps, and tool invocations. Tracing links these into a single timeline so you can see where time and tokens are spent.
Tracing Platforms
| Platform | Open Source? | Key Strength |
| Langfuse | Yes (self-host or cloud) | Simple SDK, prompt management, cost tracking |
| LangSmith | No (LangChain cloud) | Deep LangChain integration, dataset/eval pipeline |
| Phoenix / Arize | Yes (Phoenix OSS) | Embedding drift detection, span-level analysis |
| OpenTelemetry + custom | Yes | Vendor-neutral, integrates with existing APM |
Trace Anatomy
Trace (top-level) → Span: retrieve_docs (200 ms) → Span: llm_call (1400 ms, 850 tokens) → Span: tool_call (300 ms) → Span: llm_call_2 (900 ms, 420 tokens)
Notes: Show a live Langfuse or Phoenix dashboard if possible. The visual timeline makes the concept click instantly.
Lesson 31 · Slide 4
Metrics: What to Measure
Raw logs become actionable through aggregated metrics. Focus on the four golden signals adapted for LLM systems.
Latency
- p50 — typical user experience
- p95 — the slow tail that frustrates users
- p99 — worst-case for SLA compliance
- Track time to first token (TTFT) separately from total latency
Throughput
- Requests per second / minute
- Tokens per second (input + output)
- Concurrent active sessions
Error Rate
- HTTP errors (429 rate limit, 500 server)
- Timeouts and retries
- Malformed / unparseable responses
- Content filter rejections
Cost
- Cost per request (input + output pricing)
- Cost per user / per feature
- Daily and monthly burn rate
- Cost per successful outcome
Lesson 31 · Slide 5
Monitoring & Alerting
Metrics without alerts are just numbers. Define thresholds that trigger action before users notice problems.
Alert Strategy
| Signal | Warning Threshold | Critical Threshold |
| p95 latency | > 3s (sustained 5 min) | > 8s (sustained 2 min) |
| Error rate | > 2% (5 min window) | > 10% (2 min window) |
| Daily cost | > 120% of 7-day avg | > 200% of 7-day avg |
| Token throughput | Drop > 30% vs baseline | Drop > 60% vs baseline |
Dashboard Essentials
- Real-time panel: request rate, active errors, p50/p95 latency (last 15 min)
- Trends panel: daily cost, token usage, error rate over 30 days
- Model comparison: latency and cost side-by-side across model versions
- Anomaly detection: statistical deviation from rolling baselines (z-score or IQR)
Notes: Grafana + Prometheus is the most common open-source stack. Datadog and New Relic also have LLM-specific dashboards. Show a sample Grafana dashboard screenshot if available.
Lesson 31 · Slide 6
Debugging: Conversation Replay & Prompt Versioning
When something goes wrong, you need to reproduce the exact conditions. This requires two capabilities:
Conversation Replay
- Store the full message history for every trace
- Replay against the same model version to confirm the bug
- Replay against a new model or prompt to verify the fix
- Redact PII before storing — or use a secure vault
Prompt Versioning
- Version every system prompt and template change
- Tag each trace with the prompt version used
- Compare metrics across prompt versions (A/B)
- Roll back to a previous version instantly
# Langfuse prompt versioning example
from langfuse import Langfuse
langfuse = Langfuse()
# Fetch a versioned prompt
prompt = langfuse.get_prompt("summariser", version=3)
compiled = prompt.compile(topic="quarterly earnings")
# The trace automatically links to prompt name + version
trace = langfuse.trace(name="summarise-earnings")
generation = trace.generation(
name="llm-call",
model="claude-sonnet-4-20250514",
prompt=prompt, # links prompt version to trace
input=compiled,
)
Lesson 31 · Slide 7
Feedback Loops
Observability is incomplete without user signal. Automated metrics tell you what happened; user feedback tells you whether it was good.
Feedback Collection Patterns
- Thumbs up / down — lowest friction, highest volume. Attach to trace ID.
- User corrections — when users edit AI output, capture the diff as implicit negative feedback.
- Explicit ratings — 1-5 stars on specific dimensions (accuracy, helpfulness, tone).
- Escalation signals — "talk to a human" button clicks indicate failure.
Closing the Loop
Collect feedback → Aggregate by prompt version, model, feature → Identify low-scoring patterns → Curate into evaluation datasets → Iterate on prompts or fine-tuning → Deploy improved version → repeat
# Sending feedback to Langfuse
langfuse.score(
trace_id="trace-abc-123",
name="user-thumbs",
value=1, # 1 = positive, 0 = negative
comment="User clicked thumbs-up"
)
Notes: Even a 5% feedback rate gives valuable signal at scale. The key is making feedback trivially easy to give and systematically linking it to traces.
Lesson 31 · Slide 8
Lab & Homework
Lab Exercises
- Structured Logging — build a logging wrapper that captures request ID, model, tokens, latency, and cost for every Claude API call
- Langfuse Tracing — integrate the Langfuse SDK to create traces and spans for a multi-step RAG pipeline
- Metrics Dashboard — compute p50/p95/p99 latency, error rate, and cumulative cost from your logs, then visualise with matplotlib
Homework Tasks
- Add anomaly detection to your metrics: flag any request where latency exceeds 2x the rolling p95.
- Implement a feedback collection endpoint that links thumbs-up/down scores to trace IDs.
- Write a cost anomaly alert that triggers when hourly spend exceeds 150% of the trailing 24-hour average.