Polydesk-logotype
Polydesk.ai — Header

KV Cache (Cache Clé-Valeur)

Le KV cache (Key-Value cache) est un mécanisme fondamental de l’inférence des LLM qui stocke les tenseurs de clés (K) et de valeurs (V) calculés lors des étapes précédentes du décodage autorégressif, évitant de les recalculer à chaque nouveau token et réduisant la complexité temporelle de quadratique à linéaire.

KV Cache en bref
Rôle
Stocker les clés et valeurs d’attention pour éviter les recalculs
Gain
Complexité temporelle réduite de O(n²) à O(n) par token
Coût
Mémoire GPU croissante linéairement avec la longueur de séquence
Taille typique
~0,3 MB/token pour Llama 3.1 70B (BF16), ~40 GB pour 128K tokens
Optimisations
PagedAttention (vLLM), GQA, quantization FP8, offloading, compression
Problème principal
Peut dépasser la taille des poids du modèle pour les longs contextes
Impact production
Facteur limitant pour la concurrence, le context length et le coût

Pourquoi le KV cache est indispensable

Les Transformers génèrent du texte de manière autorégressive : un token à la fois. À chaque étape, le mécanisme d’attention calcule les scores entre le nouveau token (query) et tous les tokens précédents (keys et values). Sans cache, générer 1 000 tokens nécessiterait de recalculer l’attention depuis zéro 1 000 fois, avec un coût qui croît quadratiquement.

Le KV cache résout ce problème : à chaque étape de génération, on stocke les vecteurs K et V du nouveau token dans un buffer. Lors de l’étape suivante, au lieu de recalculer K et V pour toute la séquence, on ne calcule que ceux du dernier token et on concatène au cache existant. Le nouveau token fait attention à l’ensemble du cache (les K et V de tous les tokens précédents) en un seul forward pass.

Le résultat : chaque nouveau token ne nécessite qu’un seul forward pass à travers le modèle, quelle que soit la longueur de la séquence. Le coût passe de quadratique à linéaire. En contrepartie, on échange du calcul contre de la mémoire, et cette mémoire peut devenir considérable.

Entraînement vs inférence Le KV cache n’est utilisé que pendant l’inférence (génération de texte). Pendant l’entraînement, toute la séquence est traitée en parallèle et le KV cache n’a pas de raison d’être. C’est une optimisation purement liée au décodage séquentiel.

Mécanisme détaillé du KV cache

Phase de prefill (traitement du prompt)

Quand un utilisateur envoie un prompt au modèle, tous les tokens du prompt sont traités en parallèle dans un seul forward pass (c’est la phase de prefill). Durant ce pass, le modèle calcule les vecteurs K et V pour chaque token du prompt, à chaque couche d’attention. Ces vecteurs sont stockés dans le KV cache.

La phase de prefill est compute-bound : le GPU travaille à pleine capacité pour traiter tous les tokens simultanément. Le temps de cette phase correspond au TTFT (Time to First Token) ressenti par l’utilisateur.

Phase de decode (génération token par token)

Une fois le prefill terminé, la génération commence. À chaque étape, le modèle prend le dernier token généré comme entrée, calcule ses vecteurs Q, K et V, ajoute K et V au cache, puis calcule l’attention entre Q (un seul token) et tous les K/V stockés dans le cache. Cela produit le token suivant.

La phase de decode est memory-bound : le GPU passe la majorité de son temps à transférer les données (poids du modèle + KV cache) depuis la mémoire HBM vers les unités de calcul. La puissance de calcul est largement sous-utilisée. C’est ce goulot d’étranglement qui rend le décodage spéculatif si efficace : on peut vérifier plusieurs tokens pour presque le même coût qu’un seul.

Structure en mémoire

Pour chaque couche d’attention du modèle, le KV cache stocke deux tenseurs :

Cache des clés (K) : un tenseur de forme [batch_size, num_kv_heads, seq_len, head_dim] contenant les vecteurs clés de tous les tokens traités jusqu’ici.

Cache des valeurs (V) : un tenseur de même forme contenant les vecteurs valeurs correspondants.

Pour un modèle à L couches, il y a donc 2L tenseurs de cache (un K et un V par couche). Chaque couche stocke des représentations indépendantes de l’historique de la séquence.

Calcul de la mémoire du KV cache

