Part V: Distributed Inference and Serving
Chapter 24: Distributed LLM Serving

Inference Engines and Practice

"I have read every paper in this chapter. I just call them by their command-line flags now."

An Inference Engine With Too Many Backends
Big Picture

Every mechanism in this chapter (tensor and pipeline parallelism, paged and distributed KV cache, prefill/decode disaggregation, cross-node continuous batching, prefix caching, multi-LoRA, and expert-parallel MoE serving) ships today inside a small number of open inference engines, so the practical question is not how to build them but which engine to choose and how to configure it. vLLM, TensorRT-LLM, and SGLang each implement the same core ideas but make different bets on kernel compilation, prefix sharing, disaggregation support, and target hardware. This closing section maps the engine landscape onto the mechanisms you now understand, gives a decision guide for picking one, and folds the whole of Chapter 24 into a single takeaway. The runnable demo is a configurator that turns model size, context, service-level objectives (SLOs), and hardware into a recommended parallelism, disaggregation, and caching plan with an estimated node count.

The previous eight sections built distributed LLM serving from its parts. Section 24.2 split one model across devices with tensor parallelism; Section 24.3 stretched it across nodes with pipeline parallelism; Sections 24.4 and 24.5 made the KV cache paged, distributed, and disaggregated from prefill; Section 24.6 scheduled continuous batches across the fleet; Section 24.7 added prefix caching and multi-LoRA; and Section 24.8 served distributed mixture-of-experts (MoE) models with expert parallelism. None of those mechanisms is something you implement from scratch in production. They live inside inference engines, the serving runtimes that turn a model checkpoint and a request stream into tokens at a target latency and throughput. This section is the practitioner's map of that software layer: what the engines share, where they diverge, and how to choose. Figure 24.9.1 assembles the full stack the chapter has built, labeling each layer with the section that produced it, so the engine can be read as the place where those mechanisms are packaged behind a request API.

The distributed LLM serving stack Applications: chat, agents (Part VI), RAG (Part VIII) OpenAI-compatible API requests Router + continuous-batching scheduler (24.6) admission, KV-aware routing, prefix-cache hits (24.7) Inference engine (vLLM / TensorRT-LLM / SGLang) Tensor + pipeline parallelism (24.2, 24.3) Paged + prefix KV cache (24.4, 24.7) Expert-parallel MoE (24.8) Prefill pool compute-bound (24.5) Decode pool bandwidth-bound (24.5) KV GPU nodes: NVLink within node, RDMA across nodes per-node efficiency is the Chapter 22 prerequisite
Figure 24.9.1: The distributed LLM serving stack the chapter assembles. Applications hit an OpenAI-compatible API; a router and continuous-batching scheduler admit and place requests using prefix-cache locality; the inference engine holds the parallelism, the paged and prefix-aware KV cache, and the MoE expert routing; and separate prefill and decode pools run over GPU nodes whose per-node efficiency is the Chapter 22 prerequisite. Each box names the section that built it.

1. What Every Engine Shares Beginner

The engines converged on a common core because the mechanisms in this chapter are not optional once you serve at scale; they are the only known way to hit competitive throughput and latency together. Every serious engine today does continuous (in-flight) batching rather than static batching, so a finished sequence frees its slot mid-step instead of stalling the batch. Every one pages the KV cache after the PagedAttention design of Chapter 22, so memory fragmentation no longer caps the batch size. Every one supports tensor parallelism within a node and most support pipeline parallelism across nodes, the splits of Chapter 16 applied to inference. And every one now exposes an OpenAI-compatible HTTP endpoint, so the application code above the engine does not change when you swap engines underneath.

This shared core is exactly the set of ideas the chapter built. An engine, in this framing, is a packaging of Chapter 24's mechanisms behind a request API, tuned and kernel-optimized for a particular hardware target. The differences that remain, and they are the ones that decide your choice, sit in four places: how kernels are produced (interpreted versus ahead-of-time compiled), how aggressively prefixes are shared, whether prefill/decode disaggregation is a first-class feature, and which accelerators are supported. We take the three leading open engines in turn.

