← Model-serving series

Series 03 / Chapter 01

Model serving and inference.

How a checkpoint becomes a dependable service: request contracts, prefill and decode, KV-cache arithmetic, scheduling, parallel execution, numerical formats, reliability, and production evidence.

SERIES 03 / CHAPTER 01

01
MODEL SERVINGTURN WEIGHTS INTO A SERVICE

REQUEST → PREFILL → DECODE → STREAM

  • Cache
  • Schedule
  • Measure

A model server is a real-time resource allocator around an autoregressive loop. It must preserve the model’s output contract while deciding which requests run, which cached states stay in memory, how work is divided across accelerators, and where latency is spent.

MODEL SERVINGCHAPTER 01 / 01
The language-model serving pathRequests pass through validation and admission, a scheduler groups token work, model workers run prefill and decode with a KV cache, and tokens stream back while telemetry records the path.SKETCH 01 / THE ONLINE SERVING PATHREQUESTprompt + limitsADMISSIONvalidate + budgetrouteSCHEDULERtoken batchesMODEL WORKERSprefill → decodeKV CACHESTREAMtokens + finishqueue time · cache blocks · token latency · cancellations · errors
Sketch 01 The checkpoint is only one component. Admission, scheduling, cache ownership, streaming, and telemetry define the service around it.

Start with a service-level objective, not a GPU.

Offline generation optimizes the time to finish a bounded batch. An interactive service must satisfy a distribution of requests arriving over time. The objective is therefore multi-dimensional: make the first token arrive quickly, keep later tokens flowing smoothly, sustain enough concurrent work, stay within a memory and cost budget, and reject overload predictably.

MetricBoundaryWhat it exposes
Time to first token

Request accepted → first streamed token

Queueing, tokenization, prefill, and first decode step

Inter-token latency

One streamed token → the next

Decode scheduling and per-step execution

End-to-end latency

Request accepted → finish reason

Full user wait, including output length

Token throughput

Prompt and generated tokens per second

Accelerator utilization and batching

Request throughput

Completed requests per second

Capacity under the actual length mix

State percentiles and workload conditions with every number. A mean hides queue spikes; a tokens-per-second record without input lengths, output lengths, concurrency, and hardware cannot be reproduced. Separate client-observed latency from server execution so network and application overhead are not attributed to the model engine.

Define semantic requirements beside performance: tokenizer and chat-template version, maximum context, stop conditions, sampling policy, deterministic mode, tool-call schema, log-probability behavior, cancellation semantics, and compatibility rules. A faster server that silently changes tokenization or sampling is a different system.

Make every boundary explicit and observable.

A production request passes through more than a model call. The edge authenticates the caller and applies rate limits. The API validates the prompt, generation parameters, and context budget. A tokenizer converts messages to IDs. Admission control estimates the work and memory. A router selects a compatible replica. The scheduler forms token batches. Model workers produce logits, the sampler chooses tokens, and a streaming layer converts IDs back into text.

authenticatevalidatetokenizeadmitscheduleexecutesamplestream
Trace fieldReason to preserve it
request_id, tenant_id

Join events while keeping quotas and cache ownership distinct

model_revision, tokenizer_revision

Reproduce the exact serving contract

prompt_tokens, max_new_tokens

Estimate work and explain latency

sampling_config, seed

Separate engine changes from decoding changes

queue_ms, prefill_ms, decode_ms

Locate time instead of reporting one opaque total

finish_reason, error_code

Distinguish normal stop, limit, cancellation, rejection, and failure

Streaming adds backpressure. If a client reads slowly or disconnects, the server should release its sequence and cache blocks quickly. Cancellation must propagate from the edge to the scheduler and workers; otherwise invisible abandoned requests consume the scarce decode budget.

One request contains two very different workloads.

During prefill, the engine processes the prompt tokens and writes their keys and values into the cache. All prompt positions can be evaluated in parallel under the causal mask, so large matrix operations usually use the accelerator efficiently. The cost grows sharply with prompt length because each query attends across its permitted prefix.

