Polydesk-logotype
Polydesk.ai — Header

Prefix Caching

Le prefix caching est une technique d’optimisation d’inférence LLM qui stocke le KV-cache des préfixes de prompts déjà traités et le réutilise automatiquement quand une nouvelle requête commence par le même préfixe, évitant le recalcul redondant de la phase de prefill et réduisant latence et coût de calcul.

Prefix Caching en bref
Catégorie
Optimisation d’inférence LLM / Gestion mémoire GPU
Principe
Stocker les blocs KV-cache des préfixes communs, les réutiliser entre requêtes
Implémentations
vLLM (Automatic Prefix Caching / APC), SGLang (RadixAttention), TensorRT-LLM
Gain typique
Élimination du prefill sur les tokens cachés, réduction TTFT de 50-85 %
Contexte fournisseur
Équivalent côté API du prompt caching (Anthropic) et du context caching (Google)
Activation vLLM
--enable-prefix-caching (ou activé par défaut dans les versions récentes)

Pourquoi le prefix caching existe

Dans une application LLM typique, une large partie du prompt est identique entre les requêtes. Le system prompt (instructions, persona, règles métier) est le même pour chaque utilisateur. Le document de référence dans un pipeline RAG est le même pour toutes les questions sur ce document. L’historique de conversation est le même à chaque nouveau message (plus un message supplémentaire).

Sans prefix caching, le serveur d’inférence recalcule le KV-cache complet du prompt à chaque requête, y compris les parties qui n’ont pas changé. Pour un system prompt de 5 000 tokens partagé par 100 requêtes concurrentes, cela représente 500 000 tokens de prefill redondant. C’est un gaspillage de compute GPU massif.

Le prefix caching élimine ce gaspillage. Quand une requête est traitée, les blocs de KV-cache résultants sont conservés en mémoire GPU. Quand une nouvelle requête arrive avec le même préfixe, le serveur détecte la correspondance, réutilise les blocs existants, et ne calcule que les tokens nouveaux (la question de l’utilisateur).

Cette technique est distincte du prompt caching proposé par les fournisseurs d’API (Anthropic, OpenAI). Le prompt caching est un service managé côté fournisseur. Le prefix caching est implémenté dans le serveur d’inférence que vous self-hostez (vLLM, SGLang, TensorRT-LLM). Le mécanisme sous-jacent est le même (stockage et réutilisation du KV-cache), mais le contrôle et les contraintes diffèrent.

Analogie Imaginez une bibliothèque où chaque lecteur demande le même livre de référence avant de poser sa question. Sans prefix caching, le bibliothécaire recopie le livre entier pour chaque lecteur. Avec le prefix caching, il garde une copie sur l’étagère et chaque lecteur la consulte directement. Le bibliothécaire ne recopie que la question spécifique de chaque lecteur.

vLLM : Automatic Prefix Caching (APC)

vLLM implémente le prefix caching via son mécanisme PagedAttention. Les blocs de KV-cache sont des « pages » de taille fixe (typiquement 16 tokens par bloc). Chaque bloc est identifié par un hash de son contenu (les tokens qu’il représente). Quand une nouvelle requête arrive, vLLM calcule les hash des blocs de son préfixe et cherche des correspondances dans le cache existant.

Fonctionnement détaillé

1. Hashing par blocs. Le prompt est découpé en blocs de taille fixe. Chaque bloc reçoit un hash calculé à partir des tokens qu’il contient. Ce hash inclut aussi le hash du bloc précédent (chaînage), ce qui garantit que le match est un vrai préfixe (pas un match de sous-séquence au milieu du prompt).

2. Lookup dans le cache. vLLM cherche le plus long préfixe correspondant en comparant les hash du début de la requête avec les hash stockés dans le cache. Le match le plus long possible est utilisé.

3. Réutilisation. Les blocs trouvés dans le cache sont directement référencés (pas copiés) par la nouvelle requête. Grâce à la pagination, plusieurs requêtes peuvent pointer vers les mêmes blocs physiques sans duplication mémoire.

4. Calcul des tokens restants. Seuls les tokens qui ne sont pas dans le cache sont passés par le prefill. Si 90 % du prompt est caché, le prefill ne porte que sur les 10 % restants.

