Guide

Every chat completion is two different jobs glued into one API call. Prefill digests the prompt. Decode emits the reply one token at a time. They stress the GPU in opposite ways, they dominate different latency metrics, and when they share a batch they can ruin each other's SLOs.

The inference arithmetic page gave the napkin formulas. This section is the why: why input tokens and output tokens are not the same commodity, why a long RAG prompt can stall someone else's stream, and why engines invent chunked prefill and disaggregated pools.

Concepts in this section

StepConceptWhat it answers
1The prefill phaseWhy is the prompt compute-bound?
2The decode phaseWhy is each output token memory-bound?
3Prefill–decode interferenceWhy does a new prompt hitch other streams?
4Workload shapesWhich products stress which phase?

Why the asymmetry matters

PrefillDecode
Parallelism over sequenceYes, the prompt is knownNo, one new token
Typical bottleneckComputeMemory bandwidth
Primary metricTTFTTPOT / tok/s
Scales withInput lengthOutput length × steps
Batching effectLarger GEMMs, still heavyAmortizes weight reads

This is why APIs often price input and output differently. Prefill turns one weight read into work for thousands of prompt tokens. Decode re-reads weights for each output token. A 10k-token system prompt plus a 20-token "yes" is cheap on decode and expensive on prefill. A 50-token question plus a 2k-token chain of thought is the opposite.

Example

Same 70B FP8 replica: prefill 4,000 tokens is about 0.5 s. Decode 4,000 tokens is about 40 s. Equal counts, different wall time.

Preview of the fixes

You do not need the full mechanisms yet, but you should know the map.

  1. Continuous batching — admit and finish sequences every step (batching).
  2. Chunked prefill — bound how much prefill work lands in one step.
  3. Paged KV — pack variable-length caches (PagedAttention).
  4. Disaggregation — specialize hardware pools (disaggregated serving).
  5. Speculative decoding — verify several draft tokens per weight read (speculative decoding).

All of them exist because prefill and decode are different programs that happen to share a model.

Common mistakes

  • One latency SLO for both phases. "p50 latency under 2 s" hides a RAG spinner and a hitching agent stream.
  • Treating input and output tokens as the same cost. They are not, in time or in money.
  • Buying more copies of the same replica to fix a mixed workload. Prefill-heavy and decode-heavy traffic want different pools or at least different queues.

Key takeaways

  • Prefill is usually compute-bound and drives TTFT. Decode is usually memory-bound and drives TPOT.
  • Input versus output pricing follows this split.
  • Long prefills on a shared GPU stall other users' decode streams.
  • Chat, RAG, reasoning and agents stress different sides. Measure both.

Further learning

LLM Inference Performance Engineering (Databricks)databricks.com

Splitwise and DistServe on splitting the two phases.

DistServe: disaggregating prefill and decoding for goodput-optimized LLM inferencePyTorch