L’IA et la programmation : une (courte) histoire et de grandes promesses
Je me souviens, il y a quatre ans environ (ça semble déjà une éternité), lorsque j’ai vu la première démo d’une IA (je crois que c’était GPT-2) écrivant du code. C’était une simple page web, basée sur une description basique. C’était vraiment impressionnant, une belle perspective sur un monde où je n’aurais plus jamais à écrire de CSS.
Quelques mois plus tard, ChatGPT était lancé et pouvait écrire des fonctions simples. La complexité des fonctions qu’il pouvait générer n’a fait qu’augmenter depuis. Les outils des développeurs se sont adaptés à ce changement. Au début, « coder avec l’IA » signifiait copier-coller du code depuis un chat vers un IDE. Des extensions pour réduire cette friction sont apparues rapidement (Copilot, Cline, Continue.dev…). Celles-ci intégraient directement le chat dans l’IDE et affichaient un diff des modifications proposées, qu’on pouvait valider d’un simple clic.
Mais la forme ultime (jusqu’ici, du moins) de l’IA en programmation semble être les agents1 programmeurs basés dans le terminal, capables d’accéder au système, d’utiliser la ligne de commande et d’interagir avec un ordinateur de la même manière qu’un développeur. L’humain devient un superviseur d’IA qui codent au lieu d’écrire le code lui-même, et parfois même au lieu de comprendre le code lui-même.
La promesse des laboratoires d’IA est que la complexité des tâches de programmation que l’IA peut accomplir continuera d’augmenter, jusqu’à ce que les développeurs ne soient plus nécessaires comme intermédiaires entre les non-techniciens et les ordinateurs.
Exemples d’erreurs stupides
En guise d’interlude avant de lister les modes d’échec plus généraux, voici une liste d’erreurs très concrètes que fait l’IA quand je code :
- Effacer les commentaires du code, dans des endroits sans rapport avec la tâche en cours.
- Importer de nouvelles bibliothèques pour tout et n’importe quoi.
- Se tromper sur les numéros de ligne :
« Regarde à la ligne 54 » pour quelque chose qui est à la ligne 80. - Des réponses paresseuses :
« Pour implémenter cette fonctionnalité, écris simplement une fonction qui fait ça. », sans le faire elle-même (ça arrive de moins en moins) - Ou pour les tâches répétitives :
« Voici la première de faite, trouve les autres et fais de même. » (celui-là est assez rare, mais ça m’est déjà arrivé quelques fois)
Modes d’échec généraux
« Neuf femmes ne peuvent pas faire un bébé en un mois »
« Neuf femmes ne peuvent pas faire un bébé en un mois » est une citation tirée de The Mythical Man-Month, un classique bien connu en génie logiciel. Elle illustre le fait que, lorsqu’un projet prend du retard, ajouter plus de programmeurs ralentit le projet au lieu de l’accélérer. Parce que l’équipe existante doit former les nouveaux membres, parce que ceux-ci doivent apprendre le fonctionnement du projet, et parce que tous doivent apprendre à travailler ensemble et à communiquer. De plus, les efforts de communication doivent augmenter de manière exponentielle avec l’ajout de personnes. Cette tâche d’intégration d’équipe est plus difficile qu’il n’y paraît et ralentit les équipes, du moins jusqu’à ce que les nouveaux membres soient vraiment intégrés.
Les agents de code rencontrent les mêmes problèmes que les vrais développeurs, mais avec des difficultés supplémentaires inhérentes à leur nature. Les projets complexes sont difficiles à gérer, et obtenir le bon contexte pour traiter un problème particulier est compliqué. Divers outils de code commencent à s’attaquer à ce problème de « context engineering », c’est-à-dire trouver les bons morceaux de code à injecter dans le prompt pour que le modèle prenne les bonnes décisions.
Mais surtout, les agents de code sont très mauvais pour le travail d’équipe, et aucun des grands labos ne travaille là-dessus actuellement. Leur style de communication est fixé dans les poids du modèle de langage. Ils peuvent donc s’adapter à un interlocuteur au cours d’une conversation, mais chaque nouvelle session réinitialise cet apprentissage. Ils s’adaptent encore moins à une équipe entière, car ils sont généralement liés à la machine/compte d’un individu.
Pourquoi est-ce que ce sujet n’est pas plus discuté ? Mon hypothèse est que ces notions sont un peu floues, et difficiles à définir et à évaluer. Et les entreprises se concentrent sur des benchmarks (donc des métriques facilement mesurables) qui impliquent en plus de résoudre des problèmes seul, et non en collaboration avec une équipe.
Un génie amnésique
La mémoire des agents de code est différente de la mémoire humaine, et fonctionne de manière contre-intuitive. Leur harnais peut les aider à se souvenir mot pour mot d’une conversation qui date de trois mois, mais ils ne récupèrent généralement pas ces souvenirs d’eux-mêmes, ou pas de manière fiable. Actuellement, beaucoup de travaux se concentrent sur la sélection du contexte approprié pour la tâche en cours, mais l’accent est mis sur le code plutôt que sur les conversations passées.
En conséquence, les agents de code ont tendance à suivre uniquement les instructions données juste avant, sans tenir compte du reste du code. Ce sont comme des génies de la programmation, capables de construire en une fois des applications simples mieux qu’un humain, mais des génies amnésiques qui oublient tout à chaque fois que commence une nouvelle conversation. Ils ne respectent ni le style de travail ni le style de code de l’utilisateur. Ils essaient d’exécuter les instructions en un seul coup, mais cassent souvent le code existant au passage. Le code qu’ils ajoutent est souvent difficile à maintenir et finit par ajouter plus de travail pour les développeurs, sur le long terme.
L’astuce de la nouvelle session
La manière dont la mémoire des agents se réinitialise entre les sessions peut être frustrante, mais elle peut aussi parfois être un avantage. Il m’est arrivé quelquefois de passer des heures sur un problème avec un agent de code sans le résoudre ; mais après avoir démarré une nouvelle conversation, l’agent résout le problème immédiatement.
Cela arrive à cause du context momentum (inertie du contexte) : dans les longues discussions, le modèle peut rester bloqué sur de fausses hypothèses faites au début et ne plus les remettre en question. On peut alors passer des heures à chercher une erreur là où elle n’est pas, et la résoudre facilement après avoir commencé une nouvelle session, parce que la fausse hypothèse n’est plus dans le contexte du LLM.
Obéissance neutre-chaotique
Les modèles de langage n’ont pas de sentiments pour vous, pour l’état de votre projet, ou pour quoi que ce soit d’autre. Ils sont entraînés à compléter des phrases, et pas n’importe quelles phrases : la phase d’affinage les entraîne à compléter des conversations entre assistants et utilisateurs. Par conséquent, ils sont très obéissants.
C’est-à-dire qu’ils feront exactement ce que vous leur dites, même si c’est tellement stupide que ce qu’on a dit n’est clairement pas ce qu’on veut (par exemple écrire rm -rf / au lieu de rm -rf /.). Et généralement, ils ne vous préviendront pas. Comme leurs réponses ne sont pas déterministes et leur entraînement n’est pas parfait, les modèles de langage ont des performances inégales : parfois ils sont impressionnants, parfois ils font des choses stupides, mais ils essaient toujours de suivre les instructions.
Cela les rend instables, d’une certaine façon. Beaucoup de développeurs préféreront utiliser une IA capable d’implémenter de manière fiable des idées d’une certaine complexité, plutôt qu’une IA capable de gérer des tâches bien plus difficiles mais qui échoue parfois de manière imprévisible.
- My philosopher friend insists that they aren’t really agents and that the name is misused. ↩︎