Guide IA · Intermédiaire · RTX 4090 / H100

Inférence LLM self-hosted sur GPU : vLLM, Ollama, llama.cpp

Servir ses propres modèles, c'est sortir de la facturation au token, des files d'attente et des journaux de prompts chez un tiers. Ce guide couvre la chaîne complète — choix du moteur, calcul de VRAM, formats quantifiés, déploiement, benchmarks mesurés — avec les chiffres réels de notre ligne GPU, pas des promesses de plaquette commerciale.

1. Pourquoi self-héberger son inférence

Trois raisons reviennent dans chaque ticket que nous recevons sur la ligne GPU. La première est économique : une API au token facture chaque requête, y compris les prompts système répétés mille fois par jour par vos agents. Au-delà d'un certain volume, un GPU dédié à prix fixe coûte moins cher que la facture variable — nous chiffrons le point de bascule dans la FAQ. La deuxième est la confidentialité : un prompt envoyé à une API externe est un prompt journalisé quelque part, soumis à une politique de rétention que vous ne contrôlez pas. Sur votre machine, le prompt naît et meurt dans votre RAM.

La troisième est l'indépendance : pas de rate limit au milieu d'un batch, pas de dépréciation de modèle qui casse vos prompts du jour au lendemain, pas de compte suspendu par un algorithme de modération. Vous épinglez une version de modèle, vous la gardez tant qu'elle vous convient. En contrepartie — et c'est le deal du self-hosting — vous assumez la disponibilité, les mises à jour et le dimensionnement. C'est exactement le sujet de ce guide.

Note d'honnêteté : self-héberger ne rend pas un modèle magiquement meilleur. Un 8B local ne rivalisera pas avec les plus grands modèles propriétaires sur le raisonnement complexe. Le bon réflexe est de self-héberger les volumes (classification, extraction, résumé, agents outillés) et de garder une API externe pour les 5 % de requêtes vraiment difficiles.

2. Choisir son moteur d'inférence

Trois moteurs dominent l'inférence self-hosted en 2026, et ils ne répondent pas au même besoin. Le mauvais réflexe est d'en choisir un « pour toujours » ; le bon est de les faire cohabiter selon la charge.

  • vLLM — le serveur de production. Batching continu, parallélisme tensoriel multi-GPU, API compatible OpenAI, quantization AWQ/GPTQ/FP8. C'est le moteur qui transforme un GPU en service multi-utilisateurs : trente requêtes simultanées partagent la même carte sans s'effondrer. Plus lourd à installer (Docker recommandé), gourmand en VRAM pour ses propres structures, mais imbattable en débit agrégé.
  • Ollama — le chemin le plus court. Une commande pour installer, une pour télécharger un modèle, une API locale dans la minute qui suit. Parfait pour prototyper, pour un usage solo, ou comme backend local d'outils (continue.dev, Open WebUI). Sous le capot, c'est llama.cpp : les performances mono-flux sont bonnes, le multi-utilisateurs n'est pas son terrain.
  • llama.cpp — le chirurgien. Le serveur llama-server expose une API compatible OpenAI, lit les GGUF dans tous leurs niveaux de quantization, et permet l'offload partiel CPU+GPU quand un modèle dépasse la VRAM. C'est aussi le seul choix sérieux pour les formats exotiques (EXL2 via ses dérivés) ou pour presser le dernier token/seconde d'une carte.

Notre recommandation par défaut : Ollama pour valider votre cas d'usage le premier jour, vLLM dès que plus d'un utilisateur ou d'un agent tape sur le modèle, llama.cpp quand vous devez loger un modèle précis dans une VRAM précise. Les trois s'installent côte à côte sur nos images Ubuntu 24.04 + CUDA 12 sans conflit.

3. Dimensionner la VRAM : le calcul qui évite les mauvaises surprises

La règle de base tient en une ligne : la VRAM nécessaire ≈ nombre de paramètres × taille de chaque poids. En FP16/BF16, chaque paramètre pèse 2 octets — un modèle 8B occupe donc ~16 Go avant même le premier token. La quantization réduit ce poids : ~1 octet par paramètre en Q8, ~0,55–0,7 octet en 4 bits selon le format. À cela s'ajoutent le KV cache (la mémoire du contexte, qui grandit avec la longueur des conversations) et la marge du moteur lui-même : prévoyez 15 à 20 % de VRAM de tête, toujours.

