Lesson 1 · Production AI Architecture · Senior

Reviewing an AI Feature Like a Distributed System

~14 min · 3 modules · the repeatable review that turns "we added AI" into a design you can defend

Published

ReliabilityScalabilityObservabilityCost controlFailure modes

Your bar: walk into a design review for an AI feature and run it through the same lenses you’d run on any production service — reliability, scalability, availability, observability, cost, failure modes — then name the one new variable AI adds, non-determinism, and show exactly how it bends each lens. By the end you can answer the question a VP actually asks: what happens when the model is slow, wrong, rate-limited, or down — and can you see it? 1

An AI feature is not a new kind of system. It’s a service calling a remote dependency. Four moves frame the review:

it’s a distributed system — run the usual lenses

the dependency is non-deterministic — the one new variable

capacity is a token budget, not RPS

reliability now includes “correct-enough,” not just “200 OK”

Your service request in Model call remote · rate-limited Answer out maybe wrong Reliability correct-enough, not just up Scalability tokens/sec vs a provider limit Observability + a quality axis: was it right? + ONE new variable: non-determinism Same skeleton as any service you've shipped. The model is just a flaky, remote, non-deterministic dependency. Reliability theory isn't reinvented — it's inherited from SRE and distributed systems and bent by three deltas. The deltas: correctness is reliability · tokens are capacity · quality is a monitored signal.
The whole review in one picture. You already know how to review a service that depends on a remote, rate-limited, occasionally-down API. AI adds exactly one thing — the dependency can be wrong, not just down — and that single fact bends reliability, scalability, and observability.1
1

Reliability

For a normal service, reliable means “it responded, within budget.” For an AI feature you carry a second axis: was the response correct-enough? A confident wrong answer is an outage the health check never sees.2

Two axes, not one — availability AND quality

Reliable = timely AND correct-enough quality ↑ availability → correct but too slow 30s hang → user gone ✓ timely + correct the only reliable quadrant slow + wrong worst case fast but wrong 200 OK · health check happy user harmed, monitor silent
A normal service only has the horizontal axis. The bottom-right quadrant — fast but wrong — is the one AI adds, and it's invisible to availability monitoring. You must set an SLO on both axes.2

The graceful-degradation ladder — shed quality before availability

When the model is slow / throttled / down — step down, don't hang Primary model full quality Fallback model cheaper / faster Shorter context less work Cached / template no model call Honest "can't now" The principle is older than AI: under saturation, drop quality to preserve availability. A degraded answer beats a 30-second hang; an honest "I can't" beats a confident wrong answer.
The fallback model is the AI equivalent of a read replica or a static cached page — a cheaper, more-available path you route to when the primary is rate-limited, timing out, or down.2

Is Reliability for AI = the probability of a useful, correct-enough answer within budget, under real load and partial failure. Two axes: availability/latency and quality.

Why it exists The model can be “up” yet slow, rate-limited, or confidently wrong. Each of those is an outage to the user even though the endpoint returns 200.

Like (world) A specialist who’s always at their desk but sometimes gives wrong advice. “Available” isn’t the bar; “reliably useful” is.

Like (code) SRE’s SLI/SLO/error-budget discipline — but you spend a budget on two axes, latency and correctness, not one.

✗ “The model endpoint is up and returning 200, so the feature is reliable.”
✓ A 200 with a confident wrong answer passes every health check and still harms the user. Reliability needs a quality axis the health check can’t see.
✗ “If the provider is slow, we just wait — better a late right answer than none.”
✓ A 30s hang is an outage. Degrade gracefully: fall back to a faster model, shorten context, serve a cached answer, or decline honestly.

📥 Memory rule: Reliable AI means useful and correct-enough, within budget — not “the model is up.” Set an SLO on quality, not just availability.

