LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 178 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/8
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/11
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageClustering and PCACore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/24
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernanceData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/19
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnAI Lab InterviewingAI Lab System Design Interview
🏗️HardSystem Design

AI Lab System Design Interview

Design AI lab systems with clear goals, scale math, APIs, data models, overload behavior, permissions, eval gates, and operational debugging paths.

30 min read
Learning path
Step 159 of 178 in the full curriculum
AI Lab Coding Interview: Python SystemsAI Lab Behavioral Interview

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

The last chapter practiced the small stateful pieces: queues, rate limiters, cancellation flags, and explicit state machines. A system-design round asks you to place those same pieces on a board and defend the boundaries.

Don't start by drawing every box you know. Name who uses the gateway, size the constraint that actually hurts (often GPU memory or a permission SLO), then add queues, caches, model routing, eval gates, or human review only where that constraint forces them.

We'll keep one running product: an internal model gateway that teams use to call multiple LLM providers. Later follow-ups bolt on permission-aware retrieval and a long-running coding agent, the way an interviewer stretches a first design.

The design round script

Open with a constraint, not a component list:

I'll keep the first design simple, size the constraints early, then add queues, caches, sharding, model routing, or eval gates only when the requirement forces them.

Then follow this order. Each step earns the next: you can't size GPUs before you know the latency SLO, and you shouldn't draw a vector index before you know whether the product retrieves.

  1. Goal: who uses it and what success means.
  2. Requirements: functional and non-functional.
  3. Scale: QPS, tokens, tenants, documents, latency, retention.
  4. API: external contract and important internal interfaces.
  5. Data model: entities, indexes, isolation, retention.
  6. Architecture: simplest request path first.
  7. Reliability: retries, idempotency, backpressure, overload, failover.
  8. Safety/security: permissions, audit, abuse controls, rollback.
  9. Observability: metrics, logs, traces, support views.
  10. Rollout: beta gates, canaries, eval gates, kill switches.

Why start with the goal instead of Kafka, GPUs, or vector databases?

Answer

Because the right infrastructure depends on the product goal and constraints. A support lookup, a long-running coding task, and a model-serving scheduler have different latency, reliability, privacy, and eval requirements.

Design pattern taxonomy

Most frontier AI/backend prompts are combinations of these patterns. Identify the dominant pressure before drawing boxes.

PatternPrompt signalArchitecture movesFollow-up pressure
Model gatewaymulti-provider, teams, API keys, quotasauth, entitlements, route policy, quota buckets, request logstreaming, fallback semantics, budget caps, support replay
Inference schedulerlatency, batching, GPUs, overloadadmission queue, batcher, worker pool, KV/cache accounting, fairnesstail latency, starvation, preemption, 429 vs 503 policy
Permission-aware retrievalenterprise docs, ACLs, deletion, citationssource connectors, ACL snapshots, filtered retrieval, audit trailrevocation SLO, fail closed, hybrid search, stale index
Agent execution platformlong-running tasks, tools, repo accesstask state machine, sandbox, tool policy, event log, artifactscancellation, retries, secret handling, human review
Eval and rollout gatequality launch, regressions, red teamoffline evals, golden sets, canary gates, rollback triggersslice failures, noisy judges, metric ownership
Data ingestion platformconnectors, freshness, normalizationingestion jobs, versioned records, dead-letter queue, backfillschema drift, reprocessing, dedupe, deletion
Observability and supportrequest IDs, incidents, "why did this happen?"traces, decision records, support views, replayable metadataprivacy-safe debugging, retention, sampling
Abuse and safety controlpolicy, misuse, irreversible actionspolicy engine, rate limits, review queues, kill switchesfalse positives, bypass attempts, emergency disable

Use this table to avoid architecture soup. A model gateway prompt doesn't need a vector database unless the product asks for retrieval. A retrieval prompt doesn't need autonomous agent planning unless the user asks the system to take actions. The running product here is the first four rows: gateway, scheduler, retrieval, and agent.

Follow-up response bank

Interviewers often stress the first design with a new constraint. Answer by naming the boundary you'll change.

Follow-upGood moveBad move
"Traffic spikes 10x"admission control, queue SLO, tier fairness, explicit 429 or 503 causeunlimited queues
"Permissions change quickly"ACL freshness SLO, tombstones, fail-closed sensitive sourcesretrieve first, filter after generation
"Provider is down"policy-approved fallback, circuit breaker, surfaced degraded modesilently change model behavior
"Users need cancellation"durable cancel flag, cooperative checks, sandbox terminationbest-effort UI button only
"Support asks why"request ID, policy version, route decision, retrieved IDs, traceraw logs with no decision record
"Eval passes but users complain"slice analysis, online canary metrics, incident cases into regression suiteargue offline eval is enough
"Costs doubled"token accounting, cache hit tracking, model route policy, budget alertsvague autoscaling

Scale math checklist

Every design should include one small calculation. It doesn't need perfect precision; it needs to expose the bottleneck.