Key Insight: The Engine Is the Chapter, Compiled

You will almost never write a custom KV-cache pager, a cross-node continuous-batching scheduler, or an expert-parallel all-to-all by hand in production. Those mechanisms are commodities now, implemented once inside vLLM, TensorRT-LLM, and SGLang and reused by everyone. The value of having built them by hand across this chapter is not that you will reimplement them; it is that the engine's configuration flags (tensor-parallel-size, enable-prefix-caching, kv-transfer-config, enable-expert-parallel) now read as the named mechanisms you understand, and you can predict how each one moves the latency-throughput frontier.

2. vLLM: The Open Default Beginner

vLLM is the engine most teams reach for first, and for good reason: it introduced PagedAttention, it ships continuous batching, tensor and pipeline parallelism, automatic prefix caching, and multi-LoRA serving (the LoRA fleets of Section 24.7) in one package, and it runs on NVIDIA, AMD, and other backends. Its design philosophy is broad hardware reach and fast iteration in Python with high-performance custom kernels underneath, rather than a heavyweight compile step. For most workloads it delivers strong throughput out of the box with a one-line launch, which is why it has become the de facto open baseline that other engines benchmark against.

Library Shortcut: One Command Turns On the Whole Chapter

The mechanisms that took eight sections to build are configuration flags on a single launch. vLLM serves a tensor-parallel, prefix-cached, multi-LoRA endpoint with:

# vLLM: tensor parallelism + automatic prefix caching + LoRA adapters
vllm serve meta-llama/Llama-3.1-70B-Instruct \
    --tensor-parallel-size 8 \        # split the model across 8 GPUs (24.2)
    --enable-prefix-caching \         # share system-prompt prefixes (24.7)
    --enable-lora --max-loras 16 \    # serve 16 LoRA adapters on one base (24.7)
    --max-num-seqs 256                # continuous-batching width (24.6)
Code 24.9.1: A production-grade distributed serving endpoint in one command. The four flags map one-to-one onto Sections 24.2, 24.6, and 24.7; vLLM handles the paged KV cache, the cross-request scheduler, and the OpenAI-compatible API internally, collapsing what would be thousands of lines into a launch line.

The same hardware reach that makes vLLM the safe default also makes it the engine where new research lands first, because contributors can iterate without a compile gate. Prefill/decode disaggregation (Section 24.5) and expert-parallel MoE serving (Section 24.8) both arrived in vLLM as configurable features, which is the practical reason this book's mechanisms are reachable from a single tool.

3. TensorRT-LLM: Compiled Throughput on NVIDIA Intermediate

TensorRT-LLM is NVIDIA's engine, and its bet is compilation. Instead of dispatching kernels at runtime, it builds an optimized engine plan ahead of time: it fuses operations, selects kernels tuned for the exact GPU architecture, and bakes in the chosen precision (including FP8 on Hopper and later). On NVIDIA hardware this regularly yields the highest throughput and lowest latency of the three, because the compiled plan removes per-step dispatch overhead and exploits hardware features that a general runtime cannot assume. The cost is build complexity and rigidity: you compile an engine for a specific model, precision, parallelism degree, and batch profile, and changing any of those means rebuilding. It is the choice when you serve a fixed model at very high volume on NVIDIA GPUs and every percent of throughput is money.

Practical Example: Choosing an Engine for a 70B Assistant

Who: A platform engineer at a software company standing up an internal coding assistant on a reserved H100 cluster.

Situation: A single 70B model would serve every team behind one OpenAI-compatible endpoint, with a fixed checkpoint that changes roughly monthly.

Problem: The first vLLM deployment met latency targets but the cluster was billed flat, so cost per token, set by raw throughput, was the metric leadership cared about.

Dilemma: Stay on vLLM for its simplicity and fast adapter iteration, or move to TensorRT-LLM for higher compiled throughput at the price of a build pipeline and per-change recompiles.