Memory check
  • What are the two axes of AI reliability? → availability/latency (responded in budget) and quality (correct-enough)
  • Why is "200 OK" insufficient? → a fast, confident wrong answer passes the health check but harms the user — quality is invisible to availability monitoring
  • What's the degradation ladder? → fallback model → shorter context → cached/templated answer → honest decline — shed quality before availability
M1 — What does “reliability” mean for an AI feature, and why isn’t “200 OK” enough?

Hit these points: reliability for AI = the probability of a useful, correct-enough answer within budget under real load and partial failure — not “the model process is up” → a model that returns a confident wrong answer, or hangs for 30s, or is rate-limited, is an outage to the user even though the endpoint is technically healthy → so you carry two axes: availability (did it respond in budget) and quality (was the response correct/grounded/safe) → set an SLO on both, spend an error budget against both, and degrade gracefully — shorter context, cheaper fallback model, cached/templated answer, or an honest “can’t do that right now” — rather than hanging or shipping a wrong answer.

2

Scalability

A normal service scales in requests per second against your own pool. An AI feature scales in tokens per second against a provider rate limit you don’t control — and the cost of one request grows with how much it reads and writes.3

The capacity unit is the token, and the ceiling is upstream

You queue behind a token limit you don't own short request long-output job short request Admission control per-tenant token budget + queue + shed provider rate limit tokens / min · you don't set it Model cost & latency scale with output length If self-hosted the wall is KV-cache memory grows: context len × concurrency ⚠ No admission control → one long-output job consumes the budget and head-of-line-blocks everyone → latency cliff, not graceful slowdown.
Model it as a queue with a token budget and a hard upstream ceiling. Capacity planning here is the AI analogue of connection-pool and thread-pool sizing — get it wrong and you get a latency cliff, not a gentle slowdown.3

What changes vs a normal stateless service

DimensionNormal serviceAI feature
Capacity unitRequests / secTokens / sec (input + output)
The ceilingYour own pool / CPUA provider rate limit you don’t control
Per-request costRoughly flatScales with input + output length
Self-hosted bottleneckCPU / connectionsKV-cache memory (context len × concurrency)
Saturation symptomCPU pegged, queue growsProvider throttling, latency cliff

Is Inference capacity planning = sizing for tokens/sec and concurrent requests against a provider rate limit (or self-hosted GPU memory), with queueing, batching, and admission control.

Why it exists The binding constraint moved off your box. You bill and provision in tokens; the upstream limit and output length, not your CPU, decide when you saturate.

Like (world) A toll booth with a fixed cars-per-minute throughput. You can’t widen it; you meter who enters and queue the rest so nobody gridlocks.

Like (code) A bounded connection pool against a downstream you don’t own — admission control and back-pressure keep one fat query from starving the rest.

✗ “We’ll just autoscale our pods if AI traffic grows.”
✓ More pods don’t raise the provider’s token limit. Past the upstream ceiling you must queue, shed, batch, or fall back — scaling your tier does nothing.
✗ “Every AI request costs about the same, so capacity is just RPS.”
✓ Cost and latency scale with input + output length. A few long-context, long-output requests can consume the budget and block many short ones.

📥 Memory rule: Provision and bill in tokens, not requests; the ceiling is an upstream limit you don’t own. Add admission control before the wall, not after the cliff.

Memory check
  • What's the capacity unit for an AI feature? → the token (input + output) against a provider rate limit, not RPS against your own pool
  • Why won't autoscaling pods fix saturation? → the ceiling is the provider's token limit, not your CPU; more pods don't raise it — you must queue, shed, batch, or fall back
  • What's the self-hosted bottleneck? → KV-cache memory, which grows with context length × concurrency — long-context requests starve short ones
M2 — How is capacity planning different for an AI feature than for a normal stateless service?

