Electrosens R&D
Electrosens NVIDIA DGX Spark · 18 October 2026

Piles d’inférence sur DGX Spark : vLLM, llama.cpp, Ollama, SGLang, TensorRT-LLM — le comparatif 2026 (et pourquoi le bon choix vous fait gagner 2× sans changer de machine)

Sur une DGX Spark, le matériel est figé : 128 Go de mémoire unifiée, un GPU Blackwell sm_121, une bande passante modeste. Ce qui varie d’un facteur deux, ce n’est pas la machine — c’est le moteur que vous posez dessus. Voici comment choisir, régler, et surtout éviter les pièges qui coûtent des performances sans jamais afficher d’erreur.


128 Go de mémoire unifiée, un GPU sm_121 : pourquoi la pile d’inférence n’est pas un détail sur GB10

La DGX Spark n’est pas un serveur GPU classique, et c’est précisément ce qui rend le choix du moteur d’inférence structurant. Le GB10 embarque 128 Go de mémoire unifiée partagée entre un CPU ARM 20 cœurs et un GPU Blackwell crédité d’environ 1 PFLOP FP4, avec une bande passante mémoire autour de 273 Go/s et un réseau ConnectX-7 à 200 Gb/s. Sur une telle architecture, la mémoire n’est pas un goulot d’étranglement de capacité — 128 Go, c’est assez pour faire tenir des modèles que beaucoup de cartes grand public ne peuvent même pas charger — mais la bande passante l’est. Chaque token généré implique de relire des poids en mémoire, et à ~273 Go/s, la vitesse de décodage est largement dictée par la façon dont le moteur organise ces lectures.

Le deuxième point structurant est l’identité de la puce : le GB10 est un Blackwell sm_121, distinct à la fois des Blackwell datacenter (sm_100) et des Blackwell desktop (sm_120). Cette distinction, documentée par des sources techniques tierces et cohérente avec la nomenclature CUDA, est la racine de la plupart des problèmes que rencontrent les utilisateurs en 2026. Un binaire compilé pour sm_90 (Hopper) ou sm_120 « fonctionne » souvent — mais contourne le chemin GPU optimisé, ou pire, retombe silencieusement sur du calcul CPU. Sur une machine à mémoire partagée, ce genre de repli ne plante pas : il ralentit. Et comme il ne plante pas, personne ne s’en aperçoit.

C’est la thèse de cet article. Sur la DGX Spark, l’écart entre une pile mal configurée et une pile bien réglée n’est pas de 10 ou 20 % : il est de l’ordre du facteur deux, et il provient presque toujours des mêmes causes — architecture mal ciblée à la compilation, PyTorch CPU-only tiré par pip, contexte mal dimensionné, KV cache non quantifié, offload subi plutôt que choisi. Nous allons organiser le comparatif en trois familles : les moteurs serveur orientés débit et agents (vLLM, SGLang, TensorRT-LLM), les moteurs desktop orientés simplicité (Ollama, LM Studio, llamafile), et les moteurs compilés orientés latence (TensorRT-LLM, ExLlamaV2/V3, MLC). Le parti pris final est simple : il n’y a pas un gagnant, il y a une pile par profil — et souvent deux à installer en parallèle.


Le piège des cinq premières minutes : pip install, wheels aarch64 et le PyTorch CPU-only qui vous vole votre GPU

Commençons par ce qui fâche, parce que c’est là que se joue le fameux facteur deux. Le scénario le plus fréquemment rapporté en 2026 est celui de l’utilisateur qui installe vLLM avec un pip install vllm apparemment victorieux, lance son serveur, obtient des réponses… et se demande pourquoi tout est si lent. La cause : sur aarch64, la résolution PyPI a historiquement tiré un PyTorch CPU-only. Le serveur ne démarre pas du tout, ou démarre et tourne silencieusement sur CPU. Aucune erreur rouge, aucun avertissement spectaculaire — juste un GPU inutilisé.