SystemMinimum math
Gatewayrequests/minute, tokens/minute, worst-case output cap
Retrievaldocuments, chunks/document, embedding storage, update rate
Schedulerarrival rate, average service time, queue wait, GPU memory
Agent serviceconcurrent jobs, sandbox time, log/artifact storage, retry budget
Eval platformexamples per suite, runs per release, judge/model cost
Voice/chatp95 latency budget split across network, model, tools, synthesis
Ingestionsource QPS, backfill duration, dedupe key cardinality

Use this phrasing:

I'll size the constraint that most affects the design. If that assumption changes, the architecture boundary I would revisit is X.

Serving math you should have ready

For any serving prompt, two numbers decide the design before you draw a single box: how much GPU memory the weights take, and how fast the KV cache grows per request. You don't need exact figures. You need to show that you know where the memory goes.

The weight footprint is the parameter count times the bytes per parameter:

Mweights=P×bM_\text{weights} = P \times bMweights​=P×b

Here PPP is the number of parameters and bbb is bytes per parameter: 2 for FP16 or BF16, 1 for FP8. An 8B-class model in BF16 is about 8B×2=168\text{B} \times 2 = 168B×2=16 GB of weights before you serve a single token.

The KV cache is the part that scales with traffic. Every token kept in context stores key and value vectors for each key/value head in every layer:

Mtoken=2×nlayers×nKV heads×dhead×pbytesM_\text{token} = 2 \times n_\text{layers} \times n_\text{KV heads} \times d_\text{head} \times p_\text{bytes}Mtoken​=2×nlayers​×nKV heads​×dhead​×pbytes​

The leading 2 is for the key and the value. For a whole batch, multiply by the batch size BBB and the sequence length SSS:

MKV=2×B×S×nlayers×nKV heads×dhead×pbytesM_\text{KV} = 2 \times B \times S \times n_\text{layers} \times n_\text{KV heads} \times d_\text{head} \times p_\text{bytes}MKV​=2×B×S×nlayers​×nKV heads​×dhead​×pbytes​

Plug in a Llama 3 8B-shaped sketch so the scale is concrete: 32 layers, 32 query heads, head dimension 128, BF16. The first KV line is the multi-head-attention counterfactual (32 key/value heads). Llama 3 8B actually uses grouped-query attention (GQA), sharing 8 key/value heads across those 32 query heads, which is the standard memory lever.[1]Reference 1The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783[2]Reference 2GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints.https://arxiv.org/abs/2305.13245

serving-memory-math.py
1params = 8_000_000_000 2bytes_per_param = 2 # FP16 or BF16 3weights_gb = params * bytes_per_param / 1e9 4 5n_layers, d_head, p_bytes = 32, 128, 2 6n_kv_heads_mha = 32 # MHA counterfactual: one KV head per query head 7kv_bytes_per_token = 2 * n_layers * n_kv_heads_mha * d_head * p_bytes 8batch, seq = 16, 2048 9kv_gb = kv_bytes_per_token * batch * seq / 1e9 10 11n_kv_heads_gqa = 8 # Llama 3 8B GQA 12kv_bytes_per_token_gqa = 2 * n_layers * n_kv_heads_gqa * d_head * p_bytes 13kv_gb_gqa = kv_bytes_per_token_gqa * batch * seq / 1e9 14 15print("weights_gb:", weights_gb) 16print("kv_bytes_per_token:", kv_bytes_per_token) 17print("kv_mb_per_token:", round(kv_bytes_per_token / 1e6, 2)) 18print("kv_gb:", round(kv_gb, 1)) 19print("kv_gb_gqa:", round(kv_gb_gqa, 1)) 20assert weights_gb == 16.0 21assert kv_bytes_per_token == 524288 22assert round(kv_gb, 1) == 17.2 23assert round(kv_gb_gqa, 1) == 4.3
Output
1weights_gb: 16.0 2kv_bytes_per_token: 524288 3kv_mb_per_token: 0.52 4kv_gb: 17.2 5kv_gb_gqa: 4.3
HBM bar chart on a 0 to 20 GB axis for a Llama 3 8B-shaped model at batch 16 and 2048 tokens. BF16 weights sit at 16.0 GB. Multi-head attention KV cache is 17.2 GB, taller than the weights. Grouped-query attention with 8 key/value heads cuts KV to 4.3 GB.
At batch 16 and 2K context, the MHA cache (17.2 GB) is already taller than the 16 GB of weights. Switching to Llama 3 8B's 8 KV heads drops that cache to 4.3 GB, which is the room you spend on batch size and context.

At batch 16 and 2K context, this multi-head-attention cache rivals weight memory. Switching from 32 to 8 key/value heads with GQA cuts it from about 17 GB to about 4 GB. First confirm that weights and runtime overhead fit; then KV cache often sets marginal batch and context capacity. Activations and workspace still need a slice of HBM, so don't plan to fill the card to 100%.

A serving prompt asks whether you can raise batch size to improve throughput. Which memory term should you check first, and why?

Answer

After confirming that weights and runtime overhead fit, check KV cache. Weight memory is fixed for a loaded model, while KV memory grows with batch size, sequence length, layers, and key/value heads. Doubling batch or context can exhaust remaining HBM.