Decision: They moved the steady-state base model to TensorRT-LLM with FP8 because the checkpoint was stable and the volume justified the build pipeline, and kept a vLLM pool for experimental LoRA variants that changed weekly.

How: They compiled a TensorRT-LLM engine for tensor-parallel degree 8 at FP8, served it behind the same router, and routed prefix-heavy traffic with caching enabled on both pools.

Result: Tokens-per-second per GPU on the stable model rose enough to retire several nodes, while the vLLM pool absorbed the churn the compiled engine could not cheaply follow.

Lesson: Compilation buys throughput when the model is stable and the volume is high; pair it with a flexible engine for the parts of the workload that change faster than you can recompile.

4. SGLang: Prefix Sharing and Structured Generation Intermediate

SGLang's distinctive contribution is RadixAttention, a prefix cache organized as a radix tree so that any shared prefix across requests, not only a fixed system prompt, is detected and reused automatically. This is the Section 24.7 idea pushed to its general form: branching conversations, few-shot templates, and agent traces that share long common stems get near-perfect cache reuse without the application managing it. SGLang pairs this with a frontend language for structured and programmatic generation (constrained decoding, control flow, parallel calls), which makes it especially fast for the templated, agentic, and tool-calling workloads of Part IV's large models when they are driven by the orchestration patterns of Part VI. For traffic dominated by shared prefixes and structured outputs it often leads on throughput; for unstructured, low-overlap traffic the advantage narrows.

Fun Note: The Tree That Remembers Everyone's Opening Line

A radix-tree prefix cache is a little like a theater prompter who has heard the same monologue ten thousand times. When the eleven-thousandth actor walks on and starts "To be, or not to be," the prompter does not re-read the script; it picks up exactly where the words stop matching. RadixAttention does the same to your prompts: the shared stem is computed once and the cache only diverges where the requests actually differ.

5. The Rest of the Field Beginner

Three engines do not exhaust the landscape. Hugging Face's Text Generation Inference (TGI) is a production server tightly integrated with the Hugging Face ecosystem and a common choice when you already live there. LMDeploy, from the OpenMMLab community, is known for strong quantized inference and its TurboMind kernels. DeepSpeed-Inference and the older FasterTransformer contributed kernels and ideas that the newer engines absorbed. And above all of these sit managed endpoints: hosted serving from cloud and model providers that run one of these engines for you behind an API, trading control and cost transparency for the elimination of every operational concern in this chapter. The managed option is the right one whenever your team's comparative advantage is the application, not the serving fleet.

These engines do not replace the generic serving frameworks of Chapter 23; they sit inside them. Ray Serve, KServe, or Triton handle autoscaling, multi-model routing, and rollout, and call an LLM engine as the per-replica runtime. And the engines feed upward into applications: the agentic systems of Part VI and the retrieval-augmented systems of Part VIII are clients of exactly the endpoints this section configures. The engine is one well-defined layer, bounded below by the per-node efficiency of Chapter 22 and above by the orchestration of Chapter 23.

6. A Decision Guide Intermediate

The choice reduces to four questions, ordered by how often they decide the outcome. First, hardware: if you are not on NVIDIA, TensorRT-LLM is out and vLLM's broad backend support leads. Second, stability versus flexibility: a fixed, high-volume model rewards TensorRT-LLM's compiled throughput, while churning models and frequent LoRA swaps reward vLLM's no-compile iteration. Third, traffic shape: heavy shared-prefix and structured/agentic traffic favors SGLang's RadixAttention; unstructured traffic narrows that edge. Fourth, team capacity: when serving is not your differentiator, a managed endpoint or TGI inside an existing stack beats running your own. Table 24.9.1 condenses the comparison; the configurator below turns these axes into a concrete recommendation.

