Les agents de programmation par IA s'améliorent-ils vraiment?

Six mois de données de diagnostics disent oui, avec des réserves

Introduction

Lorsque les agents de programmation de Kiro IDE écrivent ou modifient du code, l'outil de diagnostics exécute des analyseurs statiques pour vérifier le résultat. Ce sont les mêmes vérifications qu'un développeur voit soulignées dans son éditeur. En pratique, l'outil détecte des choses comme un import de module manquant (Cannot find module 'aws-cdk-lib' or its corresponding type declarations), un import Java non résolu (The import org.junit cannot be resolved), une incompatibilité de type (Argument of type 'string | undefined' is not assignable to parameter of type 'string'), un implicitly typed any, ou un undefined symbol. Ce sont le genre de problèmes qui, autrement, n'apparaîtraient qu'au moment de la compilation.

Pour récapituler comment l'outil de diagnostics fonctionne concrètement dans Kiro, la capture d'écran ci-dessous montre l'outil en action : prenons le code TypeScript suivant, où l'outil signale deux incompatibilités de type (Type 'number' is not assignable to type 'string' et Cannot assign to read-only 'executionTime') et une hallucination de propriété (Property 'itemAge' does not exist on type 'StackProps'). Ces diagnostics fournissent à l'agent une rétroaction concrète pour générer des corrections et revalider les changements. Cette boucle générer → valider → affiner se produit fréquemment avec les langages à typage statique, où de nombreuses erreurs de programmation courantes peuvent être détectées tôt par les serveurs de langage.

Chargement de l'image...Capture d'écran du clavardage de Kiro exécutant la boucle de diagnostics sur ecs-cluster-stack.ts : l'agent vérifie les diagnostics et trouve 3 erreurs (une incompatibilité de type « number non assignable à string » à la ligne 25, une écriture dans « executionTime » en lecture seule à la ligne 45, et une propriété « itemAge » hallucinée sur StackProps à la ligne 55), accepte les modifications du fichier, revérifie les diagnostics et signale 0 erreur.
Figure 1 : L'outil de diagnostics en action — l'agent détecte trois erreurs, modifie le fichier, revérifie et confirme qu'il ne reste aucune erreur.

Ce billet examine les invocations de l'outil de diagnostics par l'agent pendant la génération : à quelle fréquence le modèle appelle volontairement les analyseurs statiques en cours de tâche, quelles erreurs ces analyseurs révèlent, et si le modèle les résout avant de produire sa modification finale.

Les diagnostics sont produits par les extensions de langage que le développeur a installées dans son IDE, de sorte que l'ensemble des vérifications varie selon la configuration de l'espace de travail. Dans nos données, les diagnostics proviennent des analyseurs standards derrière chaque écosystème : tsserver pour TypeScript/JavaScript, jdtls pour Java, Pyright pour Python, rust-analyzer pour Rust, le serveur de langage Kotlin, gopls pour Go, clangd pour C/C++, et des linters de style et de justesse comme ESLint. Nous avons aussi observé des diagnostics Swift (Cannot switch on a value of type Region. Only convertible int values, strings or enum variables are permitted) et, au-delà des erreurs de compilation conventionnelles, des diagnostics du démonstrateur de théorèmes Lean 4, où l'outil signale non pas une coquille de syntaxe mais une preuve incomplète (Dependent elimination failed: Failed to solve equation, unsolved goals).

Au cours des six derniers mois, Kiro a pris en charge différentes familles et variantes de modèles, d'Opus 4.5 à 4.8 et de Sonnet 4 à 4.6.

On pourrait s'attendre à ce que les modèles plus récents génèrent simplement moins d'erreurs. Et bien que les taux d'erreur diminuent, le portrait est plus nuancé que cela. Ces modèles ne font pas que commettre moins d'erreurs; ils commettent des erreurs de nature différente. Des catégories d'erreurs qui dominaient les générations précédentes disparaissent, tandis que de nouvelles émergent à leur place. La trajectoire globale est positive, mais le changement dans la composition des erreurs mérite d'être compris. Dans cet article, nous présentons ce que nous avons trouvé.

