Chapter 101 — MLOps & LLMOps in Production
📖 Definition
MLOps is the engineering discipline of taking ML models from notebooks to reliable production systems: reproducible data and training, automated deployment, monitoring and retraining. LLMOps applies the same ideas to LLM applications, where the "model" is often a prompt + retrieval + tools + a hosted or self-served LLM.
🔍 The ML Lifecycle
| Stage | Key questions | Typical tools |
|---|---|---|
| Problem framing | What decision? What metric? What baseline? | Docs, stakeholder reviews |
| Data | Where from? Labels? Quality? Versioned? | Data warehouse, DVC/lakeFS, Great Expectations |
| Features | Same logic offline and online? | Feature store (Feast, Tecton) |
| Training | Reproducible? Tracked? | MLflow, Weights & Biases |
| Evaluation | Beats baseline on all slices? | Eval suites (previous chapter) |
| Registry | Which version is approved? | MLflow Model Registry, SageMaker, Vertex |
| Deployment | Batch or real-time? Rollback? | Docker, Kubernetes, KServe, BentoML, SageMaker endpoints |
| Monitoring | Drift? Quality? Cost? | Prometheus/Grafana, Evidently, Arize, LangSmith/Langfuse |
| Retraining | Scheduled or triggered? | Airflow, Kubeflow, Prefect, Dagster |
🔍 Training–Serving Skew (Classic Senior Question)
The model sees features computed one way in training (SQL over the warehouse) and another way in production (Python in the API) → silent accuracy drop.
Fixes:
- Single feature definition used for both (feature store, shared library).
- Log features at serving time and train on those logs.
- Compare training and serving feature distributions continuously.
- Point-in-time correct joins for training data (only use values that existed at that timestamp).
💻 Code Example — Experiment Tracking with MLflow
import mlflow
import mlflow.sklearn
from sklearn.metrics import average_precision_score
mlflow.set_experiment("churn-model")
with mlflow.start_run(run_name="lgbm-v3"):
params = {"num_leaves": 63, "learning_rate": 0.05, "n_estimators": 800}
mlflow.log_params(params)
mlflow.log_param("data_version", "s3://ml-data/churn/2026-10-01") # data lineage
model = train_lgbm(X_train, y_train, **params)
pr_auc = average_precision_score(y_val, model.predict_proba(X_val)[:, 1])
mlflow.log_metric("val_pr_auc", pr_auc)
mlflow.sklearn.log_model(model, "model", registered_model_name="churn") # → model registryReproducibility = code commit + data version + config + environment (container) + random seed.
📊 Deployment Patterns
| Pattern | Latency | Use |
|---|---|---|
| Batch (nightly scores to a table) | Hours | Churn scores, recommendations precomputed, reports |
| Online / real-time API | ms–s | Fraud checks, search ranking, chat |
| Streaming | Seconds | Features/scores from Kafka events |
| Edge / on-device | ms, offline | Mobile keyboard, camera, privacy-sensitive |
Release strategies: shadow → canary → A/B → full rollout, with automatic rollback on guardrail breaches. Keep the previous model "warm" for instant rollback.
🔍 Monitoring: What to Watch
| Category | Signals |
|---|---|
| Data drift | Input feature distributions change (PSI, KL divergence, KS test) |
| Concept drift | The relationship X → y changes (fraudsters adapt, seasons) — accuracy drops even if inputs look the same |
| Prediction drift | Output distribution shifts (suddenly 30% "fraud") |
| Performance | Accuracy/precision once labels arrive (often delayed) |
| Data quality | Nulls, schema changes, out-of-range values, freshness |
| System | Latency p50/p95/p99, error rate, throughput, GPU utilisation |
| Business | Conversion, revenue, complaints |
import numpy as np
def psi(expected: np.ndarray, actual: np.ndarray, bins: int = 10) -> float:
"""Population Stability Index. < 0.1 stable, 0.1–0.25 moderate shift, > 0.25 significant."""
cuts = np.quantile(expected, np.linspace(0, 1, bins + 1))
cuts[0], cuts[-1] = -np.inf, np.inf
e = np.histogram(expected, cuts)[0] / len(expected)
a = np.histogram(actual, cuts)[0] / len(actual)
e, a = np.clip(e, 1e-6, None), np.clip(a, 1e-6, None)
return float(np.sum((a - e) * np.log(a / e)))🔍 Retraining Strategy
- Scheduled (weekly/monthly) — simple, predictable.
- Triggered — on drift alerts or performance drop.
- Continuous / online learning — for fast-changing domains (ads, fraud), with strong safeguards.
- Always: retrain → evaluate vs current champion → promote only if better (champion/challenger).
🔍 What Changes with LLMOps
| MLOps concept | LLMOps equivalent |
|---|---|
| Model version | Model ID + prompt version + retrieval config + tool set |
| Training data | Prompts, few-shot examples, RAG corpus, fine-tuning sets |
| Accuracy metric | Eval suite scores, judge win rates, task success |
| Feature drift | Query/topic drift, corpus changes, upstream model updates |
| Inference cost | Tokens in/out, caching hit rate, GPU hours |
| Debugging | Tracing each step: prompt, retrieved chunks, tool calls, outputs, latency, tokens |
💻 Code Example — Prompt as a Versioned Artifact
# prompts/support_answer/v7.yaml is checked into git and reviewed like code
PROMPT_REGISTRY = {
"support_answer": {
"version": "v7",
"model": "claude-sonnet-5-5",
"temperature": 0.2,
"max_tokens": 600,
"template_path": "prompts/support_answer/v7.yaml",
"eval_suite": "evals/support_answer.jsonl",
"min_scores": {"faithfulness": 0.95, "resolution_judge": 0.80},
}
}
def run(name: str, variables: dict, trace) -> str:
cfg = PROMPT_REGISTRY[name]
prompt = render(cfg["template_path"], variables)
with trace.span("llm", prompt_name=name, prompt_version=cfg["version"], model=cfg["model"]) as s:
out = llm_call(cfg["model"], prompt, temperature=cfg["temperature"], max_tokens=cfg["max_tokens"])
s.set(tokens_in=out.usage.input_tokens, tokens_out=out.usage.output_tokens)
return out.textCI runs the eval suite when the prompt or model changes and blocks the merge if scores fall below min_scores.
🔍 LLM Observability: What to Log per Request
- Request ID, user/tenant (hashed), timestamp, feature/route.
- Model, prompt version, parameters.
- Retrieved document IDs and scores; tool calls and results.
- Input/output tokens, latency per step, cache hits, cost.
- User feedback (thumbs, edits, escalation), safety-filter results.
- PII policy: redact or don't store raw content where not allowed; retention limits.
🔍 Cost Management
- Track cost per request / per feature / per tenant; alert on spikes.
- Model routing (small model first, escalate when needed).
- Prompt caching, response caching, batch APIs for offline work.
- Budgets and rate limits per user/tenant.
- Self-hosting break-even: compare API cost vs GPU cost at your utilisation (idle GPUs are expensive).
🔍 Build vs Buy (Hosted API vs Self-Hosted Model)
| Factor | Hosted API | Self-hosted open model |
|---|---|---|
| Quality | Usually best frontier models | Good, improving; may need fine-tuning |
| Time to market | Fast | Slower (infra, MLOps) |
| Cost at low/medium volume | Cheaper | GPUs idle → expensive |
| Cost at very high steady volume | Can be higher | Can be cheaper with high utilisation |
| Data control / residency | Depends on vendor terms and regions | Full control |
| Customisation | Prompting, some fine-tuning | Full fine-tuning, quantisation, custom decoding |
| Ops burden | Low | High (on-call, upgrades, scaling) |
🧠 What a Senior Answer Adds
- Prevents training–serving skew by design and logs features at serving time.
- Defines ownership: alerts, on-call, rollback, retraining triggers.
- For LLMs, versions everything that changes behaviour (prompt, model, retrieval, tools) and gates releases on evals.
🎯 Likely Interview Questions
- What is MLOps and why is it needed? — Practices to deploy, monitor and maintain ML reliably; models decay and need reproducibility and automation.
- What is training–serving skew and how do you prevent it? — Different feature computation offline vs online; shared feature definitions, feature store, logging serving features.
- Data drift vs concept drift? — Inputs change vs the input–output relationship changes.
- How do you detect drift? — PSI/KS/KL on features and predictions, performance once labels arrive, alerts with thresholds.
- How do you deploy a new model safely? — Registry approval → shadow → canary → A/B → rollout with automatic rollback.
- What do you version in an ML project? — Code, data, features, configs, models, environment; for LLMs also prompts, retrieval config and tools.
- Batch vs real-time inference? — Precomputed periodic scores vs on-request predictions; choose by latency need and freshness.
- What is a feature store? — Central place for feature definitions with offline (training) and online (serving) stores and point-in-time correctness.
- What would you monitor for an LLM app? — Quality evals/sampled grading, user feedback, hallucination/safety flags, latency, tokens/cost, tool errors, retrieval quality.
- When would you self-host an open model instead of using an API? — Data control, high steady volume, deep customisation, latency/edge constraints — weigh against ops burden.
- What is champion/challenger? — Current production model vs candidate evaluated on the same data/traffic; promote only if better.
← Evaluation & Responsible AI | Index | Next: GenAI System Design →