Table 24.9.1: Leading LLM inference engines along the axes that decide a choice. All share continuous batching, paged KV cache, tensor parallelism, and an OpenAI-compatible API; the columns capture where they differ.
EngineKernel strategyPrefix sharingHardwareBest fit
vLLMRuntime kernels, no compile gateAutomatic prefix cachingNVIDIA, AMD, othersOpen default; churning models, multi-LoRA, broad hardware
TensorRT-LLMAhead-of-time compiled engine planSupportedNVIDIA onlyFixed model, very high volume, top throughput on NVIDIA
SGLangRuntime kernelsRadixAttention (general prefix tree)NVIDIA, AMDShared-prefix, structured, agentic and templated traffic
TGI / LMDeployRuntime kernels (LMDeploy: TurboMind)SupportedNVIDIA (LMDeploy strong on quantized)Hugging Face stack (TGI); quantized serving (LMDeploy)
Managed endpointProvider's choiceProvider's choiceProvider's choiceWhen the application, not the fleet, is your differentiator

7. A Serving Configurator Intermediate

The decision guide picks an engine; you still have to size the deployment. The throughput of a decode step is set by memory bandwidth, because every generated token reads the model weights once across the shards that hold them. For a model of $P$ parameters in fp16 (2 bytes each) served over $\text{TP}\times\text{PP}$ GPUs of aggregate bandwidth $B$ bytes per second, the per-replica decode rate is approximately

$$\text{tok/s} \approx \frac{B}{2P}, \qquad \text{TPOT} \approx \frac{2P}{B},$$

and the tensor-parallel degree is the smallest split that lets the weights plus a context's worth of KV cache fit under a target fraction of each card's memory. The configurator below encodes exactly this reasoning: given model size, context length, SLOs (TTFT and time-per-output-token, TPOT), and a GPU, it recommends a parallelism, disaggregation, and caching plan and estimates throughput and node count. It is the same arithmetic the per-node models of Chapter 22 fed into the fleet-sizing of Chapter 23, now closed into a recommender.

GPU_DB = {  # name: (memory_GB, fp16_TFLOPs, hbm_GB_per_s)
    "A100-80GB": (80, 312, 2039),
    "H100-80GB": (80, 989, 3350),
}