Hit these points: the capacity unit is the token, not the request — you provision and bill in input+output tokens the way you provision CPU and bill in RPS → the ceiling is usually a provider rate limit (tokens/min) you don’t control, not your own thread pool → on self-hosted GPUs the binding constraint is KV-cache memory, which grows with context length × concurrency, so a few long-context requests can starve many short ones → a long output costs latency and money linearly, and queueing plus admission control decide whether you degrade gracefully or fall off a latency cliff → model it as a queue with a token budget and a hard upstream limit, and add load shedding before you hit it.

3

Observability

Logs, metrics, and traces still apply — but AI adds a fourth axis classic systems don’t have: a quality signal (was the output correct, grounded, safe?). And you must be able to reconstruct, after the fact, exactly what one request saw and did.4

Three signals + a quality axis + auditability

What you must be able to see Traces / spans agent-loop call tree: model + tool + retrieval latency · tokens / span Metrics latency (tails) error / rate-limit rate tokens & cost / request Quality signal (the new axis) eval: correct? grounded? safe? golden set + online Auditability prompt · context model+version · tools output · by request id The test: "Show me what the agent did for ticket #4471 last Tuesday — and was it right." If you can't answer that from telemetry, you can't debug a wrong answer or pass an audit. Wire format: OpenTelemetry GenAI semantic conventions (model name, token counts, tool calls) so telemetry isn't vendor-locked. Capturing prompt/completion content is opt-in — it carries PII + cost weight.
The first three are the classic logs/metrics/traces. The quality signal and per-request auditability are what AI adds — a confident wrong answer is only debuggable if you captured what it saw and scored whether it was right.4

Why this lens is heavier for AI

Question to answerNormal serviceAI feature
Is it up / fast?Metrics + tracesSame — plus token & cost metrics
Was it correct?Mostly implied by 200A separate eval/quality signal — the new axis
What did it do & why?Request logFull call tree: prompt, context, model+version, tools
Did behavior drift?Rare (you ship code)Common — provider can update the model under you

Is AI observability = answering “what did the system do and why” from telemetry across the trace/span call tree, an eval signal for quality, and cost/usage — logs/metrics/traces plus a quality axis.

Why it exists The output can be wrong while every classic signal looks green. Without a quality signal and per-request auditability you can’t detect or debug a wrong answer.

Like (world) A flight recorder: you don’t just log that the plane landed — you can replay every input and decision to explain a bad outcome afterward.

Like (code) Distributed tracing with a correctness assertion bolted on — the span tree shows what ran; the eval shows whether the result was right.

✗ “We have latency and error dashboards, so the AI feature is observable.”
✓ Those go green while the model is confidently wrong. You need a quality/eval signal and the ability to reconstruct what one request saw and did.
✗ “We’ll log everything, including full prompts and completions, by default.”
✓ Prompt/completion content carries PII and cost weight, so capturing it is opt-in and governed. Capture structured attributes by default, raw content deliberately.

📥 Memory rule: Logs, metrics, traces plus a quality axis. If you can’t reconstruct what a request saw and whether it was right, it isn’t observable.

Memory check
  • What's the fourth axis AI adds? → a quality/eval signal — was the output correct, grounded, safe — scored offline on a golden set and sampled online
  • What must auditability let you reconstruct? → the prompt, retrieved context, model+version, tool calls, and output for a given request id, retained
  • Why prefer OpenTelemetry GenAI conventions? → a standard attribute set (model, token counts, tool calls) keeps telemetry from being vendor-locked
M3 — What’s the minimum observability you’d require before letting an AI feature into production?

Hit these points: classic three signals plus a fourth axis → traces: the full agent-loop call tree — model calls, retrievals, tool calls, latency, token counts per span, ideally on the OpenTelemetry GenAI conventions so you’re not vendor-locked → metrics: latency (with tails), error and rate-limit rates, tokens/request, cost/request → the quality axis: an eval signal scoring whether output was correct, grounded, and safe, offline on a golden set and sampled online → auditability: reconstruct exactly what a request saw and did — prompt, retrieved context, model+version, tool calls, output — tied to a request id and retained → if you can’t answer “what did it do for ticket #4471 and was it right,” you’re not ready.

