Why does autoregressive generation use a KV cache?
Same topic, related formats. Practice these next.
Same topic, related formats. Practice these next.
Why does an autoregressive LLM use a KV cache during generation? What specifically is cached, and what would the cost be without it?
Without a cache, each step re-projects K and V for every past token, O(n²) wasted work. The cache stores K and V (not Q) per layer/head and reuses them, cutting per-step projection cost to O(1).
Think of cooking dinner one course at a time. Each new course uses ingredients you already chopped earlier, the onions are diced, the garlic is minced, the herbs are ready on the counter. Without a KV cache, you re-chop every ingredient from scratch for every new course, even though they're sitting right there ready to use. With a cache, you keep the pre-chopped pile on the counter and just add the one new thing for the current course. Same dinner, none of the wasted prep.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
Walk the causal attention asymmetry (Q reader vs K/V read target), the prefill/decode split, the exact cache shape and memory footprint, and the cascade of production optimizations (MHA→GQA→MLA, paged allocation, prefix sharing, quantization, spec decoding).
# Decode loop with KV cache (conceptual)
def generate(prompt_ids, model, max_new_tokens):
# Prefill: process whole prompt in one pass, get initial cache
logits, cache = model.forward(prompt_ids, cache=None)
next_token = sample(logits[:, -1])
out = [next_token]
# Decode: one token at a time, reuse and grow cache
for _ in range(max_new_tokens - 1):
logits, cache = model.forward(next_token[:, None], cache=cache)
next_token = sample(logits[:, -1])
out.append(next_token)
if next_token == eos: break
return out
# Inside model.forward at decode step:
# q_new, k_new, v_new = project(x_new)
# cache.append(k_new, v_new) # only K and V: no Q!
# attn = softmax(q_new @ cache.k.T / sqrt(d)) @ cache.vReal products, models, and research that use this idea.
What an interviewer would ask next. Try answering before peeking at the approach.
Red flags and common mistakes that signal junior thinking. Click to expand.
Confusing the prefill phase (compute K, V for the whole prompt at once) with the decode phase (append one K, V row per step), or thinking the cache stores Q, attention weights, or outputs.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.