Article

vLLM : comprendre les notions essentielles avant de servir un LLM

Comprendre vLLM : du prompt au KV cache, PagedAttention et continuous batching

TL;DR

vLLM est un moteur d'inférence et de serving pour les grands modèles de langage. Il ne sert pas à entraîner le modèle : il charge ses poids, reçoit des requêtes et produit des tokens. Son intérêt vient notamment de sa gestion efficace du KV cache, de PagedAttention et du continuous batching.

Le modèle mental minimal tient en quelques étapes :

texte utilisateur
  -> tokenizer
  -> identifiants de tokens
  -> tenseurs
  -> modèle
  -> prédiction d'un token
  -> ajout du token au contexte
  -> nouvelle prédiction
  -> réponse finale

Pendant le prefill, le moteur traite le prompt et construit le KV cache. Pendant le decode, il génère les tokens un par un en réutilisant ce cache. PagedAttention organise le KV cache en blocs, à la manière de la mémoire virtuelle d'un système d'exploitation. Le scheduler peut alors faire entrer et sortir des séquences d'un batch entre les tours de calcul afin de mieux occuper le GPU.

La vidéo de référence

La vidéo vLLM – 03. Notions & Définitions est le troisième épisode de la série. Elle adopte volontairement une approche de vulgarisation : apprendre d'abord le vocabulaire, puis revenir plus en profondeur sur chaque notion dans les épisodes suivants.

Son fil conducteur est utile pour débuter : partir du prompt et suivre les transformations jusqu'à la réponse. La vidéo insiste ensuite sur les liens entre QKV, KV cache, prefill, decode, PagedAttention, scheduler et continuous batching. Elle élargit enfin le panorama au routage, au parallélisme, à la quantification, au décodage spéculatif, aux sorties structurées et aux adaptateurs LoRA.

Le support écrit de référence est le fichier 03-notions-definitions/slides.md. Les slides fournissent les schémas, les tableaux et les définitions synthétiques sur lesquels s'appuie cet article.

vLLM, c'est quoi exactement ?

vLLM est une bibliothèque open source destinée à l'inférence et au serving de modèles de langage. La documentation officielle le présente comme un moteur capable d'exécuter des modèles et de les exposer notamment derrière une API compatible avec le format OpenAI.

Trois éléments doivent être distingués :

Élément Rôle
Modèle Réseau de neurones utilisé pour calculer le prochain token
Poids ou paramètres Valeurs apprises pendant l'entraînement et chargées en mémoire pour l'inférence
Moteur d'inférence Logiciel qui exécute le modèle, planifie les requêtes et gère les ressources

Une image de conteneur ne devient pas un processus toute seule. De la même façon, un fichier de poids reste inerte tant qu'un moteur ne le charge pas et ne l'exécute pas. vLLM joue ce rôle de moteur. Il ne réentraîne pas automatiquement le modèle et ne modifie pas ses connaissances lors de chaque requête.

Du prompt à la réponse : le modèle mental minimal

Le tokenizer transforme le texte en tokens

Un LLM ne travaille pas directement avec des phrases. Le tokenizer découpe le texte en unités appelées tokens, puis associe chaque token à un identifiant numérique. Un token peut représenter un mot, une partie de mot, un signe de ponctuation ou un autre fragment défini par le vocabulaire du modèle.

texte       : "Hello world"
tokens      : ["Hello", " world"]
identifiants: [15496, 995]

Cet exemple illustre le principe, mais le découpage et les identifiants réels dépendent du tokenizer. Il faut utiliser le tokenizer et le chat template attendus par le modèle servi. Deux modèles peuvent découper une même phrase différemment.

Les tenseurs portent les calculs

Les identifiants sont regroupés dans des tenseurs, c'est-à-dire des tableaux multidimensionnels de nombres. Le modèle transforme notamment chaque identifiant en une représentation vectorielle, puis applique une succession d'opérations matricielles.

Le GPU est adapté à cette charge parce qu'il peut exécuter de nombreuses opérations numériques en parallèle. Cela ne signifie pas que toute étape d'une application LLM doit nécessairement tourner sur GPU, mais les calculs principaux d'un grand modèle y sont généralement bien plus efficaces.

L'inférence est autorégressive