★ Principal-engineer view: Resist the urge to invent “AI architecture.” You already own the playbook — SLOs, error budgets, graceful degradation, back-pressure, tracing. Run it. Then spend your scrutiny on the three deltas non-determinism creates: correctness becomes part of reliability, tokens become the capacity unit, and output quality becomes a monitored signal that can drift. The provider and its token bill are now in your critical path — review them like any other hard dependency, with a fallback and a kill switch. 5

This review is the methodology the whole track runs on. For where these concerns land inside a multi-agent runtime, see

AI Agents · Lesson 4 — Agent systems & production

; for the context-pipeline review angle, see

Context Engineering · Lesson 5 — Architecture reviews & production design

. This track is the dedicated production-review methodology.

Retrieval practice — test the three lenses

Q1. What is the single new variable an AI feature adds over a normal remote-dependency service?

Q2. An AI endpoint returns 200 with a confident but wrong answer. How does the reliability lens treat it?

Q3. Your AI traffic is unchanged but requests start getting throttled. What is the binding constraint?

Q4. What does AI observability require that classic logs, metrics, and traces do not cover?

Q5. The model is rate-limited at peak. What is the right reliability response?

Interview — pick your bar

Answer out loud in ~60s, then reveal. Core = recall · Senior = trade-offs & failure modes · Staff = synthesis under ambiguity · System Design = open design round (a different axis, not a harder level).