During decode, the engine generates one new token per active sequence per iteration. The new query attends over cached keys and values, then the chosen token extends the cache. The arithmetic per iteration is smaller, but model weights and cache state must be accessed repeatedly. Small decode batches can therefore be dominated by memory bandwidth, communication, and launch overhead.

PhaseUnit of workDominant pressure
Prefill

Many prompt tokens per sequence

Compute, attention workspace, long-prompt queueing

Decode

One new token per active sequence

Weight/cache bandwidth and step latency

KV transfer

Move prompt state to decode workers

Network bandwidth and handoff delay

Aggregated serving runs both phases on the same worker pool. A long prefill can delay decode steps and produce visible pauses for existing users. Chunked prefill limits how many prompt tokens enter one scheduling iteration, allowing decode work to interleave. Disaggregated serving places prefill and decode on different worker pools, which permits independent scaling but adds KV-cache transfer, routing state, and failure modes.

Measure the phases separately before selecting an architecture. Disaggregation is useful only when the workload imbalance and interference it removes are worth the extra network path and operational complexity.

Cache memory is the admission currency.

Every decoder layer stores a key and value vector for every live token. With grouped-query attention, the cache uses the number of key/value heads rather than the number of query heads. Before sharding and allocator metadata, the approximate bytes for one sequence are:

KV-cache memoryM ≈ 2 × L × S × Hkv × Dh × b

L layers, S cached tokens, Hkv key/value heads, Dh head dimension, b bytes per stored element; the factor two represents keys and values.

For 32 layers, 8 key/value heads, head dimension 128, and two-byte cache values, each token consumes about 128 KiB per sequence. An 8,192-token sequence is therefore about 1 GiB before allocator overhead and any device partitioning. Batch count alone is not a capacity measure: eight short prompts and eight near-limit prompts require radically different cache budgets.

Contiguous allocation reserves a large region for each possible sequence and wastes space when lengths vary. Paged allocation divides the cache into fixed-size blocks, maps logical token positions to physical blocks, and returns blocks as sequences finish. It reduces external fragmentation and lets the scheduler admit work using available blocks rather than worst-case sequence reservations.

Prefix caching can reuse blocks for an identical token prefix, reducing repeated prefill work. Cache identity must include every value that changes model state: model revision, adapter, tokenizer, chat template, positional policy, and relevant multimodal inputs. Tenant boundaries and access policy must prevent one caller from observing or timing private cached prefixes.

Paged KV-cache allocationThree sequences of different lengths map their logical token blocks to noncontiguous physical blocks in a shared pool. Freed blocks return to the allocator and can be reassigned.SKETCH 02 / PAGED CACHE ALLOCATIONLOGICAL SEQUENCESABCblock tablePHYSICAL BLOCK POOLA0C0A1B0A2C1FREEB finishes → recycle its blockADMISSION CHECKS FREE BLOCKS, NOT ONLY REQUEST COUNT
Sketch 02 Logical sequences can grow without requiring one contiguous physical region; finished sequences return blocks to the shared pool.

Batch token work, not merely requests.

Static batching waits for a group, pads it to compatible shapes, and holds every slot until the slowest sequence finishes. Dynamic batching collects requests for a short boundary-time window. Continuous—or in-flight—batching rebuilds the active batch at each generation iteration, removes completed sequences immediately, and inserts newly admitted work into freed capacity.

PolicyDecision pointTrade-off
Static batch

Before execution

Simple, but padding and tail waste are high

Dynamic batch

Short queue window

More throughput at the cost of deliberate queue delay

Continuous batch

Every token iteration

High utilization with a stateful scheduler

Chunked prefill

Token-budget slices

Less decode interference, more scheduling transitions

A useful scheduler tracks a token budget and a cache-block budget. It must decide how much prefill and decode work to mix, whether a long prompt may monopolize an iteration, when to preempt a sequence, and how to prevent a high-volume tenant from starving others. First-come-first-served is predictable but can suffer head-of-line blocking; priority classes require quotas and aging so low-priority work eventually progresses.