Pour un modèle de génération de texte classique, la réponse n'est pas calculée d'un seul bloc. Le modèle prédit le prochain token, l'ajoute au contexte, puis recommence :

prompt                         -> token D
prompt + D                     -> token E
prompt + D + E                 -> token F
prompt + D + E + F             -> ...

Cette boucle explique plusieurs métriques importantes :

Métrique Question posée
Time to First Token, ou TTFT Combien de temps avant le premier token ?
Inter-Token Latency, ou ITL Quel délai entre deux tokens générés ?
Débit en tokens par seconde Combien de tokens le système produit-il par unité de temps ?
Latence totale Combien de temps avant la fin de la réponse ?

Le streaming affiche les tokens au fur et à mesure. Il améliore la perception de réactivité, sans changer le principe autorégressif de la génération.

QKV et attention : la base du KV cache

Dans un mécanisme d'attention, les représentations des tokens sont projetées en trois familles de tenseurs : Query, Key et Value.

Une intuition simple consiste à les lire ainsi :

Terme Intuition
Query, Q Ce que la représentation courante cherche
Key, K Ce avec quoi elle peut être comparée
Value, V L'information à agréger selon le résultat de la comparaison

Le calcul compare une query aux keys pertinentes, transforme ces scores en poids d'attention, puis combine les values correspondantes. Cette formulation est volontairement simplifiée, mais elle permet de comprendre pourquoi les tenseurs K et V déjà calculés peuvent être réutilisés pendant la génération.

La query du nouveau token sert au calcul courant. Les keys et values des tokens précédents restent nécessaires aux étapes suivantes. C'est précisément ce que conserve le KV cache.

Découvrez  Headroom : compresser le contexte des agents IA avant l appel au LLM

Prefill et decode : deux phases très différentes

Le serving d'un LLM se décompose en deux phases principales.

Le prefill traite le prompt

Pendant le prefill, le moteur traite les tokens du prompt et construit les tenseurs Key et Value qui alimentent le KV cache.

prompt : [A] [B] [C]

KV cache après prefill :
  A -> key_A, value_A
  B -> key_B, value_B
  C -> key_C, value_C

Cette phase traite plusieurs tokens du prompt et mobilise fortement les unités de calcul du GPU. Plus le prompt est long, plus le travail initial et le délai avant le premier token peuvent augmenter.

Le decode génère la réponse

Pendant le decode, le moteur produit généralement un nouveau token par séquence et par itération. Il relit le KV cache existant, calcule le token suivant, puis ajoute les nouveaux K et V au cache.

decode 1 : réutiliser KV(A, B, C)    -> générer D
decode 2 : réutiliser KV(A, B, C, D) -> générer E

Le decode effectue moins de travail parallèle par séquence, mais lit fréquemment les poids et le KV cache. Il est donc souvent décrit comme davantage limité par la bande passante mémoire que le prefill.

Phase Entrée principale Résultat Profil simplifié
Prefill Tous les tokens du prompt KV cache initial et premier calcul de sortie Davantage orienté calcul
Decode Contexte mis en cache et dernier token Un token supplémentaire Davantage orienté mémoire

Cette distinction est essentielle pour interpréter les performances. Optimiser uniquement le nombre moyen de tokens par seconde peut masquer un mauvais TTFT sur les prompts longs ou une mauvaise ITL pendant la génération.

KV cache : éviter les recalculs inutiles

Sans KV cache, le moteur devrait recalculer les keys et values des tokens précédents à chaque nouveau token. Avec le cache, il les calcule une fois et les réutilise :

sans KV cache : recalculer encore les anciens tokens
avec KV cache : relire les anciens K/V et calculer seulement la suite

Le gain de calcul a un coût : le KV cache occupe de la mémoire, souvent de la VRAM lorsque l'inférence s'exécute sur GPU. Sa taille augmente avec plusieurs dimensions du workload, notamment :

  • le nombre de séquences actives ;
  • la longueur du contexte de chaque séquence ;
  • le nombre de couches et de têtes KV du modèle ;
  • la taille des têtes ;
  • le type numérique utilisé pour le cache.

Il ne suffit donc pas de vérifier que les poids tiennent dans la VRAM. Il faut aussi réserver de la place au KV cache, aux buffers d'exécution et aux autres allocations du moteur. Le calcul rapide « nombre de paramètres multiplié par octets par poids » n'est qu'une estimation des poids, pas de toute la mémoire nécessaire au serving.

