Aller au contenu principal

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é :

ArtefactMoteurCouvre
Application de bureau, macOSMetalApple Silicon
Application de bureau, Windows et LinuxVulkanNVIDIA, AMD et Intel
CLI, presets *-cpuprocesseurtoute machine, sans offload GPU
CLI, presets *-vulkanVulkanNVIDIA, 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 recommend classe 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_LOADED fixe 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.

VariableDéfautCe 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_LAYERScalculé, sinon 999Couches 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_BATCHdéfaut du moteurTaille de batch logique.
APOLLIA_LLAMA_N_UBATCHdéfaut du moteurTaille du micro-batch physique.
APOLLIA_LLAMA_N_PARALLELplanifié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_BATCHINGtrueBatching continu.
APOLLIA_LLAMA_CACHE_TYPE_Kdéfaut du moteurQuantization du cache KV, clés.
APOLLIA_LLAMA_CACHE_TYPE_Vdéfaut du moteurQuantization du cache KV, valeurs.
APOLLIA_LLAMA_FLASH_ATTNonMode flash attention.
APOLLIA_LLAMA_CACHE_REUSEdéfaut du moteurSeuil de réutilisation de préfixe.
APOLLIA_LLAMA_METRICSfalseExpose le point de terminaison de métriques du moteur.
APOLLIA_LLAMA_LOG_VERBOSITY4Niveau 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_ARGSvideOptions 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​