The document that doesn't exist in any other Gemma 4 deployment repo.
Data to be filled withbenchmarks/radixattention_prefix_sweep.pyon your hardware.
The "SGLang is 29% faster" claim circulates without context. The reality is a function of prefix overlap:
| Prefix Overlap | Cache Hit Rate | TTFT benefit vs no cache | vs vLLM +prefix_cache | Recommendation |
|---|---|---|---|---|
| > 75% | 75-95% | 3-6x faster TTFT | ~10-15% better | ✅ Use SGLang |
| 40-75% | 30-60% | 1.5-2x faster | Neutral to +5% | |
| < 30% | < 20% | < 1.2x | vLLM can win | ❌ RadixAttention overhead hurts |
Note: These numbers are from H100 benchmarks at high concurrency. Fill in your RTX 5060 Ti SM120 measurements from
benchmarks/results/radixattention_sweep.csv. The crossover point may shift.
This is the operational knowledge that doesn't appear in any SGLang documentation.
Prefix overlap is determined by prompt structure, not just content.
RadixAttention caches the longest common prefix of a request sequence. If different requests share a long common prefix, the cache is effective. If every request starts differently, the cache provides no benefit.
# Retrieved documents vary per query → prefix changes every request
# Radix tree sees: [variable docs][fixed system][variable query]
# No sharing possible — each request has a unique start
prompt = f"{retrieved_documents}\n\nSystem: {fixed_system_prompt}\n\nUser: {query}"# Fixed system prompt first → ALL requests share this prefix
# Radix tree sees: [fixed system][variable docs][fixed query pattern]
# System prompt is cached after the first request — huge TTFT reduction
prompt = f"System: {fixed_system_prompt}\n\nContext: {retrieved_documents}\n\nUser: {query}"Why this matters: In a typical RAG pipeline with 200 users asking about the same knowledge base, the system prompt (~200-500 tokens) is constant across all requests. With correct prompt structure, SGLang caches this prefix once and serves all 200 users from the radix tree — eliminating the prefill cost entirely for that portion.
With wrong structure, the system prompt appears after variable retrieved docs. Every request has a different start → zero cache sharing.
SGLang exposes cache statistics via its metrics endpoint:
curl http://localhost:30000/metrics | grep cache
# radixattention_cache_hit_tokens
# radixattention_cache_total_tokensCache hit rate = cache_hit_tokens / cache_total_tokens.
- > 0.75 → you're in the optimal zone for SGLang
- 0.30-0.75 → marginal; benchmark both engines
- < 0.30 → switch to vLLM with
--enable-prefix-caching
# Both engines must be running
docker compose -f docker/sglang/docker-compose.yml up -d
docker compose -f docker/vllm/docker-compose.yml up -d
# Run the sweep (11 steps × 10-20ms each, ~5-10 minutes total)
python benchmarks/radixattention_prefix_sweep.py --requests-per-step 20
# Results written to:
# benchmarks/results/radixattention_sweep.csv
# benchmarks/results/radixattention_sweep.md ← copy this into the table above
# benchmarks/plots/radixattention_sweep.png ← the chart to shareDemo code: rag-integration/sglang_radixattention_demo.py
Benchmark script: benchmarks/radixattention_prefix_sweep.py