Decision log habit

When a design has many possible components, keep a visible decision log:

DecisionChosenRejectedWhyReversal signal
Queue placementbefore provider callinside every adapterone overload policyadapter-specific SLO needed
Retrieval filterbefore rerank/generationpost-generation filterprivacy fails closednone for sensitive docs
Fallback modelpolicy-gatedautomatic on any errorbehavior may changeexplicit customer opt-in
Agent writeshuman-revieweddirect writesirreversible action risknarrow, reversible tool scope

This keeps the conversation inspectable. Interviewers can disagree with a choice and still see that the choice was deliberate.

45-minute board plan

Practice with a visible clock. Leave the last 10 minutes for follow-ups instead of spending 30 minutes drawing boxes.

TimeOutput
0-4 mingoal, users, success metric, top risks
4-9 minfunctional and non-functional requirements
9-14 minone scale calculation that exposes the bottleneck
14-20 minAPI and durable data model
20-28 minrequest path with the smallest architecture that works
28-35 minreliability, overload, permissions, and support/debug flow
35-40 minrollout, eval gate, and rollback path
40-45 mintradeoffs, reversal signals, and interviewer follow-ups

If the interviewer interrupts early, jump to the dominant constraint:

The part that most changes the design is constraint. I'll size that first, then show the request path it forces.

Mock design prompts

Treat each prompt like a 45-minute design round. First write requirements, scale math, API, data model, request path, failure modes, and rollout plan. Then open the solution guide.

Prompt 1: model gateway for enterprise teams

Design an API gateway for teams calling multiple LLM providers through one company platform.

Prompt details:

  • Each organization has workspaces, users, API keys, and model access rules.
  • The gateway must enforce requests/minute, tokens/minute, and monthly spend limits.
  • Support needs a request ID that can explain which route, model, policy decision, and overload state happened.
  • Some models are beta-only and must be gated.
  • Traffic can spike 10x during customer-support incidents.

Clarifying questions to ask:

  • Are clients streaming responses, batch jobs, or both?
  • Should spend limits be hard stops, soft alerts, or tier-dependent?
  • Which decision must support explain first: auth failure, quota failure, route choice, or provider failure?
Solution guide

Put these artifacts on the board:

  1. Goal: reliable multi-model access with debuggable controls.
  2. API: POST /v1/responses, GET /v1/requests/{id}, admin endpoints for keys and limits.
  3. Data model: organization, workspace, key, route policy, model entitlement, usage bucket, request log.
  4. Request path: gateway -> auth -> quota estimate -> route policy -> admission queue -> provider adapter -> stream.
  5. Overload: return 429 with Retry-After when this tenant, key, or client exceeds its limit. Return 503 with a retry hint when healthy callers can't be admitted because fleet or provider capacity is exhausted. Route to an approved fallback only when product policy allows the behavior change.
  6. Observability: request ID, model, token estimate, queue wait, provider latency, error class, policy version.
  7. Rollout: canary new routes, kill switch beta models, regression tests for auth and quota bypass.

Common misses: no support path, no versioned policy record, no overload rejection, and no separation between authentication and authorization.

Follow-up guide

If asked about streaming, reserve quota from an estimate before admission, cap output length, then reconcile actual tokens at the end of the stream. If asked about fairness during a 10x spike, split queues by organization or tier so one incident can't starve everyone else. If asked about beta models, answer with a versioned entitlement check and a kill switch:

The gateway should log policy_version, entitlement_id, route_id, and quota_bucket_id on every request so support can explain both accepted and rejected traffic.

Prompt 2: permission-aware enterprise retrieval

Design retrieval for an internal assistant that answers employee questions from company documents.

Prompt details:

  • Documents come from multiple systems with different ACL formats.
  • Permission changes and deletions must take effect quickly.
  • Answers must cite sources.
  • The assistant must not retrieve and then filter private documents after generation.
  • Admins need auditability for "why did this answer use this document?"

Clarifying questions to ask:

  • What is the revocation target: seconds, minutes, or hours?
  • Can indexes be physically separated by tenant, or must filters enforce isolation?
  • Should the assistant fail closed when ACL freshness is unknown?
Solution guide

Put these artifacts on the board:

  1. Ingestion: connector workers pull content plus ACL snapshots and write immutable document versions.
  2. Indexing: tenant or workspace isolation plus ACL metadata filters; deleted docs move to a tombstone state.
  3. Query path: auth context -> eligible corpus filter -> hybrid retrieval -> rerank -> answer with citations.
  4. Freshness: connector lag metric, ACL refresh jobs, deletion queue, and emergency purge path.
  5. Audit: query ID, user identity, eligible filters, retrieved doc IDs, citation IDs, policy version.
  6. Evals: recall slices by source, permission-denied tests, deletion tests, faithfulness checks.
  7. Failure mode: if ACL state is stale or unknown, fail closed for sensitive sources.

Common misses: filtering after generation, no deletion story, no citation IDs, and no way to explain eligibility.

Follow-up guide