Distinguer la qualité de l'état final des signaux d'autocorrection intermédiaires. Il existe deux façons complémentaires d'évaluer si les agents de programmation par IA s'améliorent. La première est l'analyse statique a posteriori : exécuter un ensemble fixe d'analyseurs sur le résultat final de l'agent et compter les erreurs résiduelles. Cela mesure la qualité du code à l'état final (l'artefact que le développeur reçoit réellement) et constitue l'indicateur le plus direct de « le modèle a-t-il produit du code correct? ». La seconde, que cette étude examine, est les invocations de l'outil de diagnostics par l'agent pendant la génération : à quelle fréquence le modèle appelle volontairement les analyseurs statiques en cours de tâche, quelles erreurs ces analyseurs révèlent, et s'il les résout avant de produire sa modification finale.

Ce dernier signal est strictement plus informatif sur la capacité du modèle, pour deux raisons. Premièrement, il capte la capacité du modèle à s'autosurveiller, une propriété comportementale invisible dans la mesure de l'état final, puisqu'un modèle qui ne vérifie jamais son travail et produit par hasard du code propre est indiscernable d'un modèle qui vérifie, détecte les erreurs et les corrige. Deuxièmement, les données au niveau des invocations offrent une décomposition plus riche : elles révèlent quelles catégories d'erreurs le modèle génère, lesquelles il peut corriger de façon autonome, et à quel coût en appels d'outils supplémentaires, offrant une vue granulaire des endroits où la cognition du modèle réussit ou échoue. L'analyse de l'état final, en revanche, réduit ce processus à un seul bit réussite/échec. En bref, l'analyse a posteriori vous dit quelle qualité l'utilisateur a reçue; les données d'invocation de diagnostics vous disent comment le modèle a atteint (ou n'a pas atteint) cette qualité, ce qui en fait un signal plus fort pour diagnostiquer les trajectoires d'amélioration des modèles au fil du temps.

Les données

Sur une fenêtre de six mois, de janvier à juin 2026, nous avons analysé environ 1,5 million de conversations dans Kiro IDE à travers sept modèles Claude (Opus 4.5 à 4.8 et Sonnet 4 à 4.6) couvrant plusieurs langages, dont TypeScript, Python, Java, Rust, Go, Kotlin, C++ et Swift. Les données provenaient d'utilisateurs internes d'Amazon.

Nous avons extrait 406 000 invocations de diagnostics, les moments où l'agent a appelé l'outil intégré qui utilise des extensions d'analyse statique pour vérifier les fichiers de code. Opus 4.5 et 4.6 représentent plus de 51 % des données analysées, constituant l'essentiel du volume. Les modèles Opus plus récents ont moins de points de données. Les invocations de Sonnet 4.5 représentent 45 % supplémentaires de toutes les requêtes analysées, tandis que Sonnet 4 et 4.6 ont moins de points de données.

Mises en garde. Trois choses à garder à l'esprit pour interpréter ces résultats.

Ce que nous mesurons, et ce que nous ne mesurons pas. Les diagnostics analysés ici proviennent de l'outil de diagnostics de Kiro IDE, qui s'exécute après que l'agent de programmation a effectué des modifications de fichiers. Il repose sur les extensions installées dans l'environnement de l'utilisateur, généralement des serveurs de langage et des analyseurs statiques (tsc de TypeScript, ESLint, Pylint, etc.) ainsi que des extensions liées à l'infrastructure comme les validateurs CloudFormation et Terraform qui vérifient les propriétés des ressources, les arguments requis et les références de ressources avant le déploiement. Cela signifie que nous ne capturons qu'un sous-ensemble des problèmes. Les erreurs d'exécution, les bogues de logique, les régressions de performance et tout ce qui requiert une analyse dynamique ou des tests sont invisibles pour ces données. Une vérification de diagnostics propre ne signifie pas que le code est correct; cela signifie seulement que le code passe l'analyse statique.

