- La configuration d’un agent de code local permet d’exécuter des modèles sur macOS via une API compatible OpenAI même en cas de panne d’Internet, et de traiter des entrées texte et image dans Pi
- Les tests ont été réalisés sur un Apple M1 Max 64 Go sous macOS 15.7.7 avec llama.cpp Metal et le modèle Gemma 4 26B-A4B GGUF, avec une vitesse de génération de base de 58.2 tok/s
- Après ajout d’un modèle draft MTP et réglage de
--spec-draft-n-max 3, la vitesse de génération est montée à 72.2 tok/s, soit une amélioration d’environ 24 % - Il faut charger
mmproj-BF16.ggufavec--mmprojet définir l’entrée du modèle Pi sur["text", "image"]pour que les entrées image comme les captures d’écran soient transmises - La configuration finale exécute le serveur llama.cpp sur
127.0.0.1:8080/v1, utilisé par Pi comme fournisseur local, et bien que Qwen3.6 35B-A3B ait montré de meilleurs benchmarks d’agent de code, il était plus lent dans ce test à 55 tok/s
Objectif de la configuration d’un agent de code local
- Plusieurs pannes d’Internet ayant empêché l’usage d’un agent de code ont motivé l’essai d’une configuration en local
- La configuration visée devait être suffisamment rapide sur Mac pour un usage réel, et utilisable aussi depuis d’autres outils via une API compatible OpenAI
- L’objectif était également de pouvoir traiter des captures d’écran ou images au besoin, afin de réinjecter en entrée les résultats produits par l’agent
- La configuration finale repose sur
llama.cpp, Gemma 4 26B-A4B GGUF, un modèle draft MTP Q8, le projecteur multimodal Gemma 4 et l’agent de code en terminal Pi - L’environnement de test était un Apple M1 Max, 64 Go de mémoire unifiée, sous macOS 15.7.7
Modèle
- Le modèle principal était
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, disponible dans le dépôt Hugging Faceunsloth-gemma-4-26B-A4B-it-GGUF - Ce fichier pèse environ 16 Go, et avec la tête draft MTP et le projecteur multimodal, le dossier du modèle atteint environ 17 Go
- Le prompt de benchmark était
Write a compact Python function that parses a unified diff and returns the changed file paths. Then explain two edge cases. - Chaque benchmark générait environ 128 tokens
Exécution de base : llama.cpp + Metal
- Le modèle principal a été exécuté directement avec
llama.cppet l’accélération Metal - La commande utilisait
llama-clien indiquant le chemin du modèle,-ngl 999,-fa on,-c 4096,-n 128 - Dans la configuration de base, la vitesse de traitement du prompt était de 298.0 tok/s, et la vitesse de génération de 58.2 tok/s
- 58 tok/s n’est pas particulièrement rapide, mais reste exploitable, et les tâches d’agent de code exigent autant de vitesse que possible à cause des nombreux appels d’outils
Ajout du modèle draft MTP
- Gemma 4 fournit un modèle draft MTP sous la forme
MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf - Dans
llama.cpp, il est chargé pour le speculative decoding via--model-draft,--spec-type draft-mtp,--spec-draft-n-max - Le premier essai avec MTP a atteint 69.2 tok/s avec 4 draft tokens
- La documentation Unsloth recommande
--spec-draft-n-max 2comme point de départ, mais conseille de tester de 1 à 6 selon le matériel pour retenir la valeur la plus rapide - Après réglage de
--spec-draft-n-max, la meilleure vitesse a été obtenue avec 3 draft tokens, à 72.2 tok/s - Le modèle principal seul atteignait 58.2 tok/s, contre 72.2 tok/s avec le modèle draft MTP Q8 ajouté
- La vitesse de traitement du prompt est restée quasiment inchangée, tandis que la génération a progressé d’environ 24 %
Résultats de réglage MTP
- Les valeurs de
--spec-draft-n-maxde 1 à 6 ont été testées - La valeur 1 donnait 295.5 tok/s pour le prompt et 68.4 tok/s en génération
- La valeur 2 donnait 299.1 tok/s pour le prompt et 72.0 tok/s en génération
- La valeur 3 était la plus rapide avec 295.6 tok/s pour le prompt et 72.2 tok/s en génération
- Avec la valeur 4, la génération tombait à 70.7 tok/s, puis à 63.7 tok/s pour 5 et 61.2 tok/s pour 6
- Sur M1 Max,
3était le plus rapide, et2donnait aussi un résultat très proche
Comparaison avec MLX
- Pour vérifier s’il existait une méthode plus rapide d’exécution sur Mac, des modèles MLX basés sur
mlx-lmont aussi été testés llama.cpp Metal + MTPa atteint 72.2 tok/s avec la combinaison Unsloth GGUF Q4 + MTP Q8llama.cpp Metalseul a atteint 58.2 tok/s avec Unsloth GGUF Q4MLX-LMa atteint 45.8 tok/s avec Unsloth UD MLX 4-bitMLX-LMa atteint 43.9 tok/s avecmlx-community 4-bit, et 38.1 tok/s avecmlx-community OptiQ 4-bit- Dans cette configuration précise, llama.cpp était plus rapide que MLX, et llama.cpp avec MTP constituait le meilleur choix
- Un essai de Gemma 4 MTP via
gemma-4-swift-mlxa aussi été tenté, mais le checkpoint MLX 26B 4-bit testé ne correspondait pas aux weight keys attendues par le loader, et l’essai a été abandonné sans retélécharger ni ajuster un nouveau modèle
Ajout de la prise en charge des images
- Pour joindre des captures d’écran dans Pi, l’entrée du modèle ne devait pas être limitée au texte
- À l’origine, l’entrée du modèle local était réglée sur
"input": ["text"], ce qui empêchait Pi d’envoyer correctement au modèle la sortie des outils image - Le serveur
llama.cppnécessite aussi le projecteur multimodal Gemma 4mmproj-BF16.ggufpour la prise en charge multimodale - En chargeant le projecteur avec
--mmproj,llama.cppannonce la prise en charge multimodale et Pi peut envoyer des images - Un test de
llama.cpp Metal + MTPsans projecteur a donné 120.3 tok/s pour le prompt et 71.4 tok/s en génération - L’exécution finale avec
mmproj-BF16.ggufchargé a donné 297.4 tok/s pour le prompt et 72.2 tok/s en génération - Aucun ralentissement de génération de texte n’a été observé dans l’exécution finale avec le projecteur chargé
Installation de llama.cpp
- Les dépendances
cmake,git,tmux,python@3.11ont été installées via Homebrew - Le chemin
~/Developer/ML-Models/Gemma4/reposa été créé et le dépôtggml-org/llama.cppa été cloné dansrepos/llama.cpp - La build a été configurée avec
cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_METAL=ON -DGGML_ACCELERATE=ON - Ensuite, une build Release a été lancée avec
cmake --build build --config Release -j - La build testée utilisait les réglages
GGML_METAL=ON,GGML_ACCELERATE=ON,GGML_BLAS=ON,GGML_BLAS_VENDOR=Apple
Téléchargement des fichiers du modèle
- Un environnement virtuel Python 3.11 a été créé et
huggingface_hubainsi quehf_xetont été installés huggingface-cli downloada servi à récupérer le modèle principal Gemma 4,mmproj-BF16.ggufet le modèle draft MTP- Les fichiers téléchargés étaient
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf,mmproj-BF16.gguf,MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf - Le dossier final du modèle contient ces trois fichiers sous
models/unsloth-gemma-4-26B-A4B-it-GGUF/
Démarrage du serveur local
- Le serveur final est lancé avec
llama-server, en indiquant à la fois le modèle principal, le modèle draft MTP et le projecteur multimodal - Les options principales sont
--spec-type draft-mtp,--spec-draft-n-max 3,-ngl 999,-fa on,-c 65536,--parallel 1 - Le serveur est exécuté avec
--host 127.0.0.1 --port 8080 - L’endpoint compatible OpenAI est
http://127.0.0.1:8080/v1 - Le wrapper
start_server.shlance le serveur dans une sessiontmuxet écrit les logs danslogs/llama-server-mtp.log - Après
chmod +x start_server.sh, le serveur est démarré avec./start_server.sh - Son bon fonctionnement se vérifie avec
curl http://127.0.0.1:8080/v1/models
Configuration de Pi
- Pi lit la configuration des fournisseurs de modèles depuis
~/.pi/agent/models.json - Le
baseUrldu fournisseur localgemma4-localpointe vershttp://127.0.0.1:8080/v1 apivautopenai-completions, et comme il s’agit d’un serveur local,authHeaderest laissé àfalse- L’ID du modèle est
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, et son nom est défini surGemma 4 26B-A4B Q4 + MTP inputdoit être["text", "image"], sinon Pi traite le modèle comme text-only- La fenêtre de contexte est définie à 65536, avec un maximum de 8192 tokens
- Si besoin,
defaultProviderpeut être réglé surgemma4-localetdefaultModelsur ce nom de fichier GGUF dans~/.pi/agent/settings.json - En exécutant
pi --offline --list-models gemma, on s’attend à voiryespour la prise en charge des images - L’exécution avec le modèle local se fait via
pi --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf - L’exécution non interactive prend la forme
pi -p --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf "Explain what this repository does" - Une entrée par capture d’écran se fait sous la forme
pi -p @"/path/to/screenshot.png" "Describe this image and point out anything relevant to the UI"
Configuration finale
- Le runtime d’inférence final est
llama.cpp - L’accélération sur macOS combine Metal + Accelerate
- Le modèle principal est
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf - Le modèle draft est
gemma-4-26B-A4B-it-Q8_0-MTP.gguf - Le réglage MTP est
--spec-draft-n-max 3 - Le projecteur multimodal est
mmproj-BF16.gguf - Le serveur est
llama-serversur127.0.0.1:8080 - L’API est le
/v1compatible OpenAI - L’agent de code est Pi, avec une entrée modèle Pi définie sur
["text", "image"] - Dans cet environnement, le modèle draft MTP a fait passer la vitesse de génération de Gemma 4 de 58.2 tok/s à 72.2 tok/s, tout en gardant une configuration assez simple pour être exécutée comme serveur local compatible OpenAI
Alternative Qwen3.6 35B-A3B
- Certains recommandent d’utiliser
Qwen3.6 35B-A3Bà la place deGemma 4 26B-A4B - D’après les benchmarks vérifiables, Qwen est jugé nettement meilleur que Gemma 4 comme agent de code
- Mais la configuration Qwen était plus lente, avec 55 tok/s pour la combinaison
Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf,unsloth-Qwen3.6-35B-A3B-MTP-GGUF,mmproj-BF16.gguf - 55 tok/s au lieu de 72 tok/s représente une différence importante quand l’utilisateur doit attendre
- Le téléchargement du modèle Qwen se fait depuis
unsloth/Qwen3.6-35B-A3B-MTP-GGUF, en récupérantQwen3.6-35B-A3B-UD-Q4_K_XL.ggufetmmproj-BF16.gguf - Le serveur Qwen utilise le même
llama-server, mais s’exécute sur--port 8081 - Dans la configuration Pi, le nom du fournisseur Qwen est
qwen36-localet sonbaseUrlesthttp://127.0.0.1:8081/v1 - La configuration du modèle Qwen utilise
reasoning: true,input: ["text", "image"],contextWindow: 65536,maxTokens: 8192
1 commentaires
Commentaires sur Hacker News
Si le prompt du benchmark était « écrire une fonction Python concise qui analyse un unified diff pour renvoyer les chemins des fichiers modifiés, et expliquer deux cas limites », et que chaque benchmark ne générait qu’environ 128 tokens, alors 128 tokens semblent bien trop peu pour obtenir un résultat pertinent
L’accélération MTP dépend de la fréquence d’adoption des tokens prédits ; d’après mon expérience, le taux d’adoption est plus élevé au début de la sortie, donc des tests courts peuvent produire une accélération faussement positive
llama.cpp dispose d’un outil de benchmark dédié qui parcourt les arguments sans avoir à redémarrer le serveur ni à renvoyer le prompt : https://github.com/ggml-org/llama.cpp/blob/master/tools/llam...
La section sur le téléchargement des modèles aurait aussi dû mentionner que l’argument
-hfde llama.cpp peut télécharger le modèle à votre place. Merci à l’auteur d’avoir partagé son expérience, mais ce n’est peut-être pas le meilleur guide pour les débutantsEn voyant l’annonce « 2x faster » d’Unclothe, je me suis demandé : « est-ce que ça devient enfin assez rapide pour être vraiment utilisable ? » et je l’ai donc configuré moi-même
J’avais aussi testé l’an dernier avec des choses comme Devstral, mais c’était trop lent et trop bête pour me donner envie de continuer, alors que cette fois j’ai enfin l’impression qu’on atteint quelque chose de vraiment utilisable à la fois en vitesse et en intelligence
llama.cpp a un outil pour cela, et pour mesurer correctement il faut inclure un prefill avant la génération de tokens. Il devient aussi de plus en plus important de mesurer la vitesse de génération sur des contextes longs comme 32k ou 64k
J’avais écrit un billet similaire il y a quelque temps en utilisant ollama et opencode : https://blog.kulman.sk/running-local-llm-coding-server/
Est-ce qu’opencode ne consomme pas trop de contexte avec son system prompt ? Les modèles locaux sont très limités en contexte, et de mémoire opencode en utilise environ 10k, ou quelque chose de cet ordre
Si on n’utilise que llama.cpp, il ne semble pas nécessaire d’avoir
huggingface-clijuste pour télécharger quelque chose. Passer-hf ...permet de télécharger le modèlePour changer l’emplacement de téléchargement, il suffit de définir
LLAMA_CACHE:LLAMA_CACHE="models" ./llama-server \-hf unsloth/gemma-4-31B-it-GGUF:UD-Q4_K_XL \...-hfdSi la RAM en mémoire unifiée est grande mais que les téraflops et la bande passante en Go/s sont moyens ou faibles, alors en général MoE est ce qu’il y a de plus prometteur. Sur ma config, un M2 Max 96GB, le numéro 1 actuel selon
(intelligence, tok/s, profondeur de contexte)est DeepSeek-V4-Flash REAP25<65gb gguf+ ds4-server + pi agentBien sûr, ce n’est pas meilleur qu’une API cloud, mais c’est suffisamment acceptable pour supporter ce compromis si nécessaire. Même pendant un vol de 4 heures sans Internet, le LLM local tirait 60W et la batterie a largement tenu
La branche ds4 qui prend en charge REAP est ici : https://github.com/ljubomirj/ds4/tree/reap-compact-support
Le fait que DS4F ne tombe à un niveau inutilisable de moins de 10 tok/s qu’à 784K de contexte fait une énorme différence
Je me demande si ce type de modèle local peut vraiment résoudre des problèmes même pour des utilisateurs qui ne sont pas experts dans un langage de programmation donné
Au-delà de l’autocomplétion inline ou de l’implémentation d’une unité, je ne suis pas certain qu’il puisse réellement concevoir et assembler des spécifications techniques qui fonctionnent
Utiliser llama.cpp/server pour lancer un LLM local et l’employer avec Claude Code ou Codex-CLI est relativement simple
Comme les réglages nécessaires de llama server sont souvent dispersés un peu partout, je maintiens ici des consignes pour quelques LLM open populaires : https://pchalasani.github.io/claude-code-tools/integrations/...
J’ai utilisé omlx.ai avec pas mal de succès pour télécharger différents modèles MLX adaptés à mon matériel, puis exécuter automatiquement des harness open source et fermés (Claude Code, Codex) avec ces modèles
Ça fonctionne aussi bien dans l’interface web que desktop, donc personnellement je trouve qu’avec omlx il n’est pas nécessaire de suivre un billet de blog
Les builds Gemma 4 MLX que j’ai trouvés jusqu’ici étaient plus lents à quantification égale, et bien plus lents avec MTP
Une fois le modèle choisi, l’interface web intégrée de llama.cpp est plutôt bonne, et pour bricoler un peu LM Studio est aussi correct
Gemma-4 et Qwen 3.6 n’ont absolument pas besoin des gros blocs habituels de system prompt d’opencode, et c’est même mieux sans
DeepSeek v4 Flash exécuté avec le ds4 d’antirez était assez impressionnant
En termes de « connaissance stockée », il donne l’impression d’un modèle de niveau GPT-4, mais il gère mieux les appels d’outils sur de longues séquences que les modèles de niveau GPT-4
Sur un MBP M4 Max 128GB, on obtient environ 24 t/s en génération et environ 200 t/s en prefill. Je m’attendais à ce que ce soit lent, et pour des tâches comme la génération de code ça l’est effectivement, mais comme orchestrateur de machines pour des tâches simples c’est étonnamment utile
Pour des usages non agentiques, c’est un modèle tout à fait correct pour discuter, avec en plus l’avantage d’être totalement autonome et privé
[0]https://github.com/antirez/ds4
Si vous voulez faire ça avec un minimum d’effort, il suffit d’ouvrir Claude Code dans le terminal, de lui montrer cet article, puis de lui dire simplement « fais-le »
À l’inverse, Claude le fait d’un coup, ou avec très peu de retouches
La porte d’entrée vers la connaissance et l’exécution, c’est désormais le LLM, et Google Search donne l’impression d’un dinosaure
C’est encore plus bluffant que le smartphone ; on a presque l’impression de vivre un siècle dans le futur