64 points par GN⁺ 2026-03-17 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • Partage d’une méthodologie concrète pour le développement logiciel avec des LLM, fondée sur un workflow multi-agents architecte-développeur-relecteur, permettant de maintenir des projets de plusieurs dizaines de milliers de lignes avec un faible taux de défauts
  • L’intérêt portait moins sur la programmation elle-même que sur le fait de construire quelque chose ; maintenant que les LLM savent bien coder, il devient possible de se concentrer sur la création
  • Les compétences d’ingénierie liées à la conception de l’architecture système et aux bons choix deviennent bien plus importantes que la simple capacité à écrire du code
  • L’usage combiné de différents modèles améliore la qualité de la revue de code, en exploitant les forces et faiblesses de chacun selon le rôle
  • Une session complète d’ajout d’une fonctionnalité email est rendue publique, avec une documentation détaillée d’un processus de collaboration avec les LLM piloté par l’humain, des décisions d’architecture jusqu’à la QA

Les avantages de créer avec des LLM

  • Je pensais aimer programmer, mais en réalité j’aimais surtout créer des choses ; maintenant que les LLM codent bien, je construis sans arrêt
  • Autour de la sortie de Codex 5.2, puis plus récemment avec Opus 4.6, il est devenu possible d’écrire des logiciels avec un taux de défauts très faible. Ce taux peut être sensiblement inférieur à celui du code écrit entièrement à la main
  • Avant, après 2 à 3 jours de travail, le code devenait ingérable en maintenance ; aujourd’hui, il est possible de travailler plusieurs semaines d’affilée et de faire croître de manière stable des dizaines de milliers de lignes de code utiles
  • Les compétences d’ingénierie ne sont pas devenues inutiles, elles se sont déplacées : au lieu de savoir écrire correctement le code, l’essentiel est de bien architecturer le système et de faire les bons choix pour qu’il soit exploitable
  • Sur des projets dont on maîtrise bien la technologie sous-jacente (par ex. le backend), plusieurs dizaines de milliers de SLoC ne posent pas de problème ; en revanche, sur une technologie mal connue (par ex. une app mobile), l’accumulation de mauvais choix finit encore par rendre le code chaotique
  • Aux débuts des LLM (après davinci), il fallait relire chaque ligne de code ; avec les générations suivantes, une vérification au niveau des fonctions suffisait, et aujourd’hui la tendance est de ne plus contrôler qu’au niveau de l’architecture globale. L’an prochain, même cela pourrait devenir inutile

Les projets créés de cette manière

  • Stavrobot : un assistant personnel LLM centré sur la sécurité. Il gère le calendrier, évalue les disponibilités, fait de la recherche, s’auto-étend en écrivant du code, envoie des rappels, gère certaines tâches domestiques de manière autonome, etc. Sa valeur clé ne tient pas à une fonctionnalité phare, mais au fait de supprimer des milliers de petites frictions
  • Middle : un petit pendentif qui enregistre des mémos vocaux, les transcrit en texte et les envoie à un webhook. L’essentiel est de pouvoir l’avoir toujours sur soi et de l’utiliser sans friction
  • Sleight of Hand : un projet artistique d’horloge murale qui fait tic-tac de manière irrégulière à la seconde près, tout en restant toujours exacte à la minute. Il propose divers modes : ticks variables entre 500 ms et 1500 ms, ralentissements difficiles à percevoir suivis d’arrêts aléatoires, course à double vitesse puis attente de 30 secondes, etc.
  • Pine Town : une prairie interactive sous forme de canevas multijoueur infini, où chacun reçoit un petit terrain pour y dessiner
  • Tous ces projets ont été réalisés avec des LLM ; je n’ai jamais lu moi-même la majeure partie du code, mais je connais très bien l’architecture et le fonctionnement interne de chacun

L’outil de harness

  • J’utilise OpenCode comme harness, et j’ai aussi eu une bonne expérience avec Pi
  • Deux exigences indispensables pour un harness :
    • Pouvoir utiliser différents modèles de plusieurs entreprises : la plupart des harness first-party (Claude Code, Codex CLI, Gemini CLI) ne prennent en charge que leurs propres modèles, donc ne répondent pas à ce critère
    • Permettre à des agents personnalisés de s’appeler mutuellement de manière autonome