Taille de modèle FP16 / BF16 Q8 4 bits (Q4_K_M / AWQ) Plan VPSPLEX conseillé
7–8 B (Llama 3.1 8B, Mistral 7B)~16 Go~9 Go~5 GoGPU-1 (24 Go), toutes quantizations
13–14 B (Qwen 2.5 14B)~28 Go~15 Go~9 GoGPU-1 en Q8/Q4
30–34 B (Qwen 2.5 32B, Yi 34B)~64 Go~34 Go~19 GoGPU-1 en Q4, GPU-2 en Q8
70–72 B (Llama 3.3 70B, Qwen 72B)~140 Go~75 Go~40 GoGPU-2 (48 Go) en Q4, GPU-3 (H100 80 Go) en Q8
100 B+ (DeepSeek-V3, grands MoE)~60 Go et plusGPU-3, devis multi-GPU au-delà

Poids du modèle seul, arrondis au Go supérieur. Ajoutez le KV cache : ~1 Go pour 8 000 tokens de contexte sur un 8B en FP16, ~5 Go sur un 70B — les architectures GQA/MQA des modèles récents divisent nettement cette facture.

L'erreur classique consiste à regarder uniquement la ligne « 4 bits » et à oublier le contexte : un 32B Q4 qui loge à l'aise dans 24 Go à 4 000 tokens de contexte déborde dès que vous montez à 32 000. Fixez --max-model-len (vLLM) ou --ctx-size (llama.cpp) à votre besoin réel, pas au maximum théorique du modèle — chaque millier de tokens de contexte inutilisé est de la VRAM rendue au batch.

4. Les formats quantifiés, sans le jargon inutile

La quantization compresse les poids du modèle en réduisant leur précision. La perte de qualité est mesurable mais modeste aux niveaux raisonnables : un Q8 est indiscernable du FP16 à l'usage, un Q4 bien fait (Q4_K_M, AWQ) coûte typiquement 1 à 2 points sur les benchmarks courants, et c'est le compromis que choisit presque tout le monde en production. En dessous de Q3, la dégradation devient visible dans les réponses longues — à réserver aux dépannages, pas à la production.

Format Moteur principal Taille par milliard de paramètres Quand le choisir
GGUF Q4_K_M / Q5_K_M / Q6_K / Q8_0llama.cpp, Ollama0,55 à 1,05 GoLe standard universel — un seul fichier, offload CPU possible
AWQ (4 bits)vLLM, TGI~0,6 GoMeilleur débit en batch sur vLLM, kernels très optimisés
GPTQ (4 bits)vLLM, TGI~0,6 GoÉquivalent AWQ, parfois le seul format dispo pour un modèle donné
FP8 (W8A8)vLLM~1 GoH100 : qualité quasi FP16 à moitié de VRAM, le réflexe sur GPU-3
EXL2 (2–8 bits)TabbyAPI / exllamav2variable au dizième de bitAjuster la taille au dixième de Go près sur une carte pleine

Réflexe pratique : sur Hugging Face, cherchez d'abord le GGUF « Q4_K_M » (bartowski en maintient pour presque tous les modèles notables) ou l'AWQ officiel du lab. Évitez les repacks anonymes sans hash ni provenance — un fichier de poids est un fichier que vous exécutez, et la chaîne d'approvisionnement des modèles est devenue un vrai vecteur d'attaque en 2025.

5. Correspondance avec les plans GPU VPSPLEX

Concrètement, voici comment nos trois configurations couvrent le spectre. La GPU-1 (RTX 4090, 24 Go, 119 $/mois) est la machine de l'inférence quotidienne : 8B en Q8 avec un long contexte, 14B en Q6, 32B en Q4 — soit, en 2026, des modèles qui traitent correctement la synthèse, l'extraction, la classification et la plupart des tâches d'agents. La GPU-2 (2× RTX 4090, 48 Go, 229 $/mois) est le seuil des 70B en Q4 et du 32B en Q8 confortable, avec le parallélisme tensoriel de vLLM (--tensor-parallel-size 2) pour répartir le modèle sur les deux cartes.

La GPU-3 (H100 SXM5, 80 Go HBM3, sur devis) change de catégorie : 70B en FP8 à pleine vitesse, contextes très longs, fine-tuning complet, ou plusieurs modèles moyens servis simultanément sur la même carte. Sa bande passante mémoire (3,35 To/s contre 1 To/s pour une 4090) se sent exactement là où l'inférence est limitée : la génération token par token.

Nos GPU sont dédiés — la carte que vous louez est la carte que vous avez, sans voisin qui réclame ses cycles au milieu de votre batch. C'est aussi ce qui rend les chiffres de la section suivante reproductibles chez vous à ±5 %.