def recommend(name, params_B, ctx_len, ttft_ms, tpot_ms, gpu,
              n_gpu_per_node, qps, kv_bytes_per_tok):
    mem, _tflops, hbm = GPU_DB[gpu]
    w_gb = params_B * 2 * 1.15                       # fp16 weights + overhead
    kv_gb_seq = ctx_len * kv_bytes_per_tok / 1e9     # KV cache for one sequence
    usable = mem * 0.70                              # leave head-room per card
    tp = 1                                           # tensor-parallel degree
    while w_gb / tp + kv_gb_seq > usable and tp < n_gpu_per_node:
        tp *= 2
    pp = 1                                           # pipeline-parallel degree
    while tp * pp < w_gb / usable:
        pp += 1
    disagg = (ctx_len >= 8000) and (ttft_ms <= 500)  # split prefill/decode (24.5)
    prefix_cache = ctx_len >= 2000                   # share long prefixes (24.7)
    tok_s = (hbm * 1e9 * tp * pp) / (params_B * 2 * 1e9)   # decode rate, B/(2P)
    tpot_pred = 1000.0 / tok_s
    req_s_replica = max(tok_s / 200.0, 0.1)          # ~200 gen tok/s per request
    replicas = max(1, -(-int(qps * 100) // int(req_s_replica * 100)))
    per_replica = tp * pp * (2 if disagg else 1)
    total = replicas * per_replica
    nodes = -(-total // n_gpu_per_node)
    print(f"{name}: TP={tp} PP={pp} disagg={'Y' if disagg else 'n'} "
          f"prefix={'Y' if prefix_cache else 'n'} "
          f"TPOT~{tpot_pred:.1f}ms({'ok' if tpot_pred<=tpot_ms else 'MISS'}) "
          f"{tok_s:.0f}tok/s x{replicas}rep -> {total} GPUs / {nodes} nodes")

recommend("13B chat",  13,  2048, 300, 40, "A100-80GB", 8, 20,   800_000)
recommend("70B RAG",   70, 16000, 400, 50, "H100-80GB", 8,  8, 2_500_000)
recommend("405B long", 405,32000, 800, 60, "H100-80GB", 8,  4, 4_000_000)
Code 24.9.2: A pure-Python serving configurator. It picks the tensor-parallel degree so weights plus KV cache fit per card, adds pipeline stages when one node cannot hold the weights, flags disaggregation for long-context tight-TTFT traffic and prefix caching for long prompts, then estimates the bandwidth-bound decode rate and the replica and node count to meet the target QPS.
13B chat: TP=1 PP=1 disagg=n prefix=Y TPOT~12.8ms(ok) 78tok/s x52rep -> 52 GPUs / 7 nodes
70B RAG: TP=8 PP=1 disagg=Y prefix=Y TPOT~5.2ms(ok) 191tok/s x9rep -> 144 GPUs / 18 nodes
405B long: TP=8 PP=3 disagg=n prefix=Y TPOT~10.1ms(ok) 99tok/s x9rep -> 216 GPUs / 27 nodes
Output 24.9.2: The recommender at work. The 13B chatbot fits on one GPU and scales by replication; the 70B RAG model needs full-node tensor parallelism and earns disaggregation from its long context and tight TTFT; the 405B model crosses node boundaries with three pipeline stages, and its looser 800ms TTFT budget leaves prefill and decode fused rather than split.

The three rows of Output 24.9.2 trace the whole chapter in one table. Replication alone handles a small model; tensor parallelism within a node handles a medium one; pipeline parallelism across nodes plus disaggregation and prefix caching handle the large ones, and every recommendation is just the mechanisms of Sections 24.2 through 24.8 selected by the binding constraint. A real engine refines these numbers with quantization, speculative decoding, and measured kernel timings, but the structure of the decision, which parallelism, whether to disaggregate, where caching pays, is exactly what the configurator captures.

Research Frontier: Where Engines Are Heading (2024 to 2026)

The engines are racing on the mechanisms this chapter named. Prefill/decode disaggregation, introduced by DistServe (Zhong et al., 2024) and Splitwise (Patel et al., 2024), moved from research into configurable vLLM and SGLang features, with KV transfer over RDMA the active engineering frontier. RadixAttention (Zheng et al., SGLang, 2024) generalized prefix caching to arbitrary shared stems and is now widely adopted. Speculative and multi-token decoding (Medusa, EAGLE, and the Llama-style draft-and-verify lineage) cut decode latency and are landing as engine flags. On the MoE side of Section 24.8, expert-parallel serving with all-to-all dispatch and DeepSeek-style large-expert deployment is the current throughput frontier on NVIDIA and AMD fleets. The through-line is that the open engines are converging on a shared mechanism set while differentiating on kernels, hardware, and how early each feature ships.

Key Takeaway: Chapter 24 in One Breath

Serving a large language model spans machines. When one model is too big for one device, tensor parallelism splits it within a node and pipeline parallelism stretches it across nodes (Sections 24.2, 24.3). Its memory, the KV cache, is paged and distributed across the fleet so batch size is not capped by fragmentation (Section 24.4). Because prefill is compute-bound and decode is bandwidth-bound, the two phases are disaggregated into separate pools that exchange the KV cache (Section 24.5). A cross-node continuous-batching scheduler keeps every GPU full by admitting and routing requests with prefix-cache locality (Sections 24.6, 24.7), and one base model serves many fine-tunes through multi-LoRA (Section 24.7). When the model is a mixture of experts, expert parallelism shards the experts across nodes and routes tokens with an all-to-all (Section 24.8). All of these ship today inside vLLM, TensorRT-LLM, and SGLang (Section 24.9), so the engineering task is to choose and configure the engine that matches your hardware, traffic, and rate of change. The per-node economics of Chapter 22, multiplied across this fleet, are what these mechanisms exist to manage.

That closes the distributed serving of a single large model. The next chapter turns to the other half of a production LLM system: the retrieval layer that feeds it context. Vector search and approximate nearest-neighbor indices are themselves distributed systems, sharded and replicated like everything else in this book, and Chapter 25 builds them.

8. vLLM V1: The 2025 Architecture Advanced

The vLLM described in Section 2 above is V0, the design introduced with PagedAttention in 2023. In late 2024 the vLLM team released V1, a ground-up rewrite that keeps the same external API and the same PagedAttention KV-cache semantics while replacing the internal execution model. Understanding V1 matters in practice because it is the default vLLM as of 2025, and its performance characteristics differ substantially from the V0 baseline that most benchmarks cite.

What Changed from V0 to V1

V0 used a synchronous executor loop: the scheduler, the model runner, and the KV-cache manager shared state in a single Python process. On each step the scheduler decided which requests to advance, invoked the model runner for a forward pass, then updated the cache. Under low concurrency this was fine. Under high concurrency the scheduler blocked on the model forward pass, which meant that scheduling decisions for the next batch could not begin until the current GPU kernel finished. The GIL serialized everything, and the single-process design offered no way to overlap scheduling with execution.

V1 decouples these responsibilities into three cooperating asynchronous components. An async Scheduler is responsible only for deciding which requests to advance and which KV blocks to allocate; it never waits for GPU execution. An async Engine Core owns model execution and pushes completed token logits into an output queue as soon as the forward pass returns. Per-client output processors pull from that queue and handle detokenization independently of the main loop. The three components communicate by queue-based message passing: the Engine Core pushes finished logits into an output queue; the Scheduler pulls request-status updates from a status queue. Neither component holds the other's lock during execution. This eliminates the GIL bottleneck that serialized V0's step loop and allows the scheduler to prepare the next batch while the GPU is executing the current one.

Key Insight: Async Pipeline Decouples Scheduling from Execution

The V0 scheduler was a blocking call in the hot path: every token waited for it. The V1 scheduler runs in a separate async context and is never on the GPU's critical path. The result is that scheduling overhead, which grows with concurrency, no longer appears in time-per-output-token. This is the same architectural insight that motivates the actor model in Ray (Chapter 8) and the event-driven serving patterns of Chapter 23: separating the decision maker from the executor so neither blocks the other.

Key V1 Features

Beyond the async pipeline, V1 ships four mechanisms that were optional or absent in V0. First, prefix caching is enabled by default: automatic KV-cache reuse for any repeated prefix, including system prompts, few-shot templates, and branching agent traces, requires no configuration flag. Second, native FP8 support on Hopper (H100) GPUs uses PyTorch's fp8 dtype rather than a custom kernel, making quantized serving a first-class path. Third, chunked prefill is the default scheduler policy: long prefills are split into fixed-size chunks (see Section 24.6 and Chapter 22's chunked-prefill discussion), so decode batches are never starved by a large prompt. Fourth, a modular executor abstraction exposes a uniform interface for CPU, single-GPU, multi-GPU tensor-parallel, and multi-node pipeline-parallel backends, making it easier to add new accelerators without rewriting the engine core.

Performance

On LLaMA-3-8B under high-concurrency workloads (128 or more concurrent requests), V1 achieves 1.4 to 2.1 times the throughput of V0 with identical hardware. The gain is larger when prompts are long (the chunked prefill default eliminates head-of-line blocking) and when many requests share a system prompt (prefix caching eliminates redundant KV computation). The gains are smaller for short, low-overlap traffic where the scheduling overhead of V0 was already negligible.

Practical Example: V0 to V1 Migration at Production Scale

Who: An infrastructure team running a customer-facing chat product on a fleet of A100 nodes.

Situation: The serving stack was built on vLLM V0 and serving roughly 2,000 requests per minute with a 4,096-token median prompt that shared a 512-token system prompt across all requests.

Problem: P99 time-to-first-token (TTFT) was 4.2 seconds on the 4,096-token prompts, and the team had exhausted the per-node tuning headroom: larger batches improved throughput but made TTFT worse, and smaller batches did the reverse.

Migration: They upgraded to vLLM V1 without changing hardware, serving config, or model weights. Prefix caching for the shared system prompt activated by default, and the async scheduler eliminated the decode-blocks-scheduling bottleneck that had capped concurrency.

Result: The same hardware handled 3,400 requests per minute, with P99 TTFT dropping from 4.2 seconds to 1.8 seconds on 4,096-token prompts. The throughput gain (1.7x) fell within the 1.4 to 2.1x range the V1 benchmarks describe for high-concurrency, shared-prefix workloads.

Lesson: V1 is a free upgrade for shared-prefix, high-concurrency workloads. The biggest gains come precisely from the two architectural changes: async scheduling (which removes the per-step serialization penalty) and default prefix caching (which removes the recomputation of repeated prefixes).

Research Frontier: vLLM V1 and Prefix-Caching Alternatives

The V1 design document (vLLM blog, late 2024) describes the full async pipeline and the rationale for each architectural decision; it is the primary reference for the internals above. SGLang's RadixAttention (Zheng et al., 2024) is the main alternative prefix-caching strategy: instead of matching only exact prefixes, RadixAttention organizes the cache as a radix tree so any shared stem is reused, even across requests with different suffixes. V1's default prefix cache uses block-level hashing and detects exact matches; RadixAttention detects structural matches that V1's hashing can miss when stems diverge after the first block boundary. The two designs trade implementation complexity for generality, and both are active areas of production deployment and benchmarking as of 2025.

Exercise 24.9.1: Read the Flags Conceptual

For each vLLM flag in Code 24.9.1 (--tensor-parallel-size, --enable-prefix-caching, --enable-lora, --max-num-seqs), name the chapter mechanism it switches on and the section that built it, then state in one sentence which serving metric (TTFT, TPOT, throughput, or memory ceiling) it most directly moves and in which direction. Which flag would you change first if profiling showed the GPUs idle between decode steps?

Exercise 24.9.2: Extend the Configurator Coding

Add quantization to Code 24.9.2. Introduce a weight_bytes argument (2 for fp16, 1 for fp8, 0.5 for int4) and use it in both the weight-memory and the decode-rate formulas, since fewer bytes per weight both relax the memory ceiling and raise the bandwidth-bound token rate. Re-run the three workloads at fp8 and report how TP, node count, and predicted TPOT change. Then explain why quantization can lower the tensor-parallel degree even when it leaves the SLOs unchanged.

Exercise 24.9.3: Pick the Engine Analysis

Using Table 24.9.1 and the decision guide of Section 6, choose an engine for each scenario and justify it in two sentences: (a) an agent platform whose requests share a 4,000-token system prompt and emit JSON-constrained tool calls; (b) a fixed 70B model billed at flat-rate on a reserved H100 cluster serving 50,000 requests per minute; (c) a research group on AMD GPUs swapping LoRA adapters daily; (d) a three-person startup whose product is the application, not the fleet. State which of the four decision axes (hardware, stability, traffic shape, team capacity) is decisive in each.

Project Ideas

1. Benchmark the latency-throughput frontier under caching and disaggregation. Serve one open model (for example an 8B instruct model) on vLLM and measure TTFT, TPOT, and tokens-per-second as you sweep batch width, with prefix caching off then on, and with prefill/decode fused then disaggregated. Plot the latency-throughput Pareto frontier for each configuration and quantify how much each mechanism of this chapter moves it. Reuse the load generator and metric definitions from Chapter 23.

2. Validate the configurator against reality. Take the recommender of Code 24.9.2, run its three recommended configurations on real hardware (or a cloud rental), and compare predicted TPOT and throughput against measured values. Identify where the bandwidth-bound model is optimistic (kernel overhead, attention cost growing with context) and add correction terms until predictions land within twenty percent.

3. A multi-LoRA, prefix-shared agent backend. Stand up an SGLang or vLLM endpoint that serves one base model with several LoRA adapters and a long shared system prompt, then drive it with branching agent traces that share stems. Measure the cache hit rate that RadixAttention or automatic prefix caching achieves and the throughput gain over a no-cache baseline, and report how it degrades as the traces diverge earlier.