The idea: old keys and values never change

A language model writes one token at a time. To pick the next token, the newest token's query is compared with the key of every earlier token, and their values are mixed (see Self-Attention). In a decoder the causal mask means a token never looks ahead, so the key and value of token 3 are the same at step 4, step 5 and step 100. The KV cache keeps them: each step computes K and V for the new token only and appends them.

Every layer, from layer 1 to layer 32, holds a K matrix and a V matrix with one row per token. Tokens 0 to 4 are cached and token 5 adds one new row to K and V in every layer. Below: bytes per token = 2 times n_layers times n_kv_heads times d_head times bytes per number; for Llama-2-7B in fp16 that is 512 KiB per token and 2 GiB at 4,096 tokens.
One token costs one K row and one V row in every layer: 512 KiB for Llama-2-7B.

The canvas follows one request. The prompt is “the cat sat” and the model writes “on the soft mat .” (the reply is scripted: the page is about cost, not about which token wins). The left lane has no cache, the right lane has one. Under them, the memory the cache takes and how a server stores it in blocks.

Without vs with the cache

The first pass is the prefill: K and V for all 3 prompt tokens in one go. Both lanes do the same work here. Each later press is a decode step: the newest token goes in, gets its q, k and v, attends over all K,V rows and predicts the next token. (Demo: prefill, then one decode step)

steptoken fedK,V rows without cacheK,V rows with cache
prefillthe cat sat33
decode 1on41
decode 2the51
decode 3soft61
decode 4mat71
total257

Without a cache, writing n tokens computes about n²/2 K,V rows, in every layer; with it, n. The attention itself (q against every key) is the same in both lanes and gives the same numbers, so the cache changes the cost, never the text. (Demo: the whole reply — 25 vs 7 K,V rows) How a Large Language Model Works shows the same loop on a real tiny model.

How much memory

The price is memory. Per token, the cache stores a key and a value for every KV head in every layer:

bytes per token = 2 × n_layers × n_kv_heads × d_head × bytes per number
model (fp16)layersKV heads × d_headper token4,096 tokens
GPT-2 small1212 × 6436 KiB144 MiB
Llama-2-7B3232 × 128512 KiB2 GiB
Llama-3-8B328 × 128128 KiB512 MiB
Llama-2-70B808 × 128320 KiB1.3 GiB

A server runs many requests at once, so 16 requests of 4,096 tokens on Llama-2-7B need 32 GiB of cache, more than the model’s own weights (about 13 GB). Grouped-query attention (GQA) lets several query heads share one K,V head, so Llama-3-8B stores 8 KV heads instead of 32: 4 times less. Multi-query attention goes to a single KV head. (Demo: GQA — Llama-3-8B, Demo: Llama-2-70B)

PagedAttention: the cache in blocks

A server does not know how long a reply will be. Reserving max_len slots per request up front wastes most of them. PagedAttention (vLLM) splits the cache into blocks of a fixed number of tokens (16 in vLLM, 4 on the canvas) from one shared pool. Each request has a block table, a list of block numbers in order, so its blocks can sit anywhere in GPU memory, like pages in virtual memory. A request takes a new block only when its last one is full, so it wastes at most one partly filled block. (Demo: two requests share the block pool)

Left: contiguous allocation reserves 15 slots for request A and 15 for B; A uses 7 and B uses 9, so 16 reserved slots are empty. Right: paged allocation; A's block table is 0 and 3, B's block table is 2, 5 and 1, pointing into a pool of 8 physical blocks of 4 slots; 16 of the 20 slots in taken blocks are used.
Block tables let each request grow block by block from a shared pool, wherever a block is free.

Blocks also make sharing cheap: two requests with the same system prompt can point at the same blocks for that prefix, and a block is copied only when one of them writes to it.

Prefill and decode feel different

Prefill handles all prompt tokens at once, so the GPU is busy with arithmetic (compute-bound); that is the wait before the first token. A decode step does little arithmetic for one token but reads the whole cache and all weights from memory (memory-bound); that is why later tokens stream at a steady rate, and why it gets slower as the cache grows. Batching many requests helps decode, and the cache is what limits the batch size.

See also How a Large Language Model Works for the whole generation loop, Self-Attention for what q, K and V are, Decoding Strategies for how the next token is chosen, and LoRA and Quantization for storing numbers in fewer bits (the cache can be quantized too).

What the page leaves out

Real tensors (each K,V row here is d_head numbers per head), multi-head detail, batching and scheduling of many requests, prefix caching and copy-on-write, sliding-window attention, KV cache quantization (8-bit or 4-bit), eviction when memory runs out, speculative decoding, and FlashAttention kernels.