If asked about deletion, describe a fast tombstone path first, then slower compaction of embeddings and chunks. If asked about stale permissions, define a freshness SLO per source and fail closed for sensitive sources when the ACL snapshot is too old.

For auditability, store enough to replay the eligibility decision: user identity, groups, source ACL version, query filters, retrieved chunks, citations shown, and model response ID. That lets an admin answer "why this document?" without exposing unrelated private documents.

Prompt 3: long-running coding agent service

Design a service that accepts repository tasks and runs a coding agent asynchronously.

Prompt details:

  • Users submit a repo, branch, task prompt, and tool permissions.
  • Jobs can run for 30 minutes and may need retries or human review.
  • The agent can create commits, run tests, and leave artifacts.
  • Users need live progress, cancellation, logs, and final diff review.
  • Secrets and production systems must be protected.

Clarifying questions to ask:

  • Is the service allowed to push branches, or should it only produce a patch artifact?
  • Which tools need network access, and which should run offline?
  • What happens when a user cancels during a tool call or test run?
Solution guide

Put these artifacts on the board:

  1. API: create task, get task status, stream events, cancel task, list artifacts.
  2. State machine: queued, provisioning, running, blocked, review, failed, canceled, complete.
  3. Execution boundary: sandbox with scoped repo checkout, network policy, secret redaction, time and disk limits.
  4. Persistence: task row, run attempts, tool calls, logs, artifacts, branch/commit refs, cancellation flag.
  5. Recovery: checkpoint workspace state, retry transient infra failures, never replay unsafe writes without idempotency.
  6. Observability: per-tool latency, test results, token use, queue time, sandbox exits, reviewer actions.
  7. Rollout and safety: permission presets, allowlisted tools, audit log, kill switch by tool or model route.

Common misses: no cancellation semantics, no sandbox boundary, no artifact model, and no distinction between retrying a read and replaying a write.

Follow-up guide

If asked about retries, separate infrastructure retries from agent-action retries. Retrying a sandbox provision is safe; replaying a commit, comment, or external API write needs idempotency or human review.

If asked about cancellation, make it cooperative and durable: set a cancellation flag, stop scheduling new tool calls, terminate the sandbox after a grace window, persist partial logs, and mark artifacts as incomplete. If asked about secrets, say the sandbox receives scoped, short-lived credentials and the event log redacts values before storage.

Why is a support/debug path part of the design, not an afterthought?

Answer

Production AI products fail in ways users and operators need to inspect. Request IDs, traces, eligible documents, model choice, policy decisions, and overload state let support debug without guessing.

Drill 1: API gateway and rate-control plane

The gateway is the front door. It authenticates API keys, resolves workspace and organization limits, estimates request cost, routes to a model or queue, and emits a request ID that support can follow. Draw the admit path first. Model routing and streaming hang off this spine; they don't replace it.

Diagram showing Client, API gateway, Auth + quota, and Admission queue.
Client, API gateway, Auth + quota, and Admission queue.

Design checklist:

  • API keys map to workspace and organization.
  • Limits apply across requests/minute, tokens/minute, model, and tier.
  • Request IDs appear in responses and logs.
  • Tenant or client limits return 429; fleet or provider overload returns 503. Both carry a request ID and a bounded retry hint instead of silent queue growth.
  • Beta features are gated by explicit version or feature flags.
  • Rollout has canaries, kill switches, and regression checks.

Use Python to sanity-check rate math before drawing capacity boxes:

gateway-token-budget.py
1requests_per_minute = 4_000 2avg_input_tokens = 1_200 3avg_output_tokens = 450 4tokens_per_minute = requests_per_minute * (avg_input_tokens + avg_output_tokens) 5tokens_per_second = tokens_per_minute / 60 6 7print("tokens_per_minute:", tokens_per_minute) 8print("tokens_per_second:", round(tokens_per_second))
Output
1tokens_per_minute: 6600000 2tokens_per_second: 110000

The estimate is an admission-time reservation, not the final bill. A streaming response needs a maximum output budget, then a reconciliation step when the stream ends:

streaming-quota-reconciliation.py
1remaining_before = 10_000 2reserved_tokens = 1_800 3actual_tokens = 1_520 4 5remaining_after_admission = remaining_before - reserved_tokens 6remaining_after_reconcile = remaining_after_admission + (reserved_tokens - actual_tokens) 7 8print("after admission:", remaining_after_admission) 9print("after reconcile:", remaining_after_reconcile) 10assert remaining_after_admission == 8_200 11assert remaining_after_reconcile == 8_480
Output
1after admission: 8200 2after reconcile: 8480

Drill 2: inference scheduler

For LLM serving, the scheduler is where latency, cost, and fairness meet. NVIDIA documents in-flight batching as a way to interleave context and generation work so GPUs are used more efficiently while latency stays under control.[3]Reference 3Paged Attention, IFB, and Request Scheduling.https://nvidia.github.io/TensorRT-LLM/features/paged-attention-ifb-scheduler.html

Serving physics first

Before any scheduler diagram, separate the two work phases:

PhaseWhat happensTypical boundMetric it drives
PrefillProcess the full prompt into first-token KVOften compute-boundTTFT (with queue wait)
DecodeEmit one token at a time using cached KVOften memory-bandwidth-boundITL / TBT and TPOT