while running:
    release_finished_and_cancelled()
    budget = step_token_budget
    batch = select_decode_sequences(budget, fairness_policy)
    budget -= decode_tokens(batch)
    batch += select_prefill_chunks(budget, free_cache_blocks)
    logits = execute(batch)
    sample_and_stream(logits)

Preemption is not free. Swapping cache blocks to host memory spends bandwidth; recomputing a prefix spends model time. Log why each sequence was preempted and whether it was swapped, recomputed, rejected, or timed out. Scheduler policy belongs in the service version because it changes user-visible latency even when weights are unchanged.

Choose the communication pattern that matches the bottleneck.

If one accelerator holds the checkpoint, replicas provide the simplest scale-out: each replica serves independent requests and the router balances load. When the model does not fit or one replica misses the latency target, the model itself must be partitioned.

StrategyPartitionPrimary cost
Replica / data parallel

Independent full models

Duplicate weights and uneven routing

Tensor parallel

Matrix dimensions within each layer

Collective communication every layer

Pipeline parallel

Consecutive layer stages

Stage bubbles and activation transfers

Expert parallel

Sparse experts across devices

Token all-to-all and routing imbalance

Prefill/decode split

Execution phase

KV transfer and cross-pool routing

Tensor parallelism reduces per-device weight memory and can lower single-request latency when devices have a fast interconnect, but collective operations occur throughout the network. Pipeline parallelism places different layers on different stages; utilization depends on enough concurrent microbatches to fill the pipeline. Expert parallelism is natural for sparse models but makes router balance and all-to-all traffic part of the latency path.

Benchmark the whole topology. A kernel speedup can disappear behind communication, and adding devices can increase latency when the batch is too small to amortize collectives. Record topology, link type, shard count, collective time, and per-rank memory beside throughput.

Quantization changes memory traffic and the output distribution.

Reducing precision can make a model fit, allow more cache blocks, and reduce bandwidth per generated token. Weight-only quantization primarily reduces the cost of reading weights and is often attractive for decode. Weight-and-activation quantization can accelerate more operations but demands a supported kernel path and careful calibration. The KV cache can be stored at lower precision independently of the weights.

SurfacePossible gainVerification required
Weights

Smaller checkpoint and lower read bandwidth

Logit drift, task quality, kernel coverage

Activations

Faster matrix operations and less temporary memory

Outlier handling and calibration stability

KV cache

More concurrent or longer sequences

Long-context and generation-quality drift

Memory reduction is not the same as latency reduction. Dequantization overhead, unsupported layers, small batch shapes, or frequent format conversions can erase the gain. Report the exact scheme, group size, scales, calibration set, fallback operations, and kernel implementation rather than a label such as “4-bit.”

Test parity at three levels: compare logits on fixed prefixes, compare deterministic outputs under fixed seeds and settings, then rerun behavioral evaluations. A small average logit error can still alter a near-tied token choice and cause a long generated sequence to diverge.

Optimize the phase that dominates the workload.

Fused attention kernels reduce intermediate memory traffic and avoid materializing the complete attention matrix. Fused normalization, activation, projection, and sampling kernels reduce launches and round trips to device memory. CUDA graphs or similar execution capture can remove repeated host-side launch overhead when shapes and control flow permit it.

Grouped-query or multi-query attention shares key/value heads across more query heads, shrinking the KV cache and its bandwidth. Prefix caching skips repeated prefill for exact shared prefixes. Both affect model or request contracts and must be validated under the real template and length distribution.

Speculative decoding uses a cheaper draft process to propose several tokens, then asks the target model to verify them together. Accepted tokens advance the sequence; at the first rejection, normal target sampling restores the correct target distribution. The gain depends on draft cost, acceptance rate, verification shape, and available accelerator headroom.

Useful speculative workgain ∝ accepted target tokens / (draft cost + verification cost)

A low acceptance rate adds work; a saturated large batch may have little spare capacity for the speculative path.

OptimizationLikely targetCommon trap
Fused kernels

Prefill and decode execution

Unsupported shapes or silent fallback

Prefix cache

Repeated system or document prefixes