# Activer le prefix caching dans vLLM
from vllm import LLM, SamplingParams

llm = LLM(
    model="meta-llama/Llama-3.1-70B-Instruct",
    tensor_parallel_size=4,
    gpu_memory_utilization=0.90,
    enable_prefix_caching=True,  # Activer l'APC
)

# Toutes les requêtes partageant un préfixe commun
# bénéficient automatiquement du cache
system_prompt = "Vous êtes un assistant juridique expert..." * 200  # ~5K tokens

params = SamplingParams(temperature=0.7, max_tokens=512)

# Première requête : prefill complet (~5K tokens)
response1 = llm.generate([system_prompt + "nQuestion : Qu'est-ce qu'une clause résolutoire ?"], params)

# Deuxième requête : prefill partiel (seule la question est calculée)
response2 = llm.generate([system_prompt + "nQuestion : Comment fonctionne la force majeure ?"], params)

Isolation de sécurité

vLLM supporte l’isolation du cache via un mécanisme de « salt » par requête. En incluant un cache_salt dans la requête, cette valeur est injectée dans le hash du premier bloc, garantissant que seules les requêtes avec le même salt peuvent réutiliser les blocs cachés. Cela prévient les attaques par timing (où un adversaire pourrait déduire le contenu caché en observant les différences de latence entre un cache hit et un cache miss). Cette fonctionnalité est essentielle pour les déploiements multi-tenant où l’isolation entre clients doit être garantie.

SGLang : RadixAttention

SGLang, développé à UC Berkeley, adopte une approche fondamentalement différente de vLLM pour le prefix caching. Au lieu du hashing par blocs, SGLang organise les préfixes dans un arbre radix (radix tree, aussi appelé trie compressé).

Comment fonctionne RadixAttention

L’arbre radix est une structure de données arborescente où chaque nœud représente un segment de tokens et stocke les vecteurs KV correspondants. La racine contient le préfixe le plus commun à toutes les requêtes. Les branches divergent là où les prompts diffèrent.

# Visualisation simplifiée de l'arbre radix dans SGLang
#
# Racine
# └── "Vous êtes un assistant..." (system prompt, 5K tokens)
#     ├── "Document A..." (contexte RAG, 20K tokens)
#     │   ├── "Question 1 ?" → Réponse 1
#     │   ├── "Question 2 ?" → Réponse 2
#     │   └── "Question 3 ?" → Réponse 3
#     └── "Document B..." (autre contexte, 15K tokens)
#         ├── "Question 4 ?" → Réponse 4
#         └── "Question 5 ?" → Réponse 5
#
# Les nœuds partagent le KV-cache de leurs ancêtres
# Question 1, 2 et 3 partagent le KV-cache du system prompt + Document A
# Question 4 et 5 partagent le KV-cache du system prompt + Document B
# Toutes les questions partagent le KV-cache du system prompt

Avantage de l’arbre radix sur le hashing : la structure arborescente capture naturellement les patterns de divergence des prompts. Dans un workflow agentique où un system prompt commun se ramifie en plusieurs branches (tool calls différents, documents différents), l’arbre radix partage automatiquement le KV-cache au point de divergence exact, sans configuration. vLLM, avec son hashing par blocs, est plus efficace pour les préfixes strictement identiques, mais moins flexible pour les patterns de ramification.

Quand choisir SGLang vs vLLM

Critère vLLM (APC) SGLang (RadixAttention)
Mécanisme Hashing par blocs (chaîné) Arbre radix (trie compressé)
Granularité Blocs de taille fixe (16 tokens typiquement) Token par token (plus précis)
Patterns de prompts Préfixes strictement identiques (batch, templates) Patterns de ramification (agents, multi-turn, RAG multi-doc)
Cas optimal Batch inference, prompts templés, préfixes prévisibles Conversations multi-tours, workflows agentiques, RAG dynamique
Throughput brut Référence (le plus testé en production) Supérieur pour le multi-turn conversationnel
Maturité Production-ready (v0.8+), large communauté En croissance rapide (v0.4+), adoption accélérée
Isolation sécurité cache_salt par requête Isolation par arbre