Spécifications vérifiées du GB10 / DGX Spark (2026)Mémoire unifiée (Go)128valeurBande passante (Go/s)273valeurGPU Blackwell (PFLOP F1valeurCPU ARM (cœurs)20valeurRéseau ConnectX-7 (Gb/200valeur

La recommandation qui circule, attribuée au blog vLLM du 1er juin 2026, est de passer par un conteneur CUDA 13 plutôt que par pip : image vllm/vllm-openai:cu130-nightly, lancée avec --gpus all --ipc=host et un --gpu-memory-utilization 0.85. Le --ipc=host n’est pas cosmétique : sans lui, le partage mémoire entre processus (utilisé par le batching et le cache) se dégrade. Le 0.85, lui, laisse volontairement de la marge sur les 128 Go unifiés, car le CPU, l’OS et les autres processus se servent dans le même pool. Un détail à ne pas négliger : la compilation JIT de FlashInfer pour sm_121 exige CUDA 12.9 ou plus récent. En dessous, le chemin des kernels rapides n’est tout simplement pas disponible.

Le cas llama.cpp est différent mais tout aussi piégeux. Sur GB10, il faut compiler depuis les sources : aucun wheel précompilé ne cible correctement sm_121. Le flag correct est -DCMAKE_CUDA_ARCHITECTURES=121a-real. Compiler pour 90 (Hopper) ou 120 (desktop Blackwell) aboutit à un binaire qui tourne — mais qui dégrade ou contourne le chemin GPU. La compilation prend de l’ordre de 5 à 10 minutes, et llama-server atterrit dans build/bin/. Ce n’est pas cher payé, mais c’est un passage obligé que beaucoup sautent.

Un dernier piège, plus subtil, concerne le dimensionnement du contexte. llama-server dimensionne par défaut le contexte pour 4 requêtes concurrentes et recule automatiquement si ça ne tient pas ; --ctx-size fixe au contraire une limite dure qu’il faut calibrer soi-même. Sur une machine à mémoire unifiée, un contexte surdimensionné mange le pool partagé et peut forcer des offloads involontaires. C’est le genre de réglage qui ne se voit pas dans un tutoriel « ça marche » mais qui se paie en tokens par seconde.


Famille serveur (vLLM, SGLang, TensorRT-LLM) : le débit et les agents, à condition de dompter PagedAttention et le KV cache

C’est la famille qui compte pour tout ce qui ressemble à du service : API locale, agents multi-outils, plusieurs utilisateurs simultanés. Le playbook officiel NVIDIA « Install and use vLLM on DGX Spark » (dépôt NVIDIA/dgx-spark-playbooks, dossier nvidia/vllm) décrit l’architecture : PagedAttention, continuous batching, et une API compatible OpenAI. Les prérequis listés sont ARM64 + Blackwell, CUDA 13.0, Docker + NVIDIA Container Toolkit, Python 3.12 et Git ; l’installation via Docker est annoncée autour de 30 minutes. Le playbook mentionne également la quantification NVFP4 (avec génération de checkpoints custom) et des recettes de modèles — un « Nemotron-3-Nano-Omni-30B-A3B-Reasoning » en BF16 et une recette « Agent Ready Qwen3.6 35B ». Ces noms proviennent de la source et méritent d’être vérifiés à l’usage ; nous les citons comme pistes documentées, pas comme vérité gravée.

Sur le terrain, les réglages qui comptent sur DGX Spark sont peu nombreux mais décisifs. --gpu-memory-utilization fixe la part du pool unifié allouée au moteur ; --max-model-len borne le contexte et donc la taille du KV cache ; --max-num-seqs contrôle le nombre de séquences simultanées que le continuous batching peut entretenir. Sur une machine à bande passante limitée, pousser --max-num-seqs trop haut ne fait pas gagner en débit agrégé : cela dégrade la latence de chacun. Le KV cache, en particulier, est le premier poste à quantifier si l’on veut tenir un contexte long sans exploser la mémoire.

Les modèles qui passent réellement : les sources communautaires citent Qwen3.8-27B sur un seul Spark (projet vcruz305/Qwen3.8-27B-DGX-Spark), et Qwen3.8-Flash-Next en NVFP4 sur 2× DGX Spark avec vLLM (projet OsakaTX/qwen3.8-flash-next-vllm-dgx-spark). Les chiffres canoniques de notre base donnent un ordre de grandeur utile : sur 2× DGX Spark en TP=2 avec vLLM et DeepSeek-V4-Flash FP8, le débit single-stream tourne autour de ~41 tok/s, le débit agrégé à concurrence 32 autour de ~350 tok/s, et le prefill autour de ~1785 tok/s. Sur un seul Spark, un Qwen3.8-27B se situe plutôt dans la fourchette 34-38 tok/s en single-stream (août 2026). Deux Sparks supportent jusqu’à 405 milliards de paramètres selon les chiffres de notre base — c’est le plafond pratique à garder en tête.

SGLang et TensorRT-LLM méritent une mention honnête : ils figurent dans les playbooks NVIDIA (NVIDIA/dgx-spark-playbooks couvre vLLM, SGLang, llama.cpp, NVFP4, décodage spéculatif, kernels cuTile, NCCL et clustering deux/trois nœuds), mais leur documentation publique spécifique à GB10 reste mince. Le playbook « Choosing an Inference Engine » existe (référencé via DeepWiki) mais son contenu n’est pas reproduit dans nos sources : à traiter comme une piste à vérifier, pas comme une recommandation officielle citée. Pour un déploiement sérieux aujourd’hui, vLLM est le choix par défaut documenté ; SGLang et TensorRT-LLM sont des paris raisonnables pour qui accepte de bricoler.


Famille desktop (Ollama, LM Studio, llamafile) : la simplicité qui coûte cher, et comment la reprendre en main

Ollama, LM Studio et llamafile ont un mérite immense : ils font tourner un modèle en une commande, avec une interface, une gestion des GGUF et zéro compilation. C’est la porte d’entrée idéale. Le problème, c’est que cette simplicité cache exactement les réglages qui font la différence sur GB10 : dimensionnement du contexte, nombre de couches offloadées, absence de continuous batching sérieux. Un Ollama par défaut sur DGX Spark, c’est un moteur qui ne sait pas exploiter pleinement les 128 Go unifiés ni le batching multi-requêtes.

Source : gpuwerk.com

La bonne nouvelle, c’est qu’on peut reprendre la main sans quitter la famille. Côté Ollama, les variables d’environnement de contexte et de couches offloadées sont le premier levier : sur une machine à mémoire unifiée, l’offload CPU/GPU n’a pas la même signification que sur une carte discrète, et le laisser opaque revient à laisser le moteur décider à votre place. Côté GGUF, le choix des K-quants doit se raisonner en fonction de la bande passante : sur ~273 Go/s, un quant plus agressif réduit le volume de poids relus et accélère le décodage, au prix de qualité. C’est un arbitrage, pas une religion.

Le point le plus important concerne llama-server, qui est le moteur sous-jacent de nombreuses surcouches. Comme vu plus haut, il dimensionne par défaut le contexte pour 4 requêtes concurrentes et recule automatiquement ; --ctx-size fixe une limite dure. Sur DGX Spark, il faut calibrer : un contexte trop grand consomme le pool unifié et peut déclencher des offloads ; trop petit, il tronque les conversations longues et les agents. La règle pratique : dimensionner pour l’usage réel (chat court vs agent à long contexte), pas pour le maximum théorique du modèle.

Positionnement final : Ollama est une excellente porte d’entrée et un bon outil de prototypage, pas un moteur de production. Pour du service multi-requêtes, il faut passer à la famille serveur. Pour du chat mono-utilisateur avec une interface agréable, LM Studio reste imbattable en confort — à condition d’aller vérifier les réglages de contexte et d’offload plutôt que de laisser les valeurs par défaut.


Famille compilée/latence (TensorRT-LLM, ExLlamaV2/V3, MLC) : quand chaque milliseconde de TTFT se paie en heures de build

La troisième famille vise la latence, pas le débit. La logique est celle des moteurs compilés : engines pré-compilés, kernels fusionnés, quantification agressive (FP8, NVFP4, EXL2). Le gain se mesure en temps jusqu’au premier token (TTFT) et en latence mono-requête. Le prix : un support de modèles plus étroit, des cycles de compilation longs, et une fragilité accrue sur les architectures exotiques.

Sur GB10, l’état réel est contrasté. TensorRT-LLM est cité dans les playbooks NVIDIA et bénéficie de l’écosystème officiel, mais sa documentation spécifique à sm_121 reste limitée dans nos sources. ExLlamaV3 et MLC relèvent davantage du bricolage communautaire sur cette plateforme : rien dans notre corpus ne documente une prise en charge solide de sm_121. Ce ne sont pas des mauvais choix par nature — ce sont des paris, à réserver aux cas où la latence est le critère contractuel : chat interactif exigeant, voice, coding inline où chaque milliseconde de TTFT se ressent.

La recommandation est donc claire : réservez cette famille aux usages où la latence est le critère premier, pas au serving multi-agents. Pour un agent qui enchaîne les appels d’outils, ce qui compte est le débit agrégé et la stabilité, pas le TTFT d’une requête isolée. Mettre TensorRT-LLM sur un agent multi-outils, c’est payer des heures de build pour un gain que l’utilisateur ne percevra pas.


Tableaux de décision par usage : chat, coding, agents multi-outils, API locale, fine-tuning + inférence

Voici la partie la plus pratique. Pour chaque usage, un moteur recommandé, une quantification conseillée, des réglages clés et le piège à éviter.

Source : forums.developer.nvidia.com
Usage Moteur recommandé Quantification Réglages clés Piège à éviter
Chat interactif mono-utilisateur Ollama / LM Studio GGUF Q4-Q5 Contexte calibré, offload vérifié Laisser le contexte par défaut trop grand
Coding inline (latence) llama.cpp compilé sm_121 / TensorRT-LLM GGUF Q4 / FP8 --ctx-size fixe, draft MTP Compiler pour sm_90 ou sm_120
Agents multi-outils vLLM FP8 / NVFP4 --max-num-seqs modéré, KV cache quantifié Pousser le batch au-delà de la bande passante
API locale multi-utilisateurs vLLM (conteneur CUDA 13) FP8 / AWQ / GPTQ --gpu-memory-utilization 0.85, --ipc=host pip install tirant un PyTorch CPU-only
Fine-tuning + inférence Pile d’entraînement séparée + vLLM LoRA/QLoRA puis FP8 Vérifier le format de sortie du LoRA Supposer que le LoRA produit pour un moteur marche sur un autre

Le cas « fine-tuning puis inférence » mérite un développement, car c’est une source classique de déception. La pile d’entraînement (Unsloth, PEFT, TRL, NeMo) et la pile d’inférence ne sont souvent pas les mêmes, et les formats de LoRA/QLoRA produits ne sont pas universellement compatibles. Un adapter entraîné pour un moteur donné peut nécessiter une conversion avant d’être servi par un autre. La règle : décider de la pile d’inférence cible avant d’entraîner, ou prévoir une étape de conversion. Sur DGX Spark, la contrainte mémoire de 128 Go unifiés rend le QLoRA particulièrement attractif pour l’entraînement, mais l’inférence qui suit gagnera souvent à repasser en FP8 ou NVFP4 sur vLLM.

Les recettes reproductibles existent côté communauté. a1exus/sparky combine vLLM, Ollama et un routeur llama.cpp servant tous les GGUF en cache derrière Traefik, avec mDNS, Cloudflare Tunnel et Tailscale. botAGI/AGmind propose une pile RAG privée en une commande (Dify, vLLM, Weaviate, RAGFlow, Docling sur plus de 30 conteneurs) avec clustering deux nœuds via QSFP 200 Gb/s. Chrizz-lab/GB10-Agentig-Coding-Framework assemble un double vLLM Qwen3 avec orchestration CrewAI. mARTin-B78/dgx-spark_lite-llm_llama-swap_vllm_llama-cpp_ollama combine Lite-LLM, llama-swap, vLLM, llama.cpp et Ollama. Ces projets ne sont pas des références officielles — ils sont marqués « non vérifié » dans nos sources — mais ils montrent la forme que prend une installation mature : plusieurs moteurs, un routeur devant.


Le gain 2× est réel mais conditionnel : ce que disent (et ne disent pas) les benchmarks de 2026

Soyons précis sur ce que nous savons et ce que nous ne savons pas. Un benchmark communautaire du forum développeur NVIDIA compare Ollama, llama.cpp et vLLM sur un seul DGX Spark avec un harnais identique : prompt identique, 400 max_tokens, warm-up écarté, mesures single-stream, 8 concurrents et prefill long. La méthodologie est décrite ; les chiffres ne sont pas reproduits dans nos sources. Nous ne pouvons donc pas citer de tokens/s issus de ce benchmark. C’est une limite honnête, et elle doit être dite.

Ce que nous pouvons dire, en revanche, c’est d’où vient l’écart. Les variables explicatives sont connues : sm_121 mal ciblé à la compilation, PyTorch CPU-only tiré par pip, contexte mal dimensionné, KV cache non quantifié, offload subi plutôt que choisi. Chacune de ces causes produit un ralentissement silencieux, et leur combinaison explique l’essentiel du facteur deux observé entre une installation « qui marche » et une installation réglée.

Les ordres de grandeur attendus, à défaut de chiffres de benchmark citables : sur un seul Spark, un modèle de taille moyenne en single-stream se situe dans les dizaines de tokens par seconde (34-38 tok/s pour Qwen3.8-27B en août 2026, jusqu’à ~67 tok/s pour un 35B-A3B en llama.cpp GGUF). Sur deux Sparks en TP=2 avec vLLM FP8, le single-stream monte autour de ~41 tok/s et le débit agrégé à concurrence 32 autour de ~350 tok/s, avec un prefill autour de ~1785 tok/s. Ces chiffres proviennent de notre base et concernent des configurations précises ; ils ne sont pas des promesses universelles.

La conclusion est donc nuancée : le « 2× sans changer de machine » vient de la correction des pièges, pas d’un moteur magique. Aucun moteur ne double les performances par lui-même. Ce qui double les performances, c’est de compiler pour sm_121, d’éviter le PyTorch CPU-only, de calibrer le contexte, de quantifier le KV cache et de choisir l’offload au lieu de le subir.


Clusters de deux ou trois Spark, mémoire unifiée et patchs noyau : la pile change d’échelle

Passer à deux ou trois Sparks change la donne, et pas seulement en capacité. Le clustering repose sur le ConnectX-7 à 200 Gb/s, QSFP, RDMA, RoCE hétérogène et NCCL — autant de couches que les playbooks NVIDIA couvrent explicitement. Tous les moteurs ne savent pas répartir un modèle sur deux nœuds : vLLM le fait en tensor/pipeline parallel, SGLang et TensorRT-LLM également, mais avec des niveaux de maturité variables sur sm_121.

Le comportement du KV cache et de la mémoire unifiée en cluster est un point à surveiller. Sur 2× DGX Spark, notre base cite un pool de cache KV partagé de 1 105 096 tokens (août 2026) — un chiffre qui illustre l’intérêt du clustering : la capacité de contexte devient réellement confortable. Mais cette capacité ne sert à rien si le moteur ne sait pas la gérer, et c’est là que le choix du moteur redevient décisif.

Un détail qui vaut son pesant de performances : les patchs noyau. christopherowen/dgx-spark-memory-saver compacte les tables de pages GPU sur les kernels 64 KiB du DGX Spark, récupérant 3,03 GiB contre 64 KiB standard, et environ 1,8 GiB par nœud sur 4 KiB. Sur une machine à mémoire unifiée où chaque gigaoctet compte, ce n’est pas anecdotique. Ces projets sont marqués « non vérifié » dans nos sources, mais ils indiquent une réalité : sur GB10, l’optimisation ne s’arrête pas au moteur, elle descend jusqu’au noyau.

Ce que cela change pour la suite : une pile par nœud, un routeur devant (llama-swap, Traefik, Lite-LLM), et la question ouverte du support officiel de sm_121 par chaque projet. Le clustering n’est pas un mode d’emploi unique ; c’est une discipline qui combine choix de moteur, réglages réseau et patchs système. Et c’est probablement là que se jouera la prochaine vague de gains — pas dans un moteur miracle, mais dans l’ingénierie patiente de la pile complète.


Sources

Article recherché et rédigé automatiquement · Magazine Electrosens
📬 Restez à la pointe
Recevez chaque semaine les nouveautés de ce magazine par email.
💬 Une remarque, une correction ?
Aidez-nous à améliorer cet article. Nous prenons en compte vos retours.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *