Un modèle de sept milliards de paramètres en précision 16 bits pèse quatorze gigaoctets. Posez-le sur une carte de vingt-quatre gigaoctets et faites la soustraction : il reste dix gigaoctets. Cette place restante n'est pas du confort, c'est la ressource qui détermine combien de personnes peuvent poser une question en même temps. Quand elle manque, le serveur ne tombe pas : il ralentit, met des requêtes de côté et les reprend plus tard. Personne ne voit d'erreur, tout le monde voit que « c'est lent ».
Comprendre ce partage est l'essentiel du travail sur un serveur d'inférence. Le reste tient en quelques commandes.
1. Mettre le service debout
vLLM s'installe dans un environnement Python ou se lance en conteneur. La seconde voie est préférable sur un serveur : la chaîne CUDA est figée dans l'image, ce qui évite de rejouer l'assemblage à chaque montée de version.
docker run --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
-p 8000:8000 \
vllm/vllm-openai:v0.29.0 \
--model mistralai/Mistral-7B-Instruct-v0.3 \
--max-model-len 8192
Le service expose une API au format OpenAI. Un premier appel vérifie que tout répond :
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{"model":"mistralai/Mistral-7B-Instruct-v0.3","prompt":"Bonjour","max_tokens":20}'
À ce stade, ça marche sur un poste de test. Ce n'est pas encore un service.
2. Le calcul mémoire, poste par poste
Trois choses se partagent la carte.
Les poids du modèle, d'abord. Leur taille se calcule : nombre de paramètres multiplié par les octets par paramètre. Sept milliards en 16 bits font quatorze gigaoctets, en 8 bits sept, en 4 bits trois et demi. C'est arithmétique, il n'y a pas de surprise.
Le cache d'attention, ensuite, et c'est lui le sujet. Chaque conversation en cours garde en mémoire l'état de tout ce qui a déjà été écrit. Sa taille croît avec la longueur du contexte et avec le nombre de requêtes simultanées. C'est une ressource dynamique, contrairement aux poids.
L'espace de travail, enfin : activations, tampons, graphes CUDA. Modeste, mais pas nul.
Le paramètre gpu_memory_utilization fixe la part de la carte que vLLM se réserve, et donc ce qui reste pour le cache une fois les poids chargés. Le monter donne plus de conversations simultanées. Le monter trop sur une carte qui affiche aussi un bureau graphique ou partage la machine avec autre chose provoque un échec au démarrage.
3. Les quatre paramètres qui décident du comportement
max_model_len plafonne la longueur de contexte. Le baisser réduit la consommation du cache plus vite que n'importe quel autre réglage. Servir un modèle annoncé à 128 000 jetons quand vos requêtes réelles en font 4 000 revient à réserver une salle de mille places pour douze personnes.
max_num_seqs limite le nombre de requêtes traitées de front. Le baisser libère du cache, au prix de la file d'attente.
max_num_batched_tokens fixe le nombre de jetons traités par lot. La documentation recommande de dépasser 8192 pour privilégier le débit ; une valeur basse, autour de 2048, privilégie au contraire la régularité entre deux jetons, ce qui se voit à l'écran quand la réponse s'affiche au fil de l'eau.
Le piège est dans la relation entre les deux derniers : si max_num_batched_tokens est inférieur à max_model_len, le serveur peut refuser de démarrer. L'erreur est explicite quand on sait la lire, obscure quand on découvre l'outil un vendredi soir.
vllm serve mistralai/Mistral-7B-Instruct-v0.3 \
--gpu-memory-utilization 0.90 \
--max-model-len 8192 \
--max-num-seqs 64 \
--max-num-batched-tokens 16384
4. Pourquoi les mesures naïves mentent
vLLM traite les requêtes en lot continu : une requête terminée libère sa place immédiatement et une autre entre dans le lot en cours, sans attendre la fin du groupe. C'est l'essentiel de son avantage sur une boucle d'inférence classique.
Conséquence pratique : mesurer le temps d'une requête isolée ne dit rien de la capacité du serveur. Une carte qui répond en deux secondes à une requête seule ne répondra pas en deux secondes à quarante requêtes simultanées, et le rapport entre les deux n'a rien de linéaire. La seule mesure qui compte se fait en charge, avec le profil de requêtes que vous attendez vraiment. Un outil de tir de charge comme celui décrit dans notre article sur les tests de charge avec k6 fait le travail, à condition d'envoyer des prompts de longueur réaliste et non des « Bonjour » de trois jetons.
5. Le signal à superviser : la préemption
Quand le cache est saturé, vLLM met des requêtes en cours de côté pour en faire passer d'autres, puis les reprend. Le service reste disponible, les journaux le signalent, et la latence perçue s'effondre.
C'est la métrique à remonter en priorité, avant le taux d'erreur et avant l'occupation du processeur. Un serveur d'inférence en bonne santé ne préempte pas. Un serveur qui préempte régulièrement demande soit un contexte plus court, soit moins de requêtes simultanées, soit une carte de plus, dans cet ordre de coût croissant. Les métriques sont exposées au format Prometheus et se branchent sur une chaîne de supervision classique.
6. Plusieurs cartes, et ce que ça coûte vraiment
tensor_parallel_size répartit les poids sur plusieurs GPU. Chaque carte porte une fraction du modèle, ce qui libère de la place pour le cache sur chacune. C'est la réponse quand le modèle ne tient pas, ou quand le contexte visé ne rentre pas.
Ce n'est pas gratuit : les cartes discutent entre elles à chaque jeton produit. Sur un serveur où elles partagent un lien direct, le surcoût est faible. Sur des cartes reliées uniquement par le bus PCIe, il se voit. Deux cartes ne donnent jamais deux fois le débit d'une seule.
La question du passage de la carte à une machine virtuelle se pose avant tout le reste, et nous l'avons traitée pour Proxmox et le passthrough GPU. Sur un parc mutualisé, le partage de cartes entre charges change encore le calcul.
7. La quantification, arbitrage et pas remède
Passer les poids en 8 ou 4 bits divise leur empreinte d'autant, et libère la place correspondante pour le cache. Sur une carte trop juste, c'est souvent ce qui fait la différence entre un service utilisable et un service qui préempte en permanence.
La contrepartie existe et se mesure : la qualité des réponses baisse, faiblement sur des tâches de classement ou d'extraction, davantage sur du raisonnement ou de la rédaction longue. Le seul protocole honnête consiste à constituer un jeu d'une cinquantaine de cas représentatifs de votre usage réel et à comparer les sorties avant et après. Sans ce jeu, l'arbitrage se fait au doigt mouillé et se découvre en production.
8. Ce qui casse à la montée de version
Le projet avance vite. La version 0.29.0, publiée le 9 septembre 2026, compte cinq cent quatre-vingt-quatorze commits de deux cent soixante-dix-sept contributeurs. Elle supprime dix architectures de modèles dépréciées, retire un décodeur vidéo et marque l'ancien moteur d'exécution comme déprécié, avec une suppression annoncée pour une version ultérieure.
Un tel rythme impose trois règles. On épingle une version précise, jamais une étiquette flottante. On lit les notes de version avant de monter, en cherchant le nom de son propre modèle dans la liste des suppressions. Et on rejoue le jeu de cas représentatifs après chaque montée, parce qu'un changement de moteur d'exécution ne modifie pas seulement les performances.
Le projet est sous licence Apache 2.0, sans zone propriétaire, ce qui simplifie la vie de quiconque veut le déployer pour un tiers.
9. En service
Quelques points qui ne relèvent d'aucune option de ligne de commande.
Le téléchargement du modèle doit être fait une fois pour toutes et stocké sur un volume persistant. Un serveur qui retélécharge quatorze gigaoctets à chaque redémarrage ajoute plusieurs minutes à chaque incident, au pire moment.
Le service ne s'expose pas directement. Il ne porte ni authentification sérieuse ni quota par utilisateur : ces fonctions appartiennent à la couche du dessus, par exemple une passerelle qui gère les clés et les budgets.
Le démarrage est lent, quelques dizaines de secondes à plusieurs minutes selon la taille du modèle et le profilage des graphes CUDA. La sonde de disponibilité doit en tenir compte, faute de quoi l'orchestrateur tue le conteneur avant qu'il ait fini de se lever, en boucle.
Sources
- Dépôt GitHub vllm-project/vllm, licence Apache 2.0, 92 338 étoiles au 21 septembre 2026
- Notes de version v0.29.0, publiée le 9 septembre 2026, architectures supprimées et moteur V1 déprécié
- Documentation d'optimisation vLLM, paramètres mémoire, débit et causes de saturation
- Documentation officielle du projet, installation, service et API compatible OpenAI


