Retrieval, Vector Search & Production RAG
Master lexical, dense and hybrid retrieval; HNSW; chunking; reranking; filtered search; Qdrant operations; evaluation; and migration.
Learning objectives
By the end of this chapter, you should be able to:
- Explain a decoder-only transformer at whiteboard depth — tokenization, embeddings, attention, MLP, residual stream — and connect each part to a serving cost.
- Derive KV-cache memory from first principles and use it to size batch, context, and hardware before touching a benchmark.
- Explain why time-to-first-token is compute-bound and time-per-output-token is memory-bandwidth-bound, and what each implies for optimization.
- Reason about continuous batching, PagedAttention, quantization, and speculative decoding as trade-offs with measurable failure modes, not as feature names.
- Compare vLLM, TGI, TensorRT-LLM, and SGLang, and defend a serving-engine choice for a stated workload.
- Build a defensible cost-per-million-tokens model and make a build-versus-buy call across Bedrock, Vertex AI, SageMaker, and self-hosted GPU serving.
- Benchmark TTFT, TPOT, and throughput honestly — under realistic load, with percentiles, and without vendor-benchmark traps.
1. Decoder-only anatomy, priced per component
Interviewers for platform and architect roles rarely want the training math. They want to know whether you can map each architectural component to a runtime cost, because that mapping is what makes serving decisions rational. A modern chat model is a decoder-only transformer: it converts text into tokens, tokens into vectors, pushes those vectors through a stack of identical blocks, and emits a probability distribution over the next token.
Tokenization is byte-pair encoding (BPE) or a byte-level variant: a learned merge table that greedily compresses frequent byte sequences into single vocabulary entries (vocabularies today run 32K–256K). Everything downstream — context limits, latency, and your invoice — is denominated in tokens, and tokenizers are not interchangeable: code, numbers, and non-English text can tokenize 1.5–4× longer than English prose, which silently changes both cost models and cross-engine benchmark comparisons. Embeddings map each token ID to a d_model-dimensional vector; position is injected not by adding position vectors but by RoPE (rotary position embeddings), which rotates query/key vectors by an angle proportional to position — a detail that matters later because it is the hook for context extension.
Each block applies pre-normalization (RMSNorm), self-attention, a residual add, another norm, then a gated MLP (SwiGLU, expanding to roughly 3–4× d_model), and a second residual add. Two facts earn senior credit: about two-thirds of parameters live in the MLPs, not attention — so weight memory and decode bandwidth are mostly an MLP bill; and the residual stream means each block edits a shared representation rather than replacing it, which is why layers can be quantized or even skipped with graceful rather than catastrophic degradation. Attention computes, for every position, a similarity score against every prior position — an n × n score matrix, which is the O(n²) term everyone cites. Crucially, that quadratic cost is paid during prompt processing; once past keys/values are cached, each new token attends to n cached entries — linear per step.
MHA → MQA → GQA → MLA: shrinking the cache, not the compute
The attention variants exist for one dominant reason: the KV cache (next section) scales with the number of key/value heads. Multi-query attention (MQA) shares one K/V head across all query heads; grouped-query attention (GQA) shares K/V among groups — Llama-3-70B uses 8 KV heads against 64 query heads, an 8× cache reduction; multi-head latent attention (MLA, introduced by DeepSeek-V2) caches a low-rank latent compression of K/V, cutting cache size by an order of magnitude at the price of extra projection compute.
| Variant | KV heads | Cache vs MHA | Trade-off |
|---|---|---|---|
| MHA | = query heads | 1× | Maximum quality headroom, maximum cache. |
| MQA | 1 | ~1/64× | Cheapest cache; measurable quality loss on some tasks. |
| GQA | groups (e.g., 8) | ~1/8× | Near-MHA quality; the current open-weights default. |
| MLA | latent vector | ~1/10–1/30× | Big cache savings; more matmuls per token, more kernel complexity. |
2. KV cache and the two-phase request
Every autoregressive request has two phases with opposite performance characters. Prefill processes all prompt tokens in parallel — big matrix multiplies, high arithmetic intensity, compute-bound — and its duration is essentially your time-to-first-token (TTFT). Decode generates one token per forward pass; each step must stream the model weights and the growing KV cache through the GPU's memory system to do comparatively little math, so it is memory-bandwidth-bound, and it sets time-per-output-token (TPOT).
sequenceDiagram
participant C as "Client"
participant R as "API gateway"
participant S as "Engine scheduler"
participant G as "GPU worker"
C->>R: submit prompt
R->>S: enqueue request
S->>G: admit and allocate KV blocks
G->>G: prefill all prompt tokens in one pass
G-->>C: first token streamed
loop one token per step until stop
G->>G: read weights plus KV cache
G-->>C: stream next token
end
G->>S: release KV blocks
The KV cache stores every layer's keys and values for every token so decode never recomputes them. Memorize the formula and one worked example:
kv_bytes_per_token = 2 × n_layers × n_kv_heads × head_dim × dtype_bytes
Llama-3-70B (80 layers, 8 KV heads, head_dim 128, FP16):
2 × 80 × 8 × 128 × 2 = 327,680 B ≈ 320 KB per token
→ 8K-token session ≈ 2.6 GB → 32K ≈ 10.5 GB → 128K ≈ 42 GB per sequence
Set that against hardware: FP16 weights for a 70B model are ~140 GB, so an 8×H100 node (640 GB HBM) has roughly 400+ GB left for KV after weights and activation workspace — call it ~1.2M cached tokens, or about 300 concurrent 4K-context sessions, but only nine concurrent 128K sessions. This single calculation explains why long context is an economics problem before it is a quality problem, and why GQA/MLA and KV quantization exist at all.
The roofline argument is worth reciting. At batch 1, decoding one token reads every weight byte to perform ~2 FLOPs per parameter — arithmetic intensity near 1 FLOP/byte, while an H100 needs roughly 295 FLOPs per byte moved (~989 dense BF16 TFLOPS over ~3.35 TB/s HBM3) to saturate. Hence the batch-1 ceiling: an 8B model in FP16 (~16 GB) on one H100 cannot exceed ~3,350/16 ≈ 200 tokens/s no matter how clever the kernels, and measured numbers sit below that. Batching multiplies useful FLOPs per weight byte read, which is why every serving optimization ultimately serves one goal: keep many sequences in flight per weight pass. Prefill math is equally quotable: a 2,000-token prompt on that 8B model needs ~2 × 8e9 × 2000 = 32 TFLOPs, so at ~50% utilization TTFT has a floor around 65 ms — before queueing, which dominates in practice.
3. Continuous batching and PagedAttention
Naive serving batches requests statically: collect N prompts, run them together, return when the longest finishes. Two pathologies follow — the batch runs at the speed of its slowest member while finished slots idle, and arrivals wait for the next batch to form. Orca introduced iteration-level scheduling — continuous batching — where the scheduler recomposes the batch at every decode step: finished sequences leave immediately, queued requests join mid-flight. This alone yields multi-fold throughput gains over static batching and is table stakes in every modern engine.
flowchart TD
Q["Incoming request queue"] --> A["Admission control checks free KV blocks"]
A -->|"blocks available"| B["Join running batch at next step"]
A -->|"pool exhausted"| P["Queue, or preempt a sequence by swap or recompute"]
B --> F["Single forward pass for whole batch"]
F --> D{"Sequence hit stop token or max length?"}
D -->|"yes"| E["Stream final token and free KV pages"]
D -->|"no"| B
E --> A
Continuous batching made KV allocation the new bottleneck. Pre-PagedAttention engines reserved contiguous KV memory for each request's maximum possible length; measured waste from internal fragmentation and over-reservation ran 60–80% of KV memory. PagedAttention (the vLLM paper) applies virtual-memory thinking: KV lives in fixed-size blocks (e.g., 16 tokens), each sequence holds a page table, and blocks are allocated on demand — waste drops to under ~4%, which converts directly into batch size and therefore throughput. Paging also enables prefix sharing with copy-on-write: a thousand requests carrying the same 2K-token system prompt can reference one physical copy of its KV blocks. SGLang generalized this into RadixAttention, an automatic prefix-cache tree, which is why it shines on agentic workloads that re-send conversation prefixes on every step (Chapter 05 depends on this).
- Chunked prefill — split large prompt prefills into slices interleaved with decode steps, so one 100K-token upload does not spike everyone else's TPOT.
- Preemption — when the KV pool exhausts, engines evict a sequence (recompute later, or swap to CPU). Watch this metric: preemptions are the canary for KV pressure.
- Prefill–decode disaggregation — run prefill and decode on separate GPU pools and ship KV between them; removes phase interference at the cost of a KV transfer path. An emerging default for large deployments.
- Goodput, not throughput — the number that matters is tokens/s delivered while meeting TTFT/TPOT SLOs, not peak tokens/s at unbounded latency.
4. The quantization ladder
Quantization is the highest-leverage cost knob after batching, because decode speed is proportional to bytes moved. The ladder runs from BF16 (training-native baseline) down to 4-bit weights, and the senior move is knowing which rung serves which regime: weight-only quantization accelerates the memory-bound low-batch regime; weight-and-activation formats (FP8/INT8) exploit faster tensor cores and win in the compute-bound high-batch regime, where weight-only 4-bit can actually lose to FP8 because of per-step dequantization overhead.
| Rung | What is quantized | Hardware | Typical quality cost | Use when |
|---|---|---|---|---|
| BF16 / FP16 | nothing (baseline) | all | reference | Quality baselining, evals, low-risk default. |
| FP8 (E4M3) | weights + activations | Hopper/Ada and newer | usually <1% on aggregate evals | High-throughput production on H100-class GPUs; ~2× compute and half the weight bytes. |
| INT8 (LLM.int8, SmoothQuant) | weights ± activations | Ampere and newer | small, outlier-sensitive | Pre-Hopper fleets; activation outliers need special handling. |
| 4-bit weight-only (GPTQ, AWQ) | weights only | all | ~1% aggregate, but task-skewed | Fit big models on small GPUs; fastest decode at low batch. |
| NF4 (QLoRA) | weights, for fine-tuning | all | designed for training memory | PEFT on constrained GPUs — a Chapter 03 topic, not a serving format. |
| FP8 KV cache | the cache itself | Hopper-class | usually negligible | Double token capacity per GPU; pairs with long context. |
The quality caveat is where candidates get filtered. Aggregate benchmarks (MMLU-style) routinely show <1% degradation for well-executed 4-bit quantization of large models, while narrow capabilities — math, code generation, low-resource languages, strict instruction-following at long context — degrade first and disproportionately. GPTQ minimizes layer-wise reconstruction error using second-order information; AWQ instead protects the ~1% of weight channels with the largest activation magnitudes. Both are calibration-dependent: quantize with generic web-text calibration data and evaluate on your legal-summarization traffic, and you may see regressions the model card never showed. The rule: the quantization decision is an evaluation decision — your own task harness (Chapter 06) gates every rung change.
flowchart TD
S["Start at BF16 with a task eval harness"] --> Q1{"Bottleneck today?"}
Q1 -->|"memory capacity or low-batch latency"| W4["Weight-only 4-bit AWQ or GPTQ"]
Q1 -->|"throughput at high batch on Hopper"| F8["FP8 weights and activations"]
Q1 -->|"KV capacity limits concurrency"| KV["FP8 KV cache first"]
W4 --> E["Re-run task evals plus latency benchmark"]
F8 --> E
KV --> E
E --> G{"Quality within agreed budget on your slices?"}
G -->|"yes"| SHIP["Ship, monitor drift and complaints"]
G -->|"no"| ROLL["Step back up one rung or change calibration set"]
5. Faster decode: speculation, MoE, and long context
Three techniques dominate the “make decode cheaper” conversation, and each has a regime where it backfires. Speculative decoding (Leviathan et al., Chen et al.) uses a cheap drafter to propose k tokens, which the target model verifies in a single parallel pass; rejection sampling guarantees the output distribution is exactly the target model's. Because verification prices like a tiny prefill, you convert several bandwidth-bound steps into one compute-heavier step — a 1.5–3× TPOT win when acceptance rates are high (drafter matches the target's style; predictable text like code) and batch is small. At high batch the GPU is already compute-saturated, so speculation adds work and can reduce throughput; engines increasingly disable it dynamically under load. EAGLE and Medusa-style approaches replace the separate drafter with lightweight heads on the target model itself, removing the two-model operational burden.
flowchart LR
DR["Drafter proposes k tokens"] --> V["Target verifies all k in one parallel pass"]
V --> AC{"How much of the draft matched?"}
AC -->|"all k accepted"| N["Emit k plus one bonus token"]
AC -->|"partial"| PR["Emit accepted prefix plus one corrected token"]
N --> DR
PR --> DR
Mixture-of-experts models decouple parameters from per-token compute: Mixtral 8×7B holds ~47B parameters but routes each token through ~13B. The serving implications are the interview substance: all experts must be resident, so memory is priced at total parameters while compute is priced at active parameters; at batch 1 you read only the routed experts (bandwidth win), but as batch grows nearly every expert is activated by someone, so weight-read amortization converges back toward dense behavior; and multi-GPU MoE adds expert-parallel all-to-all communication plus load-balancing pathologies when routing concentrates on hot experts. MoE is a hardware-utilization bet, not a free lunch.
Long context is bounded by two costs you now own: KV memory growing linearly (Section 2's formula) and prefill compute growing quadratically-ish in practice. Models extend beyond trained context by rescaling RoPE — position interpolation, NTK-aware scaling, and YaRN — which stretches rotary frequencies so unseen positions land in familiar ranges; quality at extended lengths must be verified with needle-and-haystack and task-level evals, since "supports 128K" often means "does not crash at 128K." Operationally, pair long context with FP8 KV, chunked prefill, and prefix caching — and remember that the cheapest long-context token is the one you retrieved instead (Chapter 04's argument).
6. Serving engines: vLLM, TGI, TensorRT-LLM, SGLang
All four mainstream engines now implement continuous batching, paged KV, quantized formats, and OpenAI-compatible APIs, so the differentiation is operational: kernel pedigree, model-coverage velocity, prefix-caching sophistication, and how much build engineering they demand.
| Engine | Core strength | Cost you accept | Choose when |
|---|---|---|---|
| vLLM | Community default; fastest new-model support; PagedAttention origin; huge feature surface (LoRA serving, spec decode, P/D disaggregation). | Config surface is large; peak perf sometimes trails compiled engines. | Default choice, model churn expected, k8s self-hosting. |
| TGI | Hugging Face ecosystem integration, hardened Rust server, simple operational story. | Smaller optimization community than vLLM today. | HF-centric stack, straightforward deployments. |
| TensorRT-LLM | NVIDIA-tuned compiled kernels; frequently the raw tokens/s ceiling on NVIDIA GPUs; pairs with Triton/NIM. | Engine builds per model/GPU/config; slower model onboarding; NVIDIA lock-in. | Stable model list, extreme throughput targets, NVIDIA fleet. |
| SGLang | RadixAttention automatic prefix caching; strong structured-output and multi-call programs; excellent agent/high-QPS results. | Younger ecosystem; fewer enterprise integrations. | Agentic traffic with heavy shared prefixes; JSON-constrained decoding at scale. |
Interview framing that lands: the engine choice is reversible (they share API shapes); the benchmark methodology is what protects the decision. Comparing engines on tokens/s with different tokenizers, different default sampling, or unmatched quantization is the classic self-deception — normalize the workload first (Section 9).
7. GPU economics and build-versus-buy
Cost per million tokens is the unit that makes inference decisions comparable across managed APIs and self-hosting. The formula is trivial — GPU-hour cost divided by sustained tokens per hour — and every input is a place candidates go wrong: they use peak benchmark throughput instead of SLO-compliant goodput, and they assume 100% utilization when real diurnal traffic delivers 20–40%.
| GPU (approx. specs) | HBM | Bandwidth | Serving role |
|---|---|---|---|
| L4 | 24 GB | ~0.3 TB/s | Small models (≤8B quantized), embeddings, bursty low-QPS endpoints. |
| L40S | 48 GB | ~0.86 TB/s | Mid-size models, cost-efficient inference without HBM pricing. |
| A100 80GB | 80 GB | ~2.0 TB/s | Prior-gen workhorse; no FP8. |
| H100 80GB | 80 GB | ~3.35 TB/s | FP8 tensor cores; the current serving baseline (specs). |
| H200 | 141 GB | ~4.8 TB/s | KV-heavy and long-context serving; fewer GPUs per 70B replica. |
Managed API, on-demand
Pay per token, zero capacity risk, frontier-model access. Right up to the volume where a provisioned or self-hosted floor beats the token price — and always right for spiky, low-volume, or frontier-quality workloads.
Provisioned throughput
Reserve model capacity (Bedrock provisioned throughput, Vertex AI Provisioned Throughput) for predictable latency and volume discounts on steady traffic — commitment risk replaces queueing risk.
Self-host open weights
Wins on price only with sustained high utilization, tolerance for open-weight quality, and a team that can own GPU capacity, upgrades, and incident response. Also the only option under strict data-residency or air-gap constraints.
Hybrid routing
The common senior answer: managed frontier models for hard/low-volume traffic, self-hosted small models for high-volume narrow tasks, with an eval-gated router (Chapters 05–06) deciding.
8. Serving on AWS and GCP
Both clouds offer the same three altitudes — fully managed per-token APIs, managed endpoints you configure, and raw GPUs you orchestrate — and interviewers for cloud-aligned roles expect you to pick an altitude from workload characteristics, then name concrete services fluently.
AWS
- Bedrock on-demandpay-per-token managed FM inference; also batch mode at a discount
- Bedrock Provisioned Throughputreserved model units for steady, latency-sensitive volume
- Bedrock Custom Model Importserve your fine-tuned open weights behind the Bedrock API
- SageMaker real-time endpoints + LMI containersmanaged autoscaling endpoints running vLLM/TensorRT-LLM backends
- EKS + vLLMfull-control GPU serving; Karpenter for GPU node autoscaling
- Inferentia2 / Trainiumcustom-silicon price-performance play via the Neuron SDK
Google Cloud
- Vertex AI Gemini APIpay-as-you-go managed inference with context caching
- Vertex AI Provisioned Throughputreserved throughput for Gemini at predictable latency
- Model Garden → Vertex endpointsdeploy open models onto managed GPU endpoints, vLLM-based containers
- GKE + vLLMself-managed serving; GKE Inference Gateway adds LLM-aware load balancing
- Cloud Run GPUsserverless L4 GPUs with scale-to-zero for bursty small-model serving
- Cloud TPUalternative accelerator for supported stacks (vLLM TPU, JetStream)
flowchart TD
R["New GenAI workload"] --> Q1{"Frontier-model quality required?"}
Q1 -->|"yes"| M["Managed API on Bedrock or Vertex AI"]
Q1 -->|"open weights pass evals"| Q2{"Steady traffic at high utilization?"}
Q2 -->|"no, spiky or unproven"| M2["Managed endpoints or serverless GPUs, pay as you go"]
Q2 -->|"yes"| Q3{"Team ready to own GPU operations?"}
Q3 -->|"yes"| SH["Self-host vLLM on EKS or GKE"]
Q3 -->|"no"| PT["Provisioned throughput or managed endpoints"]
M --> RT["Re-evaluate quarterly as volume and models shift"]
SH --> RT
9. TTFT, TPOT, throughput — benchmarking without self-deception
Three metrics, three different masters. TTFT (time to first token) is queueing plus prefill — it gates perceived responsiveness in chat and agent loops. TPOT (time per output token, a.k.a. inter-token latency) is the decode rhythm — it gates streaming readability and total completion time. Throughput (aggregate tokens/s per replica) is the cost side. They trade against each other through batch depth: deeper batches raise throughput and TPOT together, and a benchmark that reports one without the others is marketing.
| Metric | Bound by | Improved by | Report as |
|---|---|---|---|
| TTFT | queueing + prefill compute | chunked prefill, prefix caching, more replicas, shorter prompts | p50 / p95 / p99 at a stated request rate |
| TPOT | memory bandwidth per weight pass | quantization, speculative decoding, shallower batches, faster HBM | p50 / p99 per token, streaming |
| Throughput | KV capacity + compute ceiling | continuous batching, paged KV, FP8, longer batch depth | sustained tokens/s at SLO-compliant load (goodput) |
- Fix the workloadSample real prompt/output length distributions — a 6K-in / 300-out RAG trace behaves nothing like ShareGPT chat. Same tokenizer accounting across engines.
- Sweep loadRamp concurrency or request rate stepwise; at each level record TTFT and TPOT percentiles plus aggregate tokens/s.
- Find the kneeIdentify where p95 TTFT or TPOT breaches SLO; the sustained rate just below it is your capacity number.
- Price itCost per million tokens at the knee — not at peak throughput — feeds the build-vs-buy model of Section 7.
- Re-run on changeNew model, quant rung, engine version, or context policy re-runs the sweep; keep results versioned like eval results.
The dishonesty patterns to name in an interview: benchmarking at batch 1 and deploying at batch 64; warm prefix caches flattering TTFT for prompts your real traffic never repeats; comparing engines with different tokenizers so “tokens/s” measures the tokenizer, not the engine; quoting mean latency where tail latency gates the product; and quoting a managed API's demo-time latency without measuring its variance under your regional, peak-hour traffic. A candidate who volunteers these earns instant credibility.
Interview playbook
For any inference-performance question, run BUDGET — size the physics before naming products:
- B — Bytes: weights at the chosen precision, plus KV per token × context × concurrency. Does it fit, and on how many GPUs?
- U — Utilization regime: is the phase compute-bound (prefill, high batch) or bandwidth-bound (decode, low batch)? The regime picks the optimization.
- D — Demand shape: traffic pattern, prompt/output length distribution, prefix reuse, latency SLOs per product surface.
- G — Gains ladder: continuous batching → paged KV/prefix cache → quantization rung → speculative decoding → disaggregation, each gated by evals.
- E — Economics: cost per million tokens at SLO-compliant load; compare managed API vs provisioned vs self-host at the actual utilization.
- T — Test honestly: load-swept percentiles on a realistic trace, re-run on every change.
Common traps
- Citing O(n²) attention as why long context is expensive, instead of KV memory pressure and prefill interference.
- Treating quantization as free compression — no calibration story, no task-slice evals, no rollback rung.
- Recommending speculative decoding for a saturated high-batch cluster where it burns the compute headroom it needs.
- Comparing self-hosting at 100% assumed utilization against a managed API's list price.
- Benchmark numbers without percentiles, load levels, or the prompt-length distribution attached.
- Naming vLLM features without being able to explain what PagedAttention actually fixed (fragmentation and over-reservation of KV memory).
Question bank
These are the questions senior GenAI platform and architect loops actually ask about inference. Practice deriving, not reciting.
Q1Walk me through what happens between an HTTP request hitting your endpoint and the first streamed token.
Strong answer outline
- Gateway: auth, rate limit, route to a replica; request enters the engine scheduler queue.
- Admission: scheduler checks free KV blocks, allocates pages, joins the request into the running batch at the next iteration.
- Prefill: all prompt tokens processed in parallel, KV cache written per layer; this compute plus the queue wait is TTFT.
- First token sampled from the LM head, detokenized, streamed; decode loop begins at one token per pass.
Follow-up probes
- Where can this request be preempted, and what happens to its KV?
- What changes if the prompt shares a 2K system prefix with other traffic?
Pass if queueing, KV allocation, and the prefill/decode split are all present; fail if the answer jumps from “request” to “the model generates.”
Q2Derive the KV-cache memory for a 70B GQA model at 32K context. What does it imply for concurrency?
Strong answer outline
- State the formula: 2 × layers × KV heads × head_dim × dtype bytes per token.
- Compute: 2 × 80 × 8 × 128 × 2 ≈ 320 KB/token → ~10.5 GB per 32K sequence at FP16.
- Subtract weights from HBM (140 GB FP16 on 640 GB node) → bound concurrent sequences; show how FP8 KV or MLA changes the bound.
- Conclude: KV capacity, not compute, usually caps batch size and thus throughput.
Follow-up probes
- Why does GQA divide this by 8 relative to MHA?
- What operational metric tells you KV pressure is biting?
Pass if the arithmetic is done live and tied to concurrency; fail if the formula is recited without consequences.
Q3Why is TTFT compute-bound and TPOT bandwidth-bound, and what follows for optimization?
Strong answer outline
- Prefill: thousands of tokens per weight read → high arithmetic intensity → limited by TFLOPS.
- Decode: one token per full weight read at low batch → ~1 FLOP/byte against a GPU needing hundreds → limited by HBM bandwidth.
- Therefore TTFT improves with compute, chunked prefill, prefix caching, shorter prompts; TPOT improves with fewer bytes — quantization, speculation, faster HBM.
- Batching moves decode toward compute-bound, trading TPOT for throughput.
Follow-up probes
- Estimate the batch-1 decode ceiling for an 8B FP16 model on an H100.
- Why does H200's bandwidth matter more than its FLOPS for serving?
Pass if arithmetic intensity is explained and each optimization maps to a phase; fail on “prefill is parallel, decode is serial” alone.
Q4Compare MQA, GQA, and MLA. Why did the industry converge on GQA, and what does MLA change?
Strong answer outline
- All three shrink KV per token; only cache size and quality differ, not O(n²) prefill.
- MQA: 1 KV head, maximum saving, measurable quality loss on some tasks; GQA: grouped middle ground with near-MHA quality — the pragmatic winner.
- MLA caches a low-rank latent instead of full K/V — order-of-magnitude smaller cache, extra projection compute and kernel complexity.
- Impact channel: cache bytes → concurrency → cost/M tokens.
Follow-up probes
- Can you convert a trained MHA model to GQA after the fact?
- Where does MLA's saving matter most — chat or long-context RAG?
Pass if the answer prices variants in KV bytes and concurrency; fail if it is an acronym tour.
Q5What problem did PagedAttention actually solve, and what became possible because of it?
Strong answer outline
- Before: contiguous KV allocation at max sequence length → 60–80% of KV memory lost to fragmentation and over-reservation.
- PagedAttention: fixed-size KV blocks with per-sequence page tables → waste under ~4%, recovered memory becomes batch depth.
- Enabled: copy-on-write prefix sharing, cheap preemption/swap, and practical continuous batching at scale.
- Distinguish from RadixAttention: automatic prefix-tree reuse across requests.
Follow-up probes
- What is the analogue of a TLB miss here, and does block size matter?
- How does prefix caching change your benchmark design?
Pass if fragmentation and the memory-to-throughput conversion are explicit; fail if PagedAttention is described as “an attention optimization.”
Q6Continuous batching raised our throughput 5× but p99 TTFT got worse. Explain and fix it.
Strong answer outline
- Diagnose interference: long prefills of admitted requests stall the decode loop; deep batches lengthen queue waits at peak.
- Instrument: queue time vs prefill time vs decode jitter; preemption counts; KV pool occupancy.
- Fix ladder: chunked prefill, admission priorities by prompt length or tenant, KV headroom targets, separate long-context pool, or prefill/decode disaggregation.
- Redefine success as goodput at SLO, not peak tokens/s.
Follow-up probes
- Which fix would you try first and how would you verify?
- When is adding replicas the wrong answer?
Pass if the interference mechanism and a measured fix sequence are given; fail on “tune the batch size” alone.
Q7Design the quantization strategy for self-hosting a 70B model. Which rung and how do you validate?
Strong answer outline
- Start from bottleneck and hardware: Hopper + high batch → FP8 W8A8; single-GPU fit or low batch → AWQ/GPTQ 4-bit weight-only; add FP8 KV if concurrency is KV-capped.
- Calibration matters: use domain-representative calibration data, not generic web text.
- Validate on your task harness with slices (math, code, multilingual, long context), plus a latency/throughput sweep — quality and speed together.
- Ship with a rollback rung and monitor drift and complaint rates.
Follow-up probes
- Why can 4-bit weight-only lose to FP8 at batch 64?
- Where does NF4 belong — and why not in serving?
Pass if regime → format mapping and eval gating are both present; fail if a single format is recommended unconditionally.
Q8When does speculative decoding help, when does it hurt, and how does it preserve output quality?
Strong answer outline
- Mechanism: drafter proposes k tokens; target verifies in one parallel pass; rejection sampling keeps exactly the target distribution — quality is provably unchanged.
- Helps when: spare compute (low batch), high acceptance (predictable text, aligned drafter) → 1.5–3× TPOT.
- Hurts when: compute-saturated high batch, or domain-shifted traffic drops acceptance — extra work, worse throughput.
- Ops: monitor live acceptance rate; prefer EAGLE/Medusa-style heads to avoid running a second model.
Follow-up probes
- What acceptance rate breaks even at draft length 4?
- Does speculation change sampling temperature semantics?
Pass if the exactness guarantee and both regimes are stated; fail if it is pitched as a universal speedup.
Q9What is different about serving a mixture-of-experts model like Mixtral?
Strong answer outline
- Memory prices at total parameters (all experts resident); compute prices at active parameters per token.
- Batch effect: at low batch, routed-expert reads save bandwidth; at high batch most experts activate across the batch, eroding the saving.
- Multi-GPU: expert parallelism adds all-to-all communication; hot-expert imbalance creates stragglers.
- Net: MoE trades memory footprint and ops complexity for per-token compute — evaluate against a dense model at equal quality, not equal parameter count.
Follow-up probes
- How would you place experts across an 8-GPU node?
- What breaks if one expert receives 40% of tokens?
Pass if the total-vs-active distinction and the batch-size erosion are both explained; fail on “MoE is cheaper” without conditions.
Q10Product wants 128K context. What actually breaks, and what is your plan?
Strong answer outline
- Cost the KV: linear growth per token (e.g., ~42 GB per 128K sequence for a 70B GQA model at FP16) — concurrency collapses first.
- Prefill: 128K prefill is a multi-second compute event that starves co-located decodes; needs chunked prefill or a separate pool.
- Quality: RoPE scaling (PI, NTK-aware, YaRN) extends positions, but verify with retrieval-in-context and task evals, not the spec sheet.
- Mitigate demand: retrieval, summarization memory, prefix/context caching — cheapest long-context token is the one not sent (Chapter 04).
Follow-up probes
- How does FP8 KV change the capacity math?
- Would you price long-context requests differently?
Pass if memory, interference, and quality verification all appear; fail if the answer is only “use YaRN.”
Q11Choose between vLLM, TGI, TensorRT-LLM, and SGLang for a given workload. What drives the decision?
Strong answer outline
- Establish workload: model churn rate, prefix reuse, structured output needs, peak throughput target, team skill, hardware fleet.
- Map: vLLM as default and fastest model coverage; TensorRT-LLM for maximum tokens/s on a stable NVIDIA-only model list at the price of engine builds; SGLang for prefix-heavy agentic and constrained-decoding traffic; TGI for HF-centric simplicity.
- Note convergence: features cross-pollinate; the choice is reversible behind an OpenAI-compatible API.
- Commit to a normalized benchmark on your trace before deciding.
Follow-up probes
- What breaks when you upgrade the engine version in place?
- How do you compare engines with different tokenizers fairly?
Pass if the decision is workload-conditional with a benchmark gate; fail if it is a leaderboard ranking.
Q12Build a cost-per-million-tokens model for self-hosting versus a managed API. Where do these models usually lie?
Strong answer outline
- Formula: GPU-hour cost ÷ SLO-compliant sustained tokens per hour, at the load knee — not peak benchmark throughput.
- Apply utilization: diurnal traffic at 20–40% average multiplies effective cost 2.5–5×; add redundancy, failover headroom, and engineering time.
- Compare against managed per-token pricing, which embeds the provider's utilization pooling; include provisioned-throughput commitments as the middle option.
- Present break-even volume and the reversal conditions.
Follow-up probes
- How do input vs output token prices change the comparison for RAG traffic?
- What utilization assumption would flip your recommendation?
Pass if utilization is the pivotal variable and numbers are labeled as examples; fail if list prices are compared at assumed 100% usage.
Q13On AWS: Bedrock on-demand vs Provisioned Throughput vs SageMaker endpoints vs EKS with vLLM — give the decision framework.
Strong answer outline
- Bedrock on-demand: frontier and partner models, per-token, zero capacity ops — default for spiky or exploratory traffic; batch mode for offline volume.
- Bedrock Provisioned Throughput: steady high volume on Bedrock models needing predictable latency; commitment risk.
- SageMaker + LMI containers: open or custom weights with managed endpoints, autoscaling, VPC control — the middle altitude.
- EKS + vLLM: maximum control and lowest unit cost at sustained utilization, highest ops burden; justify with volume, residency, or customization needs.
Follow-up probes
- Where does Bedrock Custom Model Import fit between these?
- Map the equivalent ladder on GCP.
Pass if each option gets a workload condition and a named cost/ops trade; fail if services are listed without decision criteria.
Q14How do you benchmark an inference deployment honestly? Name the ways teams fool themselves.
Strong answer outline
- Fix a realistic trace: real prompt/output length distributions, realistic prefix reuse, consistent tokenizer accounting.
- Sweep load stepwise; record p50/p95/p99 TTFT and TPOT plus tokens/s at each level; find the SLO knee.
- Report goodput and cost at the knee; version results and re-run on any model/engine/config change.
- Name traps: batch-1 numbers for a batch-64 deployment, warm prefix caches, mean instead of tails, cross-tokenizer tokens/s, off-peak API latency samples.
Follow-up probes
- How many requests do you need for a stable p99?
- How would you benchmark a managed API you cannot instrument server-side?
Pass if load-swept percentiles on a realistic trace plus at least three traps are given; fail on a single tokens/s figure.
Q15Your p99 TTFT tripled after enabling 64K contexts for one tenant. Debug it live.
Strong answer outline
- Hypothesize the two mechanisms: giant prefills monopolizing iterations (head-of-line for other requests) and KV pressure causing queueing/preemption.
- Check evidence: queue-time vs prefill-time decomposition, KV pool occupancy, preemption counters, correlation with the tenant's request timestamps.
- Mitigate in order: enable/tune chunked prefill, cap admitted prompt length per iteration, tenant-level concurrency limits, dedicated long-context pool or disaggregated prefill.
- Verify with the same load sweep and add a regression alert on p99 TTFT by tenant class.
Follow-up probes
- Why might adding a replica not fix this?
- What would you have load-tested before the rollout?
Pass if both mechanisms are named with the telemetry to distinguish them; fail if the answer is generic “scale up.”
Proof artifact: an honest inference benchmark and cost model
Build a small, reproducible study you can defend line by line: one open model, one engine, a load harness, and a one-page decision memo. This artifact backs answers across Sections 2–9 and pairs with the evaluation harness of Chapter 06.
Steps
- Deploy an 8B-class instruct model with vLLM on a single cloud GPU (an L4 or A10G-class instance keeps example cost low); record exact model, engine version, dtype, and max context.
- Build a load generator that replays a realistic trace: sampled prompt lengths (include a long-prompt slice), realistic output lengths, streaming enabled, fixed random seed.
- Sweep concurrency (e.g., 1, 2, 4, 8, 16, 32, 64) and record p50/p95/p99 TTFT and TPOT plus aggregate tokens/s at each level; chart the saturation curve and mark the SLO knee.
- Compute cost per million output tokens at the knee from the instance's hourly price; then redo the number at 25% assumed utilization and compare with two managed-API list prices as reference points.
- Quantize to AWQ (or FP8 if the GPU supports it), re-run both the load sweep and a ~100-item task eval with slices; record the quality delta next to the speed delta.
Deliberate failures
- Drive KV exhaustion with many long-context sessions; capture preemption/queueing behavior and the client-visible symptom.
- Inject one 30K-token prompt into a busy interactive load; show the TPOT jitter on other streams, then enable chunked prefill and show the repair.
- Repeat a shared system prefix across requests with prefix caching on and off; quantify the TTFT delta and note how it could flatter a dishonest benchmark.
- Compare the quantized model on the aggregate eval and on a math/code slice; show a slice regression that the average hides.
What to present
One saturation chart (TTFT/TPOT percentiles vs load), the KV arithmetic for your model done by hand, a cost table at three utilization assumptions, one failure trace with its fix, and a half-page build-vs-buy recommendation with explicit reversal conditions. State clearly that all figures are from your own small-scale study — that honesty is itself a senior signal.
Chapter review
Inference is a memory system wearing a model's clothes. Prefill spends compute and sets TTFT; decode spends memory bandwidth and sets TPOT; the KV cache converts context length and concurrency into bytes that compete with weights for HBM. Continuous batching and PagedAttention recover wasted capacity, the quantization ladder trades verified quality for bytes, speculation trades spare compute for latency, and every choice terminates in one number — cost per million tokens at SLO-compliant load — which decides build-versus-buy across Bedrock, Vertex AI, and self-hosted GPU fleets.
Glossary
- Prefill
- Parallel processing of all prompt tokens that fills the KV cache; compute-bound; determines TTFT.
- Decode
- One-token-per-pass generation that re-reads weights and KV each step; bandwidth-bound; determines TPOT.
- KV cache
- Per-layer keys/values stored per token: 2 × layers × KV heads × head_dim × dtype bytes per token.
- TTFT / TPOT
- Time to first token; time per output token thereafter. Report as percentiles at stated load.
- GQA / MLA
- Attention variants that shrink KV per token — grouped KV heads, or a cached low-rank latent.
- Continuous batching
- Iteration-level scheduling: sequences join and leave the batch at every decode step.
- PagedAttention
- Block-based KV allocation with page tables; kills fragmentation, enables prefix sharing.
- Chunked prefill
- Splitting long prefills into slices interleaved with decode to bound interference.
- Speculative decoding
- Draft-then-verify generation that preserves the target distribution exactly via rejection sampling.
- RoPE scaling
- Rescaling rotary position frequencies (PI, NTK, YaRN) to extend context beyond training length.
- MoE
- Sparse expert routing: memory priced at total parameters, compute at active parameters.
- Goodput
- Sustained tokens/s delivered while meeting TTFT/TPOT SLOs — the honest capacity number.
Mastery checklist
- I can derive KV bytes per token for a named model and turn it into a concurrency bound.
- I can explain arithmetic intensity and estimate a batch-1 decode ceiling from bandwidth and model size.
- I can describe what PagedAttention fixed, with the before/after memory-waste numbers.
- I can pick a quantization rung from the bottleneck regime and defend the eval gate around it.
- I can state both preconditions for speculative decoding to pay off — and its exactness guarantee.
- I can explain MoE serving economics: total vs active parameters, and the batch-size erosion effect.
- I can choose a serving engine conditionally and design a fair cross-engine benchmark.
- I can build a cost-per-million-tokens model where utilization is the pivotal variable.
- I can name the managed / provisioned / self-hosted ladder on both AWS and GCP with concrete services.
- I can benchmark TTFT, TPOT, and goodput with load-swept percentiles and name five benchmark deceptions.
Primary sources
Links checked . GPU specs, engine features, and cloud pricing move quickly; verify against the current official pages before quoting numbers in an interview.
- Vaswani et al. — Attention Is All You Need
- Su et al. — RoFormer: rotary position embeddings
- Shazeer — multi-query attention
- Ainslie et al. — GQA: grouped-query attention
- DeepSeek-V2 — multi-head latent attention
- Dao et al. — FlashAttention
- Kwon et al. — PagedAttention and vLLM
- Yu et al. — Orca: iteration-level scheduling for transformer serving
- Frantar et al. — GPTQ
- Lin et al. — AWQ: activation-aware weight quantization
- Dettmers et al. — LLM.int8
- Dettmers et al. — QLoRA and NF4
- Leviathan et al. — fast inference via speculative decoding
- Chen et al. — accelerating LLM decoding with speculative sampling
- Peng et al. — YaRN context extension
- Jiang et al. — Mixtral of Experts
- vLLM — official documentation
- TensorRT-LLM — official documentation
- Text Generation Inference — official documentation
- SGLang — official documentation
- Amazon Bedrock — user guide
- Amazon Bedrock — Provisioned Throughput
- Amazon SageMaker AI — documentation, incl. large model inference containers
- Vertex AI — generative AI documentation
- Vertex AI — Provisioned Throughput
- Cloud Run — GPU configuration
- NVIDIA — H100 specifications