Why is an AI feature "just a distributed system," and what's the one thing that's different?
Hit these points: it's a service calling a remote, rate-limited, occasionally-down dependency — so the model call gets the same treatment as any flaky API: timeouts, retries with backoff, circuit breakers, back-pressure → the one new variable is non-determinism: the same input can return a different, sometimes wrong, output → that's the delta you spend review time on; the rest of reliability theory is inherited, not reinvented → so the review is "run the usual lenses, then ask what non-determinism does to each."
What does "reliability" mean for an AI feature, and why isn't "200 OK" enough?
Hit these points: reliability for AI = the probability of a useful, correct-enough answer within budget under real load and partial failure — not "the process is up" → a model that returns a confident wrong answer, hangs for 30s, or is rate-limited is an outage to the user even though the endpoint is healthy → so you carry two axes: availability/latency and quality → set an SLO on both and degrade gracefully — fallback model, shorter context, cached answer, or an honest decline — instead of hanging or shipping a wrong answer.
What's the capacity unit for an AI feature, and where's the ceiling?
Hit these points: the unit is the token (input + output), not the request — you provision and bill in tokens the way you provision CPU and bill in RPS → the ceiling is usually a provider rate limit (tokens/min) you don't control, not your own pool → per-request cost and latency scale with length, so a few long-output requests can dominate → if self-hosted, the bottleneck is KV-cache memory, which grows with context length × concurrency → so capacity planning is queueing + admission control against an upstream limit.
Name the fourth observability axis AI adds beyond logs, metrics, and traces.
Hit these points: a quality / eval signal — was the output correct, grounded, and safe → scored offline on a golden set and sampled online from production → classic signals go green while the model is confidently wrong, so without a quality axis you can't detect a bad answer → pair it with auditability: reconstruct the prompt, context, model+version, tools, and output for a given request id → standardize spans on the OpenTelemetry GenAI conventions so telemetry isn't vendor-locked.
Your AI feature's p99 latency is 9s and users are abandoning. Where do you look first?
Hit these points: pull the trace for slow requests and decompose end-to-end latency: retrieval, prompt assembly, model time-to-first-token, generation time, tool calls → most AI tail latency is generation time, which scales with output length, so check whether slow requests just produce more tokens — then cap or stream output → separate provider-side latency (queueing behind a rate limit, a slow model version) from your own; the OTel GenAI span attributes tell you which → a long-output request behind a shared limit creates head-of-line blocking for everyone — add admission control and per-tenant budgets → mitigate: stream so time-to-first-token is the felt latency, hard-cap generation, fall back to a faster model near the limit.
Name three failure modes an AI dependency adds that a normal HTTP dependency doesn't, and contain each.
Hit these points: one — silent wrong answer (hallucination): the call succeeds, the answer is confidently wrong; contain with grounding/citations, an eval/guardrail check, and surfacing uncertainty → two — provider rate-limit / throttle: traffic unchanged but a global or neighbor limit hit; contain with client-side rate limiting, backoff, queueing, and a fallback model → three — model-version drift: the provider updates the model and behavior regresses; contain by pinning the version where possible and monitoring the quality signal → bonus — latency cliff from long outputs and cost blowup from runaway tokens; contain with output caps and per-tenant budgets → theme: these are partial-failure modes — apply the usual timeout/retry/circuit-breaker discipline plus a quality gate.
Why does the same input sometimes give a different output, and what does that change about review?
Hit these points: the model samples from a probability distribution over next tokens, so identical input can yield different output; provider-side model updates, sampling temperature, and floating-point non-determinism add variance → this is the one variable a normal service lacks, and it bends every lens: you can't assert exact-match in a test, a retry won't return the same answer, and a passing eval can regress silently after a version bump → so review adds: pin the model version, test on distributions and graded evals not exact strings, and treat output quality as a monitored, drift-prone signal → everything else is a normal distributed system.
You inherit an AI feature with no SLOs. Define a reliability target and an error budget.
Hit these points: pick SLIs on both axes — availability/latency (fraction answered within a latency budget, e.g. p95 under N seconds) and quality (fraction graded correct-enough on a sampled/golden set) → set SLO targets per axis from product tolerance: a code assistant tolerates more wrong-but-cheap than a medical summarizer → the error budget is the allowed miss on each; burning availability means too slow/throttled, burning quality means the model regressed or retrieval degraded → alert on budget burn rate, not raw errors, and tie release/throttle decisions to remaining budget → the trap: measuring only availability — a feature can be 100% available and 40% wrong, which the user experiences as broken.
Walk me through how you'd review a proposed AI feature the way you review any new service.
Hit these points: it IS a distributed system — a call to a remote, rate-limited, occasionally-down dependency — so run the usual lenses: reliability, scalability, availability, observability, cost, failure modes → add exactly one new variable: the dependency is non-deterministic, so the same input can return a different, sometimes wrong, output → that bends every lens — reliability now includes "correct-enough" not just "returned 200"; capacity is tokens/sec against a provider rate limit, not RPS against your pool; observability needs a quality axis → name the new dependencies: provider availability and token cost are now in your critical path and on your bill → close with the VP's question: what happens when the model is slow, wrong, rate-limited, or down — and can you see it.
A team says "it's just an API call to the model, treat it like any other microservice." Where's that right, where does it break?
Hit these points: right — it is a remote dependency, so timeouts, retries with backoff, circuit breakers, bulkheads, idempotency, and back-pressure apply unchanged; don't reinvent reliability theory → where it breaks — the dependency is non-deterministic and can fail by being wrong, not just down, so a 200 with a confident hallucination passes every classic health check while harming the user → capacity is a token budget against a provider rate limit you don't own, not RPS against your pool, so saturation looks like throttling and latency cliffs, not CPU → observability needs a quality axis and per-request auditability a stateless microservice never needed → so: same skeleton, three deltas — correctness as reliability, tokens as capacity, quality as a monitored signal.
Design-round framework — narrate an AI-feature review in this order so the interviewer hears "distributed system first, then the deltas":
  1. Frame it: a service calling a remote, rate-limited, non-deterministic dependency — run the usual lenses, then ask what non-determinism does to each.
  2. Scope & blast radius: who sees it, cost of a wrong vs slow vs down answer, is the model in the critical path or can it be async / advisory?
  3. Reliability: SLOs on availability AND quality; graceful-degradation ladder (fallback model → shorter context → cached/templated → honest decline); timeouts / retries / circuit breaker around the provider.
  4. Scalability: capacity in tokens/sec against the provider rate limit; queueing, admission control, output caps, per-tenant budgets; KV-cache limits if self-hosted.
  5. Observability: OTel GenAI traces, latency / cost / token metrics, an eval signal for quality, request-level auditability.
  6. Failure modes: hallucination, rate-limit, version drift, latency cliff, cost blowup — each with a containment.
  7. Cost & control: tokens/request, caching, model tiering, per-tenant metering, and a kill switch — then close on the VP's question.