That split is why dual SLOs matter: a design can meet mean tokens/sec while still failing stream feel (bad ITL) or first-token UX (bad TTFT). DistServe treats goodput as the request rate that still meets both TTFT and decode-pacing constraints. Colocating the two phases couples those SLOs: a long prefill in the same batch delays every in-flight decode.[4]Reference 4DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving.https://arxiv.org/abs/2401.09670 Chunked prefill, separate prefill/decode pools, and prefill/decode disaggregation are answers to this physics, not optional jargon. Chunked prefill reduces interference by bounding each step. Disaggregation removes it by putting the phases on different GPUs.

Metrics to name in the lab loop

  • Time to first token (TTFT): arrival → first output token (queue + prefill + first token).
  • Inter-token latency (ITL) / time between tokens (TBT): each gap after the first token; use the distribution (including tail) for stream feel.
  • Time per output token (TPOT): mean decode pacing after the first token (not a synonym of ITL).
  • Queue wait time before admission or first scheduled work.
  • p95 and p99 end-to-end latency, plus p95/p99 of TTFT and ITL when the product streams.
  • Fleet goodput / admitted RPS under dual TTFT and ITL SLOs (raw tokens/sec without SLO attainment is not capacity).
  • Tokens per second only with a label: per-request decode rate, fleet aggregate, or prefill rate. Undifferentiated TPS is not a substitute for ITL or TPOT.
  • GPU utilization.
  • Error rate and overload rejections.
  • Cost per successful request.

Serving toolkit (when to reach for each)

LeverWhat it fixesReach for it when
PagedAttention / paged KVKV fragmentation and rigid block allocationLong contexts or high concurrency thrash contiguous KV slots
Continuous (iteration-level) batchingMid-flight admit/finish without waiting for the slowest sequenceStatic batches waste GPU on finished or padded slots
Prefix / radix cacheReuse shared prompt prefixesMany requests share system prompts or multi-turn history
Speculative decodingExtra draft tokens validated in parallelDecode is bandwidth-bound and a smaller draft model is cheap
Chunked prefillCap prefill burst length so decode keeps streamingLong prompts spike TTFT and stall in-flight decode
Prefill/decode disaggregationSeparate pools for the two phasesOne pool fails to meet dual TTFT and ITL SLOs together

Continuous batching and paged attention are orthogonal: continuous batching decides when sequences join or leave the batch; paged attention decides how KV blocks are laid out and freed. Name both mechanisms separately in an interview.

Model-fit scale math

If weights plus KV don't fit one GPU, say the next move in interconnect language: tensor parallelism (TP) for layer shards over high-bandwidth links (often NVLink within a node), pipeline parallelism (PP) across stages (more tolerant of inter-node links, pays bubble cost), and expert parallelism when MoE routing requires it. Always state the communication cost you accept for the fit.

Start capacity planning with a measured workload-specific fleet capacity, not a generic GPU estimate:

scheduler-headroom.py
1measured_capacity_tokens_per_second = 125_000 2expected_demand_tokens_per_second = 110_000 3 4headroom = measured_capacity_tokens_per_second - expected_demand_tokens_per_second 5headroom_percent = headroom / measured_capacity_tokens_per_second * 100 6 7print("headroom_tokens_per_second:", headroom) 8print("headroom_percent:", round(headroom_percent, 1))
Output
1headroom_tokens_per_second: 15000 2headroom_percent: 12.0

For an interview-sized overload policy, estimate queue wait before admission. This approximation deliberately stays simple: it treats tokens as homogeneous. A real scheduler tracks two resources separately (prefill token backlog vs active decode sequences / free KV blocks) and measured tail latency for each SLO.

Keep rejection ownership visible. 429 Too Many Requests says the caller exceeded a tenant, key, or client policy and could succeed after its quota window resets. 503 Service Unavailable says the service fleet or an upstream provider lacks capacity for an otherwise eligible request. A full tenant bucket can produce 429 even when GPUs are idle; a saturated fleet can produce 503 for a tenant that is under quota.

Two admission paths on one gateway. Left: tenant A is over its requests-per-minute bucket while GPUs sit idle, so the gateway returns 429. Right: tenant B is under quota, but estimated queue wait is 0.4 seconds against a 0.25-second SLO, so the gateway returns 503.
Tenant A is over quota and gets 429 even if GPUs are idle. Tenant B is under quota but the estimated wait is 0.4 s against a 0.25 s SLO, so the rejection is 503. The status code names the owner, not the vibe of the outage.

The wait check below is the 503 side of that split. 20,000 queued tokens clear a 0.25 s budget at 125,000 tokens/s. 50,000 don't. The two-resource sketch then adds decode slots and free KV blocks so a request can fail admission even when the prefill backlog looks fine.

