All articles
AI News

vLLM v0.28.0: How Automatic Prefix Caching Slashes LLM Serving Costs

FDE Coach EditorialAugust 31, 20269 min read

The Release: What Actually Changed

vLLM v0.28.0 dropped on October 31, 2024, and the headline feature is Automatic Prefix Caching (APC) . This isn't an incremental patch—it's a fundamental shift in how the serving engine manages the KV-cache. Prior versions required manual configuration to share KV-cache blocks between requests. v0.28.0 makes this detection automatic, hashing the token sequences of incoming requests and reusing computed KV-cache blocks when identical prefixes are detected.

The release notes also ship chunked prefill improvements and speculative decoding fixes, but APC is the feature that changes the economics of serving. The core idea: if you're serving the same long system prompt to thousands of users, you compute it once, not thousands of times.

Why Engineers Should Care: The Cost Math

Let's put numbers on this. A typical enterprise RAG chatbot has a 2,000-token system prompt with domain-specific instructions, tool definitions, and guardrails. Every user query starts by processing that identical prefix.

Without APC:

  • Time to first token (TTFT) for a 2,000-token prefix on an A100: ~1.2 seconds
  • If you serve 10,000 requests/day, that's 12,000 seconds of GPU time just recomputing the same prefix
  • At $2.50/hour for an A100 on-demand, that's roughly $8.30/day wasted on redundant computation

With APC:

  • The system prompt is computed once and the KV-cache blocks are hashed
  • Subsequent requests hit the cache and skip the prefill entirely for those tokens
  • TTFT drops to near-zero for the cached portion, and GPU utilization shifts from compute-bound to memory-bandwidth-bound

For a Forward Deployed Engineer managing an enterprise deployment, these numbers directly translate to either lower cloud bills or higher throughput on fixed infrastructure. If you're running a multi-tenant system where dozens of organizations share the same base prompt but customize a few parameters, the savings compound.

Inside the Black Box: How Automatic Prefix Caching Works

APC isn't magic—it's a hash table bolted onto the block manager. Here's the step-by-step:

  1. Token Sequence Hashing: When a request arrives, vLLM tokenizes the prompt and computes a rolling hash over the token IDs. The hash function is designed to be collision-resistant enough for cache lookups—it's not cryptographic, but it doesn't need to be.

  2. Block-Level Granularity: The KV-cache is divided into blocks (default 16 tokens per block). APC hashes sequences at block boundaries. If the first 32 tokens of your prompt match a cached sequence, you get two block hits.

  3. Cache Lookup: Before scheduling a new block computation, the block manager checks the hash against an in-memory hash table. A hit returns a pointer to the existing physical block.

  4. Copy-on-Write Semantics: If a request shares a prefix but then diverges (different user query after the system prompt), the shared blocks are reference-counted. When a block needs modification, it's copied. This prevents cache poisoning.

  5. Eviction Policy: The cache uses an LRU policy. When GPU memory pressure hits, the least recently used blocks are evicted. The system prompt blocks that get hit constantly stay resident.

# Simplified mental model of what happens under the hood
# Not the actual vLLM source, but captures the logic
class AutomaticPrefixCache:
    def __init__(self, block_size=16):
        self.block_size = block_size
        self.hash_table: dict[int, list[Block]] = {}
        self.ref_counts: dict[Block, int] = {}
    
    def match_prefix(self, token_ids: list[int]) -> list[Block]:
        matched_blocks = []
        for i in range(0, len(token_ids), self.block_size):
            block_tokens = token_ids[i:i + self.block_size]
            block_hash = self._rolling_hash(block_tokens)
            if block_hash in self.hash_table:
                matched_blocks.append(self.hash_table[block_hash][0])
            else:
                break  # Prefix match ends at first miss
        return matched_blocks

The key engineering insight: this happens automatically. You don't annotate which parts of the prompt are cacheable. The system detects common prefixes regardless of where they appear in the request stream.

The Architecture: How APC Fits Into the Serving Stack

The Prefix Hasher sits between the scheduler and the block manager. It's a thin layer that intercepts block allocation requests and checks if the hash already exists. If it does, it short-circuits the computation and returns a reference. If not, it allocates a new block and registers the hash.

This architecture means APC is transparent to the model runner. The model sees the same KV-cache tensors regardless of whether they came from cache or fresh computation. Zero model code changes required.

Getting Your Hands Dirty: Configuration and Tuning

APC ships enabled by default in v0.28.0, but you'll want to tune it for your workload. Here's what matters:

Enable and configure:

# Start vLLM with APC explicitly enabled (on by default, but explicit is better)
vllm serve meta-llama/Llama-3.1-8B-Instruct \
  --enable-prefix-caching \
  --max-num-batched-tokens 8192 \
  --gpu-memory-utilization 0.90

Key knobs:

  • --enable-prefix-caching: The main switch. On by default in 0.28.0.
  • --max-num-batched-tokens: Larger values mean more tokens can be batched, which increases the chance of prefix matches across concurrent requests.
  • --gpu-memory-utilization: APC needs headroom for the hash table and reference-counting metadata. Pushing this to 0.95 might leave you OOM. Start at 0.85-0.90.