L'environnement varie d'un utilisateur à l'autre. Les diagnostics disponibles dépendent des extensions installées par l'utilisateur. Un développeur ayant des règles ESLint strictes et un validateur CloudFormation fera apparaître plus d'avertissements qu'un autre avec une configuration minimale. Cela rend les comparaisons entre utilisateurs bruitées et signifie que les taux d'erreur agrégés reflètent un mélange de qualité de programmation et de sévérité de l'outillage. En pratique, on devrait évaluer la qualité de la programmation par IA par pile technologique, par langage et par environnement, en plus du taux d'erreur. Cela dit, comme nos données proviennent d'utilisateurs internes d'Amazon qui partagent des normes d'outillage et des pratiques exemplaires communes, la variabilité des environnements dans ce jeu de données est probablement plus étroite qu'elle ne le serait dans la population générale des développeurs.

Les améliorations des modèles ne sont pas la seule variable. Les diagnostics ne s'exécutent pas de façon isolée. Ils fonctionnent au sein d'un système plus large qui comprend le Steering, les Hooks, les sous-agents et d'autres couches d'orchestration qui façonnent la manière dont les modèles génèrent du code. Des changements apportés à l'un ou l'autre de ces composants au cours de la fenêtre de six mois pourraient affecter les taux d'erreur indépendamment des améliorations de capacité des modèles. Nous ne pouvons pas attribuer proprement les améliorations montrées ici aux seules mises à niveau des modèles. Certaines portions reflètent probablement une meilleure infrastructure environnante. Démêler les deux nécessiterait des expériences contrôlées qui maintiennent fixe la couche d'orchestration, ce que ces données observationnelles ne permettent pas.

1. À quelle fréquence les modèles appellent-ils les diagnostics?

Nous avons d'abord examiné le taux d'invocation des diagnostics : la fraction des conversations de programmation dans lesquelles le modèle a choisi d'appeler l'outil de diagnostics au moins une fois. Ce ratio reflète à quel point un modèle utilise proactivement l'outillage de diagnostics disponible pour vérifier son propre travail.

Chargement de l'image...Graphique linéaire intitulé « Diagnostics Invocation Rate » comparant Opus et Sonnet selon les versions : Opus 4.5 14,58 %, Opus 4.6 22,26 % (le point le plus élevé), Opus 4.7 10,15 %, Opus 4.8 10,85 %; Sonnet 4 7,65 %, Sonnet 4.5 2,74 % (le point le plus bas), Sonnet 4.6 13,89 %.
Figure 2 : Part des conversations de programmation dans lesquelles chaque modèle a invoqué l'outil de diagnostics au moins une fois.

Opus 4.6 se démarque comme le plus proactif, invoquant les diagnostics dans 22,26 % de ses conversations. Cependant, les versions Opus suivantes (4.7 et 4.8) sont redescendues à environ 10 %. La famille Sonnet raconte une histoire différente : Sonnet 4.5 n'a presque pas invoqué les diagnostics (2,74 %), mais Sonnet 4.6 a bondi à 13,89 %, une forte hausse qui signale une prise de conscience croissante de l'outil. Dans l'ensemble, les taux d'invocation se situent autour de 3 à 22 %, ce qui indique que la plupart des conversations sont encore menées à terme sans que le modèle vérifie proactivement les erreurs détectées statiquement. Cela concorde avec des résultats récents montrant que les modèles s'en tiennent par défaut aux outils vus à l'entraînement et utilisent rarement l'outillage de diagnostics sans requête explicite ni affinage. Des expériences similaires suggèrent que le fait d'utiliser les diagnostics pour empêcher l'agent de finaliser tant que les erreurs ne sont pas résolues peut réduire considérablement l'acceptation de code incorrect, d'environ 90 % à environ 8 %, un effet bien plus important que le simple fait de rendre les diagnostics disponibles comme outil optionnel.

2. Erreurs signalées par fichier vérifié : les modèles s'améliorent-ils?

