Reuse the shared opening
Look at real traffic and most prompts aren't unique — they share a fat, identical opening. Prefix caching is the runtime noticing that and refusing to do the same prefill twice.
Most prompts share a head
A system prompt, a few-shot block, a tool spec — these sit at the front of every request and rarely change. The model's expensive prefill computes KV for that shared head over and over, even though the result is byte-for-byte identical each time.
RAG makes it worse — and better
With RAG, retrieved documents are fetched and pasted into the prompt, which makes prompts long and largely shared. Long shared prefixes are exactly the workload prefix caching was built to win.
Compute the shared KV once
Prefix caching prefills the shared opening a single time, stores its KV blocks, and reuses them. A new request only pays to process the part that's actually new — so TTFT drops.
Keywords — tap to unfold the plain meaning
Shared openings — system prompts, few-shot, RAG context — produce identical KV. Prefill it once, reuse it, and a new request only pays for what's new.
Hash the prefix, hit the cache
The mechanism is almost boring, which is why it works: turn the prefix into a key, look it up, and if it's there, don't redo the work.
Hash in, lookup out
The engine hashes each incoming prefix. If that hash is already in the cache — a hit — it reuses the cached KV blocks and skips re-prefilling them. If it's not there — a miss — it does the full prefill and stores the result for next time.
Only the new part is computed
On a hit, prefill resumes at the first token after the shared prefix. The user waits only for the new question to be processed, not the whole repeated opening — which is where the TTFT win comes from.
Keywords — tap to unfold the plain meaning
Math, decoded
- Lprefixlength of the shared opening — system prompt, few-shot, RAG context
- Lnewlength of the new suffix — the user's actual question this time
- ∝ Lnewon a hit, prefill cost scales only with the new part; the shared prefix is free
Without caching, prefill processes the whole prompt (prefix + new). On a hit, it processes only the new suffix — so when the shared prefix dominates, TTFT drops a lot.
Hash the prefix; a hit reuses cached KV blocks and skips re-prefilling them. Prefill resumes at the new suffix, so the user only waits for what's new.
The KV memory hierarchy
VRAM is tiny, so you can't keep every prefix hot forever. The hierarchy is how you keep more cache around — but only as far down as it still pays off.
Three tiers, getting colder
Cached KV spans a hierarchy: VRAM (hottest, faster, smaller) → host RAM → local SSD (bigger, slower). The deeper you go, the more you can store, but the longer it takes to fetch a block back.
The break-even rule
Fetching a cached block from a lower tier isn't always worth it. The rule: if a lower tier is slower to fetch than to re-prefill, just re-prefill. A cache only helps when reading it back beats recomputing it.
Keywords — tap to unfold the plain meaning
Math, decoded
- tfetchtime to read the cached KV block back from a lower tier (RAM or SSD)
- treprefilltime to just recompute that block's KV with a fresh prefill
- <the cache only helps when the fetch is genuinely faster than redoing the work
A lower tier is worth using only while fetching from it is faster than re-prefilling. Past that break-even, the "cache" is slower than recomputation — so you re-prefill.
Cached KV lives across VRAM → host RAM → SSD, getting bigger and slower. If fetching from a lower tier is slower than re-prefilling, re-prefill instead.
RadixAttention & partial overlap
Exact-match caching only helps when whole openings are identical. A tree lets prompts that share part of an opening still split the cost at the branch point.
A tree of shared prefixes
SGLang generalizes prefix caching with RadixAttention — a radix tree of all live prefixes. Common openings sit near the root; where two prompts diverge, the tree branches.
Even partial overlaps share
Because matches happen along the tree, prompts don't need identical openings to benefit — even partial overlaps share. Two requests that agree for the first few thousand tokens reuse that shared run, then branch where they differ.
Keywords — tap to unfold the plain meaning
RadixAttention (SGLang) keeps a radix tree of all live prefixes, so prompts that share even part of an opening reuse the common run and branch where they differ.
Routing must be cache-aware
You can build the perfect cache and still get zero benefit if the router scatters matching requests across replicas. The cache only pays off where the request actually lands.
Caches are per-replica
Prefix caches are per replica. Each server holds its own cached KV; a block cached on replica A is invisible to replica B. So a hit depends not just on whether a prefix is cached, but on where.
A blind router throws the win away
If your load balancer sends a request to a replica that doesn't hold its prefix, it's a miss: full re-prefill, no savings. The fix is cache-aware routing — send matching requests to the same replica so they actually hit.
Keywords — tap to unfold the plain meaning
Prefix caches are per-replica. A blind load balancer turns hits into misses; cache-aware routing sends matching requests to the same replica so the cache actually pays off.
On your cluster
This isn't a hypothetical optimization for your box. The flag is already set, and the traffic shape is exactly the one prefix caching was built for.
Turn it on (it already is)
In vLLM, prefix caching is enabled with --enable-prefix-caching. On the cluster this is confirmed in the server args — your vLLM runs it.
Your traffic is the ideal case
Measured on the box, traffic is 19–47:1 prefill-heavy: each request prefills far more tokens than it decodes. Long shared openings plus a heavy prefill ratio is precisely where caching the prefix pays off most.
vLLM server arg (confirmed on the 4×H100 box)
vllm serve Qwen3.6-27B-FP8 \ --enable-prefix-caching
--enable-prefix-caching is ON (confirmed in the server args), and traffic measured at 19–47:1 prefill-heavy — the ideal prefix-caching workload. With a fat shared prefix and that ratio, hits skip re-prefilling the opening and TTFT drops.
Keywords — tap to unfold the plain meaning
Check yourself
- Explain to a colleague: "Prefix caching helps our RAG app because…" — what makes the KV identical, what gets reused, and what the user no longer waits for?
- Cached KV can sit in VRAM, host RAM, or SSD. What's the rule for when you should stop fetching from a lower tier and just re-prefill?
- Why does prefix caching need cache-aware routing to actually pay off — what happens on a replica that doesn't hold the prefix?
Your vLLM already runs --enable-prefix-caching, and 19–47:1 prefill-heavy traffic is the ideal case. Shared prefix + cache-aware routing = lower TTFT.