Monitoring cache hit rate: vLLM exposes metrics via its Prometheus endpoint. The key metric is vllm:prefix_cache_hit_rate. Hook this into your Grafana dashboard and set an alert if it drops below your expected baseline.

# Example: query the metrics endpoint
import requests
metrics = requests.get("http://localhost:8000/metrics").text
# Parse for vllm:prefix_cache_hit_rate

Workload design for maximum cache efficiency:

  1. Standardize system prompts: If every tenant has a slightly different system prompt, APC can't help. Template them with variables that get filled client-side.
  2. Prefix-heavy, suffix-light: APC shines when the shared portion is at the beginning. If your shared content is in the middle of the prompt, you're out of luck.
  3. Batch similar requests: If you can group requests that share prefixes temporally, you'll keep those blocks hot in the LRU cache.

For a deeper dive on building systems that leverage this kind of caching effectively, the architecture patterns in Domain-Driven Agents: Bounded Contexts for Reliable AI Workflows apply directly—treat your system prompt as a bounded context that gets computed once and reused.

When APC Fails: The Balanced Take

APC isn't a silver bullet. Here's where it breaks down:

Random or unique prefixes: If every request starts with a unique user-specific preamble, the hash table becomes a write-only graveyard. You're paying the overhead of hashing with zero cache hits.

Memory pressure: The LRU eviction policy is a blunt instrument. Under heavy load with diverse prefixes, the cache thrashes—blocks are evicted before they can be reused. You need enough GPU memory to hold your working set of shared prefixes plus the active request batch.

Prefix alignment: APC operates on block boundaries (16 tokens by default). If your shared prefix is 20 tokens, you get one block hit (16 tokens) and the remaining 4 tokens are recomputed. This can lead to surprising TTFT behavior where you expect a full cache hit but get a partial one.

Cross-model incompatibility: The KV-cache is model-specific. You can't share cached blocks between Llama-3 and Mistral, even if they're processing the same text. Each model has its own cache namespace.

The cold start problem: The first request after server startup always misses. If you're doing canary deployments or frequent model updates, you'll spend more time in the cold-start regime. Consider warming the cache with a synthetic request on startup.

The FDE Angle: Selling This to an Enterprise Customer

If you're a Forward Deployed Engineer managing an LLM deployment for a customer, APC is a lever you can pull in a technical business review. Here's the playbook:

Quantify the waste first: Pull the metrics. Show the customer how many GPU-hours they're burning on redundant prefix computation. Most enterprise RAG deployments have a 30-50% redundancy rate in their prompt processing.

Translate to dollars: "At your current throughput of 50,000 requests/day with a 2,000-token system prompt, you're spending roughly $X/month recomputing the same prefix. Upgrading to vLLM 0.28.0 with APC enabled brings that to near-zero."

Address the operational concern: The customer's ops team will ask about risk. APC is a no-model-change optimization. The output quality is identical—bit-for-bit the same logits. It's purely a scheduling and memory management optimization.

Tie it to their scaling story: "You mentioned you want to add three more enterprise tenants next quarter. Without APC, that triples your redundant compute. With APC, those tenants share the same system prompt cache blocks. Your marginal cost per tenant drops significantly."

This kind of technical cost optimization is exactly the muscle you build when you understand how AI-Native Startups Use Forward Deployed Engineers to Win Enterprise Deals. The FDE who can walk into a QBR and demonstrate a 30% cost reduction without touching model quality is the FDE who gets renewals.

If you're preparing for an FDE interview where you'll need to walk through a scenario like this, the decomposition and customer-scenario skills covered in Inside the Cohere and Anthropic FDE Interview Process are directly applicable.

FAQ

Q: Does APC change the model output? No. The KV-cache is mathematically identical whether computed fresh or retrieved from cache. The logits are deterministic given the same KV state. This is a pure performance optimization.

Q: What's the memory overhead of the hash table? Minimal—typically less than 1% of GPU memory. The hash table stores token-sequence hashes (8 bytes each) and block pointers (8 bytes each). For a cache with 100,000 blocks, that's roughly 1.6 MB.

Q: Can I use APC with LoRA adapters? Yes, but with caveats. The base model's KV-cache is shared, but LoRA-specific activations are not cached. If you're serving multiple LoRA adapters, each adapter's prefix computation is separate.

Q: How do I know if APC is working? Check the vllm:prefix_cache_hit_rate metric. A rate above 0.5 for a workload with standardized system prompts means it's working. Below 0.1 and you're likely dealing with unique prefixes or memory thrashing.

Q: Does this work with chunked prefill? Yes. v0.28.0 ships improvements to chunked prefill that are compatible with APC. The chunked prefill scheduler will preferentially schedule chunks that have cache hits, improving throughput further.

Q: What if my system prompt changes dynamically? If the system prompt changes per request (e.g., user-specific instructions injected into the prefix), APC won't help for that portion. Consider factoring your prompt into a static shared prefix and a dynamic suffix to maximize cache reuse.

#llm-serving#prefix-caching#cost-optimization#open-source

Want to build like a Forward Deployed Engineer?

FDE Coach is a cohort-based program in frontend, backend, AWS, and AI. Build real products and get referred to 200+ hiring partners.

Explore the program

More ai news

August 15 · 0d left
Enroll Now
vLLM v0.28.0: How Automatic Prefix Caching Slashes LLM Serving Costs | FDE Coach