Formule de base

La mémoire consommée par le KV cache se calcule avec la formule suivante :

Mémoire KV cache = 2 × L × H_kv × D × S × B × bytes_per_element Où : 2 = facteur pour K et V L = nombre de couches (layers) H_kv = nombre de têtes KV (KV heads, souvent < query heads si GQA) D = dimension par tête (head_dim) S = longueur de séquence (tokens) B = taille du batch bytes = 2 pour BF16/FP16, 1 pour FP8/INT8, 0.5 pour INT4

Exemples concrets

Modèle Couches KV Heads Head Dim KV / token (BF16) KV pour 8K tokens KV pour 128K tokens
Llama 3.1 8B 32 8 128 ~0,13 MB ~1,1 GB ~17 GB
Llama 3.1 70B 80 8 128 ~0,31 MB ~2,6 GB ~40 GB
Llama 3.1 405B 126 8 128 ~0,49 MB ~4,0 GB ~63 GB
Mistral Large 3 ~88* 8* 128* ~0,34 MB* ~2,8 GB* ~44 GB*

* Valeurs estimées, l’architecture exacte de Mistral Large 3 n’étant pas entièrement documentée.

Le « crossover point » : quand le cache dépasse les poids Pour Llama 3.1 7B, le KV cache dépasse la taille des poids du modèle (~13 GB en FP16) à environ 26 700 tokens. Pour les modèles plus gros avec GQA (peu de KV heads), ce point est repoussé. Mais avec un batch de 32 requêtes sur Llama 3.1 70B à 8K tokens, le cache total atteint ~83 GB, soit bien plus que les ~140 GB de poids en FP16. C’est la mémoire du KV cache, pas celle des poids, qui limite la concurrence en production.

Impact du Grouped-Query Attention (GQA)

La plupart des LLM modernes utilisent le Grouped-Query Attention (GQA) pour réduire drastiquement la taille du KV cache. Au lieu de maintenir autant de têtes KV que de têtes de queries, GQA partage chaque tête KV entre plusieurs têtes de queries.

Par exemple, Llama 3.1 70B utilise 64 têtes de queries mais seulement 8 têtes KV. Le cache est donc 8x plus petit que si le modèle utilisait le Multi-Head Attention classique (64 têtes KV). Sans GQA, le cache de Llama 3.1 70B à 128K tokens occuperait ~320 GB au lieu de ~40 GB.

Le KV cache : le goulot d’étranglement de l’inférence

Fragmentation mémoire

Avant l’introduction de PagedAttention, les systèmes d’inférence allouaient des blocs de mémoire contigus pour chaque requête, dimensionnés pour la longueur de séquence maximale possible. Si le modèle supporte 8K tokens mais qu’une requête n’en utilise que 200, 97,5% de la mémoire allouée est gaspillée. Les systèmes classiques gaspillent ainsi 60 à 80% de la mémoire KV cache par fragmentation et sur-allocation.

Limite de concurrence

La mémoire GPU restante après le chargement des poids du modèle détermine combien de requêtes simultanées peuvent être servies. Sur un A100 40 GB avec Llama 2 7B (~14 GB de poids en FP16), il reste environ 24 GB pour le KV cache, soit une capacité totale d’environ 20 000 tokens (prompts inclus). Cela ne permet pas de servir beaucoup de requêtes longues simultanément.

Contrainte sur le long contexte

Les fenêtres de contexte des LLM modernes atteignent 128K à 1M de tokens. Mais exploiter un contexte de 128K tokens sur Llama 3.1 70B nécessite ~40 GB de KV cache pour une seule requête. Avec 4 requêtes simultanées à cette longueur, il faut 160 GB rien que pour le cache, plus les ~140 GB de poids du modèle. On dépasse les capacités d’un seul GPU H100 (80 GB) et même d’un H200 (141 GB).

PagedAttention : la révolution de la gestion mémoire

PagedAttention, introduit par vLLM en 2023, est l’innovation qui a transformé l’économie de l’inférence LLM. Inspirée de la mémoire virtuelle des systèmes d’exploitation, cette technique découpe le KV cache en pages (blocs de taille fixe) qui peuvent être allouées n’importe où dans la mémoire GPU, de manière non contiguë.

Principe de fonctionnement