Prefix caching : réutiliser un début de prompt

Le KV cache d'une requête évite les recalculs pendant son propre decode. Le prefix caching va plus loin : il permet de réutiliser des blocs déjà calculés lorsque plusieurs requêtes partagent exactement un même préfixe tokenisé.

Les cas typiques cités dans les slides et la vidéo sont :

  • un long prompt système commun à tous les utilisateurs ;
  • des règles ou politiques d'entreprise répétées ;
  • un document RAG injecté dans plusieurs requêtes ;
  • une partie stable d'un historique de conversation ;
  • des instructions applicatives identiques.
préfixe commun : système + règles + document

requête 1      : préfixe commun + question A
requête 2      : préfixe commun + question B
requête 3      : préfixe commun + question C

Cette technique est surtout intéressante lorsque le préfixe est suffisamment long, strictement identique au niveau des tokens et réellement réutilisé. Elle ne doit pas être confondue avec un cache de réponse : le moteur réutilise des calculs intermédiaires, pas nécessairement la réponse finale.

PagedAttention : organiser le KV cache en blocs

Le KV cache pose un problème d'allocation. Les séquences n'ont pas toutes la même longueur, ne commencent pas au même moment et ne se terminent pas ensemble. Réserver à chacune une grande zone mémoire continue peut créer de la fragmentation et gaspiller de la VRAM.

PagedAttention applique une idée proche de la mémoire virtuelle : la vue logique d'une séquence est continue, tandis que ses blocs physiques peuvent être dispersés.

KV logique de la requête A : A0 -> A1 -> A2 -> A3

blocs physiques GPU :
  slot 0 : C0
  slot 1 : A2
  slot 2 : libre
  slot 3 : B0
  slot 4 : A0
  slot 5 : A3
  slot 6 : A1

block table de A :
  A0 -> slot 4
  A1 -> slot 6
  A2 -> slot 1
  A3 -> slot 5

Lorsqu'une séquence grandit, le moteur peut lui attribuer un nouveau bloc libre sans déplacer tout son cache. Lorsqu'elle se termine, ses blocs redeviennent disponibles.

Mémoire virtuelle PagedAttention
Espace logique d'un processus KV cache logique d'une requête
Page virtuelle Bloc KV logique
Cadre de page physique Bloc KV physique en mémoire GPU
Table de pages Block table

Cette analogie aide à comprendre l'abstraction, mais PagedAttention reste un mécanisme spécialisé pour les tenseurs K/V et les kernels d'attention. La documentation de conception de PagedAttention précise d'ailleurs que son document décrit historiquement le kernel issu du travail original et ne reflète pas tous les détails du code actuel.

Scheduler et continuous batching : garder le GPU occupé

Le scheduler décide quelles séquences seront exécutées lors du prochain tour de calcul. Il doit concilier plusieurs contraintes : requêtes en attente, séquences déjà actives, budget de tokens, espace disponible dans le KV cache et équité entre requêtes.

Le chapitre introduit ce vocabulaire :

Terme Définition pratique
Waiting Requêtes reçues mais pas encore planifiées
Running Séquences actuellement prises en charge par le moteur
Swapped Séquences dont les données ont été déplacées hors de la mémoire GPU
max-num-seqs Limite du nombre de séquences actives
max-num-batched-tokens Budget de tokens traité dans une itération
KV budget Blocs mémoire disponibles pour les séquences

Dans un batch statique, les requêtes rapides laissent des emplacements inutilisés jusqu'à ce que la plus lente termine :

tour 1 : A B C
tour 2 : A B C
tour 3 : A B -
tour 4 : A - -

Avec le continuous batching, une requête terminée peut être remplacée entre deux itérations :

tour 1 : A B C
tour 2 : A B C
tour 3 : A B D
tour 4 : A E D

Le batch reste un ensemble de travail exécuté conjointement, mais sa composition évolue. Cette planification à l'échelle des itérations est une raison majeure pour laquelle un moteur de serving spécialisé peut atteindre un meilleur débit qu'un script d'inférence conçu pour une requête isolée.

Data, tensor, pipeline et expert parallelism

