Amazon Web Services ブログ
AI コーディングエージェントは本当に良くなっているのか?
本記事は「Are AI coding agents actually getting better?」を翻訳したものです。
Kiro IDE のコーディングエージェントがコードを書いたり変更したりすると、diagnostics ツールが静的解析器を実行して出力をチェックします。これは、開発者がエディタ上で下線として目にするのと同じチェックです。実際にこのツールは、モジュールの import 漏れ(Cannot find module 'aws-cdk-lib' or its corresponding type declarations)、解決できない Java の import(The import org.junit cannot be resolved)、型の不一致(Argument of type 'string | undefined' is not assignable to parameter of type 'string')、implicitly typed any、undefined symbol といったものを検出します。これらは、本来であればビルド時になって初めて表面化するような種類の問題です。
Kiro での diagnostics ツールの実際の動きをおさらいするために、下のスクリーンショットはツールが動作している様子を示しています。次の TypeScript コードを考えてみてください。ツールは 2 件の型の不一致(Type ‘number’ is not assignable to type ‘string’ と Cannot assign to read-only ‘executionTime’)と、1 件のプロパティのハルシネーション(Property ‘itemAge’ does not exist on type ‘StackProps’)を報告します。これらの diagnostics は、エージェントに対して修正を生成し、変更を再検証するための具体的なフィードバックを与えます。この「生成 → 検証 → 修正」のループは、静的型付け言語を扱うときに頻繁に発生します。多くのよくあるコーディングエラーを、language server が早期に捕捉できるためです。
図1: diagnostics ツールの動作。エージェントは 3 件のエラー(25 行目の number を string に代入できない型不一致、45 行目の read-only な ‘executionTime’ への書き込み、55 行目の StackProps に存在しない ‘itemAge’ プロパティのハルシネーション)を検出し、ファイルを編集して再チェックし、残りエラーがゼロであることを確認しています。
この記事では、生成中のエージェントによる diagnostics ツールの呼び出しを調べます。すなわち、モデルがタスクの途中でどのくらいの頻度で自発的に静的解析器を呼び出すのか、それらの解析器がどのようなエラーを表面化させるのか、そしてモデルが最終的な編集を行う前にそれらを解決しているのか、という点です。
diagnostics は、開発者が IDE にインストールしている言語拡張機能によって生成されるため、チェックの内容はワークスペースの構成によって変わります。今回のデータでは、diagnostics は各エコシステムの標準的な解析器から生成されています。TypeScript/JavaScript は tsserver、Java は jdtls、Python は Pyright、Rust は rust-analyzer、Kotlin は Kotlin language server、Go は gopls、C/C++ は clangd、そして ESLint のようなスタイル・正当性のリンターです。Swift の diagnostics(Cannot switch on a value of type Region. Only convertible int values, strings or enum variables are permitted)も観測されました。さらに従来のコンパイルエラーの枠を超えて、Lean 4 の定理証明器の diagnostics も観測されており、ここではツールが構文の誤りではなく不完全な証明を指摘しています(Dependent elimination failed: Failed to solve equation, unsolved goals)。
この 6 か月間、Kiro はさまざまなモデルファミリーとバリアントをサポートしてきました。Opus 4.5 から 4.8、Sonnet 4 から 4.6 までです。
新しいモデルは単純にエラーを生成しなくなる、と予想するかもしれません。エラー率は確かに低下しているものの、実態はそれよりも込み入っています。これらのモデルは単に間違いを減らしているのではなく、異なる種類の間違いをするようになっているのです。以前の世代で支配的だったエラーのカテゴリが姿を消し、その代わりに新しいカテゴリが現れています。全体の軌跡は前向きですが、エラー構成のこの変化は理解しておく価値があります。この記事では、私たちが見つけたことを共有します。
最終状態の品質と、途中の自己修正シグナルを区別する。AI コーディングエージェントが改善しているかどうかを評価するには、互いに補完的な 2 つの方法があります。1 つ目は事後(post-hoc)の静的解析で、エージェントの最終出力に対して固定の解析器一式を実行し、残存エラーを数える方法です。これは最終状態のコード品質(開発者が実際に受け取る成果物)を測るもので、「モデルは正しいコードを生成したか?」の最も直接的な代理指標です。2 つ目は本研究が調べるもので、生成中のエージェントによる diagnostics ツールの呼び出しです。すなわち、モデルがタスクの途中でどのくらいの頻度で自発的に静的解析器を呼び出すのか、それらの解析器がどんなエラーを表面化させるのか、そしてモデルが最終的な編集の前にそれらを解決しているのか、という点です。
この後者のシグナルは、2 つの理由からモデルの能力についてより多くを語ります。1 つ目に、これはモデルの自己監視の能力を捉えます。これは最終状態の計測では見えない振る舞い上の性質です。というのも、自分の成果物を一度もチェックせずにたまたまきれいなコードを出したモデルと、チェックしてエラーを検出し修復したモデルとは、最終状態だけを見ると区別がつかないからです。2 つ目に、呼び出しレベルのデータはより豊かな分解を可能にします。モデルがどのエラーカテゴリを生成するのか、そのうちどれを自律的に修正できるのか、そのために追加でどれだけのツール呼び出しがかかるのかを明らかにし、モデルの認知がどこで成功しどこで失敗するのかを粒度細かく見せてくれます。対して事後解析は、このプロセスを 1 つの合否ビットに畳み込んでしまいます。要するに、事後解析はユーザーが受け取った品質が何であったかを教えてくれますが、diagnostics 呼び出しのデータはモデルがその品質をどのように達成した(あるいは達成しそこねた)かを教えてくれ、時系列でのモデル改善の軌跡を診断するうえでより強力なシグナルになります。
データ
2026 年 1 月から 6 月までの 6 か月間の窓で、私たちは Kiro IDE における約 150 万件の会話を、7 つの Claude モデル(Opus 4.5 から 4.8、Sonnet 4 から 4.6)にわたり、TypeScript、Python、Java、Rust、Go、Kotlin、C++、Swift を含む複数の言語を対象に分析しました。データは Amazon 社内ユーザーから得たものです。
私たちは 40.6 万件の diagnostics 呼び出し、すなわちエージェントが静的解析拡張機能を使ってコードファイルをチェックする組み込みツールを呼び出した瞬間を抽出しました。Opus 4.5 と 4.6 が分析データの 51% 超を占め、ボリュームの大半を構成しています。より新しい Opus モデルはデータ点が少なめです。Sonnet 4.5 の呼び出しがさらに全分析リクエストの 45% を占め、Sonnet 4 と 4.6 はデータ点が少なめです。
これらの結果を解釈する際に心に留めておくべきことが 3 つあります。
私たちが測っているもの、測っていないもの。ここで分析している diagnostics は、コーディングエージェントがファイル編集を行った後に実行される Kiro IDE の Diagnostics Tool から来ています。これはユーザーの環境にインストールされた拡張機能に依存します。典型的には language server や静的解析器(TypeScript の tsc、ESLint、Pylint など)に加え、リソースのプロパティ・必須引数・リソース参照をデプロイ前にチェックする CloudFormation や Terraform のバリデーターといったインフラ関連の拡張機能です。つまり、私たちが捉えているのは問題の一部にすぎません。ランタイムエラー、ロジックのバグ、パフォーマンス退行、そして動的解析やテストを要するものはすべて、このデータには見えません。diagnostics のチェックがクリーンであることは、コードが正しいことを意味しません。それは単に、コードが静的解析を通過したことを意味するだけです。
環境はユーザーごとに異なる。利用できる diagnostics は、ユーザーがインストールしている拡張機能に依存します。厳格な ESLint ルールと CloudFormation バリデーターを備えた開発者は、最小構成の開発者よりも多くの警告を表面化させます。このことがユーザー間の比較をノイズの多いものにし、集計されたエラー率がコーディング品質とツールの厳格さの両方を混ぜ合わせたものになることを意味します。実務上は、AI のコーディング品質をエラー率に加えて、スタック別・言語別・環境別に評価すべきです。ただし、今回のデータは共通のツール標準とベストプラクティスを共有する Amazon 社内ユーザーから来ているため、このデータセットでの環境のばらつきは、一般的な開発者集団全体で見た場合よりも狭い可能性が高いです。
モデルの改善だけが変数ではない。diagnostics は孤立して動作するわけではありません。steering プロンプト、hooks、subagents、その他のオーケストレーション層を含む、より広いシステムの中で動作します。これらのコンポーネントのいずれかがこの 6 か月の窓の中で変更されれば、モデルの能力改善とは独立にエラー率へ影響し得ます。ここで示された改善を、モデルのアップグレードだけにきれいに帰属させることはできません。一部はおそらく、周辺インフラの改善を反映しています。この 2 つを切り分けるには、オーケストレーション層を固定した対照実験が必要ですが、この観察データはそれを提供しません。
1. モデルはどのくらいの頻度で diagnostics を呼び出すのか?
まず私たちは、diagnostics 呼び出し率、すなわちモデルが diagnostics ツールを少なくとも 1 回呼び出したコーディング会話の割合を調べました。この比率は、モデルが自分の成果物をチェックするために、利用可能な diagnostics ツールをどれだけ積極的に使うかを捉えます。
図2: 各モデルが diagnostics ツールを少なくとも 1 回呼び出したコーディング会話の割合。Opus 4.5 が 14.58%、Opus 4.6 が 22.26%(最高点)、Opus 4.7 が 10.15%、Opus 4.8 が 10.85%、Sonnet 4 が 7.65%、Sonnet 4.5 が 2.74%(最低点)、Sonnet 4.6 が 13.89%。
Opus 4.6 が最も積極的で、会話の 22.26% で diagnostics を呼び出しています。しかし、その後の Opus のバージョン(4.7 と 4.8)は約 10% まで戻りました。Sonnet ファミリーは別の物語を語ります。Sonnet 4.5 は diagnostics をほとんど呼び出しませんでした(2.74%)が、Sonnet 4.6 は 13.89% へ跳ね上がりました。これはツールへの意識の高まりを示す大きな増加です。全体として呼び出し率はおおよそ 3〜22% で、ほとんどの会話が、モデルが静的に見つかるエラーを積極的にチェックしないまま完了していることを示しています。これは、モデルは学習時のツールをデフォルトで使い、明示的なプロンプトやファインチューニングなしには diagnostics ツールをめったに使わない、という最近の知見と整合します。同様の実験は、エラーが解決されるまでエージェントの確定をブロックするために diagnostics を使うと、誤ったコードの受け入れを約 90% から約 8% へ大幅に減らせることを示唆しています。これは、diagnostics を単に任意のツールとして利用可能にしておくよりもはるかに大きな効果です。
2. チェックされたファイルあたりの報告エラー数: モデルは良くなっているのか?
私たちは、モデルのバージョンをまたいでファイルあたりの平均エラー数を比較しました。この指標は、生成されたコードがどれだけ「コンパイルに近い」かを捉えます。完全に成功しない場合でも、ファイルあたりのエラーが少なければ、手作業の修正が少なくて済みます。
図3: モデルのバージョン別の、チェックされたファイルあたりの平均 diagnostics エラー数。Sonnet の線は 3.01(Sonnet 4)から 2.90(Sonnet 4.5)、1.29(Sonnet 4.6)へ低下。Opus の線は 1.74(Opus 4.5)、1.21(Opus 4.6)、1.82(Opus 4.7)、1.21(Opus 4.8)で、両ファミリーとも最新版では 1.2 付近に収束。
Sonnet の線は明確な改善の物語を語ります。Sonnet 4 のファイルあたり 3.01 エラーから Sonnet 4.6 の 1.29 まで、57% の削減が観測されました。Opus ファミリーは非単調なパターンを示します。Opus 4.6 と 4.8 はいずれも 1.21 に達する一方、Opus 4.5 と 4.7 は 1.7〜1.8 前後とやや高めです。これは、Opus ファミリーの中では、静的に見つかる diagnostics の観点で必ずしもすべてのバージョンが厳密な改善を表すわけではない、ということを示唆しているのかもしれません。全体として、両ファミリーとも本研究の最新版ではチェック済みファイルあたり約 1.2 エラーへ収束します。これは、そのままでコンパイル可能なコードを生成するモデルへ向けた意味のある前進を示している可能性があります。
3. 呼び出しあたりのチェック対象ファイル数: 広いスコープか、狭いスコープか
エラー率を超えて、モデルが diagnostics ツールをどう使うかについて興味深いことに気づきました。新しいモデルは、1 回の呼び出しでより多くのファイルをチェックしています。
図4: モデルが diagnostics ツールを呼び出すたびにチェックする平均ファイル数。Opus は 1.78(Opus 4.5)から 1.87(Opus 4.6)、2.04(Opus 4.7)、その後 1.91(Opus 4.8)へ上昇。Sonnet は 1.57(Sonnet 4)から 1.72(Sonnet 4.5)、1.86(Sonnet 4.6)へ上昇し、新しいモデルほど 1 回の呼び出しでより多くのファイルをチェックしている。
初期の頃、Sonnet 4 は diagnostics を呼び出すたびに平均 1.57 ファイルをチェックしていました。実質的には一度に 1 ファイル、たまに 2 ファイル目という程度です。Sonnet 4.5 でこれは 1.72 へ、Sonnet 4.6 は 1.86 へ上がりました。Opus ファミリーも同様の傾向を示します。Opus 4.5 は呼び出しあたり平均 1.78 ファイル、Opus 4.6 は 1.87、Opus 4.7 は 2.04 でピークに達し、Opus 4.8 は 1.91 に落ち着きました。
これが重要なのは、コードチェック戦略の転換を表しているからです。ファイルを編集してそのファイルだけをチェックするのではなく、新しいモデルは関連するファイルをまとめてチェックすることが増えています。たとえば、実装とそのテスト、あるいはモジュールとその利用側です。
呼び出しあたり約 1.6 ファイルから約 2.0 ファイルへの移行はささやかに聞こえるかもしれませんが、数十万回の呼び出しにわたって見れば、モデルが以前の世代よりも高い頻度でクロスファイルの退行(import の破損、インターフェースの不一致、下流の型エラーなど)を捕捉していることを意味します。
4. 報告されたエラーカテゴリのトップ5
診断されたエラーが何なのかを理解するため、私たちはエラーの種類を分類し、各モデルごとに分布を可視化しました。
図5: 各モデルの diagnostics エラーカテゴリの分布。Opus 4.5・4.6・4.7・4.8、Sonnet 4・4.5・4.6 の 7 つのドーナツチャート。カテゴリは解決できない import、未定義シンボル、構文エラー、implicit any、プロパティアクセス、解決できない参照、Kotlin 標準ライブラリの解決、その他。解決できない import はすべてのモデルで最大のスライスで、Opus 4.7 では 57.6% に達する。一方 Sonnet 4.5 や Opus 4.5 のようなモデルはカテゴリ間により均等に広がっている。
すべてのモデルにわたって、「解決できない import」が単独で最大のエラーカテゴリであり、多くの場合すべての diagnostics の約 3 分の 1 を占め、Opus 4.7 では半分超に達します。「未定義シンボル」と、型システムのエラーの長い裾(構文エラー、解決できない参照、implicit any など)が残りを構成します。注目すべきは、エラー分布がモデル間で異なる点です。Opus 4.7 は import 解決の失敗に大きく偏っており、他のエラータイプは比較的少ないのに対し、Sonnet 4.5 や Opus 4.5 のようなモデルはカテゴリ間により均等に広がった分布を示します。これは、モデルによって失敗の仕方が異なることを示唆しているのかもしれません。あるモデルは主に依存関係の解決に苦戦し、別のモデルは型システムとシンボルの全体にわたって間違いをより広く分散させます。
5. ソースファイル対テストファイル: どちらがより多くのエラーを生むのか?
テストコードは、モデルが正しく書くのが一貫して難しい対象です。テストにはモッキングフレームワーク、アサーションライブラリ、複雑なセットアップのパターンが関わり、テストツールとテスト対象コードの両方を理解している必要があります。
図6: モデル別の、ソースファイルとテストファイルにおけるファイルあたり平均エラー数。ソースエラーは青、テストエラーは赤。Opus 4.5 は 1.35 対 5.98、Opus 4.6 は 0.96 対 3.64、Opus 4.7 は 1.40 対 4.62、Opus 4.8 は 0.81 対 6.00、Sonnet 4 は 2.20 対 7.31、Sonnet 4.5 は 2.26 対 9.13(最も差が大きい)、Sonnet 4.6 は 1.08 対 3.56 で、テストファイルは常にソースファイルよりはるかに高い。
Opus ファミリーは概してソースファイルのエラーを 1.4 未満に保ちますが、テストファイルのエラーは 3.64(Opus 4.6)から 6.00(Opus 4.8)まで幅があります。Sonnet 4.5 は最も差が大きく、ソースファイルあたり 2.26 エラーに対しテストファイルあたり 9.13 エラーです。Sonnet 4 はソースエラー 2.20、テストエラー 7.31 を生み、Sonnet 4.6 は Sonnet の中で最も強く、それぞれ 1.08 と 3.56 です。モデルのサイズや世代にかかわらず、テストファイルが依然としてエラーの主な発生源であるように見えます。
6. 言語の地形図: Java は難しく、Python は易しい
コードを生成するとき、他より多くのエラーを生む言語があります。Opus 4.6(最大のトラフィック)のファイルレベルのエラー率を見ると、そのばらつきは非常に大きいです。ただし、これらの数値はモデルの能力を超えた 2 つの要因によっても形作られています。顧客がインストールしている静的解析拡張機能の精度(より厳格なリンターほど多くの問題を表面化させる)と、Kiro IDE のユーザー層が各言語をどう使うかのばらつきです。
図7: Opus 4.6 における言語別のファイルエラー率(低いほど良い)。低い順に、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%、Java 26.7%(最も長いバー)。
Java は 26.7% のファイルエラー率でトップに位置します。これは、生成された Java ファイルの 4 つに 1 つ超が少なくとも 1 件の diagnostics エラーを含むことを意味します。冗長な import、複雑なジェネリクス、検査例外、厳格な型解決の組み合わせが、本研究で分析した AI モデルにとって Java を最も難しい言語にしており、その差は大きく開いています。次に来るのは Rust の 15.1%、続いて C++ の 12.2% です。
中間層は TSX/React、TypeScript、Kotlin、Go で構成され、エラー率は 8〜11% の範囲です。これらはモデルをつまずかせるだけの構造を持った静的型付け言語ですが、Java ほど厳格ではありません。
最下位に位置するのは Python(4.0%)と JavaScript(1.6%)です。Python の動的型付け、import のボイラープレートの少なさ、寛容な構文は、一貫してきれいな結果を生みます。JavaScript の底値の 1.6% は少しばかり誤解を招きます。これはモデルがより良いコードを書いていることではなく、素の JS で利用できる静的解析が最小限であることを反映しています。TypeScript の型システムを上に乗せると、この率は 8.6% へ跳ね上がります。JavaScript に当てはまる同じ但し書きが、より微妙な形で Python にも当てはまります。動的型付け言語であり、静的解析が通常は軽いため、一部の Python のエラーはランタイムになるまで diagnostics として表面化しません。したがって、低い静的エラー率は編集時に捕捉できるものを反映しているのであって、そのコードが Java よりも必ずしも正しいことを意味しません。Java ではコンパイラがほぼすべてを前もって捕捉するのです。
チームが Java コードベースで AI コーディングエージェントを重点的に使っているなら、Python や TypeScript のコードベースよりも diagnostics のクリーンアップに多くの時間を費やすことを見込んでおいてください。
まとめ
6 か月と 50 万件近い diagnostics 呼び出しは、AI コーディングエージェントが正しいコードを書くうえで測定可能なかたちで改善していることを示していますが、その実態は単一の数字よりも込み入っています。
- エラー率は低下している。両モデルファミリーとも、より強力なバージョンでファイルあたり約 1.2 エラーへ収束します。
- モデルは会話の 3〜22% で diagnostics ツールを積極的に呼び出す。
- 新しいモデルは一度により多くのファイルをチェックする。より最近のモデルでは、関連ファイル(たとえば実装とそのテスト)をまとめてチェックすることが増えています。
- 解決できない import が支配的。モデルにかかわらず、全エラーの約 30〜58% を占めます。
- テストコードは正しく書くのが 3〜4 倍難しいように見える。モッキングフレームワークやアサーションライブラリは、実装ファイルよりも一貫してはるかに多くのエラーを生みます。
- 言語は重要。Java のエラー率(26.7%)は Python(4.0%)の 6.7 倍です。JavaScript の低い 1.6% は、より良い生成ではなく弱い静的解析を反映しています。
diagnostics は、Kiro のエージェントがコードを書いて洗練させる過程で自動的に実行されます。その仕組みを見て、さらに深く知るには、diagnostics のドキュメントとモデルの概要を読み、Kiro をダウンロードしてご自身のコードベースで試してみてください。