scheduler-admission.py
1def admit(queued_tokens: int, service_tokens_per_second: int, max_queue_wait_seconds: float) -> bool: 2 estimated_wait = queued_tokens / service_tokens_per_second 3 return estimated_wait <= max_queue_wait_seconds 4 5def admit_two_resource( 6 prefill_backlog_tokens: int, 7 prefill_tokens_per_second: int, 8 active_decode_sequences: int, 9 max_decode_sequences: int, 10 free_kv_blocks: int, 11 kv_blocks_needed: int, 12 max_prefill_wait_seconds: float, 13) -> bool: 14 """Sketch dual capacity: prefill backlog and decode/KV slots both must clear.""" 15 prefill_wait = prefill_backlog_tokens / prefill_tokens_per_second 16 decode_ok = active_decode_sequences < max_decode_sequences 17 kv_ok = free_kv_blocks >= kv_blocks_needed 18 return prefill_wait <= max_prefill_wait_seconds and decode_ok and kv_ok 19 20print(admit(queued_tokens=20_000, service_tokens_per_second=125_000, max_queue_wait_seconds=0.25)) 21print(admit(queued_tokens=50_000, service_tokens_per_second=125_000, max_queue_wait_seconds=0.25)) 22print( 23 admit_two_resource( 24 prefill_backlog_tokens=10_000, 25 prefill_tokens_per_second=80_000, 26 active_decode_sequences=48, 27 max_decode_sequences=64, 28 free_kv_blocks=120, 29 kv_blocks_needed=16, 30 max_prefill_wait_seconds=0.25, 31 ) 32)
Output
1True 2False 3True

When should the system return 429 or 503 instead of queueing more work?

Answer

Reject before queueing violates latency or fairness. Use 429 when the caller's own quota or rate policy blocks admission. Use 503 when the shared fleet or provider is overloaded despite the caller remaining eligible. Include Retry-After when the service can estimate a safe retry window.

Drill 3: permission-aware retrieval

For enterprise retrieval, the critical rule is: don't retrieve private data and filter it after generation. Permission constraints must be part of candidate selection, ranking, and auditing.

Architecture pieces:

  • Connector ingestion workers with backpressure.
  • Per-document ACLs or delegated auth checks.
  • Tenant-isolated indexes or strict metadata filters.
  • Hybrid retrieval plus reranking.
  • Citation output with source IDs.
  • Deletion and retention jobs.
  • Offline evals for recall and answer faithfulness.
  • Support traces that show which documents were eligible.
Diagram showing Enterprise source, Connector worker, ACL snapshot, and Hybrid index.
Enterprise source, Connector worker, ACL snapshot, and Hybrid index.

The ACL snapshot and hybrid index both feed candidate selection. That connection matters: unauthorized chunks shouldn't reach the reranker or model context.

For sensitive sources, encode the freshness decision as a fail-closed policy:

acl-freshness-policy.py
1def source_is_eligible(snapshot_age_seconds: int, freshness_slo_seconds: int, sensitive: bool) -> bool: 2 if sensitive and snapshot_age_seconds > freshness_slo_seconds: 3 return False 4 return True 5 6print(source_is_eligible(snapshot_age_seconds=20, freshness_slo_seconds=60, sensitive=True)) 7print(source_is_eligible(snapshot_age_seconds=90, freshness_slo_seconds=60, sensitive=True)) 8print(source_is_eligible(snapshot_age_seconds=90, freshness_slo_seconds=60, sensitive=False))
Output
1True 2False 3True

Filter tombstones and ACLs before ranking. The tiny fixture below makes the order visible:

acl-filter-before-rank.py
1documents = [ 2 {"id": "public-access-policy", "groups": {"employees"}, "deleted": False, "score": 0.82}, 3 {"id": "finance-plan", "groups": {"finance"}, "deleted": False, "score": 0.99}, 4 {"id": "old-handbook", "groups": {"employees"}, "deleted": True, "score": 0.95}, 5] 6user_groups = {"employees"} 7 8eligible = [ 9 document 10 for document in documents 11 if not document["deleted"] and document["groups"] & user_groups 12] 13ranked_ids = [document["id"] for document in sorted(eligible, key=lambda item: item["score"], reverse=True)] 14 15print(ranked_ids) 16assert ranked_ids == ["public-access-policy"]
Output
1['public-access-policy']
Three retrieval candidates for an employees-only user. Ranked by score, finance-plan leads at 0.99, old-handbook is 0.95, and public-access-policy is 0.82. After ACL and tombstone filters, finance-plan is blocked for the finance group, old-handbook is tombstoned, and only public-access-policy at 0.82 reaches rerank.
finance-plan scores 0.99 and still never reaches the reranker: the user isn't in finance. old-handbook is tombstoned. Only public-access-policy (0.82) is eligible. Rank after the filter, not before it.

Drill 4: long-running coding agents

Long-running agent infrastructure has to persist intent, tool calls, artifacts, checkpoints, logs, and permissions. The main design risk isn't just failed execution. It's uncontrolled execution.

Cover:

  • Task states: queued, provisioning, running, blocked, review, failed, canceled, complete.
  • Checkpoints for resumability.
  • Tool permission scopes and audit logs.
  • Secret redaction.
  • Git branch and conflict handling.
  • Streaming progress.
  • Cancellation and deadlines.
  • Evals for task success and regression.