Au lieu d’allouer un bloc de mémoire continu pour la longueur maximale de séquence, PagedAttention divise le cache en blocs fixes (typiquement 16 tokens par bloc). Une table de blocs (similaire à une table de pages OS) maintient le mapping entre les positions logiques de tokens et les emplacements physiques en mémoire GPU.

Les blocs sont alloués à la demande, au fur et à mesure que la séquence grandit. Quand une séquence se termine, ses blocs sont immédiatement libérés et disponibles pour d’autres requêtes. Le gaspillage est limité au dernier bloc partiellement rempli de chaque séquence.

Résultat concret : le gaspillage mémoire passe de 60-80% à moins de 4%. Pour un modèle 7B en FP16 sur un H100 80 GB, cela peut faire la différence entre servir 30 requêtes simultanées et 100+.

Partage de mémoire (memory sharing)

PagedAttention permet aussi le partage de blocs entre requêtes. Quand plusieurs requêtes partagent un même préfixe (system prompt, few-shot examples), les blocs KV de ce préfixe sont partagés physiquement via un mécanisme de copy-on-write. Si une requête diverge, seuls les blocs modifiés sont copiés.

L’Automatic Prefix Caching (APC) de vLLM automatise ce partage : il détecte les préfixes communs entre requêtes et réutilise les blocs KV existants au lieu de recalculer l’attention. Pour les workloads avec un system prompt identique (chatbots, agents), l’APC réduit significativement le TTFT en évitant le prefill redondant. Des taux de cache hit de 87%+ sont atteignables avec des prompts bien structurés.

Adoption

PagedAttention est désormais intégré dans tous les frameworks d’inférence majeurs : vLLM (natif), SGLang, TensorRT-LLM, et Hugging Face TGI. C’est devenu un prérequis de base pour tout déploiement LLM en production.

Techniques d’optimisation du KV cache

La recherche sur l’optimisation du KV cache est extrêmement active. Les techniques se répartissent en trois niveaux : optimisations au niveau des tokens, au niveau du modèle, et au niveau système.

Optimisations au niveau des tokens

Sélection de cache (éviction). Toutes les entrées du cache ne sont pas aussi importantes. Certaines techniques identifient et suppriment les entrées les moins pertinentes. StreamingLLM (Xiao et al., 2024) a montré que les premiers tokens d’une séquence (« attention sinks ») concentrent une proportion disproportionnée d’attention et doivent être conservés, tandis que les tokens intermédiaires peuvent souvent être supprimés sans perte significative de qualité.

Allocation de budget par couche. La technique de caching guidé par l’entropie (NeurIPS 2025, NVIDIA) mesure l’entropie des poids d’attention dans chaque couche. Les couches à haute entropie (attention dispersée) reçoivent plus de budget cache, tandis que les couches à faible entropie (type « sink ») en reçoivent moins. Cette allocation adaptative améliore le throughput de 26,5% par rapport à une allocation uniforme.

Compression sémantique (ChunkKV). Au lieu de compresser token par token, ChunkKV (NeurIPS 2025, NVIDIA) traite des chunks sémantiques comme unités de compression, préservant les structures linguistiques complètes. La compression atteint des gains de performance jusqu’à 8,7% par rapport aux méthodes état de l’art au même ratio de compression.

Quantization du cache. Réduire la précision des tenseurs KV de BF16 (2 bytes) à FP8 (1 byte) ou INT4 (0,5 byte) divise la mémoire par 2 ou 4. Sur les GPU Hopper et Blackwell, vLLM supporte nativement le KV cache en FP8 via un simple paramètre de configuration. La dégradation de qualité est généralement négligeable pour FP8, mais devient mesurable en INT4.

Fusion et merging. Les entrées KV similaires ou redondantes peuvent être fusionnées pour réduire la taille du cache sans perdre d’information significative.

Optimisations au niveau du modèle

Grouped-Query Attention (GQA). La réduction architecturale la plus impactante. GQA réduit le nombre de têtes KV, diminuant proportionnellement la taille du cache. C’est intégré dans l’architecture du modèle pendant le pré-entraînement.

Multi-Query Attention (MQA). Version extrême de GQA où toutes les têtes de queries partagent une seule tête KV. Minimise la taille du cache mais peut légèrement dégrader la qualité.