Recommandation : vLLM reste le choix par défaut pour la production, grâce à sa maturité et son écosystème. SGLang est préférable pour les applications conversationnelles multi-tours et les workflows agentiques complexes où les patterns de cache sont imprévisibles et ramifiés.

Prefix caching distribué

En production, l’inférence LLM tourne sur un cluster de plusieurs pods/serveurs GPU. Le prefix caching local (sur un seul pod) fonctionne bien, mais quand les requêtes sont réparties entre les pods par un load balancer, le cache de chaque pod est différent. Une requête routée vers le pod A ne bénéficie pas du cache du pod B.

Routage prefix-aware

La solution est le routage orienté cache : le scheduler (ou l’API Gateway) connaît l’état du cache de chaque pod et route les requêtes vers le pod qui a le meilleur cache hit pour le préfixe donné. C’est ce que le projet llm-d (Kubernetes-native) implémente :

1. Index de cache distribué. Chaque pod vLLM expose l’état de son KV-cache (quels préfixes sont cachés). Un composant central (kvcache.Index) agrège ces informations.

2. Score d’affinité. Quand une requête arrive, le scheduler calcule un « score d’affinité cache » pour chaque pod : quel pourcentage du préfixe de la requête est déjà caché sur ce pod.

3. Routage équilibré. Le score d’affinité est combiné avec un score de charge (éviter d’envoyer toutes les requêtes vers un pod surchargé). Le pod optimal est celui qui a le meilleur cache ET une capacité disponible.

Les benchmarks llm-d sur un cluster de 8 pods vLLM (16 H100) montrent que le routage prefix-aware augmente significativement le taux de cache hits par rapport à un round-robin classique, réduisant le TTFT moyen et le coût de compute.

Manus et le context engineering Manus (plateforme d’agents IA) a partagé des insights précieux sur l’optimisation des prompts pour maximiser le prefix caching. Leur conseil principal : retirer tout contenu dynamique ou spécifique à l’utilisateur du system prompt. Le contenu stable (instructions, règles, persona) doit être au début. Le contenu variable (données utilisateur, résultats d’outils) doit être à la fin. Cette structuration « context engineering » maximise le préfixe commun entre requêtes et donc le taux de cache hits.

Cas d’usage et gains

Workflows agentiques

Les agents IA sont le cas d’usage le plus impactant pour le prefix caching. Un agent typique enchaîne 10 à 20 appels LLM pour une seule tâche : system prompt + contexte → tool call → résultat → raisonnement → tool call → résultat → réponse finale. Le system prompt et le contexte initial (souvent > 80 % des tokens) sont identiques à chaque appel. Certains workloads agentiques ont un ratio input/output de 100:1, rendant le coût du prefill redondant disproportionné.

Le paper KVFlow (2025) montre que les politiques d’éviction LRU classiques sont sous-optimales pour les workflows agentiques. Un cache-aware scheduler qui anticipe quels préfixes seront réutilisés (basé sur la structure du workflow) atteint des speedups de 1,5 à 1,8× par rapport à SGLang avec cache hiérarchique standard.

RAG multi-documents

Un pipeline RAG qui sert un ensemble fixe de documents (documentation produit, base de connaissances) bénéficie massivement du prefix caching. Le system prompt est identique pour toutes les requêtes. Chaque document est partagé entre les questions qui le concernent. Seule la question utilisateur diffère. Avec un arbre radix (SGLang), le KV-cache du system prompt est à la racine, chaque document est un nœud intermédiaire, et chaque question est une feuille. Le partage est maximal.

Batch inference

Si vous traitez un batch de 1 000 requêtes avec le même template de prompt (classification, extraction, scoring), le prefix caching réduit le prefill total d’un facteur proportionnel au nombre de requêtes. Au lieu de 1 000 × prefill complet, vous faites 1 × prefill complet + 999 × prefill partiel (question seule).

Conversations multi-tours

À chaque nouveau message, l’historique de conversation s’allonge. Le prefix caching stocke le KV-cache des messages précédents et ne recalcule que le dernier message. Plus la conversation est longue, plus le pourcentage de tokens cachés est élevé. SGLang excelle ici grâce à l’arbre radix qui gère naturellement l’ajout de branches (chaque nouveau message est une nouvelle feuille dans l’arbre).

Gestion de la mémoire et éviction

