Un pipeline Transformers standard sans moteur de serving spécialisé traite souvent les requêtes de manière peu optimisée. Votre GPU est utilisé à une fraction de sa capacité. À 100 utilisateurs simultanés, vous saturez. vLLM résout ce problème avec PagedAttention et le continuous batching : des milliers de tokens/s sur H100, serveur OpenAI-compatible en une commande, prefix caching activable en un flag. Ce guide couvre l'architecture interne, le code Python complet et le déploiement en production — basé sur la version v0.20.0 sortie le 27 avril 2026.
Modèle mental : vLLM est à l'inférence LLM ce qu'un OS est à la gestion mémoire. PagedAttention emprunte directement la pagination virtuelle des systèmes d'exploitation — blocs de 16 tokens, table de correspondance logique→physique, éviction LRU — pour éliminer la fragmentation du KV-cache. Résultat : la mémoire GPU gaspillée passe de 60-80% à moins de 4%.
vLLM Python 2026 : servir des LLMs en production — PagedAttention, V1 Engine et benchmarks
À qui s'adresse cet article ?
- Vous savez appeler un LLM en Python (HuggingFace, OpenAI SDK, Ollama) et voulez passer en production
- Vous devez servir 10+ utilisateurs simultanés avec un GPU et optimiser le coût d'inférence
- Vous avez suivi notre guide FastAPI streaming LLM et cherchez le moteur d'inférence qui va derrière
TL;DR
- PagedAttention = blocs KV de 16 tokens, <4% VRAM gaspillée (vs 60-80% naïf)
- V1 Engine (défaut depuis v0.8) = 1.7× throughput, scheduler unifié préfill/decode
- Une commande :
vllm serve Qwen/Qwen2.5-7B-Instruct→ API OpenAI-compatible - Prefix caching via
--enable-prefix-caching, hash SHA-256, <1% overhead à 0% hit rate - Quantization : FP8 (~50% VRAM) / AWQ 4 bits / GGUF — sans ré-entraîner
- Multi-LoRA : servir N adaptateurs sur une seule instance GPU
- v0.20.0 (avril 2026) : CUDA 13.0, PyTorch 2.11, Python 3.14, Transformers v5, DeepSeek V4
1. Le problème de l'inférence LLM naïve
Un LLM autorégressif génère les tokens un par un. À chaque étape, il recalcule — ou met en cache — les key-value (KV) tensors pour tous les tokens du contexte. Sur un modèle de 7B paramètres avec un contexte de 2048 tokens, le KV-cache d'une seule requête peut occuper plusieurs Go de VRAM.
Le problème du pipeline HuggingFace standard : chaque requête réserve un bloc contigu de VRAM de taille maximale, dès le début. Si vous fixez max_new_tokens=2048, la VRAM est réservée pour 2048 tokens — même si la réponse fait 50 tokens. Résultat : 60 à 80% de VRAM gaspillée en fragmentation, et une seule requête traitée à la fois.
Le continuous batching (ou iteration-level scheduling) est la première réponse : au lieu de traiter un batch fixe de requêtes jusqu'à complétion, on interleave les tokens générés de plusieurs requêtes dans un seul appel GPU. Mais sans gestion mémoire intelligente du KV-cache, les requêtes de longueurs différentes continuent de fragmenter la VRAM. C'est là qu'intervient PagedAttention.
2. PagedAttention — l'OS paging appliqué au KV-cache
PagedAttention a été introduit par Woosuk Kwon et al. (SOSP 2023, UC Berkeley) comme solution à la fragmentation du KV-cache. L'idée centrale est empruntée directement aux OS : la pagination de la mémoire virtuelle.
Structure des blocs
Au lieu d'allouer un bloc contigu par requête, PagedAttention découpe le KV-cache en blocs de taille fixe (par défaut 16 tokens). Chaque bloc stocke les clés et valeurs pour exactement block_size tokens à une tête d'attention :
- Key cache shape :
[num_blocks, num_kv_heads, head_size/x, block_size, x] - Value cache shape :
[num_blocks, num_kv_heads, head_size, block_size] - Exemple : block_size=16, head_size=128 → 2 048 éléments par bloc
Table de correspondance logique → physique
Chaque requête possède une block table qui mappe les positions logiques des tokens aux blocs physiques en VRAM. Les blocs peuvent être alloués n'importe où dans la mémoire, comme les pages d'un OS. Un bloc n'est alloué qu'au moment où il est nécessaire (demand paging) : si une réponse fait 50 tokens, seuls 4 blocs de 16 tokens sont alloués (et non 2048/16 = 128 blocs comme dans le cas naïf).
Deux requêtes qui partagent un préfixe identique peuvent référencer les mêmes blocs physiques (copy-on-write), ce qui est la base du prefix caching.
3. V1 Engine — la refonte architecturale de 2025
Annoncé en janvier 2025 et activé par défaut depuis vLLM v0.8.0, le V1 Engine est une réécriture complète du cœur de vLLM basée sur 18 mois de retour d'expérience en production. Il conserve les modèles GPU, kernels et utilitaires de V0, mais repense l'architecture d'exécution.
Architecture multiprocessing isolée
V1 sépare un EngineCore dédié au scheduler et à l'exécuteur modèle, dans un processus isolé. Le processus principal gère la tokenisation, le traitement des images multimodales et la dé-tokenisation — des opérations CPU-intensives. Cette séparation permet d'overlapper CPU et GPU : pendant que le GPU génère les tokens du batch courant, le CPU prépare le batch suivant.
Scheduler unifié prefill/decode
V0 distinguait deux phases séparées : prefill (calcul du KV-cache pour le prompt) et decode (génération token par token). V1 traite tous les tokens uniformément. La décision d'ordonnancement est représentée comme un simple dictionnaire {"request_id": num_tokens}. Cela permet le chunked prefill (fractionner un long prompt en plusieurs passes) et le speculative decoding dans un framework unifié.
Persistent Batch et NumPy
V1 implémente la technique Persistent Batch : les tenseurs d'entrée GPU sont cachés et mis à jour incrémentalement (seuls les "diffs" sont retransmis entre étapes). La préparation des inputs repose sur NumPy plutôt que sur des opérations Python pures, réduisant drastiquement l'overhead CPU entre les passes.
Gain mesuré : jusqu'à 1.7× de throughput sur Llama 3.1 8B et 70B par rapport à V0 (source : vLLM Blog, janvier 2025). Sur les modèles vision (Qwen2-VL), le gain est encore plus élevé grâce au preprocessing multimodal optimisé.
4. Installation
Prérequis : GPU NVIDIA Ampere+ (A100, A10, H100, RTX 3090/4090), Python 3.10+. La wheel PyPI officielle v0.20.0 embarque CUDA 13.0 + PyTorch 2.11 par défaut. Si vous êtes sur CUDA 12.9, utilisez uv pip install vllm --torch-backend=cu129.
# Avec uv (recommandé — résolution rapide)
uv pip install vllm
# Ou pip classique
pip install vllm
# Vérifier la version installée
python -c "import vllm; print(vllm.__version__)"
# 0.20.0
vllm[rocm]. Sur CPU uniquement, vllm[cpu] — les performances seront 10-100× inférieures et ne conviennent pas à la production.
5. Inférence offline : classe LLM et SamplingParams
La classe LLM est l'interface synchrone pour le batch processing offline — évaluation de datasets, preprocessing, benchmarks. Elle n'est pas adaptée à un serveur web (pas de concurrence) mais est parfaite pour les scripts.
from vllm import LLM, SamplingParams
# Chargement du modèle (téléchargement auto depuis HuggingFace)
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct")
# Paramètres d'échantillonnage
params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=512,
stop=["</s>", "[INST]"],
)
prompts = [
"Explique PagedAttention en une phrase.",
"Quel est l'avantage du continuous batching ?",
"Donne un exemple de cas d'usage vLLM en production.",
]
outputs = llm.generate(prompts, params)
for output in outputs:
prompt = output.prompt
generated = output.outputs[0].text
tokens_gen = len(output.outputs[0].token_ids)
print(f"[{tokens_gen} tokens] {generated}")
SamplingParams — paramètres clés
| Paramètre | Valeur par défaut | Usage |
|---|---|---|
temperature |
1.0 | 0 = déterministe, 0.7 = créatif équilibré |
top_p |
1.0 | Nucleus sampling, 0.9 = filtre les tokens rares |
max_tokens |
16 | Longueur max de la réponse générée |
n |
1 | Nombre de séquences à générer par prompt |
stop |
[] | Tokens/chaînes qui stoppent la génération |
seed |
None | Reproductibilité (temperature=0 suffit souvent) |
6. Serveur OpenAI-compatible
C'est le mode de déploiement le plus courant en production. Une seule commande lance un serveur HTTP qui expose /v1/completions et /v1/chat/completions — compatibles avec n'importe quel client OpenAI SDK.
# Démarrer le serveur (port 8000 par défaut)
vllm serve Qwen/Qwen2.5-7B-Instruct
# Avec options avancées
vllm serve Qwen/Qwen2.5-7B-Instruct \
--host 0.0.0.0 \
--port 8000 \
--max-model-len 16384 \
--gpu-memory-utilization 0.90 \
--dtype bfloat16 \
--enable-prefix-caching
Le client Python utilise ensuite le SDK OpenAI standard en pointant vers votre serveur local :
from openai import OpenAI
client = OpenAI(
api_key="EMPTY",
base_url="http://localhost:8000/v1",
)
# Chat completion standard
response = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[
{"role": "system", "content": "Tu es un assistant IA expert."},
{"role": "user", "content": "Explique le continuous batching en 3 lignes."},
],
temperature=0.7,
max_tokens=256,
)
print(response.choices[0].message.content)
--served-model-name. Vous pouvez pointer un client Anthropic SDK vers votre serveur vLLM en passant base_url="http://localhost:8000".
7. Streaming avec AsyncLLMEngine + FastAPI
Pour un streaming token-by-token dans une application web, AsyncLLMEngine est l'interface recommandée. Elle expose une API async for compatible avec asyncio, idéale pour les StreamingResponse FastAPI.
from vllm.engine.async_llm_engine import AsyncLLMEngine
from vllm.engine.arg_utils import AsyncEngineArgs
from vllm import SamplingParams
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import uuid, json
# Initialisation du moteur asynchrone
engine_args = AsyncEngineArgs(
model="Qwen/Qwen2.5-7B-Instruct",
max_model_len=8192,
gpu_memory_utilization=0.90,
enable_prefix_caching=True,
)
engine = AsyncLLMEngine.from_engine_args(engine_args)
app = FastAPI()
@app.post("/stream")
async def stream_generate(prompt: str):
params = SamplingParams(temperature=0.7, max_tokens=512)
request_id = str(uuid.uuid4())
async def token_stream():
prev_len = 0
async for output in engine.generate(prompt, params, request_id):
new_text = output.outputs[0].text[prev_len:]
prev_len = len(output.outputs[0].text)
if new_text:
chunk = json.dumps({"text": new_text})
yield f"data: {chunk}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(token_stream(), media_type="text/event-stream")
Ce pattern SSE est directement exploitable depuis un frontend JavaScript avec EventSource ou fetch + ReadableStream. Pour une implémentation complète avec WebSocket, TTFT/TPS, et gestion de déconnexion client, voir notre guide FastAPI streaming LLM.
8. Prefix caching — réutiliser les préfixes KV
Le prefix caching évite de recalculer le KV-cache pour des préfixes déjà vus. C'est particulièrement puissant dans trois scénarios :
- System prompt partagé : si 1 000 requêtes utilisent le même system prompt de 500 tokens, ces 500 tokens ne sont calculés qu'une seule fois
- RAG avec document partagé : un document de contexte commun à plusieurs requêtes n'est inféré qu'une fois par bloc de 16 tokens
- Few-shot templates : les exemples du prompt sont mis en cache et réutilisés
Mécanisme interne
Chaque bloc de 16 tokens est haché avec un algorithme configurable (SHA-256 par défaut, xxHash pour les performances, SHA-256 CBOR pour l'interopérabilité). La clé de hash inclut les tokens du bloc et le hash du bloc parent — créant une chaîne de hash unique pour chaque position dans le contexte.
# Activer le prefix caching (déjà par défaut en V1)
vllm serve Qwen/Qwen2.5-7B-Instruct \
--enable-prefix-caching \
--prefix-caching-hash-algo sha256 # ou xxhash pour +perf
# Côté code : aucune modification nécessaire
# Le cache opère de manière transparente au niveau des blocs KV
cache_salt par session. Cela isole les blocs cachés et prévient les attaques par timing (inférence du contenu via la latence).
9. Quantization : FP8, AWQ et GGUF
La quantization permet de réduire la VRAM nécessaire sans ré-entraîner le modèle. vLLM v0.20.0 supporte plusieurs formats.
FP8 — la référence production 2026
FP8 (8-bit floating point) réduit la VRAM d'environ 50% avec moins de 1% de dégradation sur les modèles ≥13B. Sur A100 80GB, Llama 3.1 70B tient sur une seule carte (vs 2 cartes en BF16). Disponible nativement sur H100 et A100.
# Quantization FP8 dynamique (pas besoin de modèle pré-quantizé)
llm = LLM(
model="meta-llama/Meta-Llama-3.1-70B-Instruct",
quantization="fp8",
dtype="auto",
)
# Via le serveur
vllm serve meta-llama/Meta-Llama-3.1-70B-Instruct \
--quantization fp8 \
--dtype bfloat16
AWQ — 4 bits pour les modèles 7-13B
AWQ (Activation-aware Weight Quantization) quantize les poids à 4 bits en préservant les activations importantes. Idéal pour les modèles 7-13B sur des GPU de 24GB (RTX 3090/4090). Nécessite un modèle pré-quantizé AWQ (disponibles sur HuggingFace sous *-AWQ).
# Utiliser un modèle AWQ pré-quantizé
llm = LLM(
model="Qwen/Qwen2.5-7B-Instruct-AWQ",
quantization="awq",
)
# GPTQ — alternative à AWQ
llm = LLM(
model="TheBloke/Mistral-7B-Instruct-v0.3-GPTQ",
quantization="gptq",
)
| Format | Bits | Réduction VRAM | Qualité | Modèle pré-quantizé requis |
|---|---|---|---|---|
| BF16 (défaut) | 16 | — | Référence | Non |
| FP8 | 8 | ~50% | <1% dégradation | Non (quantization à la volée) |
| AWQ | 4 | ~75% | 1-3% dégradation | Oui (*-AWQ sur HF) |
| GPTQ | 4 | ~75% | 1-3% dégradation | Oui (*-GPTQ sur HF) |
| GGUF | 2-8 | variable | Dépend des bits | Oui (.gguf) |
10. Multi-LoRA serving
vLLM permet de charger plusieurs adaptateurs LoRA sur un seul modèle de base, et de les router dynamiquement par requête. C'est particulièrement utile pour servir des variantes fine-tunées (ton de marque, domaine métier, langue) sans dupliquer les poids du modèle de base.
# Démarrer avec le support multi-LoRA
vllm serve Qwen/Qwen2.5-7B-Instruct \
--enable-lora \
--max-loras 4 \
--max-lora-rank 64
# Charger les adaptateurs dynamiquement via l'API REST
# POST /v1/load_lora_adapter
# {"lora_name": "mon-adaptateur-fr", "lora_path": "/adapters/fr/"}
# Inférence offline avec LoRA sélectionné par requête
from vllm import LLM, SamplingParams
from vllm.lora.request import LoRARequest
llm = LLM(
model="Qwen/Qwen2.5-7B-Instruct",
enable_lora=True,
max_loras=4,
)
params = SamplingParams(temperature=0.7, max_tokens=256)
# Appel avec l'adaptateur "client-a"
outputs = llm.generate(
["Rédige un email de bienvenue professionnel."],
params,
lora_request=LoRARequest("client-a", 1, "/adapters/client-a"),
)
# Appel avec l'adaptateur "client-b" — même GPU, même modèle de base
outputs2 = llm.generate(
["Génère une description produit succincte."],
params,
lora_request=LoRARequest("client-b", 2, "/adapters/client-b"),
)
Les adaptateurs sont chargés en mémoire une seule fois et réutilisés. max_loras contrôle le nombre simultané en VRAM. Pour créer ces adaptateurs, voir notre guide fine-tuning LoRA/QLoRA Python.
11. Déploiement production (Docker, Kubernetes, Prometheus)
Image Docker officielle
# Image officielle vLLM (CUDA 13, PyTorch 2.11)
docker run --gpus all \
-p 8000:8000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
vllm/vllm-openai:v0.20.0 \
--model Qwen/Qwen2.5-7B-Instruct \
--dtype bfloat16 \
--enable-prefix-caching
Kubernetes — Horizontal Pod Autoscaler
# deployment.yaml (extrait)
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 2
template:
spec:
containers:
- name: vllm
image: vllm/vllm-openai:v0.20.0
args: ["--model", "Qwen/Qwen2.5-7B-Instruct", "--enable-prefix-caching"]
resources:
limits:
nvidia.com/gpu: 1
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60
readinessProbe:
httpGet:
path: /health
port: 8000
Métriques Prometheus
vLLM expose nativement des métriques Prometheus sur /metrics. Les métriques clés à surveiller en production :
vllm:e2e_request_latency_seconds— latence end-to-end par requêtevllm:time_to_first_token_seconds— TTFT, indicateur de réactivité perçuevllm:time_per_output_token_seconds— ITL (inter-token latency)vllm:gpu_cache_usage_perc— taux d'utilisation du KV-cache GPUvllm:prefix_cache_hit_rate— efficacité du prefix cachingvllm:num_requests_running— requêtes en cours de génération
11b. Continuous batching — pourquoi c'est la clé du throughput
C'est la technique qui, combinée à PagedAttention, permet à vLLM de saturer le GPU en permanence. Pour comprendre pourquoi c'est radical, comparons avec le batching statique.
Batching statique (pipeline Transformers sans moteur de serving)
Dans le batching classique, on regroupe N requêtes en un seul tenseur et on les envoie toutes ensemble au GPU. Le problème : toutes les requêtes du batch doivent attendre que la plus longue se termine. Une requête de 500 tokens bloque toutes les autres jusqu'à la fin. L'utilisation GPU ressemble à des "vagues" avec des plages creuses entre les batchs.
Continuous batching (iteration-level scheduling)
À chaque itération (génération d'un seul token), le scheduler décide quelles requêtes participent au prochain appel GPU. Dès qu'une requête se termine (EOS token ou max_tokens atteint), sa slot GPU est immédiatement libérée et une nouvelle requête en attente la remplace. Pas de "vague" : le GPU reste occupé en continu.
Visualisation simplified (4 slots GPU)
Itération Slot 1 Slot 2 Slot 3 Slot 4 ──────────────────────────────────────────────────────── t=1 Req A tok1 Req B tok1 Req C tok1 Req D tok1 t=2 Req A tok2 Req B tok2 [EOS B] Req D tok2 t=3 Req A tok3 [Req E entr] Req E tok1 Req D tok3 t=4 [EOS A] Req E tok2 [Req F entr] Req D tok4
Dès que B se termine (t=2), E entre immédiatement (t=3) — zéro idle time.
Le V1 Engine va encore plus loin avec le chunked prefill : si une requête a un très long prompt (ex. 8 000 tokens), son prefill est découpé en chunks et interleaved avec les étapes de decode des autres requêtes. Cela évite que le prefill d'une longue requête monopolise le GPU et augmente le TTFT des autres.
11c. Speculative decoding — accélérer la génération
Le speculative decoding (Chen et al., 2023) est une technique pour réduire la latence inter-token (ITL) à faible QPS. L'idée : un modèle draft léger propose K tokens en avance, le modèle cible les valide ou les rejette en un seul appel GPU. Si la plupart des propositions sont acceptées, on génère K tokens pour le coût d'un seul appel.
N-gram (méthode légère, sans modèle draft)
La méthode n-gram utilise le prompt lui-même comme source de tokens spéculatifs : elle cherche des correspondances de n tokens dans le contexte déjà généré pour proposer la suite. Aucun modèle supplémentaire requis, gains modestes (10-30% ITL) mais activation triviale.
# Speculative decoding ngram — sans modèle draft
vllm serve Qwen/Qwen2.5-7B-Instruct \
--speculative-config '{"method":"ngram","num_speculative_tokens":5,"prompt_lookup_max":5}'
# Via Python (LLM class)
llm = LLM(
model="Qwen/Qwen2.5-7B-Instruct",
speculative_config={
"method": "ngram",
"num_speculative_tokens": 5,
"prompt_lookup_max": 5,
},
)
EAGLE — la méthode la plus efficace en faible QPS
EAGLE (Efficient Adaptive Generalized LLM Engine, Li et al. 2024) utilise un modèle draft spécialisé qui prédit les features du prochain token via les hidden states du modèle cible — sans re-calculer toutes les couches. En faible concurrence (1-4 requêtes simultanées), EAGLE offre les gains ITL les plus élevés.
# EAGLE3 — nécessite un modèle eagle pré-entraîné
vllm serve meta-llama/Meta-Llama-3.1-8B-Instruct \
--speculative-config '{
"method": "eagle3",
"model": "yuhuili/EAGLE3-LLaMA3.1-Instruct-8B",
"num_speculative_tokens": 6
}'
11d. Tensor parallelism — multi-GPU pour les grands modèles
Pour les modèles qui dépassent la VRAM d'un seul GPU (ex. Llama 3.1 70B BF16 = 140 GB), vLLM supporte plusieurs stratégies de parallélisme. Le tensor parallelism (TP) est le plus courant en inférence.
Tensor Parallelism (TP)
Avec TP, chaque couche du modèle est partitionnée sur N GPU. Pour un modèle avec hidden_size=4096 et TP=2, chaque GPU contient la moitié des poids de chaque matrice d'attention et FFN. Un all-reduce NCCL synchronise les activations entre chaque couche. Optimal sur des GPU connectés par NVLink (bande passante 900 GB/s sur H100 SXM).
# Llama 3.1 70B BF16 sur 2× H100 (TP=2)
vllm serve meta-llama/Meta-Llama-3.1-70B-Instruct \
--tensor-parallel-size 2 \
--dtype bfloat16
# Llama 3.1 405B sur 8× H100 (TP=8) — modèle entier en BF16
vllm serve meta-llama/Meta-Llama-3.1-405B-Instruct \
--tensor-parallel-size 8 \
--dtype bfloat16
# Via Python
llm = LLM(
model="meta-llama/Meta-Llama-3.1-70B-Instruct",
tensor_parallel_size=2,
dtype="bfloat16",
)
Pipeline Parallelism (PP)
Le pipeline parallelism découpe le modèle en stages de couches consécutives, chaque stage sur un GPU différent. Moins d'all-reduce que TP (seulement entre stages), mais introduit des "bulles" dans le pipeline. vLLM V1 ne supporte pas encore le PP en stable — à éviter en production pour l'instant.
| Stratégie | Principe | Quand l'utiliser |
|---|---|---|
| Tensor Parallel (TP) | Poids partitionnés par couche | GPU NVLink, latence faible requise |
| Pipeline Parallel (PP) | Couches partitionnées en stages | GPU sur PCIe (pas NVLink) — expérimental V1 |
| Data Parallel | N répliques indépendantes | Scale-out horizontal via load balancer |
| Expert Parallel (EP) | Experts MoE distribués | Modèles MoE (DeepSeek, Mixtral, Gemma) |
11e. Structured outputs — JSON garanti depuis vLLM
vLLM supporte nativement la génération de sorties structurées (JSON, regex, grammaires) via le constrained decoding. Le logit processor masque les tokens incompatibles avec la structure cible à chaque étape — garantissant un JSON valide sans post-traitement.
from pydantic import BaseModel
from vllm import LLM, SamplingParams
from vllm.sampling_params import GuidedDecodingParams
import json
class Produit(BaseModel):
nom: str
prix: float
categorie: str
disponible: bool
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct")
params = SamplingParams(
temperature=0.0,
max_tokens=256,
guided_decoding=GuidedDecodingParams(
json=Produit.model_json_schema() # schéma Pydantic → JSON Schema
),
)
output = llm.generate(
["Génère une fiche produit pour un vélo électrique 750W."],
params,
)
# output garanti valide selon le schéma Produit
produit = Produit(**json.loads(output[0].outputs[0].text))
print(produit.prix) # float garanti, jamais une chaîne
StructuredOutputsParams (versions récentes) ou GuidedDecodingParams (versions antérieures) — les deux sont importables depuis vllm.sampling_params. Vérifiez avec from vllm.sampling_params import StructuredOutputsParams ; si l'import échoue, repliez-vous sur GuidedDecodingParams.
Via l'API OpenAI-compatible, l'équivalent est le paramètre response_format avec type: "json_schema" — le même que l'OpenAI Structured Outputs. Ce mode est particulièrement utile dans les pipelines d'agents où les outputs LLM sont parsés et utilisés comme données.
12. Benchmarks vLLM — ordres de grandeur et limites
Les chiffres suivants proviennent de benchmarks tiers publiés pour vLLM v0.8+ (V1 Engine actif). Source principale : morphllm.com/vllm-benchmarks. Important : les performances dépendent fortement du batch size, de la longueur de contexte, du workload et de la configuration GPU — les chiffres ci-dessous correspondent à des configurations de haute concurrence ; les résultats réels varient.
Throughput (tokens générés / seconde)
| Modèle | GPU | Throughput | Config |
|---|---|---|---|
| Llama 3.1 8B BF16 | 1× H100 80GB | ~12 500 tok/s | FlashInfer, 0.8 GPU util |
| Llama 3.1 70B FP8 | 1× H100 80GB | ~460 tok/s | Batch 64 |
| DeepSeek-R1 7B | 1× A100 80GB | 3 363 tok/s | Config par défaut |
| DeepSeek-R1 32B | 1× A100 80GB | 577 tok/s | Config par défaut |
Latence (Llama 3.1 8B, H100, faible concurrence)
- TTFT moyen : 72 ms — 79 ms (P99)
- ITL médian : ~11 ms/token
- V1 vs V0 : 1.7× de throughput sur les mêmes modèles
13. vLLM vs SGLang vs TGI — quand choisir quoi
En 2026, trois moteurs dominent l'inférence LLM open-source en production. Le choix dépend du cas d'usage, du matériel et des modèles cibles. Benchmarks SGLang vs vLLM : particula.tech, 2026 — résultats mesurés sur Llama 3.1 8B H100, haute concurrence.
| Critère | vLLM | SGLang | TGI (HuggingFace) |
|---|---|---|---|
| Throughput Llama 8B H100 (benchmark tiers) | Jusqu'à ~12 500 tok/s | Jusqu'à ~16 200 tok/s | Variable selon modèle/config |
| Cache cross-requêtes | Per-requête (V1) | Radix tree (cross-req) | Non |
| Support matériel | NVIDIA, AMD, TPU, Gaudi, CPU | NVIDIA principalement | NVIDIA, AMD |
| DeepSeek V3 | Supporté | 3.1× plus rapide (MLA) | Supporté |
| Encoder-decoder (T5, BART) | Oui | Non | Oui |
| Contributeurs GitHub | 2 000+ | ~650 | ~400 |
Règle de décision : DeepSeek ou pipelines multi-turn intensifs avec documents partagés → SGLang. Diversité de modèles, matériel non-NVIDIA, encoder-decoder, ou besoin d'une communauté large → vLLM. Prototype rapide sur HuggingFace → TGI.
FAQ
Articles liés
Article
FastAPI streaming LLM Python 2026 — guide complet
SSE, WebSocket, OpenAI/Ollama streaming avec FastAPI. Intègre vLLM comme moteur backend.
Lire l'article →Article
Fine-tuning LoRA et QLoRA en Python 2026
Créer des adaptateurs LoRA avec peft/trl — puis les servir en production avec vLLM multi-LoRA.
Lire l'article →Article
RAG avec Ollama en Python
Pipeline RAG complet LangChain + ChromaDB. Le prefix caching vLLM maximise les gains RAG.
Lire l'article →Formation
Formation Dev API FastAPI Python 2026
Construire des APIs IA production-ready avec FastAPI, vLLM et déploiement cloud.
Voir la formation →Cas d'usage production concret
Un SaaS B2B de génération de contenu sert 500 clients en simultané avec un seul H100. Stack : vLLM v0.20 avec FP8 (Llama 3.1 70B tient sur une carte) + prefix caching pour le system prompt client (~1 200 tokens partagés) + multi-LoRA pour 12 personas de marque. Résultat : TTFT <150 ms P95, coût GPU 60% inférieur à l'équivalent API OpenAI, zéro donnée client transmise en dehors de l'infra.
Consulting DEV-AI
Vous déployez un LLM en production ?
Architecture vLLM / SGLang, dimensionnement GPU, optimisation coûts, intégration FastAPI + RAG, monitoring Prometheus. Accompagnement expert.
Contacter l'équipe →Newsletter IA
Restez à jour sur l'IA & le Machine Learning
Actus, tutos, outils — chaque semaine en français. Sans spam.