Pourquoi utiliser plusieurs modèles

  • On peut considérer un modèle donné comme une personne à part entière : même après réinitialisation du contexte, il tend à conserver les mêmes opinions, points forts et points faibles
  • Demander à un modèle de relire le code qu’il a lui-même écrit est presque inutile, car il tend à être d’accord avec lui-même ; en revanche, confier la revue à un autre modèle améliore fortement la qualité
  • À ce jour, Codex 5.4 convient bien à la revue parce qu’il est méticuleux et exigeant ; Opus 4.6 correspond bien aux décisions que je prendrais moi-même ; Gemini 3 Flash propose parfois des solutions que les autres modèles n’ont pas vues
  • Pour obtenir les meilleurs résultats, il faut mélanger tous les modèles

Workflow : architecte → développeur → relecteur

  • Le workflow se compose d’un architecte, d’un développeur et de 1 à 3 relecteurs. Ils sont configurés comme des agents OpenCode (fichiers de skills)
  • Trois raisons d’utiliser plusieurs agents :
    • Utiliser les modèles coûteux (Opus) pour la planification, et les modèles moins chers (Sonnet) pour écrire le code, afin d’économiser des tokens
    • Faire la revue avec différents modèles permet de détecter des problèmes différents
    • Il est possible de séparer les permissions par rôle (par ex. lecture seule vs écriture autorisée)
  • Utiliser deux agents avec le même modèle et les mêmes permissions revient un peu à faire porter deux casquettes à une seule personne, ce qui n’a pas beaucoup d’intérêt
  • Les fichiers de skills sont rédigés manuellement. Faire écrire des skills par un LLM revient à demander à quelqu’un d’écrire « comment devenir un excellent ingénieur », puis à lui renvoyer ces consignes en disant : « maintenant, deviens excellent »

Le rôle de l’architecte

  • L’architecte (actuellement Claude Opus 4.6) est le seul agent avec lequel je parle directement, et il doit être le modèle le plus puissant
  • Je lui présente un objectif de fonctionnalité ou de correction de bug très précis, puis nous discutons jusqu’à 30 minutes pour fixer les objectifs, contraintes et compromis
  • Le résultat est un plan assez bas niveau, détaillé jusqu’au fichier et à la fonction
  • Il ne s’agit pas simplement de prompting, mais d’un processus de formation du plan avec l’aide du LLM. Je corrige beaucoup lorsque le LLM se trompe ou s’écarte de ma façon de faire, et c’est là ma contribution essentielle pour que le projet reste « à moi »
  • Il est configuré pour ne pas commencer l’implémentation tant que je n’ai pas explicitement prononcé le mot « approved ». Certains modèles ont tendance à se lancer prématurément dès qu’ils pensent avoir compris
  • Après validation, l’architecte découpe le travail en tâches, les documente en détail dans un fichier de plan, puis appelle le développeur

Le rôle du développeur

  • Le développeur peut utiliser un modèle plus faible mais plus efficace en tokens (Sonnet 4.6)
  • Comme le plan laisse très peu de place à l’interprétation, son rôle consiste strictement à implémenter les changements prévus
  • Une fois l’implémentation terminée, il appelle les relecteurs

Le rôle des relecteurs

  • Chaque relecteur examine indépendamment le plan et le diff, puis formule sa critique
  • Codex est toujours utilisé au minimum ; Gemini est parfois ajouté ; pour les projets importants, Opus peut aussi être ajouté
  • Les retours sont renvoyés au développeur et, en cas de désaccord entre relecteurs, l’escalade se fait vers l’architecte
  • Opus excelle pour choisir les bons retours, et certains retours trop tatillons (avec une faible probabilité de poser un vrai problème au regard du coût d’implémentation) sont parfois ignorés