Sliding Window Attention. Utilisé par les modèles Mistral, cette technique limite chaque couche d’attention à une fenêtre glissante de taille fixe (par exemple 4 096 tokens). Le cache ne grandit que jusqu’à la taille de la fenêtre, offrant une empreinte mémoire constante quelle que soit la longueur de séquence.

Architectures non-Transformer. Les architectures alternatives comme Mamba (SSM) et RWKV éliminent complètement le KV cache en utilisant des mécanismes de mémoire récurrents. La taille de leur état est constante par rapport à la longueur de séquence.

Optimisations au niveau système

PagedAttention (détaillé ci-dessus) : gestion paginée de la mémoire, allocation à la demande, partage de blocs.

Offloading hiérarchique. Le cache peut être déchargé du GPU (HBM) vers la RAM CPU, ou même vers des SSD rapides, quand il n’est pas activement utilisé. LMCache, un moteur d’extension pour vLLM, implémente un stockage hiérarchique (GPU HBM → CPU DRAM → SSD local) avec rechargement à la demande. Le projet llm-d (IBM, Google, Red Hat) va plus loin avec un routage de requêtes tenant compte du cache (KV cache-aware routing), dirigeant les requêtes vers les pods qui contiennent déjà le contexte pertinent en mémoire GPU, atteignant des taux de cache hit de 87% et un TTFT 88% plus rapide.

KV cache global distribué. L’architecture ICMS (Inference Context Memory Storage) de NVIDIA, combinée aux DPU BlueField-4, vise à transformer le KV cache en ressource partagée à l’échelle du cluster. Au lieu de limiter le cache à la mémoire d’un seul GPU, le cache devient accessible à tous les GPU du data center via un réseau haute performance. Pure Storage propose déjà un produit commercial (Pure KVA) dans cette direction.

KV cache-aware routing (Google GKE, llm-d). Au niveau de l’orchestration, les requêtes sont routées intelligemment vers les instances qui ont déjà en cache le préfixe pertinent. Google Cloud et Red Hat ont démontré des gains significatifs avec cette approche sur Kubernetes.

KV cache et décodage spéculatif

Le KV cache joue un rôle central dans le décodage spéculatif. Quand un draft model propose K tokens candidats, le modèle cible les vérifie en un seul forward pass. Les tokens acceptés voient leur KV cache conservé dans le cache du modèle cible. Les tokens rejetés voient le cache tronqué au point de divergence.

Les méthodes self-speculative comme LayerSkip tirent un avantage spécifique du KV cache : les couches superficielles (utilisées pour le drafting) et les couches profondes (utilisées pour la vérification) partagent le même KV cache pour les couches communes, évitant toute duplication. C’est un avantage mémoire significatif par rapport au décodage spéculatif classique à deux modèles, qui nécessite deux KV caches séparés.

KV cache en production : guide pratique

Dimensionnement mémoire

Pour planifier votre déploiement, calculez la mémoire totale nécessaire :

Mémoire totale = Poids modèle + KV cache max + Activations + Overhead framework Exemple : Llama 3.1 70B sur H100 80 GB Poids (FP16) : ~140 GB → nécessite 2x H100 en tensor parallel KV cache (8K, batch 8, BF16) : 8 × 2,6 GB = ~21 GB Activations + overhead : ~5-10 GB Total : ~166-171 GB → tient dans 2x H100 (160 GB) avec FP8 KV cache

Configuration vLLM recommandée