Nous avons comparé le nombre moyen d'erreurs signalées par fichier à travers les versions successives des modèles. Cette mesure reflète à quel point le code généré est « près de compiler ». Même lorsqu'il n'y parvient pas complètement, moins d'erreurs par fichier signifie moins de corrections manuelles.

Chargement de l'image...Graphique linéaire intitulé « Average Errors per File » : la courbe Sonnet chute de 3,01 (Sonnet 4) à 2,90 (Sonnet 4.5) puis à 1,29 (Sonnet 4.6); la courbe Opus indique 1,74 (Opus 4.5), 1,21 (Opus 4.6), 1,82 (Opus 4.7), 1,21 (Opus 4.8), les deux familles convergeant vers environ 1,2 dans leurs versions les plus récentes.
Figure 3 : Nombre moyen d'erreurs de diagnostics signalées par fichier vérifié, selon la version du modèle.

La courbe Sonnet raconte une nette amélioration. De 3,01 erreurs par fichier pour Sonnet 4 à 1,29 pour Sonnet 4.6, nous avons observé une réduction de 57 %. La famille Opus présente un profil non monotone. Opus 4.6 et 4.8 atteignent tous deux 1,21, tandis qu'Opus 4.5 et 4.7 se situent plus haut, autour de 1,7 à 1,8. Cela pourrait suggérer qu'au sein de la famille Opus, toutes les versions ne représentent pas une amélioration stricte en matière de diagnostics détectés statiquement. Dans l'ensemble, les deux familles convergent vers environ 1,2 erreur par fichier vérifié dans les versions les plus récentes de notre étude. Cela pourrait indiquer un progrès significatif vers des modèles qui produisent du code compilable d'emblée.

3. Fichiers vérifiés par invocation : portée plus large ou plus étroite

Au-delà des taux d'erreur, nous avons remarqué quelque chose d'intéressant sur la manière dont les modèles utilisent l'outil de diagnostics. Les modèles plus récents vérifient plus de fichiers par invocation.

Chargement de l'image...Graphique linéaire intitulé « Files Checked per Invocation » : Opus passe de 1,78 (Opus 4.5) à 1,87 (Opus 4.6) puis 2,04 (Opus 4.7) et 1,91 (Opus 4.8); Sonnet passe de 1,57 (Sonnet 4) à 1,72 (Sonnet 4.5) puis 1,86 (Sonnet 4.6), montrant que les modèles plus récents vérifient plus de fichiers par appel.
Figure 4 : Nombre moyen de fichiers vérifiés chaque fois qu'un modèle a invoqué l'outil de diagnostics.

Au début, Sonnet 4 vérifiait en moyenne 1,57 fichier chaque fois qu'il appelait les diagnostics, essentiellement un fichier à la fois, parfois un deuxième à l'occasion. Avec Sonnet 4.5, ce nombre a grimpé à 1,72, et Sonnet 4.6 a atteint 1,86. La famille Opus montre une tendance similaire. Opus 4.5 a vérifié en moyenne 1,78 fichier par appel; Opus 4.6 a atteint 1,87; Opus 4.7 a culminé à 2,04; et Opus 4.8 s'est stabilisé à 1,91.

Cela importe parce que cela représente un changement de stratégie de vérification du code. Plutôt que de modifier un fichier et de ne vérifier que ce fichier, les modèles plus récents vérifient de plus en plus ensemble les fichiers liés, p. ex. l'implémentation et son test, ou un module et ses consommateurs.

