> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Devops agentique, et si le LLM ne devait pas tout décider ?
- URL: https://www.sfeir.dev/devops-agentique-et-si-le-llm-ne-devait-pas-tout-decider/
- Published: 2026-09-23T07:57:20.000Z
- Updated: 2026-09-23T07:58:20.000Z
- Description: Et si le LLM ne devait pas tout décider ? Avec Agent Smith, j'explore une architecture où le modèle prend les décisions qui nécessitent son raisonnement, tandis qu'un kernel déterministe construit, vérifie et garantit les invariants du code généré.
- Author: Gilles Stenger
- Tags: agents IA, LLM, déterminisme, neuro-symbolique, Devops augmenté, Python, llama.cpp

Les LLM savent aujourd'hui générer du code avec une facilité déconcertante. Mais lorsqu'on leur demande de construire une application complète, on exige bien plus d'eux que d'écrire quelques fonctions. Ils doivent comprendre le besoin, choisir une architecture, concevoir des structures de données, gérer les dépendances entre fichiers, respecter les interfaces, écrire le code et décider comment tester ce qu'ils viennent de produire.

Autrement dit, on demande à un moteur probabiliste de prendre en charge une succession de décisions dont certaines ont pourtant des réponses parfaitement déterministes.

Et si le problème venait en partie de là ? Plutôt que de chercher uniquement à construire des modèles toujours plus capables, une autre approche consiste à se demander : quelles décisions avons-nous réellement besoin de confier au LLM ?

## Le problème : un LLM fait beaucoup de choses

Dans une approche classique de génération de code par agent, le modèle est progressivement transformé en un développeur virtuel à qui l'on délègue presque tout :

- architecture et choix des fichiers ;
- structures de données et interfaces ;
- implémentation et gestion des imports ;
- écriture des tests, corrections et parfois exécution.

