Faire évoluer les LLM à l’échelle des grandes bases de code
(blog.kierangill.xyz)- Pour utiliser efficacement les LLM dans de grandes bases de code, il est essentiel d’investir dans le « guidage » (guide) et la « supervision » (oversight)
- Le guidage fournit le contexte et l’environnement pour aider le LLM à faire de meilleurs choix, tandis que la supervision vérifie les résultats et donne la direction à suivre
- Il est important de construire une bibliothèque de prompts afin que le LLM puisse comprendre les règles, la documentation et les bonnes pratiques de la base de code
- La gestion de la dette technique, la simplicité de la structure du code, sa modularité et sa cohérence sont directement liées à l’amélioration de la compréhension du code et de la productivité du LLM
- Des mécanismes automatisés de supervision et de vérification sont essentiels à la scalabilité à long terme en aidant le LLM à générer un code sûr et cohérent
Concepts clés pour faire évoluer les LLM
- La manière d’appliquer les LLM à de grandes bases de code n’est pas encore pleinement établie, mais investir dans le guidage et la supervision est présenté comme l’approche la plus efficace
- Le guidage (Guidance) désigne le contexte et l’environnement qui aident le LLM à faire les bons choix, tandis que la supervision (Oversight) consiste à vérifier les résultats générés et à en ajuster la direction
Investir dans le guidage
- Pour permettre au LLM de produire du code de haute qualité dès la première tentative, c’est-à-dire en « one-shot », il faut un guidage clair
- À l’inverse, quand le résultat est inadéquat et nécessite une correction manuelle, on tombe dans le rework, ce qui est inefficace
- Comme le LLM génère tous les choix présents dans le code — noms de variables, structure des fonctions, stack technique, etc. — l’idéal est que le prompt contienne uniquement les exigences métier, tout le reste pouvant être inféré ou déjà encodé
Construire une bibliothèque de prompts
- Une bibliothèque de prompts est un ensemble de contexte destiné au LLM, comprenant la documentation de la base de code, les bonnes pratiques et des cartes structurelles
- Chaque fois que la sortie du LLM dévie, il faut examiner « ce qui aurait dû être clarifié » et l’ajouter à la bibliothèque
- L’équilibre entre exhaustivité et concision est essentiel
- Dans l’exemple, des documents comme
@prompts/How_To_Write_Views.md,@prompts/The_API_File.md, etc. sont fournis au LLM pour guider le développement de fonctionnalités - Les prompts doivent être suffisamment spécifiques, mais il faut tout de même relire chaque ligne du code généré
Environnement et qualité du code
- Une base de code chargée en dette technique (technical debt) réduit l’efficacité d’utilisation des LLM
- Le cas de Meta est cité pour souligner que la dette technique a compliqué l’atteinte des objectifs d’automatisation
- Un code propre, modulaire, avec un nommage clair et une structure simple améliore la compréhension et la précision du LLM
- Dans l’exemple Django, chaque application place son point d’entrée dans un fichier
_api.py, afin de structurer le projet pour que le LLM trouve rapidement les fonctionnalités nécessaires- Exemple :
visit_api.handoff_to_doctor(user)comme point d’accès externe unifié - Le motif
_apiest explicité dans la bibliothèque de prompts pour orienter le LLM vers le bon emplacement
- Exemple :
Investir dans la supervision
- L’automatisation par LLM doit être pensée non pas comme un remplacement des ingénieurs, mais comme un moyen de renforcer l’équipe
- La supervision implique des investissements dans l’équipe, l’alignement (alignment) et les workflows
- À l’échelle de l’équipe, il est important d’améliorer les capacités de conception, ce qui se traduit ensuite par une meilleure qualité architecturale
- Parmi les moyens de renforcer les compétences en design, on cite la lecture de livres, de blogs et de code, la reproduction de masterworks, ainsi que la pratique d’implémentations directes
- Exemples : analyser du code de TLDraw, SerenityOS Jakt, etc. pour affiner son sens de la conception
Supervision automatisée
- Une partie de la validation de conception peut être automatisée de manière programmatique
- Exemple : fournir un feedback immédiat dans l’environnement en cas d’erreur de type ou de violation de règle
- La « safety » consiste à protéger les abstractions
- Selon la définition de Pierce, un langage sûr garantit qu’un programmeur ne puisse pas casser involontairement les abstractions
- Exemple : automatiser, via un script d’inspection basé sur l’AST, une règle interdisant l’accès direct aux fichiers internes entre applications Django
- Détection d’accès illégaux de la forme
from visit import logic.internal_file
- Détection d’accès illégaux de la forme
Vérification (Verification)
- Au-delà de la conception et de l’implémentation, l’étape de vérification (code review, QA) est indispensable pour garantir la qualité
- À mesure que la charge de travail augmente, la vitesse de revue devient un goulot d’étranglement ; plusieurs pistes d’amélioration sont proposées
- Réduire les barrières pour permettre de faire la QA même sans environnement de développement
- Mettre en place un environnement où écrire des tests est simple, notamment pour la génération de données de test
- Documenter les retours récurrents sur les PR afin de permettre au LLM d’automatiser une partie de la revue
- Intégrer les règles de sécurité dans les valeurs par défaut du framework
Conclusion et observations complémentaires
- Les LLM fonctionnent particulièrement bien sur les projets greenfield
- Parce qu’il n’existe pas encore de contexte hérité et que les exigences de cohérence y sont moindres
- Plus un projet grandit, plus la cohérence et la modularité déterminent la productivité
- Une structure modulaire réutilisant des composants validés est la clé d’un développement efficace
1 commentaires
Avis sur Hacker News
À mesure que les modèles s’améliorent, ils sont devenus capables de gérer des codebases complexes et de longs fichiers
J’ai donc créé une boucle de framework simple que je réutilise en continu
En faisant tourner cette boucle pendant 20 à 30 minutes, on obtient des résultats assez exploitables. Au fond, l’essentiel est de gérer le contexte et de mettre en place une boucle de feedback par les tests
Si on lance l’exploration avec le mot-clé « explore », ils peuvent faire la phase de recherche sans plan séparé ni réinitialisation du contexte
En revanche, ils ont tendance à supposer que le langage est du C ou du Python, et génèrent parfois du code non structuré, par exemple en découpant l’état en cinq fonctions au lieu de l’encapsuler dans un objet
De plus, Claude ignore souvent CLAUDE.md ; il est donc plus fiable de lui faire lire ce fichier d’abord, puis de lancer « explore »
Les modèles récents éliminent assez bien le contexte inutile, mais avec les anciens, une approche fondée sur un document de plan reste souvent meilleure
Il m’est souvent arrivé de le voir exécuter les plans et consignes à l’exact opposé, ou relire la même phrase pour en tirer la conclusion inverse
Pendant un temps, j’ai cru qu’on pouvait bâtir un processus centré sur les LLM, mais j’en suis bien moins convaincu aujourd’hui
Quand le modèle est dans un « bon état », ça va, mais le mettre dans cet état reste encore largement une question de chance
J’ai ajouté à Claude Code des commandes personnalisées comme
/research_codebase,/create_plan,/implement_planQuand on révise et corrige soigneusement, ça marche très bien, mais ça n’a pas réussi à se diffuser dans toute l’équipe
Je ne réinitialise le contexte que lorsque je crée une fonctionnalité totalement nouvelle. Dans Codespaces ça va, mais la fonctionnalité Tasks est presque inutile
Si on lui confie un gros travail, il peut partir dans une direction absurde, donc il faut le surveiller en permanence
C’est aussi très utile pour le repriming du contexte, donc je m’en sers souvent
Pour rendre une bibliothèque de prompts utile, il faut une amélioration itérative
Chaque fois qu’un LLM dévie légèrement, je me demande : « Qu’aurais-je dû clarifier davantage ? », puis j’ajoute la réponse au prompt
Appuyer simplement sur Entrée ou tout approuver automatiquement ne fait que gaspiller des tokens. À la place, j’observe où le LLM bloque et je le note brièvement dans CLAUDE.md
Quand le fichier de contexte grossit trop, je le sépare par type de tâche
Mes principaux cas d’usage sont l’exploration de la codebase, le suivi des chemins d’exécution et la fourniture de résumés des fichiers nécessaires. Définir le format attendu de restitution selon le type de question rend le tout bien plus efficace
J’appelle cela le « Student Pattern (Fresh Eyes) ». Un subagent lit la documentation ou le code avec le regard d’un débutant et repère les zones de confusion, contradictions et informations manquantes
C’est excellent pour faire émerger les connaissances implicites que les développeurs oublient. Très utile comme étape préalable à la relecture de nouvelle documentation ou à l’évaluation d’un prompt
Même si on lui dit plusieurs fois de lire CLAUDE.md, il l’ignore fréquemment, y compris de façon aléatoire juste après le début d’une session
Même avec tous les documents et commandes prêts, il lui arrive encore très souvent « d’oublier »
Je fais des expérimentations pour structurer de grandes codebases de façon agent-friendly
Je décompose le projet en graphe orienté basé sur des flakes nix, où chaque nœud dispose de son propre environnement de développement indépendant
En lançant Claude Code dans le devshell du flake, il ne voit que ce périmètre, ce qui évite la surcharge de contexte
Je fais collaborer les flakes via leurs entrées/sorties, en leur faisant s’échanger demandes de fonctionnalités et tests
Je pense que cette segmentation du contexte est la clé pour réduire le problème d’explosion des tokens
Au lieu de simplement améliorer les workflows existants, il faut concevoir une structure nouvelle que les LLM peuvent faire évoluer facilement
J’explore la relation entre des propriétés comme la « testabilité, l’extensibilité et la sécurité » et la structure du code
J’ai fait des expériences similaires sur des projets basés sur Docker, et j’aimerais qu’il existe un outil pour automatiser cela
Les LLM expliquent très bien les sujets que je maîtrise mal, mais dans mes domaines d’expertise, ils se trompent avec assurance
J’ai un point de vue différent. La meilleure façon d’améliorer les performances des LLM, c’est d’intégrer le sens directement dans la codebase
Autrement dit, un code structuré comme en DDD (Domain-Driven Design) est aussi plus facile à comprendre pour un LLM
Essayer de forcer des outils à manipuler un code complexe, c’est gaspiller de l’argent
Au fond, ce que les LLM ont prouvé, c’est que la philosophie du DDD, centrée sur « le langage et le sens », était juste
Article connexe : DDD & the Simplicity Gospel
À la question « Pourquoi les LLM marchent-ils bien sur les projets greenfield ? », j’ai eu l’expérience inverse
Dès qu’un motif se répète 2 ou 3 fois dans une codebase, le LLM l’apprend et le reproduit de façon cohérente
Mais la « cohérence » n’est pas la « qualité ». Si on vise seulement la cohérence sans critère, on obtient du code impossible à maintenir
Dire que « le code qu’un ingénieur ne comprend pas, un LLM ne le comprendra pas non plus » est vrai, mais l’inverse ne l’est pas
Il y a de nombreux cas où des humains comprennent, mais pas les agents
Rendre une codebase plus compréhensible pour des agents que pour des humains est encore plus difficile
Certains disent que « si on transfère le feedback à l’ordinateur, le taux de réussite en one-shot augmente », mais c’est un peu comme affirmer P=NP
Ce n’est pas parce que la vérification est facile que trouver la solution l’est aussi
Des langages comme ATS ou Idris permettent d’écrire avec le code des preuves de correction
Si cette thèse était vraie, les LLM devraient obtenir leurs meilleures performances avec ce type de langage
Or ce n’est pas ce qu’on observe. Au final, je pense qu’aujourd’hui mieux vaut attendre une amélioration des modèles
À cause de ces problèmes, je pense que les frameworks très directifs vont améliorer la productivité du code assisté par IA
Comme le LLM connaît déjà les règles du framework, il n’y a pas besoin de directives supplémentaires
En revanche, Go, Rust, Elixir et C# demandaient beaucoup plus de dépendances et de consignes
Rust donnait de bons résultats, mais allait chercher plus de 200 packages, ce qui était très lourd
Le principe « Garbage in, garbage out » est vrai, mais il ne s’applique pas complètement aux LLM
Ils ont été entraînés sur le bruit de l’ensemble d’Internet, et pourtant ils fonctionnent plutôt bien
Les hallucinations surviennent plus souvent à cause d’un contexte inexact qu’à cause d’un simple bruit
Même une codebase mal structurée peut encore fournir un contexte utile si elle contient beaucoup d’informations
Au fond, les gens sont en train de réapprendre les principes de base
Ils redécouvrent que la documentation (= bibliothèque de prompts) et une structure de code bien rangée accélèrent le développement