vLLM prend en charge Flint de Recursive dès le jour 0. Ses deux checkpoints NVFP4 et BF16 fonctionnent sur un seul GPU, et une requête unique décode à environ 500 tokens/s sur un GB200, même avec 100K tokens de contexte.
Flint est un MoE de 40B paramètres qui n'active qu'environ 2.5B paramètres par token, avec une attention à fenêtre glissante dans la plupart des couches et un contexte de 262K tokens. Il est livré sous forme de deux checkpoints distincts : NVFP4 (entraîné avec quantization-aware training) et BF16.
Démarrage rapide
L'image Docker du jour 0 vllm/vllm-openai:flint (x86_64 et arm64, CUDA 13.0) intègre la prise en charge de Flint :
# NVFP4 checkpoint (GGUF): config and tokenizer come from the BF16 repo
docker run --gpus all --ipc=host -p 8000:8000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
vllm/vllm-openai:flint \
RecursiveSI/flint-nvfp4-gguf \
--hf-config-path RecursiveSI/flint --tokenizer RecursiveSI/flint \
--enable-auto-tool-choice --tool-call-parser glm47 \
--reasoning-parser glm47 --exclude-tools-when-tool-choice-none
# BF16 checkpoint
docker run --gpus all --ipc=host -p 8000:8000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
vllm/vllm-openai:flint \
RecursiveSI/flint \
--enable-auto-tool-choice --tool-call-parser glm47 \
--reasoning-parser glm47 --exclude-tools-when-tool-choice-noneLa prise en charge de Flint est en cours de fusion dans vLLM (#62938). Avec une build de vLLM qui l'inclut, servez de la même manière :
# NVFP4 checkpoint (GGUF): config and tokenizer come from the BF16 repo
vllm serve RecursiveSI/flint-nvfp4-gguf \
--hf-config-path RecursiveSI/flint --tokenizer RecursiveSI/flint \
--enable-auto-tool-choice --tool-call-parser glm47 \
--reasoning-parser glm47 --exclude-tools-when-tool-choice-none
# BF16 checkpoint
vllm serve RecursiveSI/flint \
--enable-auto-tool-choice --tool-call-parser glm47 \
--reasoning-parser glm47 --exclude-tools-when-tool-choice-noneArchitecture du modèle
Flint est un MoE pre-norm de 49 couches avec une taille cachée de 2048. Ce qui le distingue, c'est la faible proportion de couches qui regardent l'ensemble du contexte.
Figure 1 : la pile de couches de Flint et ses deux sous-couches. L'or signale ce qui diffère d'un MoE pre-norm standard. Ouvrez-le en plein écran.
- Principalement une attention locale. 35 couches assistent à une fenêtre glissante de 513 tokens avec RoPE ; les 14 autres assistent à tout le contexte sans encodage positionnel. Seules ces 14 conservent le KV pour toute la séquence, si bien que le cache coûte 28 KiB par token.
- Des learned attention sinks, du GQA avec 32 têtes de requête et 4 têtes KV, et une RMSNorm par tête pour Q/K.
- 256 experts, top-6 sigmoïde, plus un expert partagé. Les couches 0 et 1 utilisent un MLP dense à la place.
Le checkpoint NVFP4 est un fichier GGUF dont les blocs sont au format NVFP4 de NVIDIA dans un ordre d'octets différent. vLLM le recompacte sans perte au chargement et l'exécute en weight-only (W4A16), avec activations et cache KV en BF16, comme le fait l'implémentation de référence de Recursive. Chaque noyau Flint suit les points d'arrondi de la référence, et la précision correspond sur GSM8K, GPQA-Diamond, MRCR en contexte long et une suite d'appels d'outils.
Optimisations
Notre première implémentation, construite à partir des couches standard de vLLM, était lente à petite taille de lot : une étape de décodage exécutait 1,096 noyaux, dont beaucoup étaient optimisés pour des lots bien plus grands. Nous les avons remplacés par des noyaux spécifiques à Flint, un changement à la fois, en vérifiant chacun par rapport à la référence.
Figure 2 : latence de la passe avant du modèle sur un GB200 après chaque changement, pour un décodage de lot 1 à 100K de contexte et un prefill de 8,192 tokens. Changez de checkpoint ou affichez le tableau pour chaque forme. Ouvrez-le en plein écran.
- Fusion de la norme Q/K, de RoPE et de l'écriture du cache KV (−8%) : un seul noyau au lieu de trois.
- Noyaux MoE pour petits lots (−27 %) : les GEMV de routage et d'experts qui ne lisent que les poids des experts sélectionnés. C'est aussi le plus grand gain de prefill.
- GEMV dense à petit lot (−25 %) sur les mêmes poids NVFP4 compactés que le noyau à grand lot.
- Noyaux Norm et SiLU (−10 %) qui suivent l'arrondi de la référence.
- Attention de décodage (−5 %) avec sinks et fenêtres glissantes, en CuTe DSL.
- Chemin de décodage à faible latence (−14 %), montré ci-dessous.
Pour jusqu'à 8 requêtes, le chemin à faible latence exécute chaque couche MoE en sept noyaux : la norme Q/K, RoPE, le routage et la combinaison des experts sont fusionnés dans les noyaux GEMV adjacents. Chaque noyau est lancé avec un lancement dépendant programmatique, si bien qu'il charge ses poids pendant que le précédent s'exécute encore.
Figure 3 : Les sept noyaux d'une couche MoE sur le chemin de décodage à faible latence.
Au total, le décodage NVFP4 est passé de 4.81 à 1.78 ms (2.7×), le décodage BF16 de 3.53 à 2.34 ms (1.5×), et un prefill de 8K tokens de 207 à 145 ms (1.4×). Une passe forward exécute désormais 346 kernels au lieu de 1,096. Servi de bout en bout, le décodage en batch de 1 à un contexte de 100K tokens prend 2.06 ms par token (environ 485 tokens/s), ce qui inclut la passe forward plus la tête LM et l'échantillonnage.
Notes d'utilisation
- Flint émet des appels d'outils et des blocs de réflexion à la manière de GLM-4.7, d'où les
glm47parsers.--exclude-tools-when-tool-choice-nonesupprime les définitions d'outils du prompt lorsquetool_choiceest"none", conformément à la référence. - Les paramètres d'échantillonnage par défaut sont une température de 1.0, un top-p de 0.95 et un top-k de 20. Le raisonnement compte dans
max_tokens, prévoyez donc au moins 32K pour les problèmes difficiles. - Les noyaux Flint ciblent un seul GPU Blackwell (TP=1, cache KV BF16) ; les autres configurations reviennent aux couches standard de vLLM.