6. Déploiement : du provisionnement au premier token

Chaque GPU est livré avec Ubuntu 24.04, CUDA 12, les pilotes NVIDIA et le NVIDIA Container Toolkit. Vérifiez d'abord que la carte répond :

Terminal · root@gpu-1
nvidia-smi
# Doit afficher : RTX 4090, 24564 MiB, pilote 560.x, CUDA 12.x

docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
# Confirme que Docker voit le GPU via le Container Toolkit

Voie production — vLLM en Docker

Terminal · root@gpu-1
docker run -d --gpus all --name vllm \
  -p 8000:8000 \
  -v /data/hf:/root/.cache/huggingface \
  vllm/vllm-openai:latest \
  --model Qwen/Qwen2.5-32B-Instruct-AWQ \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.92

# Suivi du chargement des poids (quelques minutes au premier run)
docker logs -f vllm

vLLM expose une API compatible OpenAI sur le port 8000. Testez-la comme vous testeriez n'importe quel endpoint :

Terminal · test de l'API
curl -s http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-32B-Instruct-AWQ",
    "messages": [{"role": "user", "content": "Explique le KV cache en trois phrases."}],
    "max_tokens": 200
  }'

Le point de migration est là : n'importe quel code écrit pour l'API OpenAI fonctionne en changeant deux lignes — base_url vers votre serveur, api_key vers une valeur quelconque. Vos agents, vos scripts, vos outils tiers basculent sans réécriture.

Voie express — Ollama

Terminal · root@gpu-1
curl -fsSL https://ollama.com/install.sh | sh
ollama pull llama3.1:8b-instruct-q8_0
ollama run llama3.1:8b-instruct-q8_0

# L'API écoute sur localhost:11434 — test :
curl -s http://localhost:11434/api/generate \
  -d '{"model":"llama3.1:8b-instruct-q8_0","prompt":"Bonjour","stream":false}'

Voie chirurgicale — llama-server

Terminal · root@gpu-1
# Binaire officiel CUDA, ou compilation : cmake -B build -DGGML_CUDA=ON
./llama-server \
  -m /data/models/qwen2.5-32b-instruct-q4_k_m.gguf \
  -ngl 99 \
  --ctx-size 8192 \
  --port 8080

# -ngl 99 = toutes les couches sur GPU ; baissez-le pour l'offload CPU partiel

7. Benchmarks : les chiffres mesurés sur notre ligne GPU

Mesures internes d'août 2026, sur machines de production à Rotterdam : vLLM 0.9, llama.cpp b6xxx, prompt de 512 tokens, génération de 256 tokens, température 0. « Décode » = vitesse de génération pour un utilisateur seul ; « agrégé » = somme des débits avec 32 requêtes simultanées sous vLLM. Ce sont les chiffres que vous reproduirez chez vous, pas des maximums de laboratoire.

Configuration Moteur Décode (1 flux) Débit agrégé (batch 32)
Llama 3.1 8B Q8 · GPU-1vLLM68 tok/s~1 900 tok/s
Llama 3.1 8B Q4_K_M · GPU-1llama.cpp74 tok/smono-flux
Qwen 2.5 14B Q6_K · GPU-1Ollama47 tok/s~600 tok/s
Qwen 2.5 32B AWQ · GPU-1vLLM26 tok/s~340 tok/s
Llama 3.3 70B Q4_K_M · GPU-2llama.cpp14 tok/smono-flux
Llama 3.3 70B FP8 · GPU-3 (H100)vLLM31 tok/s~2 400 tok/s

Deux enseignements. D'abord, l'écart mono-flux / agrégé : un 8B sert un utilisateur à 68 tok/s, mais trente-deux à ~60 tok/s chacun — le batching continu de vLLM est la seule raison pour laquelle un seul GPU peut faire office d'API pour toute une équipe. Ensuite, le 70B en Q4 sur 2× 4090 reste une expérience « confortable en lecture » (14 tok/s ≈ 10 mots/seconde) mais lente pour des agents qui enchaînent les appels : si votre charge est agentive, préférez un 32B rapide à un 70B lent — la qualité perdue se regagne souvent avec un meilleur prompt et des outils.

8. Mise en production : exposer l'API proprement

vLLM et llama-server n'ont pas vocation à écouter sur Internet en clair. Le montage que nous déployons : le moteur lié à 127.0.0.1, un reverse proxy Caddy devant (TLS automatique), une clé API exigée par le proxy ou par vLLM lui-même (--api-key), et UFW qui ne laisse passer que 443 :