Write legal transitions down before discussing workers. That prevents a cancellation or retry from jumping into an impossible state:

agent-task-state-machine.py
1ALLOWED_TRANSITIONS = { 2 "queued": {"provisioning", "canceled"}, 3 "provisioning": {"running", "failed", "canceled"}, 4 "running": {"blocked", "review", "failed", "canceled"}, 5 "blocked": {"running", "review", "failed", "canceled"}, 6 "review": {"running", "complete", "canceled"}, 7 "failed": set(), 8 "canceled": set(), 9 "complete": set(), 10} 11 12def can_transition(current: str, target: str) -> bool: 13 return target in ALLOWED_TRANSITIONS[current] 14 15print(can_transition("running", "review")) 16print(can_transition("complete", "running"))
Output
1True 2False

Retries need a policy boundary too. Reads and sandbox provisioning can retry automatically. External writes need an idempotency key or review:

agent-retry-policy.py
1def retry_mode(action: str, has_idempotency_key: bool = False) -> str: 2 if action in {"repo_read", "sandbox_provision"}: 3 return "automatic" 4 if has_idempotency_key: 5 return "automatic-with-idempotency" 6 return "human-review" 7 8print(retry_mode("repo_read")) 9print(retry_mode("create_commit")) 10print(retry_mode("post_comment", has_idempotency_key=True))
Output
1automatic 2human-review 3automatic-with-idempotency

Drill 5: eval gates and staged rollout

An evaluation monitor isn't just a dashboard. It turns fixed expectations and incident discoveries into a regression suite, then blocks launch when a critical slice fails.

eval-launch-gate.py
1checks = { 2 "retrieval_recall": (0.94, 0.92), 3 "citation_faithfulness": (0.93, 0.95), 4} 5permission_leaks = 0 6 7failures = [ 8 name 9 for name, (observed, minimum) in checks.items() 10 if observed < minimum 11] 12if permission_leaks > 0: 13 failures.append("permission_leaks") 14 15print("launch_allowed:", not failures) 16print("failures:", failures)
Output
1launch_allowed: False 2failures: ['citation_faithfulness']

Keep online canaries reversible. Offline evals can pass while latency, provider errors, or permission failures regress under real traffic:

canary-rollout-decision.py
1def rollout_decision(error_rate: float, p95_latency_ms: int, permission_failures: int) -> str: 2 if permission_failures > 0: 3 return "rollback" 4 if error_rate > 0.01 or p95_latency_ms > 900: 5 return "hold" 6 return "expand" 7 8print(rollout_decision(error_rate=0.004, p95_latency_ms=720, permission_failures=0)) 9print(rollout_decision(error_rate=0.004, p95_latency_ms=720, permission_failures=1))
Output
1expand 2rollback

Common serving misconceptions

Stale claimWhy it's outdatedCurrent answer
"Static batching with fixed padding is fine for LLM inference"It pads every request to the longest sequence and holds the batch until the slowest one finishes, wasting GPU on padding and blocking short requests behind long onesTwo fixes, not one: continuous (iteration-level) batching admits and finishes sequences mid-flight so the GPU stays busy on real tokens; paged attention lays out KV in non-contiguous blocks so finished sequences free memory without reshaping the whole batch[3]Reference 3Paged Attention, IFB, and Request Scheduling.https://nvidia.github.io/TensorRT-LLM/features/paged-attention-ifb-scheduler.html[5]Reference 5Efficient Memory Management for Large Language Model Serving with PagedAttention.https://arxiv.org/abs/2309.06180
"Slurm is the only scheduler for multi-node GPU clusters"Slurm still fits bare-metal HPC training, but it isn't the only option for serving or enterprise platformsKubernetes with KubeRay deploys Ray clusters that can run training and inference on the same substrate.[6]Reference 6KubeRay and Ray clusters on Kubernetes.https://docs.ray.io/en/latest/cluster/getting-started.html
"Quantization always wrecks quality"True for some naive low-bit schemes, not every calibrated methodFP8 roughly halves BF16 weight bytes; 4-bit methods such as AWQ and GPTQ can reduce weight memory further. Quality and speed remain workload- and runtime-dependent, so evaluate both before release.[7]Reference 7AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration.https://arxiv.org/abs/2306.00978[8]Reference 8GPTQ: Accurate Post-Training Quantization for Generative Pre-Trained Transformershttps://arxiv.org/abs/2210.17323

For each row, name the old approach's failure and the mechanism that replaces it. Don't stop at "we use vLLM now."

Failure modes to avoid

  • Starting with implementation technology before naming user value.
  • Caching without invalidation, privacy, or freshness.
  • Monitoring without exact metrics.
  • Ignoring overload and support/debug needs.
  • Treating safety as a slogan instead of evals, permissions, staged rollout, and rollback.
  • Forgetting that agent systems need reversible actions and audit trails.
Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.A system-design candidate starts with Kafka, GPUs, and vector databases before naming users or success criteria. Which opening creates the right dependency order?

Correct answer: Name users and success criteria, clarify constraints, then size the dominant bottleneck and its failure mode before choosing components.