Approche générale et modes d’échec

  • Avec cette méthode, toutes les décisions au-delà du niveau fonction restent comprises, et cette connaissance sert pour les travaux ultérieurs
  • Lorsque le LLM a un angle mort et manque un élément précis du codebase, le fait de lui dire « il faut utiliser Y » lui fait prendre conscience de l’existence de Y et basculer vers une meilleure approche
  • Si l’on ne maîtrise pas la technologie, on peut ne pas repérer les mauvaises décisions du LLM ; celles-ci s’accumulent alors jusqu’à rendre la situation insoluble
  • Un schéma d’échec classique consiste à répéter « le code ne marche pas », ce à quoi le LLM répond « compris, je vais corriger », tout en aggravant encore le problème
  • Il faut donc, même sans être expert d’une technologie donnée, essayer d’en comprendre un maximum dès la phase de planification

Session réelle : ajout du support email à Stavrobot

  • La transcription complète d’une session réelle annotée est publiée ; les appels d’outils et les passages trop verbeux sont omis, mais la conversation et le processus de décision restent intacts
  • Conversation initiale : formulation d’un objectif de haut niveau (« je veux ajouter le support email à ce bot ») → le LLM lit le code, identifie le schéma actuel (webhook entrant → enqueueMessage → traitement par LLM → réponse), puis pose des questions de conception
    • Mode entrant (polling IMAP, webhook, serveur SMTP), mode sortant, bidirectionnel ou non, architecture (conteneur séparé vs in-process), traitement des emails HTML, suivi des threads, pièces jointes, etc.
  • Décisions de conception : webhook Cloudflare Email Worker en entrée, client SMTP en sortie, conversations entièrement bidirectionnelles, traitement in-process, conversion en Markdown, traitement des emails comme indépendants, prise en charge des pièces jointes
  • Proposition de conception détaillée du LLM : parsing MIME (avec mailparser), authentification du webhook (secret partagé), nécessité d’un sujet sur les emails sortants, traitement des emails HTML-only, identité de l’adresse From, gestion des emails transférés, pièces jointes sortantes — soit 7 points d’attention avec des propositions de conception concrètes
    • Proposition de simplifier la payload du Worker en { from, to, raw } et de faire le parsing côté serveur
    • Présentation de la structure de config, des flux entrant/sortant, de la liste des fichiers à modifier, et des éléments explicitement hors périmètre (YAGNI)
  • Affinage du plan : l’humain signale des oublis, comme la mise à jour de README.md et de config.example.toml, ou la suppression de la validation E.164 sur la page de liste d’autorisation des emails → le LLM les intègre
  • Découpage en 6 tâches : config/dépendances, liste d’autorisation, validation UI/backend de la liste d’autorisation, email entrant, email sortant, README/tests
  • Amélioration supplémentaire : proposition de rendre les champs SMTP optionnels pour que l’email entrant fonctionne même sans configuration SMTP → implémenté
  • Bug découvert en QA : les messages étaient abandonnés parce que l’email du propriétaire n’était pas enregistré → la cause venait de seedOwnerInterlocutor, qui omettait le canal email → correction appliquée
  • Suggestion d’amélioration du code : refactoriser les blocs if codés en dur par canal en itérant sur une liste partagée de canaux. Après discussion sur le cas particulier de conversion numérique pour Telegram, il est décidé d’appliquer la boucle uniquement à seedOwnerInterlocutor et de conserver getOwnerIdentities, car la différence de types y est essentielle
  • Liste d’autorisation email avec wildcard : ajout de la prise en charge des wildcards au niveau du domaine sous la forme *@example.com, nécessaire dans un cas d’usage réel avec des adresses email jetables
    • Considération de sécurité : pour éviter des attaques du type "me@mydomain.com"@evildomain.com, le * est converti en [^@]* afin de ne pas pouvoir franchir la frontière du @
    • Les wildcards partielles comme myusername+*@gmail.com sont également prises en charge
    • L’humain souligne que, lors de l’usage d’expressions régulières, tous les autres caractères de l’adresse email doivent être échappés
  • Vérification du fonctionnement des wildcards à la fois dans le champ propriétaire et dans la liste d’autorisation, avec usage du même helper matchesEmailEntry
  • L’ensemble de la fonctionnalité a demandé environ 1 heure

Épilogue

  • Ce n’est pas une configuration extrêmement sophistiquée, mais elle fonctionne très bien, et la fiabilité du processus est jugée satisfaisante
  • Stavrobot tourne quasiment en 24/7 depuis près d’un mois et se montre très stable

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.