Ajouter des GPU peut répondre à deux besoins différents : servir davantage de requêtes ou faire tenir et exécuter une instance de modèle plus lourde.

Technique Ce qui est réparti Cas d'usage simplifié
Data parallelism Des copies complètes du modèle servent des requêtes différentes Le modèle tient sur un GPU ou un groupe de GPU, mais le trafic augmente
Tensor parallelism Les opérations et poids d'une même couche sont découpés entre GPU Une instance de modèle nécessite plusieurs GPU fortement interconnectés
Pipeline parallelism Des groupes de couches sont placés sur différents GPU Le modèle est découpé en étapes successives
Expert parallelism Les experts d'un modèle Mixture of Experts sont distribués Le modèle contient des experts activés sélectivement
Découvrez  T3MP3ST : un framework multi-agent pour le red teaming autorise

Le tensor parallelism n'est donc pas simplement le découpage du prompt. Il répartit les calculs et les paramètres au sein des couches, puis nécessite des communications entre GPU. Le pipeline parallelism répartit plutôt la pile de couches en plusieurs étapes.

Deux règles donnent une première orientation :

Plus d'utilisateurs : ajouter des réplicas, donc scale out.
Une instance plus grande : ajouter des GPU au groupe, donc scale up.

Le choix réel dépend toutefois de la taille du modèle, du trafic, des objectifs de latence, de la mémoire et de l'interconnexion. La documentation vLLM propose un guide dédié au parallélisme et au scaling.

Quantification, décodage et LoRA : où placer les autres notions ?

La fin du chapitre présente plusieurs techniques qui seront approfondies plus tard dans la série.

Quantification

La quantification réduit la précision numérique des poids, par exemple de FP16 vers FP8 ou INT4. Pour un modèle de 7 milliards de paramètres, l'ordre de grandeur brut des seuls poids est approximativement :

Format simplifié Octets par paramètre Taille brute pour 7 milliards de paramètres
FP16 2 14 Go
FP8 1 7 Go
INT4 0,5 3,5 Go

Ces nombres ignorent les métadonnées, les buffers, le KV cache et les particularités du format. Une précision plus faible peut aussi modifier la qualité, la compatibilité et les performances. Il faut donc mesurer le modèle quantifié sur le cas d'usage plutôt que choisir uniquement la plus petite taille.

Décodage spéculatif

Le speculative decoding emploie un mécanisme de proposition moins coûteux, par exemple un petit modèle draft, pour suggérer plusieurs tokens. Le modèle principal les vérifie. L'accélération dépend notamment du coût du draft, du taux d'acceptation et du matériel ; elle n'est pas automatique.

Guided decoding et sorties structurées

Le guided decoding contraint les sorties autorisées, par exemple avec un schéma JSON, une grammaire ou une expression régulière. L'objectif est d'obtenir un format exploitable par une application plutôt qu'un texte libre qu'il faudrait parser de manière fragile.

LoRA et multi-LoRA

Un adaptateur LoRA ajoute un petit ensemble de paramètres entraînables à un modèle de base gelé. Il permet d'adapter le comportement sans réentraîner tous les poids. Le multi-LoRA consiste à servir plusieurs adaptateurs au-dessus d'un même modèle de base, selon les capacités et la configuration du moteur.

Quand utiliser vLLM et quand choisir une autre approche ?

vLLM cible principalement le serving efficace de modèles, avec gestion de requêtes concurrentes et API. Le bon choix dépend du besoin réel.

Besoin Orientation possible
Développer localement avec une expérience très simple Un outil local intégré peut suffire
Servir un modèle à plusieurs clients avec une API vLLM correspond directement à ce besoin
Contrôler le batching, le KV cache et le parallélisme Un moteur spécialisé comme vLLM devient pertinent
Exécuter principalement sur CPU ou matériel très contraint Comparer avec des runtimes conçus pour ce contexte
Ne pas exploiter d'infrastructure GPU Une API managée peut réduire l'exploitation nécessaire
Garder modèles et données dans son infrastructure Le self-hosting avec vLLM peut répondre à cette contrainte

La décision doit être guidée par les SLO : TTFT, ITL, débit, concurrence, coût par token, qualité du modèle et exigences de sécurité. Une comparaison sans benchmark représentatif donne peu d'informations utiles.

Lire les slides et démarrer la suite du tutoriel