Infrastructure follows the product and its constraints. Goal, requirements, and one scale calculation determine whether the design needs retrieval, batching, queues, or a particular storage path.

2.A model gateway serves an 8B BF16 model with 16 GB of weights. At batch 16 and 2,048 tokens, its MHA-shaped KV cache is about 17.2 GB, while GQA with 8 KV heads is about 4.3 GB. Which capacity conclusion follows?

Correct answer: KV state can exceed weight memory, and reducing KV heads can recover substantial batch or context headroom.

KV memory scales with batch, sequence length, layers, KV heads, head dimension, and bytes per value. The worked numbers show why a serving design must budget KV separately from fixed weights.

3.A gateway rejects an under-quota tenant because fleet capacity is saturated and the queue would miss its SLO. Which response assigns ownership correctly?

Correct answer: Return 503 with a retry hint for service capacity, while reserving 429 for caller, key, or tenant quota exhaustion.

The error should identify the failing boundary. A healthy tenant blocked by shared fleet capacity receives a service-overload signal, while quota rejection belongs to the caller's budget or entitlement.

4.An enterprise retrieval query finds a private finance chunk with the highest similarity score and a deleted public chunk with the second-highest score. When should ACL and tombstone checks run?

Correct answer: Before reranking and generation, so unauthorized or deleted chunks never enter model context or later citations.

Filtering after generation is too late: the private content may already influence the answer. Eligibility, deletion, and ACL freshness belong before ranking or model context, with audit metadata recording why each chunk was allowed.

5.A coding agent has a durable task state, tool events, and checkpoints. Which transition policy is safest when a user cancels during a test run?

Correct answer: Persist cancellation, stop new calls, clean up the sandbox, retain logs, and mark incomplete artifacts for review.

Long-running jobs need durable cancellation semantics. Persisted intent prevents new side effects, cooperative termination bounds cleanup, and retained evidence lets support explain what happened without claiming a complete result.

6.A launch gate records retrieval recall 0.94 against 0.92, citation faithfulness 0.93 against 0.95, and zero permission leaks. What should happen?

Correct answer: Block launch because one required quality threshold fails, even though recall and permission checks pass.

A gate is a set of required checks, not an average. Citation faithfulness is below its minimum, so the candidate needs a fix or an explicit policy change before user exposure.

7.An interviewer asks what a design should record so support can explain route choice, quota state, and an overload error for one request. Which receipt is sufficient?

Correct answer: Request ID, route and model, policy or entitlement version, quota decision, queue wait, provider result, and error class.

A per-request decision receipt separates authentication, authorization, quota, routing, queue, provider, and failure boundaries. Aggregate metrics or final text can't recover those choices reliably.

8.A service has an offline-passing candidate but a canary with one permission failure, 0.4% errors, and 720 ms p95 against thresholds of 1% and 900 ms. What controller action matches the policy?

Correct answer: Rollback immediately because any permission failure overrides healthy error and latency thresholds.

Permission failures are a safety-critical rollback condition. Passing latency and error thresholds doesn't cancel a policy violation, and offline results can't replace a reversible live gate.

9.A design review asks for one reversal signal for an in-process connector choice. Which signal is tied to the stated tradeoff?

Correct answer: Queue time or deploy coupling becomes the bottleneck despite the connector contract and tests, so measure that path before adding services.

The in-process choice traded independent scaling and deployment for migration speed and one debugger. Queue or deploy coupling becoming the bottleneck is evidence that the rejected service boundary now solves the dominant problem.

9 questions remaining.

Next Step
Continue to AI Lab Behavioral Interview

The decision log, 429 vs 503 ownership, fail-closed retrieval, and eval-gate rollbacks you just designed are the evidence a behavioral round will ask you to narrate. Next you'll turn those mechanisms into judgment stories without sounding rehearsed.

PreviousAI Lab Coding Interview: Python Systems
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

The Llama 3 Herd of Models.

Dubey, A., et al. · 2024 · arXiv preprint

https://arxiv.org/abs/2407.21783

GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints.

Ainslie, J., et al. · 2023 · EMNLP 2023

https://arxiv.org/abs/2305.13245

Paged Attention, IFB, and Request Scheduling.

NVIDIA · 2026

https://nvidia.github.io/TensorRT-LLM/features/paged-attention-ifb-scheduler.html

DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving.

Zhong, Y., et al. · 2024 · OSDI 2024

https://arxiv.org/abs/2401.09670

Efficient Memory Management for Large Language Model Serving with PagedAttention.

Kwon, W., et al. · 2023 · SOSP 2023

https://arxiv.org/abs/2309.06180

KubeRay and Ray clusters on Kubernetes.

Ray (Anyscale) · 2026

https://docs.ray.io/en/latest/cluster/getting-started.html

AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration.

Lin, J., et al. · 2023 · MLSys 2024

https://arxiv.org/abs/2306.00978

GPTQ: Accurate Post-Training Quantization for Generative Pre-Trained Transformers

Frantar, E., et al. · 2023 · ICLR 2023

https://arxiv.org/abs/2210.17323

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.