Low exact-match rate or unsafe sharing

Speculation

Low-batch decode latency

Draft overhead exceeds accepted work

Long-context chunking

Decode smoothness during prefill

Too many tiny chunks and transitions

Change one lever at a time and retain output-parity checks. The correct optimization is workload-specific: an interactive coding assistant, an offline synthetic-data job, and a high-concurrency short-answer API should not share one unquestioned configuration.

Overload must be a designed state.

Capacity depends on the joint distribution of prompt length, output length, arrival rate, concurrency, cache reuse, and sampling settings. Request count is insufficient because one 100-token answer and one 10,000-token answer occupy the decode scheduler for very different durations. Maintain separate prompt-token and generated-token budgets, then estimate memory before admission.

Concurrency sanity checkaverage in-flight requests ≈ arrival rate × average service time

Use measured distributions and tail service times for provisioning; this relation is only a first-order check.

Admission control should reject or defer work before the device reaches an unrecoverable memory state. Bound queue length, prompt tokens, generated tokens, live cache blocks, and per-tenant concurrency. Apply deadlines and propagate cancellation. Use backpressure rather than accepting unlimited work and converting every request into a timeout.

ControlFailure it contains
token-aware admission

Cache exhaustion and oversubscribed decode steps

queue deadline + maximum depth

Unbounded tail latency during bursts

cancellation propagation

Compute spent after clients disconnect

worker drain + warmup

Requests routed to cold or terminating replicas

revision-aware routing

Mixed tokenizer, adapter, or engine contracts

bounded retry policy

Duplicate work and retry storms

Autoscaling on accelerator utilization alone is late and ambiguous: a server can be memory-full with modest arithmetic use, or compute-busy while the queue is healthy. Combine queue delay, admitted token work, cache occupancy, active sequences, deadline misses, and load per replica. Keep warm capacity when model loading and compilation take longer than the service’s recovery objective.

Fail closed on contract mismatch. A replica with the wrong tokenizer, adapter, numerical engine, or model revision should not receive traffic merely because its health endpoint responds. Readiness should include a fixed prompt probe, expected token IDs, and a small deterministic output or logit checksum.

Benchmark a workload, not a demo prompt.

Create a replayable workload manifest containing prompt-length and output-length distributions, arrival process, concurrency, sampling settings, prefix-reuse rate, cancellation rate, and tenant mix. Run warmup separately, then hold hardware, model revision, and request corpus fixed while changing one serving parameter.

LayerEvidenceFailure exposed
Semantic parity

Tokenizer IDs, fixed-prefix logits, deterministic outputs

Engine or precision changed behavior

Latency

p50/p95/p99 first-token, inter-token, and end-to-end

Queue spikes and decode stalls

Capacity

Request and token throughput at rising load

Saturation knee and unstable overload

Resources

Weight memory, cache occupancy, bandwidth, collectives

The actual hardware bottleneck

Reliability

Rejects, timeouts, cancellations, OOMs, restarts

Work lost or hidden during stress

Plot throughput against tail latency while increasing arrival rate. The useful operating point lies before the saturation knee where queue time starts rising rapidly. Repeat with long prompts, long outputs, bursty arrivals, mixed tenants, cache hits and misses, worker loss, slow clients, and cancellation storms. A configuration is production-ready only if degradation is bounded and observable.

ArtifactRequired contents
model_contract

Weights, tokenizer, template, adapters, numerical format, sampling defaults

engine_manifest

Runtime revision, kernels, build flags, parallel topology, cache format

scheduler_config

Token budget, batch limit, prefill policy, priorities, preemption

workload_manifest

Length distributions, arrival pattern, concurrency, seeds, corpus hash

evidence_report

Semantic parity, latency percentiles, throughput, resources, failures, cost

Performance is part of intelligence.

If a strong checkpoint cannot deliver useful tokens inside the user’s latency, availability, and cost envelope, its capability is inaccessible. Serving quality is therefore the joint result of model design, memory allocation, scheduling policy, numerical implementation, and operational discipline.

Return to the model-serving series