from vllm import LLM, SamplingParams llm = LLM( model="meta-llama/Llama-3.1-70B-Instruct", tensor_parallel_size=4, gpu_memory_utilization=0.90, # 90% du GPU pour le modèle + cache max_model_len=32768, # Limite le context length max kv_cache_dtype="fp8", # Réduit le cache de 50% sur Hopper/Blackwell enable_prefix_caching=True, # Active l'APC pour system prompts partagés )

Métriques à surveiller

vLLM expose des métriques Prometheus essentielles pour le monitoring du KV cache en production :

kv_cache_usage_percent : pourcentage du cache alloué en cours d’utilisation. Au-dessus de 90%, il faut augmenter la capacité ou réduire le batch size. prefix_cache_hit_rate : efficacité du prefix caching. En dessous de 50%, revoir la configuration des prompts. kv_cache_total_blocks / kv_cache_used_blocks : blocs totaux vs utilisés, pour comprendre la fragmentation résiduelle.

Recherche active et futur du KV cache

Le KV cache est l’un des sujets de recherche les plus actifs en inférence LLM. Plusieurs directions prometteuses se dessinent :

Élimination complète. Les architectures à état constant comme Mamba, RWKV, et les SSM hybrides (DeepSeek V3 utilise la Multi-head Latent Attention) visent à remplacer l’attention classique par des mécanismes dont la mémoire ne croît pas avec la longueur de séquence.

KV cache recyclable. Des travaux récents explorent la réutilisation de caches calculés pour un prompt sur des prompts similaires (token recycling), évitant le recalcul complet quand le nouveau prompt est un préfixe ou une variante du précédent.

Compression au niveau des chunks sémantiques. ChunkKV et les méthodes apparentées traitent des groupes de tokens ayant une cohérence sémantique comme unités de compression, préservant le sens mieux que la compression token par token.

Infrastructure de cache globale. NVIDIA (ICMS), Google Cloud (GKE + LMCache), IBM/Red Hat (llm-d), et Pure Storage construisent des systèmes où le KV cache est une ressource partagée à l’échelle du cluster, pas confiné à un seul GPU. Cela représente un changement de paradigme : le cache passe de mémoire jetable à ressource persistante et distribuée.


Questions fréquentes sur le KV cache

Le KV cache est-il utilisé pendant l’entraînement ?

Non. Le KV cache est une optimisation exclusivement liée à l’inférence (la génération de texte). Pendant l’entraînement, toute la séquence est traitée en parallèle dans un seul forward pass, et le modèle n’a pas besoin de stocker les clés et valeurs intermédiaires pour une utilisation ultérieure. La mémoire pendant l’entraînement est dominée par les activations (pour la backpropagation), les gradients et les états de l’optimiseur, pas par un KV cache.

Combien de mémoire GPU le KV cache consomme-t-il ?

Cela dépend du modèle, de la longueur de séquence et du batch size. Pour Llama 3.1 70B en BF16, chaque token consomme environ 0,31 MB de KV cache. À 8K tokens de contexte, cela fait ~2,6 GB par requête. Avec un batch de 32 requêtes, le cache total atteint ~83 GB, ce qui dépasse les poids du modèle. C’est le facteur limitant principal pour la concurrence en production. La quantization en FP8 divise ces chiffres par deux.

Qu’est-ce que PagedAttention et pourquoi est-ce important ?

PagedAttention est une technique de gestion mémoire inspirée de la mémoire virtuelle des systèmes d’exploitation. Au lieu d’allouer un bloc contigu de mémoire pour la longueur maximale de séquence (gaspillant 60 à 80% de la mémoire), PagedAttention découpe le KV cache en petits blocs (pages) alloués à la demande. Cela réduit le gaspillage à moins de 4%, permettant de servir 2 à 4x plus de requêtes simultanées avec le même GPU. PagedAttention est intégré dans vLLM, SGLang, et TensorRT-LLM.

Comment réduire la taille du KV cache ?

Plusieurs techniques se combinent. Au niveau architectural : utiliser des modèles avec GQA (la plupart des LLM récents) ou Sliding Window Attention. Au niveau inférence : activer la quantization FP8 du cache (divise par 2 sur Hopper/Blackwell), utiliser PagedAttention avec prefix caching (réduit les recalculs pour les préfixes partagés), et considérer l’éviction intelligente de tokens peu importants (StreamingLLM, entropie-guidée). Au niveau système : offloader les caches inactifs vers la RAM CPU via LMCache.

Le KV cache est-il la même chose que le prompt caching proposé par les fournisseurs d’API ?

Pas exactement, mais c’est lié. Le KV cache est le mécanisme interne du Transformer qui stocke les clés et valeurs d’attention pour chaque requête. Le « prompt caching » proposé par des fournisseurs comme Anthropic, OpenAI ou Google est une fonctionnalité de leur infrastructure de serving qui réutilise le KV cache calculé pour un préfixe de prompt entre des requêtes successives, évitant de refaire le prefill. C’est l’équivalent de l’Automatic Prefix Caching de vLLM, mais géré côté fournisseur avec une facturation réduite (typiquement 50 à 90% moins cher que l’input standard).

Polydesk.ai — Footer