L’IA générative est partout, et soyons honnêtes : faire tourner un modèle compact sur un ordinateur du quotidien comme un Mac M1 16 Go n'a plus rien d'un exploit. Llama.cpp ou Ollama le font très bien en deux lignes de commande.
Pour un ingénieur DevOps, la vraie question n'est plus de savoir si c'est possible, mais si l'on peut réellement en tirer quelque chose. Est-il possible d'obtenir un résultat viable, productif et directement utilisable, ou sommes-nous condamnés à passer plus de temps à corriger les hallucinations du modèle qu'à écrire le code nous-mêmes ?
Nous avons testé les limites de Qwen3-4B-Instruct-2507 en conditions réelles pour voir si, au-delà du gadget, ce type d'architecture pouvait délivrer de la vraie valeur.
Pourquoi le modèle brut ne produit rien de productif ?
Si l'on utilise un petit LLM de manière classique (en lui demandant d'écrire tout le code d'un bloc), le résultat est quasi inexploitable. Cela s'explique par deux verrous majeurs.
Le syndrome du "Lost in the Middle": Sur le papier, les serveurs d'inférence affichent des fenêtres de contexte gigantesques (32k tokens ou plus). En pratique, la fonction Softmax dilue l'attention sur la longueur. Plus le document s'allonge, plus la probabilité affectée aux instructions situées au milieu de la séquence s'effondre.
Sur notre Qwen3-4B-Instruct-2507, la fenêtre d'attention effective ne dépasse pas 3 000 tokens. Au-delà, le modèle perd le fil, invente des types, oublie la charte technique et produit un code qui ne compile pas. Résultat : zéro gain de productivité.
Pourquoi temp=0 ne suffit pas à rendre le modèle fiable: Fixer --temp 0 et --seed 42 ne garantit pas un résultat identique à chaque exécution. L'addition en virgule flottante IEEE 754 n'étant pas associative, l'ordre des calculs parallèles sur le GPU Metal varie légèrement à chaque run :
Exemple possible :
(1e16 + -1e16) + 1 = 1.0 mais
1e16 + (-1e16 + 1) = 0.0
Ces micro-variations modifient les derniers bits des logits. Si deux tokens ont des probabilités très proches, le choix final bascule. Dans du texte, échanger deux synonymes n'a pas d'impact. Mais dans du code, basculer entre = et += casse toute l'application.
À cela s'ajoutent les optimisations logicielles :
- FlashAttention : accélère les calculs par un facteur 2 à 4 en découpant les matrices, mais accentue la non-associativité.
- La quantification : réduire les poids en 4-bit (Q4_K_M) introduit des arrondis où deux valeurs proches comme 0.1234 et 0.12345 finissent par être confondues.
L'Infrastructure: simple à monter mais à sanctuariser
Faire tourner l'infrastructure est simple. L'enjeu est de calibrer le serveur llama.cpp pour maximiser le débit sans étouffer la machine.
Ligne de commande utilisée :
Pourquoi ces choix :
- Le déchargement Metal (-ngl 99) pousse l'intégralité des 99 couches sur le GPU Apple Silicon. On atteint 400 tokens/s en ingestion et 40 tokens/s en génération.
- La sérialisation (--parallel 1) bloque le multi-flux pour réserver toute la puissance à une seule tâche et limiter le non-déterminisme.
- Le tout consomme 6 Go de RAM, laissant le Mac fluide pour le reste du travail.
L'infra tourne sans problème. Mais qu'en sort-il concrètement ?
Perte de temps vs vrai GAIN: le benchmark des agents
Nous avons soumis les différentes approches au même test fonctionnel : générer une application CLI CRUD complète en Python 3.12 (gestion de ventes, persistance SQLite et rapports d'agrégation) en utilisant 3 approches.
La clef pour en tirer quelque chose: l'approche NeuroSymbolique
La réponse à notre question initiale est là : pour tirer quelque chose d'un LLM de 4B, il faut changer de paradigme. Il ne faut plus lui demander d'écrire du code textuel libre, mais s'en servir comme d'un simple moteur de décision au sein d'un pipeline déterministe.
C'est ce que fait le pipeline d'Agent Smith (illustré par le schéma de pipeline de génération de code) :

Étape 1 : StepDesign (PIPELINEDESIGN & PIPELINEMANIFEST) Analyse du besoin fonctionnel. Le LLM ne produit aucun code, mais génère un schéma JSON strict sous grammaire GBNF. Il définit uniquement les entités et les contrats.
Étape 2 : StepRender (MODELRENDER, REPORENDER, SERVICERENDER) Génération 100 % déterministe en Python pur, hors-LLM. Le schéma SQLite, les dataclasses, les repositories et les signatures de services sont générés automatiquement par du code traditionnel. Aucun token n'est consommé, zéro hallucination possible.
Étape 3 : StepLLM (LLMFILL, ASTUTILS, SPLICE) Le LLM est sollicité uniquement pour remplir des stubs de logique métier très ciblés (des fonctions contenant uniquement "NotImplementedError"). Chaque morceau généré passe par une analyse d'Arbre de Syntaxe Abstraite (ASTUTILS) puis est découpé et réinjecté à la ligne exacte (SPLICE).
Étape 4 : StepCLI (CLIRENDER, CLIPROPAGATE, PIPELINEGENERATE) L'interface CLI Click et l'assemblage final sont générés de manière déterministe pour produire le projet final.
Résultat : en 3 à 4 minutes sur le Mac M1, on obtient une application fonctionnelle, testée, formatée avec Ruff, sans avoir eu à intervenir.
Verdict: Alors, peut-on vraiment en tirer quelque chose ?
La réponse est OUI, mais à une condition stricte : abandonner l'idée du LLM "magique" qui écrit tout tout seul.
Ce qu'on y gagne vraiment :
- Une productivité réelle sur des tâches répétitives (CRUD, microservices, CLI) sans taper une seule ligne d'infrastructure.
- Une confidentialité absolue (127.0.0.1) : aucune donnée, aucun schéma ni aucun secret ne quitte la machine.
- Un coût d'exécution nul et une autonomie totale, même sans connexion Internet.
Les limites à accepter :
- Cela demande un effort d'ingénierie initial important (créer les générateurs AST, les valideurs et les grammaires).
- Ce système est redoutable sur des périmètres bien cadrés, mais n'a pas la flexibilité d'un grand modèle cloud pour de l'exploration métier complexe ou du refactoring flou.
Un modèle de 4B en local n'est pas un gadget, à condition de le traiter comme un composant logiciel sous contrôle plutôt que comme un développeur virtuel autonome.