Tirer le meilleur parti de l'inférence locale
L'inférence LLM locale est servie par un llama-server embarqué (le projet
llama.cpp en amont) que le daemon lance et supervise via son API HTTP compatible
OpenAI. C'est le moteur des modèles GGUF, et il n'y a aucun processus séparé à
installer, à lancer, ni vers lequel pointer Apollia. Sur macOS arm64,
l'application desktop livre aussi un moteur MLX (vllm-mlx) pour les modèles au
format MLX : le format d'un modèle choisit son moteur, et Système > Moteurs règle
le moteur de chaque format. Cette page traite de llama-server. Il est livré
préconstruit dans l'application desktop, et sur une build depuis les sources, le
daemon retrouve llama-server sur votre PATH (voir
Installer et lancer le runtime).
Deux capacités qui exigeaient auparavant un serveur additionnel lancé à la main sont désormais actives par défaut, parce que le moteur embarqué est ce serveur :
- Batching continu. Le moteur décode plusieurs séquences dans la même passe GPU : les requêtes concurrentes et par lot se partagent le matériel au lieu de se sérialiser l'une derrière l'autre. Rien à activer.
- Appel d'outils natif. Le moteur est piloté avec
--jinja, si bien que les appels d'outils passent par le template de conversation propre au modèle plutôt que par un chemin de grammaire sur mesure. Les modèles locaux appellent vos outils de façon fiable, sans réglage de votre côté.
Suivre llama.cpp en amont élargit aussi la couverture de modèles : les nouvelles architectures arrivent dans le moteur au fur et à mesure qu'elles arrivent en amont.
Quel moteur part avec quel artefact
Le moteur embarqué est choisi à la construction de l'artefact, un par artefact, donc il n'y a rien à sélectionner à l'installation. Il y a un installeur par système. Ce qui est livré :
| Artefact | Moteur | Couvre |
|---|---|---|
| Application de bureau, macOS | Metal | Apple Silicon |
| Application de bureau, Windows et Linux | Vulkan | NVIDIA, AMD et Intel |
CLI, presets *-cpu | processeur | toute machine, sans offload GPU |
CLI, presets *-vulkan | Vulkan | NVIDIA, AMD et Intel |
Vulkan dans le paquet de bureau est un arbitrage assumé. Un binaire de 32 Mo atteint les trois fabricants, là où le moteur CUDA ne couvre que NVIDIA, pèse 238 Mo plus 373 Mo de runtime, et retombe sur le processeur avec toute autre carte. Le moteur CUDA n'est donc dans aucun installeur. Il est publié à part, sur le canal des moteurs, et l'application le télécharge à la demande : sur une machine dotée d'une carte NVIDIA, l'écran IA le propose, Accélérer avec votre carte NVIDIA, et un clic l'installe. Le prochain chargement d'un modèle l'utilise, et le moteur Vulkan embarqué reste en place comme repli. Sous Windows, le téléchargement porte les bibliothèques d'exécution CUDA ; sous Linux, le moteur s'appuie sur celles de la machine.
Rien n'est exécuté avant d'être vérifié. Le canal publie un manifeste qui liste chaque archive avec son SHA-256, signé au format minisign avec une clé de distribution dédiée. L'application porte la moitié publique de cette clé, ne demande aucune archive avant que la signature tienne, et supprime une archive dont l'empreinte diffère. Une machine sans réseau importe les trois mêmes sortes de fichier, manifeste, signature et archive, depuis un disque, par les mêmes contrôles.
Les archives de ligne de commande n'ont aucun preset CUDA, sur aucune plateforme. Si vous exécutez le daemon depuis la ligne de commande sur une carte NVIDIA et que vous voulez CUDA plutôt que Vulkan, désignez une compilation à vous, plus bas.
Configurer un backend local
Enregistrez un modèle .gguf comme backend local et laissez le daemon le
servir. Le nom du fournisseur est llama-cpp :
apollia-os llm setup --local --model /path/to/model.gguf
apollia-os llm reload
apollia-os llm status
Le daemon démarre le llama-server embarqué pour ce modèle à la demande et lui
route l'inférence. Le streaming SSE et les appels d'outils empruntent le même
chemin, déjà câblé et testé.
Obtenir un bon débit
Le moteur gère la mécanique (déport GPU, batching, cache KV). Les choix qui font varier le débit se situent en amont de lui :
- Choisir un modèle dimensionné pour votre matériel. Un modèle
mixture-of-experts (MoE) n'active qu'une fraction de ses paramètres par token,
ce qui lui permet de dépasser un modèle dense de qualité comparable à la fois
en vitesse et en débit par lot. Préférez une quantization qui laisse de la
marge pour le cache KV.
apollia-os model recommendclasse les candidats pour cette machine, avec la mémoire que chacun demande et le nombre de ses couches qui tiennent sur le GPU. - Un modèle par processus de moteur. Chaque modèle chargé tourne dans un
moteur à lui, et plusieurs restent résidents quand le garde-fou de chargement
juge qu'ils tiennent ensemble ;
APOLLIA_LLAMA_MAX_LOADEDfixe un plafond explicite. - Les slots sont planifiés pour vous. Le batching continu est actif par
défaut, et le nombre de slots de décodage est planifié à chaque démarrage
d'après le modèle et la mémoire de la machine, jusqu'à huit : des requêtes
simultanées décodent ensemble quand il y a la place.
APOLLIA_LLAMA_N_PARALLEL(voir plus bas) impose le nombre à la place.
Régler le moteur embarqué
Le moteur embarqué lit treize variables d'environnement à chaque démarrage, si bien qu'un réglage peut être modifié sans build depuis les sources. Définissez- les dans l'environnement de ce qui lance le daemon.
| Variable | Défaut | Ce qu'elle fait |
|---|---|---|
APOLLIA_LLAMA_N_CTX | (non définie) | Fenêtre de contexte en tokens, au-dessus de toute autre source. Non définie, la fenêtre est celle du preset, celle du backend, puis le défaut de [llm.defaults] dans apollia.toml, et 32768 en dernier. |
APOLLIA_LLAMA_N_GPU_LAYERS | calculé, sinon 999 | Couches déportées vers le GPU ; 0 force le CPU. Non définie, la valeur est calculée pour chaque modèle sur un GPU dédié (voir plus bas). |
APOLLIA_LLAMA_N_BATCH | défaut du moteur | Taille de batch logique. |
APOLLIA_LLAMA_N_UBATCH | défaut du moteur | Taille du micro-batch physique. |
APOLLIA_LLAMA_N_PARALLEL | planifié | Slots de décodage servis simultanément. Non définie, le nombre est planifié d'après le modèle et la mémoire, jusqu'à 8 ; définie, elle est prise telle quelle. |
APOLLIA_LLAMA_CONT_BATCHING | true | Batching continu. |
APOLLIA_LLAMA_CACHE_TYPE_K | défaut du moteur | Quantization du cache KV, clés. |
APOLLIA_LLAMA_CACHE_TYPE_V | défaut du moteur | Quantization du cache KV, valeurs. |
APOLLIA_LLAMA_FLASH_ATTN | on | Mode flash attention. |
APOLLIA_LLAMA_CACHE_REUSE | défaut du moteur | Seuil de réutilisation de préfixe. |
APOLLIA_LLAMA_METRICS | false | Expose le point de terminaison de métriques du moteur. |
APOLLIA_LLAMA_LOG_VERBOSITY | 4 | Niveau de journal du moteur (-lv). À 4, le chargement nomme son périphérique et le nombre de couches déchargées, que le journal du daemon rapporte sous llama.server.device, llama.server.offload et llama.server.buffer. |
APOLLIA_LLAMA_EXTRA_ARGS | vide | Options supplémentaires transmises telles quelles. |
Le nombre de slots est ce qui transforme le batching continu en véritable
concurrence : avec un seul slot, les requêtes s'empilent. N'imposez N_PARALLEL
que si le nombre planifié ne convient pas à votre charge.
Quand APOLLIA_LLAMA_N_GPU_LAYERS n'est pas définie et que la machine a une
carte graphique dotée de sa propre mémoire, le daemon ne demande plus toutes les
couches. Il lit l'en-tête du fichier du modèle, retire de la mémoire de la carte
le cache de contexte et le contexte graphique, et déporte autant de couches que
le reste en contient ; les autres tournent sur le processeur. Demander toutes
les couches sur une carte trop petite pour le modèle faisait échouer
l'allocation du moteur au lieu de placer ce qui tenait. Le journal rapporte la
décision sous llama.server.ngl.planned, avec n_gpu_layers rapporté à
total_layers. Sur Apple Silicon, où le processeur et le GPU partagent une même
mémoire, et sur une machine où aucun GPU n'a été détecté, le daemon transmet
toujours 999 : toutes les couches vont sur un GPU à mémoire partagée, et sans
GPU le moteur ignore la valeur. Définir la variable l'emporte toujours.
Pour vérifier qu'un modèle a bien chargé sur l'accélérateur, lisez le journal
du daemon au démarrage suivant du moteur : llama.server.offload porte le
nombre de couches placées contre le total du modèle, et llama.server.buffer
la taille de chaque tampon par périphérique.
La liste complète, y compris les variables de stockage de secrets et de diagnostic, se trouve dans Variables d'environnement.
Lancer un moteur à vous
Sur une build depuis les sources, le daemon utilise le llama-server qu'il
trouve sur votre PATH plutôt qu'un binaire embarqué. Le dépôt fournit une
recette pour en lancer un pour des tests locaux :
just llama-server /path/to/model.gguf
Cette recette lance le binaire en amont, si bien que les options habituelles de
llama.cpp s'appliquent lorsque vous expérimentez en local : contexte total
(-c) réparti entre slots parallèles (-np), déport GPU (-ngl), flash
attention (--flash-attn on), et cache KV quantifié (-ctk q8_0 -ctv q8_0, qui
nécessite flash attention). Ce sont des options llama.cpp en amont, utiles pour
sonder ce que votre matériel encaisse avant d'arrêter votre choix sur un modèle
et une quantization.
APOLLIA_LLAMA_SERVER_BIN désigne au démon le binaire de votre choix, et il
l'emporte sur celui qui est embarqué :
export APOLLIA_LLAMA_SERVER_BIN=/opt/llama.cpp/build/bin/llama-server
C'est aussi le chemin pour une compilation CUDA à vous. Un exploitant qui fait tourner des cartes NVIDIA dispose en général déjà d'un llama.cpp compilé pour ces cartes et réglé pour sa charge ; Apollia l'utilise plutôt que de lui en substituer une autre.
Voir aussi
- Installer et lancer le runtime pour la build et
l'exigence de
PATHsur une build depuis les sources. - Déployer en production pour servir depuis un serveur.
- La référence CLI pour les commandes
llm.