Ce chapitre est conceptuel et n'impose pas de lancer un serveur. Le dépôt utilise mdp pour afficher les slides dans le terminal :

# macOS
brew install mdp

# Debian ou Ubuntu
sudo apt-get install mdp

# depuis la racine du dépôt
mdp 03-notions-definitions/slides.md

Le README du dépôt décrit ensuite le parcours complet. Le chapitre 04 prépare l'instance GPU chez Infomaniak, puis le chapitre 05 lance un premier modèle avec vllm serve.

Liens utiles

FAQ vLLM, KV cache et PagedAttention

vLLM entraîne-t-il les modèles ?

Non. vLLM est d'abord un moteur d'inférence et de serving. Il charge des poids déjà entraînés et exécute le modèle pour répondre aux requêtes. Un entraînement ou un fine-tuning se fait avec une chaîne d'outils distincte.

Quelle différence entre un token et un mot ?

Un token est une unité définie par le tokenizer. Il peut correspondre à un mot complet, une partie de mot, un espace, un signe ou un autre fragment. Le nombre de tokens n'est donc pas égal au nombre de mots.

À quoi sert le KV cache ?

Le KV cache conserve les tenseurs Key et Value des tokens déjà traités. Pendant le decode, le moteur les réutilise au lieu de recalculer toute l'attention sur l'historique à chaque nouveau token.

Le KV cache contient-il le texte du prompt ?

Pas sous sa forme textuelle. Il contient des tenseurs numériques dérivés des tokens par les couches d'attention. L'application peut conserver le texte par ailleurs, mais ce n'est pas ce que désigne le KV cache.

Quelle différence entre KV cache et prefix caching ?

Le KV cache accélère la suite d'une séquence en cours. Le prefix caching permet de réutiliser des blocs KV associés à un préfixe identique entre plusieurs traitements compatibles.

PagedAttention est-il un système de swap GPU ?

Non. PagedAttention organise le KV cache en blocs logiques et physiques afin de mieux utiliser la mémoire. Le déplacement de données vers la mémoire CPU ou un stockage externe est une problématique d'offloading ou de swapping distincte.

Pourquoi le continuous batching améliore-t-il le débit ?

Parce que les séquences terminées peuvent quitter le batch et être remplacées par des requêtes en attente entre les itérations. Le GPU passe ainsi moins de temps avec des emplacements inutilisés à cause de requêtes de longueurs différentes.

Quelle différence entre prefill et decode ?

Le prefill traite les tokens du prompt et construit le KV cache initial. Le decode génère ensuite les tokens un par un en réutilisant ce cache. Les deux phases n'ont pas le même profil de calcul ni les mêmes métriques de latence.

La quantification réduit-elle aussi automatiquement le KV cache ?

Pas nécessairement. La précision des poids et le type numérique du KV cache sont des réglages distincts. Un modèle peut avoir des poids quantifiés tout en utilisant un autre format pour son cache.

Faut-il utiliser tensor parallelism pour servir plus d'utilisateurs ?

Pas toujours. Si le modèle tient déjà dans un GPU ou un petit groupe de GPU, plusieurs réplicas complets peuvent être plus simples pour augmenter le débit. Le tensor parallelism sert surtout à répartir une même instance de modèle et implique des communications entre GPU.

Conclusion

Comprendre vLLM commence moins par une commande que par une chaîne de concepts. Le texte devient des tokens, les tokens deviennent des tenseurs, puis le modèle génère la réponse de manière autorégressive. Le prefill construit le contexte de calcul, le decode l'étend token par token et le KV cache évite de recommencer inutilement le travail déjà effectué.

PagedAttention rend ce cache plus simple à allouer sous forme de blocs. Le scheduler et le continuous batching organisent ensuite plusieurs séquences concurrentes pour utiliser efficacement les ressources. Quantification, prefix caching, parallélisme, speculative decoding et LoRA sont des leviers supplémentaires, mais ils prennent tout leur sens une fois ce socle compris.

La suite logique du parcours est le chapitre 04-infomaniak-cloud-setup, consacré à la préparation d'une machine GPU, avant le premier lancement réel de vllm serve au chapitre 05.

Explorer les formations Xavki

Pour apprendre dans l ordre, repartez depuis la roadmap ou une playlist thematique.