Cela fonctionne relativement bien avec les modèles les plus puissants. Mais avec un petit modèle local, les limites apparaissent rapidement. [Mon précédent article](https://www.sfeir.dev/ia/devops-augmente-en-local-avec-un-petit-llm-peut-on-vraiment-en-tirer-quelque-chose/) montrait notamment qu'un modèle d'environ 4 milliards de paramètres, exécuté localement, perd vite le fil dès qu'on lui demande de produire une application multi-fichiers à partir de texte libre.

Une première réponse consiste à contraindre la forme. Avec une grammaire GBNF (*GGML Backus-Naur Form*, utilisée notamment pour contraindre les sorties de modèles locaux), on peut par exemple l'obliger à produire un JSON structurellement valide plutôt qu'un texte arbitraire. Mais un JSON valide peut parfaitement décrire une mauvaise architecture. Contraindre la forme de la réponse ne suffit pas à contraindre la décision elle-même.

## Et si le LLM ne faisait que décider ?

Au passage : Agent Smith a changé de corps. 

Si vous avez lu le premier épisode, vous connaissez ce projet sous le nom **l'agent Smith**. Il s'appelle désormais **[Esus](https://github.com/stengerg-sfeir/esus?ref=sfeir.dev)**. Non, ce n'est pas un fork : **Smith a simplement changé de corps.** 😉 

Et pour son nouveau corps, il lui fallait un nouveau nom. **[Esus](https://github.com/stengerg-sfeir/esus?ref=sfeir.dev)**, divinité gauloise représentée sur le Pilier des Nautes à Paris, est notamment associé à l'image d'un artisan travaillant un arbre. Une référence plutôt appropriée pour un projet qui cherche justement à transformer des décisions abstraites en construction logicielle. 

Le LLM ne devrait pas nécessairement écrire la structure du programme. Il pourrait plutôt répondre à des questions décisionnelles précises :

- Quelles sont les entités et leurs attributs ?
- Quelles opérations sont nécessaires ?
- Quelles sont les interfaces entre les composants ?
- Quelle primitive connue du système permet de réaliser cette opération ?

Le résultat n'est plus du code libre, mais une décision structurée, exprimée dans un format que le logiciel déterministe peut ensuite interpréter. Un kernel déterministe prend la main pour générer les fichiers, construire l'AST, produire le schéma de base de données ou appliquer des transformations aux règles connues.

On obtient une séparation simple : **le modèle explore l'espace des décisions ; le logiciel garantit les invariants.**

Cette approche rejoint par certains aspects le [Harness Engineering](https://www.sfeir.dev/ia/harness-engineering-construire-la-confiance-dans-vos-agents-ia/) : plutôt que de tout miser sur le modèle, on construit autour de lui un environnement fait de contraintes, d'outils et de mécanismes de vérification.

## Pourquoi le code est un domaine particulièrement intéressant

Cette approche n'est pas applicable de la même manière à tous les domaines. Le développement logiciel possède une propriété exceptionnelle : nous avons passé des décennies à formaliser ses règles.

Un programme possède une syntaxe représentable par un AST. Il existe des systèmes de typage, des compilateurs, des analyseurs statiques, des linters et des suites de tests. Nous n'avons pas besoin de demander à un LLM de « deviner » si une structure Python est syntaxiquement correcte : Python possède déjà un analyseur syntaxique pour cela.

Cette formalisation rend le développement logiciel particulièrement adapté à une approche neuro-symbolique. Dans le cas d'Esus, la composante symbolique réunit les structures formelles du logiciel : contrats, types, AST, contraintes et primitives déterministes. On prend des méthodes d'ingénierie éprouvées pour les transformer en mécanismes du système. Et cela change aussi la place de l'humain.

## « Human-in-the-loop » par contrat plutôt que par inspection

Le problème du Human-in-the-loop avec un agent très autonome est simple : si l'agent prend des centaines de micro-décisions, demander à un humain de toutes les vérifier revient à remplacer un problème par un autre. L'humain devient le reviewer permanent d'une avalanche de décisions probabilistes.

Avec une architecture déterministe autour du modèle, on déplace cette frontière. L'humain valide l'intention et les contrats :

- cette entité est-elle correcte ?
- cette règle métier correspond-elle au besoin ?
- cette interface est-elle celle que nous voulons ?

Une fois ces décisions validées, leur réalisation est confiée à des mécanismes déterministes et testés. Le kernel n'a pas besoin d'être « intelligent » : il doit surtout être fiable sur le domaine qu'il couvre.

Le développeur peut alors davantage jouer son rôle de **concepteur** : il valide les décisions qui nécessitent réellement son jugement, plutôt que de devenir le correcteur ligne par ligne d'un code produit par l'agent.

Ce n'est pas une suppression du contrôle humain, mais une tentative de le rendre compatible avec l'échelle et la vitesse des agents.

## Esus : un laboratoire plutôt qu'une théorie

Esus est un prototype open source disponible sur [GitHub](https://github.com/stengerg-sfeir/smith?ref=sfeir.dev). Le nom fait référence à une divinité gauloise attestée notamment sur le Pilier des Nautes à Paris, où Esus est représenté en train d'ébrancher un arbre. Une référence assez appropriée pour un projet qui cherche justement à transformer des décisions abstraites en construction logicielle.

Esus est volontairement limité : il cible principalement des applications Python CRUD utilisant SQLite. Cette limitation permet de déplacer une partie importante de la génération vers un kernel au comportement maîtrisé.

Le pipeline suit quatre grandes étapes :

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/09/Gemini_Generated_Image_1qzmd31qzmd31qzm-3.jpg)

- **StepDesign** : le LLM produit un manifeste, des modèles de données et des signatures de services sous forme de JSON contraint.
- **StepRender** : le kernel génère les éléments structurels dont la forme est connue.
- **StepLLM & Splice** : le modèle intervient localement pour compléter certaines fonctions dans des contextes isolés. Le code produit est ensuite vérifié puis réinjecté (*splice*) dans la structure générée par le kernel.
- **StepCLI & Validation** : le câblage de la CLI et la validation sont réalisés de manière déterministe.

Le modèle n'est donc pas appelé pour tout : une partie majeure du travail intermédiaire repose sur du code classique.

## Réduire l'espace des décisions

C'est le bénéfice le plus fondamental. Si le modèle doit décider simultanément du nom des fichiers, de la structure des classes, des imports, des signatures, du schéma de base de données et du câblage de la CLI, l'espace des solutions possibles devient immense.

Mais certaines de ces décisions n'ont aucune raison d'être probabilistes. Si Esus sait comment générer un modèle Python à partir d'un contrat donné, il n'y a aucun intérêt à demander au LLM de le réinventer à chaque génération.

La "déterminisation" consiste à retirer au modèle les décisions qui n'ont pas lieu d'être probabilistes. On ne cherche pas nécessairement à rendre le modèle plus intelligent : **on rend le problème plus petit.**

## Le coût du contexte et la dette de contexte

Cette séparation apporte un avantage décisif : la maîtrise de la taille du contexte.

Lorsqu'un agent travaille dans une longue conversation, les décisions précédentes s'accumulent. Plus le projet avance, plus le modèle doit relire d'informations pour comprendre l'état courant.

Avec Esus, les générations sont réalisées dans des contextes indépendants et éphémères. Le kernel transporte l'information pertinente entre les étapes sans retransmettre l'historique au modèle. On évite ainsi d'accumuler une *dette de contexte* — un problème qui rappelle, par certains aspects, le pattern [MCP Code Execution](https://www.sfeir.dev/ia/mcp-code-execution-cest-quoi-ce-fameux-pattern-pour-economiser-des-tokens/). Chaque décision ne devrait pas avoir à payer pour toutes celles qui l'ont précédée.

## Contenir le non-déterminisme

Il faut toutefois être précis sur ce que signifie « déterministe ». Le passage à un kernel local ne fait pas disparaître toute variabilité (calculs numériques, environnements, plateformes).

L'enjeu est d'utiliser le harness pour définir ce qui constitue un résultat acceptable (valeur exacte, tolérance numérique, ensemble de résultats valides ou invariant à respecter). La "déterminisation" ne signifie pas que tout doit produire exactement le même résultat, mais que le système sait quelle variabilité il accepte. Le non-déterminisme devient une propriété maîtrisée.

## Ce que les benchmarks d'Esus montrent

Le harness d'Esus est plus exigeant qu'un simple test de compilation. Il vérifie plusieurs propriétés : le programme fonctionne-t-il réellement ? Respecte-t-il la surface demandée ? Les invariants métier sont-ils respectés ?

Le dépôt contient actuellement **66 spécifications de test** (60 prompts numérotés et 6 spécifications nommées pour les comparaisons externes). Le test de façade couvre 46 de ces spécifications.

Sur les six spécifications nommées, les six projets sont fonctionnels (compilation, CLI, workflows et façade). La conformité stricte au texte est de **4/6**.

Une comparaison exploratoire avec Claude Code sur ces six mêmes spécifications montre un résultat éclairant : Esus passe les six spécifications sur le plan fonctionnel, alors que les deux modèles Claude testés rencontrent plusieurs échecs fonctionnels ou de conformité.

Ce résultat ne conclut pas à une supériorité générale des petits modèles sur un domaine large. Il montre en revanche qu'un système spécialisé peut obtenir de très bons résultats même avec un modèle local beaucoup plus petit.

En matière de temps et de volume, Esus produit environ **104 000 caractères de code Python en 17 minutes** (contre 8 minutes pour Haiku et 18,5 minutes pour Sonnet).

Enfin, l'instrumentation révèle où se situe le coût réel du pipeline : **89,2 % du temps passé dans le LLM est consacré aux phases de conception et d'extraction du domaine (StepDesign)** ; les générations de corps de fonctions ne représentent que **10,8 %**.

La déterminisation déplace le problème : elle réduit l'espace de génération libre, mais rend plus visible la difficulté de comprendre et formaliser correctement le besoin.

## Le harness fait partie de l'expérience

Un autre enseignement est apparu pendant les benchmarks : un test peut lui-même être trop faible. Une première version se contentait de vérifier que la CLI **retournait** `exit 0`. Or une commande peut retourner `exit 0` sans exécuter l'opération requise.

Il a fallu renforcer les contrôles pour vérifier la mutation effective des données. Le harness n'est pas une couche de tests ajoutée après coup : il fait partie de l'architecture. Cette séparation rejoint d'ailleurs [l'expérimentation SFEIR sur la vérification des faits produits par un agent](https://www.sfeir.dev/ia/agent-code-verification-faits-pull-request/).

## Le prix à payer : déplacer la complexité

Cette architecture n'est évidemment pas gratuite. On ne supprime pas la complexité : on choisit où elle réside.

Dans un agent généraliste, la complexité est portée implicitement par le modèle et les prompts. Avec une architecture neuro-symbolique, elle devient du logiciel explicite : il faut développer le kernel, définir les contrats, maintenir les primitives et écrire les validateurs.

Et si une spécification demande une opération non couverte par le kernel, il faut soit l'étendre, soit redonner la main au LLM. Le domaine de liberté du modèle est progressivement réduit à ce qui nécessite réellement sa capacité de raisonnement.

## Vers une architecture hybride

Cette observation ouvre une possibilité intéressante : il n'est pas nécessaire de choisir entre « tout faire avec un petit modèle local » et « tout déléguer à un grand modèle cloud ».

On peut imaginer une architecture hybride :

- un modèle cloud puissant analyse le besoin et produit les décisions de haut niveau ;
- le kernel local prend en charge la construction déterministe ;
- un petit modèle local intervient sur des fonctions métier isolées ;
- des tests logiciels vérifient le résultat.

C'est une direction que j'explore autour d'une exposition du kernel d'Esus via MCP. **Claude pourrait devenir le penseur, et Esus le bâtisseur.**

## Et si l'on inversait la question ?

Cette expérience m'amène à une conclusion différente de la simple recherche du « meilleur modèle ». La question ne devrait plus être : « Quel LLM est suffisamment intelligent pour tout faire correctement ? », mais plutôt : « Qu'est-ce que nous sommes réellement obligés de lui demander de faire ? »

Chaque fois qu'une réponse peut être obtenue par un algorithme déterministe, un schéma, un compilateur, un analyseur ou un test, il n'est pas nécessaire de la confier au modèle. Chaque décision retirée au modèle réduit d'autant l'espace dans lequel il peut se tromper.

L'approche neuro-symbolique ne cherche pas à rendre le LLM infaillible en soi : elle cherche à construire un système dans lequel nous n'avons pas besoin qu'il le soit.

## Et maintenant ?

Esus reste un prototype, avec un domaine volontairement limité et beaucoup d'améliorations à venir. Mais les premières expérimentations montrent qu'il est possible de déplacer la complexité d'un agent en transformant certaines de ses décisions en connaissances exécutables par le système.

La prochaine étape sera de repousser cette frontière : que faire lorsque le kernel ne connaît pas encore la règle métier demandée ? Peut-on laisser le LLM identifier lui-même les invariants tout en conservant une génération déterministe dès que ces invariants sont connus ? Et surtout, peut-on mesurer ce que l'on gagne en fiabilité sans simplement déplacer le problème ailleurs ?

C'est ce que je vais essayer d'explorer dans la suite d'Esus.