Le passage d'environ 1,6 fichier par appel à environ 2,0 fichiers par appel peut sembler modeste, mais sur des centaines de milliers d'invocations, cela signifie que les modèles détectent les régressions inter-fichiers (p. ex. imports brisés, incompatibilités d'interface et erreurs de type en aval) plus souvent que les générations précédentes.

4. Les 5 principales catégories d'erreurs signalées

Pour comprendre la nature des erreurs diagnostiquées, nous avons catégorisé les types d'erreurs et visualisé la distribution pour chaque modèle indépendamment.

Chargement de l'image...Sept graphiques en anneau intitulés « Error Category Breakdown by Model » pour Opus 4.5, 4.6, 4.7, 4.8 et Sonnet 4, 4.5, 4.6, répartis entre imports non résolus, symboles non définis, erreurs de syntaxe, implicit any, accès aux propriétés, références non résolues, résolution de la bibliothèque standard Kotlin, et autres; les imports non résolus constituent la plus grande part dans chaque modèle et atteignent 57,6 % pour Opus 4.7, tandis que des modèles comme Sonnet 4.5 et Opus 4.5 se répartissent plus uniformément entre les catégories.
Figure 5 : Distribution des catégories d'erreurs de diagnostics pour chaque modèle.

Pour tous les modèles, les « imports non résolus » constituent à eux seuls la plus grande catégorie d'erreurs, représentant environ un tiers de tous les diagnostics dans la plupart des cas, et plus de la moitié pour Opus 4.7. Les « symboles non définis » et une longue traîne d'erreurs du système de types (erreurs de syntaxe, références non résolues, implicit any, etc.) composent le reste. Fait notable, la distribution des erreurs diffère selon les modèles : Opus 4.7 est fortement dominé par les échecs de résolution d'imports avec relativement peu d'autres types d'erreurs, tandis que des modèles comme Sonnet 4.5 et Opus 4.5 présentent une répartition plus uniforme entre les catégories. Cela pourrait suggérer que différents modèles échouent de différentes manières. Certains peinent surtout avec la résolution des dépendances, tandis que d'autres répartissent leurs erreurs plus largement sur le système de types et les symboles.

5. Fichier source ou fichier de test : lequel introduit le plus d'erreurs?

Le code de test est systématiquement plus difficile à réussir pour les modèles. Les tests font intervenir des cadres de simulation (mocking), des bibliothèques d'assertions et des modèles de configuration complexes qui exigent de comprendre à la fois l'outil de test et le code testé.

Chargement de l'image...Graphique en haltères intitulé « Source Files vs. Test Files: Average Errors » par modèle, erreurs de source en bleu et erreurs de test en rouge : Opus 4.5 1,35 c. 5,98, Opus 4.6 0,96 c. 3,64, Opus 4.7 1,40 c. 4,62, Opus 4.8 0,81 c. 6,00, Sonnet 4 2,20 c. 7,31, Sonnet 4.5 2,26 c. 9,13 (l'écart le plus grand), Sonnet 4.6 1,08 c. 3,56, les fichiers de test étant toujours bien plus élevés que les fichiers source.
Figure 6 : Nombre moyen d'erreurs par fichier dans les fichiers source par rapport aux fichiers de test, selon le modèle.

La famille Opus maintient généralement les erreurs de fichiers source sous 1,4, mais leurs erreurs de fichiers de test vont de 3,64 (Opus 4.6) à 6,00 (Opus 4.8). Sonnet 4.5 présente l'écart le plus grand, avec 2,26 erreurs par fichier source mais 9,13 par fichier de test. Sonnet 4 produit 2,20 erreurs de source et 7,31 erreurs de test, tandis que Sonnet 4.6 est la variante Sonnet la plus performante, à 1,08 et 3,56 respectivement. Il apparaît que, peu importe la taille ou la génération du modèle, les fichiers de test demeurent la source dominante d'erreurs.

6. Le paysage des langages : Java est difficile, Python est facile

Certains langages introduisent plus d'erreurs que d'autres lors de la génération de code. En regardant les taux d'erreur au niveau des fichiers pour Opus 4.6 (notre plus grand trafic), l'écart est énorme. Cela dit, ces chiffres sont façonnés par deux facteurs au-delà de la capacité du modèle : la précision des extensions d'analyse statique que les clients ont installées (des linters plus stricts font apparaître plus de problèmes), et la variation dans la façon dont la base d'utilisateurs de Kiro IDE utilise chaque langage.