Le prefix caching consomme de la mémoire GPU (VRAM) pour stocker les blocs cachés. Quand la VRAM est pleine, le serveur doit évincer des blocs pour faire place aux nouvelles requêtes. C’est le problème de l’éviction du cache.

LRU (Least Recently Used) est la politique par défaut dans vLLM et SGLang : les blocs les moins récemment accédés sont évincés en premier. C’est simple et fonctionne bien pour les patterns de trafic uniformes. Mais pour les workflows agentiques séquentiels (agent A → agent B → agent C → retour à agent A), le cache de l’agent A est évincé pendant que B et C s’exécutent, ce qui force un recalcul quand A est re-invoqué.

Éviction workflow-aware. KVFlow propose une politique d’éviction qui anticipe les réutilisations futures basées sur la structure connue du workflow. Les blocs qui seront réutilisés dans les prochaines étapes sont protégés de l’éviction, même s’ils n’ont pas été accédés récemment. Gains de 1,5 à 1,8× sur les workflows agentiques.

Offloading GPU → CPU. Quand la VRAM est insuffisante, les blocs KV-cache peuvent être déchargés vers la RAM CPU (via LMCache ou les intégrations natives de vLLM). La latence de récupération (10-50 ms) est inférieure au recalcul du prefill (plusieurs secondes pour un long contexte). C’est le compromis optimal quand la mémoire GPU est le goulot d’étranglement.

Guide d’implémentation

Activer le prefix caching

# vLLM - activation via CLI
python -m vllm.entrypoints.openai.api_server 
    --model meta-llama/Llama-3.1-70B-Instruct 
    --enable-prefix-caching 
    --gpu-memory-utilization 0.90 
    --tensor-parallel-size 4

# SGLang - RadixAttention est activé par défaut
python -m sglang.launch_server 
    --model-path meta-llama/Llama-3.1-70B-Instruct 
    --tp 4

# TensorRT-LLM - activation dans la config
# enable_kv_cache_reuse: true dans le fichier de configuration

Structurer les prompts pour le cache

La règle fondamentale : contenu stable au début, contenu dynamique à la fin. Le cache fonctionne sur les préfixes. Si le premier token diffère, aucun cache hit.

# Structure optimale pour maximiser le prefix caching
prompt = (
    # Bloc 1 : System prompt (identique pour TOUTES les requêtes) → caché
    "Vous êtes un assistant juridique expert en droit français. "
    "Répondez de manière précise et citez les articles de loi pertinents.nn"
    
    # Bloc 2 : Contexte / Document (identique pour un groupe de requêtes) → caché
    f"DOCUMENT DE RÉFÉRENCE :n{long_document}nn"
    
    # Bloc 3 : Historique de conversation (grandit à chaque tour) → partiellement caché
    f"HISTORIQUE :n{conversation_history}nn"
    
    # Bloc 4 : Question utilisateur (unique à chaque requête) → PAS caché
    f"QUESTION : {user_question}"
)

Erreurs courantes à éviter : injecter un timestamp ou un request ID au début du prompt (invalide tout le cache), placer les données utilisateur avant le system prompt, changer l’ordre des few-shot examples entre les requêtes (même exemples mais dans un ordre différent = préfixe différent).

Métriques à monitorer

Cache hit rate : pourcentage de tokens servis depuis le cache sur le total des tokens d’input. Visez > 60 % pour les workloads avec system prompts longs. Si le hit rate est faible, vérifiez la structure de vos prompts.

TTFT (Time To First Token) : la métrique la plus impactée par le prefix caching. Comparez le TTFT avec et sans cache pour quantifier le gain. Un gain de 50 à 85 % est typique pour les prompts avec un long préfixe caché.

Mémoire cache utilisée : pourcentage de la VRAM dédiée aux blocs de cache. Si c’est proche de 100 %, l’éviction est fréquente et le hit rate peut baisser. Augmentez gpu_memory_utilization ou ajoutez des GPU.

Bonnes pratiques

Activez le prefix caching par défaut. Il n’y a quasiment aucun inconvénient. Le surcoût mémoire est minimal (les blocs non réutilisés sont évincés), et le gain est potentiellement massif. Si vos prompts n’ont jamais de préfixe commun (cas rare), le cache reste simplement vide.