Run a full architecture review of a proposed customer-facing AI summarization feature.
A strong answer covers: frame it as a distributed system with a non-deterministic remote dependency, then run the lenses in priority order → scope and blast radius: who sees it, cost of a wrong vs slow vs down answer, is the model in the critical path or can it be async → reliability: SLOs on availability and quality, a graceful-degradation ladder, timeouts/retries/circuit breaker around the provider → scalability: capacity in tokens/sec against the provider limit, queueing and admission control, output caps, per-tenant budgets, KV-cache limits if self-hosted → observability: OTel GenAI traces, latency/cost/token metrics, an eval signal for quality, request-level auditability → failure modes: hallucination, rate-limit, version drift, latency cliff, cost blowup — each with a containment → cost: tokens/request, caching, model tiering, kill switch → close on what a VP asks: what happens when it's slow, wrong, throttled, or down, and can you see it and roll back.
Stress-test this: "a single shared model gateway in front of every team's AI feature, primary provider only, retry-on-error." Where does it hurt at scale?
A strong answer covers: the gateway shape is right — one place for auth, metering, telemetry, and policy — but the stated config concentrates risk → single provider, no fallback makes the provider a hard dependency: a regional outage or a global rate-limit event takes down every team at once, so add a fallback model and degrade rather than fail → naive retry-on-error amplifies a throttle into a retry storm and burns the shared rate limit; use bounded retries with jittered backoff, a circuit breaker, and shed load before the upstream limit → a shared limit with no per-tenant budget means one team's long-output batch starves everyone (noisy neighbor / head-of-line blocking); add per-tenant token budgets and admission control → retrying a non-deterministic call may return a different answer, so retries must be safe/idempotent at the feature level → observability and a per-tenant kill switch are mandatory because the blast radius is now everyone → net: keep the gateway, add fallback, back-pressure, per-tenant budgets, and isolation.
Sources
Kleppmann, M., 2017, "Designing Data-Intensive Applications" (DDIA), O'Reilly. Reliability / scalability / maintainability framing and partial-failure discipline (retries, back-pressure, idempotency) ported onto an AI runtime.
Google, "Site Reliability Engineering" (the SRE Book) — sre.google/books. SLI / SLO / error budgets, graceful degradation, load shedding. AI inherits this reliability vocabulary rather than getting a new one.
AWS, "Well-Architected Framework: Generative AI Lens" — docs.aws.amazon.com/wellarchitected/latest/generative-ai-lens. Reviews a GenAI workload across the six pillars; performance/cost framing for token-based capacity. Numbers illustrative.
OpenTelemetry, "GenAI semantic conventions" — opentelemetry.io/docs/specs/semconv/gen-ai. Standard span attributes (model name, token counts, tool calls); prompt/completion content capture is opt-in. Conventions still evolving — verify exact attribute names against the current spec.
OWASP, "Top 10 for LLM Applications" — owasp.org; and NIST, "AI Risk Management Framework (AI RMF 1.0, NIST AI 100-1, 2023)" — nist.gov/itl/ai-risk-management-framework. Production threat model and GOVERN / MAP / MEASURE / MANAGE functions behind treating the provider as a governed dependency.
Was this lesson helpful? Thanks — noted.

These notes reflect my current understanding and are updated as I learn, build, and discover better explanations.