/etc/caddy/Caddyfile · reverse proxy
llm.example.com {
    reverse_proxy 127.0.0.1:8000
    # TLS Let's Encrypt automatique ; journalisation désactivée si vous le souhaitez
}
Règles UFW · pare-feu
ufw allow OpenSSH
ufw allow 443/tcp comment 'API LLM TLS'
ufw default deny incoming
ufw enable

# Le port 8000 reste injoignable de l'extérieur : proxy ou rien
  • Supervision : le conteneur vLLM en --restart unless-stopped, ou un service systemd pour llama-server. Un GPU dédié ne redémarre pas souvent, mais un OOM de VRAM arrive — le service doit repartir seul.
  • Surveillance : nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv -l 60 dans un log, ou le node exporter + dcgm-exporter si vous avez déjà une stack Prometheus. La métrique qui compte est la VRAM libre : sa disparition annonce l'OOM.
  • Snapshots : une fois le serveur au point, un snapshot (1 $/mois) fige l'état propre. Réinstaller une GPU-1 de zéro prend dix minutes ; retrouver votre configuration exacte peut prendre une journée.

Questions fréquentes

vLLM, Ollama ou llama.cpp : par quoi commencer concrètement ?
Ollama, sans hésiter, pour le premier jour : trois commandes et vous dialoguez avec un modèle. Passez à vLLM dès que plusieurs utilisateurs ou agents frappent le modèle en parallèle — c'est là que son batching continu change tout (×20 à ×30 de débit agrégé dans nos mesures). Gardez llama.cpp/llama-server pour les cas précis : un GGUF qui n'existe pas en AWQ, un offload CPU partiel, ou la chasse au dernier tok/s sur une carte pleine.
Un modèle 70B tient-il sur 24 Go de VRAM ?
Pas en qualité exploitable. Un 70B demande ~40 Go en Q4_K_M : il lui faut la GPU-2 (48 Go) ou un offload CPU partiel qui effondre le débit à 2–4 tok/s — inutilisable pour un agent. Sur 24 Go, le plafond confortable est le 32B en Q4, qui est en 2026 un excellent niveau de capacité pour la synthèse, l'extraction et l'outillage. Pour du 70B sérieux (Q8, long contexte, batch), c'est la GPU-3 H100.
Combien de VRAM le contexte long consomme-t-il ?
Le KV cache grandit linéairement avec la longueur de contexte et dépend de l'architecture : comptez ~1 Go pour 8 000 tokens sur un 8B GQA en FP16, ~5 Go sur un 70B, et davantage sur les architectures MHA anciennes. vLLM peut quantifier le KV cache en FP8 (--kv-cache-dtype fp8) et diviser cette facture par deux avec une perte négligeable. Fixez toujours --max-model-len à votre besoin réel plutôt qu'au maximum du modèle.
Puis-je exposer mon endpoint LLM sur Internet en toute sécurité ?
Oui, à condition de ne jamais exposer le moteur brut : moteur sur 127.0.0.1, reverse proxy TLS (Caddy ou nginx) sur 443, clé API exigée (--api-key côté vLLM ou vérification dans le proxy), UFW en deny-by-default. Ajoutez une limite de débit au proxy si l'endpoint est public : un endpoint LLM ouvert est immédiatement trouvé par les scanners et vidé de sa capacité. Enfin, sachez ce que vous servez : un modèle sans filtre accessible publiquement engage votre responsabilité vis-à-vis de notre AUP.
À partir de quel volume le self-hosted bat-il les API au token ?
Le calcul honnête : une GPU-1 à 119 $/mois servant un 8B à ~1 900 tok/s agrégé représente une capacité de l'ordre de plusieurs milliards de tokens mensuels si elle tourne en continu. Aux tarifs 2026 des API mutualisées pour des modèles équivalents, le point de bascule purement financier se situe autour de 100 à 300 millions de tokens par mois — vite atteint par des agents en boucle, rarement par un usage interactif seul. En dessous, le self-hosted se justifie par la confidentialité, la latence stable et l'absence de rate limit, pas par l'économie. Nous préférons vous le dire avant la commande.

Votre premier token local peut sortir ce soir.

GPU-1 RTX 4090, 119 $/mois, provisionnée sous 24 h, payée en crypto — CUDA 12 et les pilotes déjà installés. Il ne reste que le docker run.

Choisir mon GPU