Chargement de l'image...Diagramme à barres horizontales intitulé « File Error Rate by Language — Opus 4.6 » (lower is better), classé du plus faible au plus élevé : JavaScript 1,6 %, Python 4,0 %, Go 8,0 %, Kotlin 8,5 %, TypeScript 8,6 %, TSX (React) 11,2 %, C++ 12,2 %, Rust 15,1 % et Java 26,7 % (la plus longue barre).
Figure 7 : Part des fichiers générés comportant au moins une erreur de diagnostics, par langage, pour Opus 4.6 (plus le taux est faible, mieux c'est).

Java arrive en tête avec un taux d'erreur par fichier de 26,7 %. Cela signifie que plus d'un fichier Java généré sur quatre contient au moins une erreur de diagnostics. La combinaison d'imports verbeux, de génériques complexes, d'exceptions vérifiées et d'une résolution de types stricte en fait le langage le plus difficile pour les modèles d'IA que nous avons analysés dans cette étude, et de loin. Rust vient ensuite à 15,1 %, suivi de C++ à 12,2 %.

Le palier intermédiaire est composé de TSX/React, TypeScript, Kotlin et Go, dont le taux d'erreur se situe entre 8 et 11 %. Ce sont des langages à typage statique dotés d'assez de structure pour faire trébucher le modèle, mais pas aussi exigeants que Java.

Tout en bas se trouvent Python (4,0 %) et JavaScript (1,6 %). Le typage dynamique de Python, l'absence de code d'amorçage pour les imports et sa syntaxe indulgente produisent des résultats constamment propres. Le taux plancher de 1,6 % de JavaScript est un peu trompeur. Il reflète l'analyse statique minimale disponible pour le JS ordinaire plutôt qu'un modèle qui écrit du meilleur code. Lorsqu'on ajoute par-dessus le système de types de TypeScript, le taux bondit à 8,6 %. La même mise en garde qui s'applique à JavaScript s'applique plus subtilement à Python. En tant que langage à typage dynamique avec une analyse statique généralement légère, certaines erreurs de Python n'apparaissent comme diagnostics qu'à l'exécution. Ainsi, un faible taux d'erreur statique reflète ce qui est détectable au moment de l'édition, et non que le code est nécessairement plus correct qu'en Java, où le compilateur détecte presque tout d'entrée de jeu.

Si votre équipe utilise intensivement des agents de programmation par IA sur des bases de code Java, attendez-vous à passer plus de temps à nettoyer les diagnostics que sur des bases de code Python ou TypeScript.

Conclusion

Six mois et près d'un demi-million d'invocations de diagnostics nous montrent que les agents de programmation par IA s'améliorent de façon mesurable pour écrire du code correct, mais le portrait est plus nuancé qu'un simple chiffre.

  • Les taux d'erreur diminuent. Les deux familles de modèles convergent vers environ 1,2 erreur par fichier dans leurs versions les plus puissantes.
  • Les modèles invoquent l'outil de diagnostics de façon proactive dans 3 à 22 % des conversations.
  • Les modèles plus récents vérifient plus de fichiers à la fois. Dans les modèles plus récents, les fichiers liés (p. ex. l'implémentation ainsi que ses tests) sont plus souvent vérifiés ensemble.
  • Les imports non résolus dominent. Ils représentent environ 30 à 58 % de toutes les erreurs, peu importe le modèle.
  • Le code de test semble 3 à 4 fois plus difficile à réussir. Les cadres de simulation (mocking) et les bibliothèques d'assertions produisent systématiquement bien plus d'erreurs que les fichiers d'implémentation.
  • Le langage compte. Le taux d'erreur de Java (26,7 %) est 6,7 fois celui de Python (4,0 %); le faible 1,6 % de JavaScript reflète une analyse statique faible plutôt qu'une meilleure génération.

Les diagnostics s'exécutent automatiquement à mesure que les agents de Kiro écrivent et affinent du code. Pour voir comment cela fonctionne et aller plus loin, consultez la documentation sur les diagnostics et l'aperçu des modèles, et téléchargez Kiro pour l'essayer sur votre propre base de code.