BLOG
PagedAttention de vLLM : comment la gestion de la VRAM soutient l'inférence des grands modèles
Démontage technique : analyse des frameworks d’IA — explication, analyse, évaluation technique, jugement de valeur et mise en œuvre. Auteur : Yongliang
En 2023, l’inférence des grands modèles souffrait d’un problème reconnu : la VRAM du GPU semblait suffisante sur papier, mais en pratique, la taille des batch (lots) restait faible. La cause n’était pas les poids du modèle — ceux-ci sont statiques, on sait dès le premier calcul combien ils occupent — mais le cache KV : il gonfle au fur et à mesure que la conversation s’allonge, et sa taille diffère pour chaque requête. Le Sky Computing Lab de l’UC Berkeley a proposé cette année-là une réponse qui serait citée maintes fois par la suite : transposer la pagination de la mémoire virtuelle des systèmes d’exploitation dans le calcul de l’attention. C’est ainsi qu’est né PagedAttention, ainsi que le moteur de service qui se cache derrière, vLLM.
Plus de deux ans plus tard, vLLM est passé du statut d’article SOSP à celui de standard de fait pour les services d’inférence : en septembre 2026, il compte environ 92 000 étoiles sur GitHub, 415 000 téléchargements hebdomadaires sur PyPI et plus de 2000 contributeurs. Cet article décompose, comme d’habitude, six aspects : ce que c’est, le mécanisme central jusqu’à la couche source, l’évaluation des données, comment choisir par rapport à SGLang, s’il vaut la peine d’être utilisé, comment le déployer, et — si vous souhaitez écrire votre propre système de gestion de mémoire similaire — quelle est l’approche minimale.
I. Qu’est-ce que c’est
Positionnement en une phrase : vLLM est un moteur d’inférence et de service pour LLM à haut débit et efficace en mémoire (description originale du dépôt GitHub). Il résout le problème central — le cache KV occupe la majeure partie de la mémoire d’inférence ; une gestion grossière entraîne du gaspillage, ce qui réduit la taille du batch, et la taille du batch détermine directement le débit.
Faits clés : le dépôt a été créé en février 2023, initialement par le Sky Computing Lab de l’UC Berkeley ; l’article « Efficient Memory Management for Large Language Model Serving with PagedAttention » a été publié à la conférence de pointe SOSP 2023, numéro arXiv 2309.06180, avec neuf auteurs dont des pointures du domaine des systèmes distribués comme Ion Stoica et Joseph Gonzalez ; licence Apache-2.0 ; environ 91 598 étoiles et 22 113 forks. Le README indique qu’il est « maintenu par une communauté composée de dizaines d’institutions académiques et d’entreprises ». La liste des contributeurs, classée par nombre de commits, montre que les 100 premiers développeurs ont totalisé plus de 12 000 commits — le nombre élevé d’étoiles n’est pas artificiel, c’est une vraie équipe qui investit sur le long terme.
II. Mécanismes centraux
2.1 Calculons d’abord : combien de VRAM le cache KV consomme-t-il exactement
PagedAttention n’est pas une idée sortie de nulle part, c’est d’abord le résultat d’un calcul précis. Ce calcul vaut encore la peine d’être retenu par quiconque fait de l’inférence aujourd’hui :
Octets de cache KV par token = 2 × nombre de couches × nombre de têtes KV × dimension de la tête × octets par paramètre (multiplié par 2 car il y a K et V).
Prenons la configuration officielle de Qwen2.5-72B (Hugging Face config.json) : 80 couches, architecture GQA avec 8 têtes KV, dimension de tête 128, précision fp16 soit deux octets — chaque token occupe 327 680 octets, soit environ 0,31 Mo. Une requête avec un contexte de 8k tokens nécessite à elle seule 2,5 Go de cache KV ; avec cent requêtes simultanées, cela fait 250 Go. Ici, la GQA rend un grand service : 64 têtes d’attention partagent 8 têtes KV. Si l’on gardait l’ancienne architecture multi-têtes, ce chiffre serait multiplié par huit.
Ce calcul explique pourquoi les trois types de gaspillage mentionnés dans l’article sont fatals. La réservation : les anciens systèmes allouaient une fois pour toutes une mémoire VRAM continue pour chaque requête en fonction d’une longueur maximale estimée, laissant la plupart des emplacements vides. La fragmentation interne : la longueur réelle n’atteint pas la longueur estimée, la fin est gâchée. La fragmentation externe : la mémoire est découpée en trous de tailles variées, incapables de former un grand bloc continu — les anciens systèmes exigeaient une mémoire continue, c’est un piège qu’ils se sont creusé eux-mêmes. La conclusion expérimentale de l’article est la suivante : dans les anciens systèmes, le taux d’utilisation effective du cache KV peut descendre à environ 20 %, soit 80 % de la mémoire occupée inutilement. Or, le serving est un scenario limité par la mémoire ; le fait d’occuper inutilement se traduit directement par une incapacité à augmenter le batch et donc le débit.
2.2 PagedAttention : les trois composants de l’idée de pagination de l’OS
L’idée de PagedAttention est d’une simplicité déconcertante : les systèmes d’exploitation gèrent la mémoire virtuelle en découpant l’espace d’adresses continu vu par le processus en pages de taille fixe, et s’appuient sur une table de pages pour les mapper vers la mémoire physique — pourquoi ne pas gérer le cache KV de la même manière ?
Dans la mise en œuvre, cela se traduit par un trio. Premièrement, la pagination : le cache KV n’est plus réservé comme un espace continu pour chaque requête, mais découpé en blocs de taille fixe (dans les expériences de l’article, souvent 16 tokens par bloc), et un bloc n’est alloué que lorsque nécessaire. Deuxièmement, la table des blocs (block table) : chaque requête maintient une table de mappage des numéros de blocs logiques vers les numéros de blocs physiques ; le noyau d’attention utilise cette table pour rassembler (gather) les blocs physiques correspondants, sans exiger qu’ils soient continus. Cette étape est la clé de tout l’article — l’hypothèse de « continuité » est précisément la source de la fragmentation externe, et la table des blocs l’élimine totalement. Troisièmement, l’allocation à la demande : on ne demande un nouveau bloc que lorsque le précédent est rempli de gauche à droite ; le gaspillage par requête est comprimé dans un seul bloc, proche du zéro déchet (selon les termes de l’article).
2.3 Copy-on-write : comptage de références pour les blocs partagés
La pagination apporte aussi un bénéfice imprévu : le partage. L’échantillonnage parallèle (générer n candidats à partir du même prompt), les multiples chemins du beam search — le cache KV du préfixe est identique — les anciens systèmes soit stockaient plusieurs copies, soit comptaient sur une logique spéciale pour forcer le partage. L’approche de vLLM est identique à celle des systèmes d’exploitation : on incrémente le compteur de références du bloc partagé ; si quelqu’un doit écrire et que le compteur de références est supérieur à un, on copie d’abord puis on écrit (copy-on-write). Le résultat est que le cache KV du préfixe peut être réutilisé à l’intérieur et entre les requêtes. L’article cite cela comme la deuxième contribution majeure de PagedAttention : outre le « near-zero waste », on ajoute le « flexible sharing ».
2.4 Niveau source : pool de blocs et chaîne de hachage de V1
En 2025, vLLM a terminé la réécriture du moteur V1, et aujourd’hui toute la logique d’ordonnancement se trouve dans le répertoire vllm/v1, l’ancien code du moteur ayant été supprimé. Le point d’entrée de la gestion des blocs est BlockPool dans vllm/v1/core/block_pool.py, qui gère deux structures :
La première est la file d’attente des blocs libres free_block_queue — une liste doublement chaînée, triée par « plus récemment utilisé ». Les blocs qui ont été réutilisés sont renvoyés à la fin de la file lors de leur libération, les nouvelles allocations prennent au début de la file ; si le bloc au début contient encore du contenu de cache de préfixe, il est d’abord évicté du cache avant d’être alloué. L’éviction LRU ne nécessite aucune structure de données supplémentaire, l’ordre de la file est lui-même l’ordre d’éviction. La deuxième est le mappage de hachage vers bloc cached_block_hash_to_block, qui supporte la recherche dans le cache de préfixe.
Le hachage d’un bloc n’est pas un simple « hachage du contenu du bloc », mais chaîné. Dans kv_cache_utils.py, la fonction hash_block_tokens ressemble à ceci : sha256(hachage du bloc parent, séquence de tokens du bloc, clé supplémentaire). Le hachage du parent sert de sel — si le contenu du préfixe diffère d’un seul token, les hachages de toute la chaîne suivante seront différents, et différents préfixes ne peuvent pas produire la même clé ; la fonction elle-même possède un cache LRU, donc le même contenu de bloc n’est pas recalculé. Lorsqu’une nouvelle requête arrive, get_computed_blocks dans kv_cache_manager.py prend son prompt et compare bloc par bloc cette chaîne de hachage ; les blocs qui correspondent voient leur compteur de références incrémenté et sont repris directement, et la partie correspondante du prefill est entièrement sautée.
Il y a un détail dans le code source qui mérite d’être mentionné : même si chaque bloc du prompt atteint le cache, le dernier token doit être recalculé — car pour obtenir les logits, il faut calculer en temps réel (commentaire original du code source : When all tokens hit the cache, we must recompute the last token to obtain logits). Ce petit design de « recalculer une étape même en cas de succès total » garantit que le succès du cache ne modifie pas la sémantique de la sortie.
2.5 Ordonnanceur : une boucle qui gère le prefill, le decode et la préemption
Le point d’entrée de l’ordonnancement se trouve dans vllm/v1/core/sched/scheduler.py. En haut de ce fichier, il y a un commentaire de l’auteur Woosuk qui vaut la peine d’être lu en entier : dans l’ordonnanceur, il n’y a pas de distinction entre « phase de decode » et « phase de prefill ». Chaque requête ne maintient que deux nombres — num_computed_tokens (nombre de tokens déjà calculés) et num_tokens_with_spec (position jusqu’à laquelle calculer, égal à la longueur du prompt plus la longueur générée plus les tokens spéculatifs). Ce que fait l’ordonnanceur à chaque étape, c’est allouer un budget de tokens à chaque requête pour aider le premier à rattraper le second.
L’avantage de cette abstraction est que trois scénarios sont gérés par la même boucle unifiée : les longs prompts découpés et mélangés dans le batch (chunked prefill, une longue requête ne affame pas un groupe de decode) ; les requêtes qui atteignent le cache de préfixe continuent directement à partir de la position intermédiaire ; pour le décodage spéculatif, calculer quelques tokens candidats supplémentaires revient simplement à ajouter un segment à num_tokens_with_spec. Le budget total de chaque étape est plafonné par max_num_scheduled_tokens.
Lorsque la mémoire est insuffisante, le moyen utilisé est la préemption : _preempt_request retire les requêtes en fin de file d’attente running vers la file waiting, libérant tous leurs blocs et leur cache d’encodeur. Dans V1, la préemption ne connaît qu’une seule forme : le recalcul (recompute) — la requête retirée, lorsqu’elle sera à nouveau son tour, recommencera le prefill depuis le début, sans faire de swap (échange) vers la mémoire CPU. C’est un compromis évident : le recalcul gaspille de la puissance de calcul, mais le swap est simple à réaliser et évite la gigue due au transfert du cache KV entre le CPU et le GPU. Dans un vrai système en production, le nombre de préemptions est un indicateur à surveiller — des préemptions fréquentes indiquent un problème de configuration de capacité ou de paramètres d’ordonnancement.
V1 réalise également deux niveaux de chevauchement : le traitement de la sortie (detokenize, envoi en flux continu) avec le calcul GPU ; en mode d’ordonnancement asynchrone, la préparation de la décision d’ordonnancement pour l’étape suivante chevauche le calcul de l’étape actuelle. L’ordonnanceur est en pur Python, ce genre de chevauchement est son repas gratuit.
2.6 De la table des blocs au GPU : noyaux, backend et multiprocessus
La table des blocs doit finalement devenir quelque chose sur le GPU : à chaque étape d’ordonnancement, la block_table est transmise sous forme de tenseur au noyau d’attention. Pour le decode, vLLM utilise ses propres noyaux d’attention paginée écrits à la main en CUDA/CUTLASS dans csrc/attention, qui rassemblent les blocs physiques selon la table ; pour le prefill, la forme de l’attention est différente (calculer tout le prompt en une seule fois), il n’emprunte pas ce chemin et se connecte directement aux backends existants comme FlashAttention ou FlashInfer. Au-dessus des deux se trouve la couche d’abstraction AttentionBackend ; NVIDIA, AMD, CPU, TPU implémentent chacun leur propre backend, les détails des noyaux étant invisibles pour l’ordonnanceur.
La forme de l’étape de decode est hautement régulière (chaque requête ajoute exactement un token à chaque étape), V1 capture l’étape entière de decode avec un CUDA Graph, éliminant les frais de lancement entre Python et CUDA ; les scénarios où prefill et decode sont mélangés s’appuient sur la compilation par morceaux (piecewise compilation) pour laisser les parties changeantes de forme à l’extérieur du graph. Cette étape est complémentaire à la pagination : précisément parce que chaque requête augmente ou diminue sa mémoire par blocs, le fait que quelqu’un parte ou reste dans le batch n’affecte pas la disposition mémoire des autres, et le calcul entier peut être capturé de manière stable en graph.
Enfin, l’ossature multiprocessus : le processus API server reçoit les requêtes HTTP, effectue le tokenize et le chargement multimodal, et communique via ZMQ avec le engine core (topologie many-to-many avec plusieurs API server pour plusieurs engine core) ; le processus engine core prend les décisions d’ordonnancement ; les processus GPU worker, un par carte, en nombre égal à DP×PP×TP, ne sont responsables que de l’exécution forward ; si le parallélisme de données est activé, il y a aussi un coordinateur DP pour l’équilibrage de charge. Le déploiement standard sur une seule machine à 4 cartes en parallélisme tensoriel est : 1 API server + 1 engine core + 4 workers, soit 6 processus au total.
III. Évaluation technique : 2-4 fois est la métrique de l’article, regardons contre qui elle se compare
Les données de l’article : à latence égale, le débit de vLLM est 2 à 4 fois supérieur aux systèmes les plus performants de l’époque, FasterTransformer et Orca ; plus la séquence est longue, plus le modèle est grand, plus l’algorithme de décodage est complexe, plus l’avantage est évident (citation de l’article). Notez la base de comparaison — c’est une comparaison de 2023, Orca était déjà le système d’ordonnancement par itérations le plus avancé de l’époque, et vLLM l’a emporté grâce à la gestion de la mémoire, pas aux opérateurs.
Mon interprétation se fait sur deux niveaux. Le premier niveau, la mesure de l’article selon laquelle « l’utilisation effective de la mémoire des anciens systèmes peut descendre à environ 20 % », est plus fondamentale que le 2-4× — elle explique pourquoi l’amélioration fonctionne : en réduisant le gaspillage de 80 % à moins d’un bloc, la même carte peut accueillir plusieurs fois plus de requêtes, et le débit double naturellement. Cette causalité est solide. Le deuxième niveau, placé dans le référentiel de 2026, le 2-4× ne peut plus être recopié tel quel comme slogan ; les adversaires d’aujourd’hui sont SGLang, TensorRT-LLM, et l’écart s’est réduit à quelques dizaines de pour cent, liées à la charge de travail.
La popularité se lit en trois chiffres : environ 92 000 étoiles ; les 100 premiers contributeurs totalisent plus de 12 000 commits ; environ 415 000 téléchargements hebdomadaires sur PyPI. Ces trois chiffres s’imbriquent, la scale de l’utilisation réelle ne fait aucun doute — c’est l’infrastructure numéro un dans le domaine des services d’inférence.
Il faut aussi tempérer l’enthousiasme. Les benchmarks sont ceux de l’article, pour sa propre reproduction, il faut regarder sa propre distribution de longueur de requêtes et son modèle de concurrence ; le cache de préfixe offre un bénéfice limité pour les scénarios de requêtes courtes et de prompts très diversifiés, occupant la mémoire inutilement ; l’architecture multiprocessus de V1 a une surcharge CPU pour les petits modèles sur une seule carte, et la documentation officielle recommande elle-même de configurer les ressources CPU en fonction du nombre de GPU.
IV. Comparaison avec SGLang, comment choisir
Portrait de SGLang en une phrase : framework de service haute performance issu de LMSYS, créé en janvier 2024, environ 36 000 étoiles, Apache-2.0, la différenciation centrale est RadixAttention — qui organise le cache de préfixe en un arbre radix (base) plutôt qu’en table de hachage, revendication officielle de « jusqu’à 5 fois d’accélération de l’inférence » (blog officiel de janvier 2024, données auto-évaluées), très adopté cette dernière année dans les workflows d’agents et les frameworks d’entraînement RL (verl, slime, etc.).
Trois phrases pour le choix : sans raison explicite, choisissez vLLM par défaut — l’écosystème, la documentation, l’adaptation matérielle (support de premier plan pour NVIDIA/AMD/Intel/CPU, plugin pour TPU/Gaudi/Ascend/Apple Silicon) sont les plus complets, et le coût de recherche pour éviter les pièges est le plus bas ; si votre charge de travail consiste en appels agents multi-tours, des sorties structurées complexes, ou doit être intégrée dans une boucle d’entraînement RL, il vaut la peine d’inclure SGLang dans les tests de charge comparatifs, ses optimisations agressives ont des avantages prouvés dans ces scénarios ; les deux sont sous licence Apache-2.0, le coût de migration n’est pas élevé, laissez votre propre trafic décider.
En termes de philosophie, les deux ont la même origine : le partage de préfixes de RadixAttention et PagedAttention est la même idée avec deux structures de données différentes (arbre radix vs table de hachage de blocs), et le projet SGLang lui-même réutilise largement l’infrastructure de vLLM. Ce n’est pas une compétition à somme nulle, c’est toute l’industrie qui converge vers le consensus que « le cache KV est une ressource réutilisable ».
V. Jugement de valeur
Vrai problème : le coût de l’inférence égale l’efficacité de la mémoire multipliée par la taille du batch. vLLM a fait passer le cache KV du « système de réservation » au « système de pagination », et à mes yeux, c’est l’amélioration individuelle la plus importante de la pile d’inférence depuis 2023 — elle ne change pas le modèle, ne change pas la puce, et se contente, grâce au logiciel système, d’extraire plusieurs fois le débit du même matériel. Aujourd’hui, presque tous les frameworks d’inférence open source utilisent son idée de gestion par blocs, ce qui est en soi une preuve de valeur.
Les limites sont aussi claires. Faire tourner un petit modèle sur une seule machine avec une concurrence à un chiffre, les bénéfices de la pagination et du traitement par lots continu sont limités, une solution simple peut être plus rassurante ; cela ne résout pas la latence du premier token — le goulot d’étranglement de calcul du prefill dépend des noyaux et des stratégies de parallélisation, c’est un autre champ de bataille ; le support pour les architectures non standard (modèles à espace d’état comme Mamba) vient tout juste de voir la couche HybridKVCacheCoordinator apparaître dans V1, c’est encore en évolution. Quand l’utiliser : dans tout scénario où l’on fournit sérieusement un service LLM à l’extérieur, c’est le point de départ par défaut. Quand ne pas l’utiliser : pour un traitement hors ligne ponctuel de quelques données, ou pour l’utiliser dans l’entraînement — c’est le territoire d’autres outils.
VI. Comment déployer
L’installation se fait en une ligne :
uv pip install vllm # ou pip install vllm
Lancer le service externe se fait aussi en une ligne, vllm serve démarre une interface compatible OpenAI (supporte également l’API Messages d’Anthropic et gRPC) :
vllm serve Qwen/Qwen3-32B --tensor-parallel-size 2
Pour l’inférence hors ligne par lots, on utilise la classe Python LLM, quelques lignes suffisent pour obtenir un résultat ; supporte plus de 200 architectures de modèles — decoder-only, MoE, attention mixte/espace d’état, multimodal, embedding, modèles de récompense, tous peuvent être servis, et couvre l’échantillonnage parallèle, le beam search, la sortie structurée (xgrammar/guidance), l’analyse des appels d’outils, le multi LoRA. Côté distribué, cinq types de parallélisme sont configurables : tensoriel, pipeline, données, expert, contexte. Deux conseils de déploiement : le cache de préfixe (prefix caching) doit être activé ou désactivé en fonction des caractéristiques du trafic, activé pour les charges de travail de type dialogue multi-tours, désactivé pour les charges de requêtes courtes et très diversifiées ; en environnement de production, intégrez le taux d’utilisation du cache KV et le nombre de préemptions dans la surveillance, ces deux indicateurs révèlent les problèmes de capacité plus tôt que l’utilisation du GPU.
VII. Comment construire soi-même une solution similaire
« Écrire sa propre solution » n’est pas un exercice hypothétique. Le dépôt GitHub nano-vllm (GeeeekExplorer/nano-vllm, open source en juin 2025, MIT, environ 15 000 étoiles) est une réplique minimale lisible écrite par la communauté après avoir lu le code source de vLLM, le moteur entier fait quelques milliers de lignes — il prouve une chose : l’idée centrale de PagedAttention tient en une page. Le squelette en six étapes :
- Pool de blocs et table des blocs : au démarrage, découpez la mémoire VRAM du cache KV en un pool de blocs physiques de taille fixe ; chaque requête maintient une table de blocs logiques vers blocs physiques, l’attention fait un gather selon la table.
# Squelette minimal : pool de blocs
free_blocks = deque(range(num_gpu_blocks)) # File d'attente de blocs physiques libres
block_table = {} # req_id -> [numéro de bloc physique]
-
Allocation à la demande : après chaque étape de decode, vérifiez si le bloc actuel est plein, et ne prenez un nouveau bloc dans la file d’attente libre que s’il est plein — le gaspillage ne dépasse naturellement pas un bloc.
-
Comptage de références et copy-on-write : incrémentez le refcount des blocs partagés ; avant d’écrire, si refcount est supérieur à un, copiez d’abord puis écrivez. Le partage pour l’échantillonnage parallèle et le beam search repose là-dessus.
-
Boucle d’ordonnancement qui ne poursuit que deux nombres : chaque requête note
num_computedetnum_total; à chaque étape, choisissez les requêtes dans le budget de tokens, pour que computed rattrape total ; qui a fini quitte, si ça ne tient pas, on préempte par priorité (retirer la requête, libérer les blocs, recommencer le prefill depuis le début plus tard). Le chunked prefill, le cache de préfixe, le décodage spéculatif, ne sont que des cas particuliers de cette boucle. -
Cache de hachage de préfixe : construisez un hachage chaîné avec
sha256(hachage du bloc parent + tokens du bloc), comparez bloc par bloc, en cas de succès sautez le prefill, le début de la file d’attente libre est le candidat à l’éviction. -
N’écrivez pas les noyaux vous-même : pour l’attention, connectez-vous directement à FlashAttention, laissez CUDA/CUTLASS pour quand vous aurez une vraie équipe de performance. C’est ce que fait nano-vllm.
Ces six étapes additionnées font quelques centaines de lignes de Python plus des noyaux existants, et ça marche — l’intuition centrale de l’article PagedAttention n’a jamais été complexe, la difficulté est de la maintenir au niveau production pendant deux ans. C’est aussi pourquoi le code source de vLLM vaut la peine d’être lu plus que l’article : l’idée architecturale se tient en une page, c’est la finition d’ingénierie qui fait le fossé protecteur.
Conclusion
La contribution de PagedAttention peut se résumer en une phrase : le cache KV n’est pas « un tableau continu par requête », mais « une ressource mise en pool, allouée à la demande et partagée par blocs ». vLLM a résolu un nouveau problème de l’inférence des grands modèles avec une vieille méthode des systèmes d’exploitation, et est devenu un standard de fait grâce à cela. Pour la plupart des équipes, le choix ne nécessite pas d’hésitation — vLLM par défaut, et si vous avez une charge spéciale, faites un test comparatif avec SGLang ; pour les ingénieurs qui veulent faire des systèmes d’inférence, son code source est un meilleur manuel que l’article.
Références
- Dépôt GitHub vLLM (README, documentation d’architecture) : https://github.com/vllm-project/vllm
- Article : Efficient Memory Management for Large Language Model Serving with PagedAttention, SOSP 2023, arXiv:2309.06180 (résumé, §2 analyse du gaspillage, §6 évaluation)
- Documentation officielle de l’architecture vLLM Architecture Overview (docs.vllm.ai, architecture multiprocessus V1 et index du code source)
- Code source vLLM V1 : vllm/v1/core/block_pool.py (pool de blocs et file d’attente libre), vllm/v1/core/kv_cache_utils.py (hachage chaîné hash_block_tokens), vllm/v1/core/kv_cache_manager.py (succès du préfixe get_computed_blocks), vllm/v1/core/sched/scheduler.py (boucle principale d’ordonnancement et préemption _preempt_request), csrc/attention (noyaux CUDA/CUTLASS paged attention)
- Configuration du modèle Qwen2.5-72B (Hugging Face config.json : 80 couches / GQA 8 têtes KV / dimension tête 128, base de calcul de la mémoire du cache KV)
- Métadonnées du dépôt GitHub et liste des contributeurs, pypistats.org téléchargements vllm (septembre 2026)
- Réplique minimale nano-vllm (GitHub: GeeeekExplorer/nano-vllm, MIT) : https://github.com/GeeeekExplorer/nano-vllm
- Documentation secondaire de lecture du code source (pour référence croisée) : série « Analyse du code source Nano-vLLM » sur le blogue du Jardin (Blog Garden), série « KV Cache et Paged Attention de nano-vllm » sur Juejin, série « Notes d’étude du moteur d’inférence vLLM » sur CSDN (partie Architecture V1 et Prefix Caching)
- Dépôt GitHub SGLang (README et métadonnées) : https://github.com/sgl-project/sglang ; blog LMSYS 2024-01-17 (position officielle sur RadixAttention)