What’s one thing you learned? What’s still confusing?
Building a Production ML/LLM System (Capstone)
Capstone — integrate everything. 16-point hardening checklist. Reference architectures for chatbots, fraud, content moderation.
Privacy-Preserving ML: DP & Federated Learning
Differential privacy, DP-SGD, federated learning with FedAvg, GDPR compliance, and machine unlearning.
DICOM & Medical Imaging Standards
DICOM file format, PACS protocols, HU conversion, photometric interpretation, anonymization for ML, and HIPAA-aligned clinical imaging pipelines.
Interactive Labs for This Track
DNS Flow
You type google.com — trace the journey from your browser through DNS servers to the actual website
Load Balancer
10 million users hit your app — watch how traffic is distributed across servers
Rate Limiter
An API getting hammered — build a rate limiter that protects it without blocking real users
Ask questions, share insights
Site Reliability Engineering brought a vocabulary that maps cleanly onto ML serving — once you adapt the metrics. The three terms:
A typical ML serving SLO bundle in 2026 looks like:
| SLI | Target SLO |
|---|---|
| Inference p95 latency | < 400 ms |
| Inference success rate | > 99.5% |
| Eval-set accuracy vs. baseline | within -2% |
| Cost per 1,000 inferences | < $X |
| Time to rollback after incident | < 5 minutes |
The error budget concept also adapts: you have a budget of "wrong answers" per quarter, separate from the budget of HTTP 5xx errors. Burning through the accuracy budget triggers an investigation just as a 5xx-rate burn would. This is what "ML observability" platforms (Arize, Fiddler, WhyLabs) productize.
A team sets a single SLO for their LLM chatbot: 'p95 latency under 2 seconds.' Six months later, latency is good, but the bot is hallucinating product features that don't exist. What was the SLO missing?
| Incident | Detection | Response |
|---|---|---|
| Sudden accuracy drop | Eval pipeline regression alert | Roll back model to previous version |
| Silent quality regression | Drift detector + human-eval sample | Investigate: data drift / model drift / upstream change |
| Cost spike | Token / GPU-hour cost dashboard alert | Rate limit; investigate runaway loop or attack |
| Prompt injection / jailbreak | Output classifier + abuse detection | Block offending prompts; tighten input filter |
| Downstream tool failure | Tool-call success-rate alert | Failover to backup tool; notify users |
| GPU / infra outage | Cloud provider status + heartbeat | Failover to multi-region; degraded mode |
For ANY ML incident:
1. Identify (1 min): which service? which model? when did it start?
2. Bound (1 min): how many users affected? how severe? trending?
3. Mitigate (3 min): roll back / disable / degrade gracefully
4. Communicate: status page update, stakeholder notification
5. Investigate: only AFTER mitigation
| Pattern | Implementation | Recovery Time |
|---|---|---|
| Model registry version revert | MLflow registry: re-promote previous version | < 60s |
| Blue-green deployment | Two identical environments; switch traffic | < 30s |
| Canary rollback | Progressive deploy hit issue at 5%; roll back before 50% | Automatic |
| Feature flag | Flip a flag to disable new model code | < 10s |
| Shadow mode | New model only logs predictions; safe to abandon | Instant |
For larger-scale failures (region outage, major model corruption):
A runbook for each of the top-five incident classes, in compressed form. Each follows the 5-minute triage protocol but adds class-specific diagnostics.
Triage:
- Quantify: which features drifted? By how much (PSI > 0.2 is significant)?
- Bound: is the quality drop user-visible? Compare to error budget.
- Mitigate: depends on severity
* mild + recoverable: deploy a hotfix data filter, plan retrain
* severe: rollback to previous model version
Investigation:
- Upstream change: did the data producer release new code? Check change log.
- Distribution shift: real-world change (seasonality, viral event, regulatory)?
- Data pipeline bug: is the schema still as expected?
Resolution:
- Retrain on the shifted distribution OR
- Add drift-resilient features OR
- Move to online/continual learning
Triage:
- Cold start vs steady state: check GPU utilization and pod-age dashboards
- Sudden vs gradual: sudden = infra event, gradual = leak or accumulating queue
- Mitigate:
* cold-start storm: scale up replicas, force warm pool
* queue backup: drop the oldest requests; degrade to smaller model
* memory leak: rolling restart
Investigation:
- Recent deploy: did latency regress at exact deploy time?
- GPU thermal throttling: check DCGM metrics
- KV cache OOM (LLM-specific): is max_seq_len too high for available HBM?
Resolution:
- Right-size the pod or pre-warm pool
- Cap max sequence length / batch
- Add a slow-query timeout to shed load gracefully
Triage:
- Identify the failing DAG/task
- Bound: how many feature groups affected? How long stale?
- Mitigate:
* short outage: serve last-known-good features from cache; alert
* long outage: failover model to a feature-light variant
Investigation:
- Upstream producer outage: check their status page
- Schema change: validate against contract; check DLQ for rejected records
- Resource exhaustion: cluster autoscaling, quota limits
Resolution:
- Restart the failed task; retry from checkpoint
- Backfill missing windows
- Add the failure mode to runbook for next time
Triage:
- Sample 10-20 hallucinated outputs; identify pattern (factual? structural? persona drift?)
- Bound: which queries trigger it? Specific topics? Specific users?
- Mitigate:
* jailbreak-induced: tighten input filter
* prompt-template regression: revert template
* model regression: rollback to previous model
* RAG retrieval gap: increase recall, broaden corpus
Investigation:
- Recent prompt template change?
- Recent model swap (e.g., went from Claude-3 to a faster Haiku variant)?
- Coverage gap: are users asking about topics absent from the corpus?
Resolution:
- Restore last-good prompt template
- Add eval cases that catch this pattern
- For RAG: expand corpus or improve retrieval recall
Triage:
- Identify: which model, which customer, which endpoint?
- Pattern: malicious DDOS, runaway agent, legitimate high usage?
- Mitigate:
* suspected attack: block IP/user immediately
* runaway loop: kill all jobs for that customer; investigate prompt
* legitimate burst: apply rate limit; communicate
Investigation:
- Agent stuck in tool-thrashing loop? Check trace for repeated tool calls.
- Missing rate limit on a new endpoint?
- Prompt injection that exhausts token budget intentionally?
Resolution:
- Add per-customer and per-endpoint rate limits + hard daily cost caps
- Add a circuit breaker on agent loops (> 20 iterations -> halt)
- Add a max-cost-per-conversation guard
A blameless post-mortem template that maps to SRE practice with ML-specific fields:
# Incident: [short name]
## Summary
- **Date**: 2026-05-12
- **Duration**: 47 minutes (T+0 detection at 14:32 UTC, mitigated 15:19)
- **Severity**: P1
- **User impact**: ~12,500 users received degraded predictions; estimated revenue loss $X
## Timeline (UTC)
| Time | Event |
|---|---|
| 14:32 | Continuous eval pipeline alert: val_acc dropped 0.92 -> 0.78 |
| 14:34 | On-call acknowledged in PagerDuty |
| 14:36 | #incidents-ml notified |
| 14:40 | Bounded scope: only checkout-recommendation model affected |
| 14:48 | Decision: rollback to v3.2.1 (previous Production version) |
| 14:52 | Rollback executed via MLflow registry |
| 15:06 | Verified val_acc returned to 0.91 |
| 15:19 | Incident closed; status page updated |
## Root cause (5-whys)
1. Why did accuracy drop? -> Model v3.2.2 was trained on corrupted data
2. Why was the data corrupted? -> Upstream events service deployed a schema change that renamed `purchased_at` -> `bought_at`
3. Why did training succeed despite the rename? -> Our pipeline silently null-filled missing columns
4. Why did the pipeline null-fill? -> No data contract validation at ingest
5. Why no contract? -> The team hadn't adopted contracts yet
Root cause: missing data contract at the events-service boundary.
## Action items
- [ ] **[Owner: data-platform]** Add Pydantic contract for events ingest by 2026-05-20
- [ ] **[Owner: ml-platform]** Eval pipeline should refuse to promote models with > 5% feature null-rate change by 2026-05-26
- [ ] **[Owner: incident-response]** Update model-accuracy-regression runbook with 'check for upstream schema change' step by 2026-05-15
## What went well
- Detection: continuous eval caught it within 5 minutes of deploy
- Mitigation: rollback completed in 4 minutes
- Communication: stakeholders informed before any social-media noise
## What didn't
- Data contract was a known gap, not yet implemented
- The training pipeline silently null-filled instead of failing loudly
## What we'll change
- All upstream boundaries get Pydantic contracts by end of Q2 2026
- Pipeline never silently null-fills; missing-column = hard failure with alert
The discipline matters: blameless framing (no naming the person who deployed the rename), 5-whys to systemic cause (not just "the model broke"), action items with owners and dates (not vague "we'll do better"), explicit "what went well" so good responses get reinforced.
ML on-call differs from web-service on-call in three ways:
| Pattern | When |
|---|---|
| Single rotation, business-hours-only | Pre-revenue products; non-critical ML |
| Single rotation, 24/7 | Critical ML systems, small team |
| Primary + secondary, weekly | Mid-size team (10-15 ML engineers) |
| Follow-the-sun across regions | Large org with EU + US + APAC engineers |
| Dedicated "ML SRE" subteam | Hyperscale ML platforms (FAANG, top AI labs) |
The escalation chain inside each rotation: primary on-call (acknowledge in < 5 min), secondary (page if primary doesn't respond in 10 min), tech lead (page on P0 or 30 min unresolved), engineering manager (P0 or 1 hour unresolved). Document this on the team's runbook page so nobody has to figure it out at 3am.
Case studies make the abstract concrete. Three high-visibility incidents that motivated industry-wide practice changes:
An Air Canada customer asked the airline's website chatbot about bereavement fares. The bot confidently described a refund policy that did not exist. The customer relied on it, booked the flight, and was denied the refund. The Civil Resolution Tribunal of British Columbia ordered Air Canada to pay damages and ruled that the chatbot's statements were the airline's responsibility.
Klarna had publicly celebrated replacing ~700 customer-service agents with an AI assistant. After ~12 months in production, NPS dropped, complex tickets escalated to humans without context, and the company partially rolled back — re-hiring human agents for tickets above a complexity threshold.
A team deployed a coding agent that, under specific prompts, entered a tool-thrashing loop calling its own browser tool with progressively longer URLs. The loop ran for ~6 hours overnight before the daily cost alert fired. Total bill: mid-six figures.
max_tokens_total=200000, kill at limit) at the application layer, not just per-requestAn on-call engineer is paged at 3am: 'agent loop runaway, $200/min burn rate'. Which action comes first?
After every incident, run a blameless post-mortem:
The goal: every incident makes the system more resilient. Same incident type happening twice means the post-mortem failed.
Tests · Verify the runbook covers all 5 steps clearly. Verify escalation path is documented. Pretend you're on-call at 2am — can you follow this without prior context?
Why is 'mitigate before investigate' the standard incident-response order?
Your team has runbooks for top-10 incident classes but has never run a chaos drill. A real P0 hits — the runbook for the affected class is 18 months old. Most defensible response?
| Model server OOM |
| Memory alerts + OOM kills |
| Scale up memory; reduce batch size; investigate leak |
| Embedding drift | Vector similarity to baseline | Re-embed corpus; investigate model change |