Choisissez vLLM pour les workloads batch et templates, SGLang pour le conversationnel et l’agentique. Le hashing par blocs de vLLM est optimal quand les préfixes sont strictement identiques et prévisibles. RadixAttention de SGLang est supérieur quand les prompts se ramifient de manière imprévisible (conversations, agents, multi-documents).

Implémentez le routage prefix-aware en cluster. Si vous avez plusieurs pods d’inférence, un round-robin classique gaspille le cache. Un scheduler qui connaît l’état du cache de chaque pod et route vers le pod avec le meilleur match améliore considérablement le hit rate. llm-d (projet Kubernetes-native) offre cette fonctionnalité.

Utilisez cache_salt pour l’isolation multi-tenant. Si votre serveur d’inférence sert plusieurs clients, le cache_salt de vLLM empêche les attaques par timing (déduction du contenu caché via la différence de latence hit/miss). Chaque tenant reçoit un salt unique.

Ne cachez pas ce qui change souvent. Si un document de contexte change toutes les 5 minutes, le cache est constamment invalidé. Le prefix caching est rentable quand le préfixe est stable sur de nombreuses requêtes. Pour du contenu fréquemment mis à jour, le recalcul est inévitable.


Questions fréquentes sur le prefix caching

Quelle est la différence entre prefix caching (vLLM) et prompt caching (Anthropic/OpenAI) ?

Le mécanisme technique est le même : stocker le KV-cache d’un préfixe de prompt et le réutiliser. La différence est le lieu d’exécution. Le prompt caching d’Anthropic et OpenAI est un service managé côté fournisseur. Le prefix caching est implémenté dans votre serveur d’inférence self-hosté (vLLM, SGLang, TensorRT-LLM). Avec le prefix caching local, vous avez un contrôle total (isolation, éviction, mémoire), mais vous gérez l’infrastructure. Avec le prompt caching fournisseur, c’est transparent mais vous dépendez du TTL et du hit rate du fournisseur.

RadixAttention de SGLang est-il meilleur que l’APC de vLLM ?

« Meilleur » dépend du pattern de trafic. RadixAttention excelle pour les patterns de ramification (conversations multi-tours, agents qui divergent), car l’arbre radix capture naturellement les points de divergence et partage le KV-cache au niveau exact de la bifurcation. L’APC de vLLM est plus efficace pour les préfixes strictement identiques (batch inference, prompts templés) grâce au hashing rapide par blocs. Pour les workloads agentiques et conversationnels, SGLang montre des gains significatifs. Pour le batch inference à haute concurrence, vLLM reste la référence.

Le prefix caching consomme-t-il beaucoup de mémoire GPU ?

Le prefix caching réutilise la mémoire qui serait de toute façon allouée au KV-cache. Grâce à PagedAttention, les blocs partagés entre requêtes ne sont stockés qu’une seule fois en mémoire physique (comme les pages de mémoire partagée dans un OS). Le surcoût net est donc minimal : les blocs qui ne sont plus utilisés sont évincés (policy LRU) quand la mémoire est nécessaire pour de nouvelles requêtes. Le principal risque est une mémoire saturée si le nombre de préfixes distincts est très élevé, mais ce cas est rare en pratique.

Comment fonctionne le prefix caching en cluster multi-GPU ?

En cluster, chaque pod a son propre cache local. Sans routage intelligent, les requêtes sont distribuées aléatoirement et le hit rate chute. La solution est le routage prefix-aware : un scheduler (comme llm-d) interroge l’état du cache de chaque pod et route les requêtes vers le pod avec le meilleur match préfixe, tout en équilibrant la charge. Les benchmarks montrent que ce routage augmente significativement le taux de cache hits par rapport au round-robin, avec un impact direct sur le TTFT et les coûts de compute.

Le prefix caching change-t-il la qualité des réponses du modèle ?

Non. Le prefix caching réutilise les vecteurs KV exactement identiques à ceux qui auraient été calculés sans cache. Le mécanisme d’attention produit les mêmes résultats que le KV-cache soit frais ou caché. La seule différence est la performance (latence, throughput), pas la qualité. Les réponses sont mathématiquement identiques avec et sans prefix caching.

Polydesk.ai — Footer