過去6か月、ゼロから自律的に動くコーディングエージェントを作っては壊し、作り直してきました。誰かの既存フレームワークは使わずに。GPT-4をループでラップするようなこともしない。実際の実行エンジン、テストランナー、修復ロジック、そしてLLMカスケードまで——全部です。
ここでは、ベンチマーク論文では誰も話していないことを、私が学んだ内容を紹介します。
誇大広告(バズ) vs. 現実
毎週、新しいデモがあります。「AIエージェントが30秒でアプリを丸ごと書いた」。クリップは拡散されます。コメント欄は大荒れ。ところが、実際に開発者が試すと分かります:
デモ用の入力では動く
少しでも違う入力だと失敗する
失敗すると、静かに(エラーが見えない形で)落ちる
何をしたかを再現する方法がない
これはモデルの問題ではありません。モデルは本当に能力があります。問題はアーキテクチャです。
実際にエージェントを壊すもの
Python、Go、TypeScript、Rustで何千ものベンチマークケースを回した結果、失敗は5つのカテゴリに固まることが分かりました——それらはどれも「生のLLM知能」についてではありません。
- 修復ループがない ほとんどのエージェントデモは1回で終わります:プロンプト → コード → 完了。実際のコードは、最初の試行でうまくいくことはほぼありません。構文エラー、importの欠落、型の不一致、ロジックバグ——これらは普通に起こります。 構造化された修復ループのないエージェントは、デモであってツールではありません。 実際に機能するもの: 計画 → 実行 → テスト → 失敗? ↓ 失敗の種類を分類 ↓ 対象を絞った修復プロンプトを作成 ↓ 再実行 → 再テスト ↓(最大3回の試行) それでも失敗ならロールバック キーワードは「分類」です。「エラーはこれだから直して。」ではなく、「ファイルXの行YにあるこれはSyntaxErrorで、Zパターンが原因——関連するコードはこれ。」のようにする。 エージェントがエラー出力をそのままLLMに渡すとトークンを浪費し、構造化された失敗コンテキストを抽出するエージェントより結果が悪くなります。
- 不安定なテスト実行 意外かもしれませんが、エージェントが失敗する理由は、生成されたコードが間違っているからというより、書いたテストが弱いからであることがよくあります。 間違った実装でも通ってしまうテストは、テストではありません。誤ったシグナルです。これは突然変異テスト(ミューテーションテスト)の問題です。 たとえば: pythondef is_even(n): return n % 2 == 0 通るテスト: pythondef test_is_even(): assert is_even(4) == True コードを突然変異させる: pythondef is_even(n): return n % 2 != 0 # 間違い! このテストは、is_even(4)しか見ていないならまだ通ります。4 % 2 != 0 は False で、False == True は……待って、それは失敗します。ですが、突然変異後のコードで is_even(3) は True を返すので、テストが「偶数だけ」を確認しているなら見逃します。 ミューテーションテストを強制しないエージェントは、テストでは通るコードを作っても、本番で失敗します。 修正方法:毎回の成功したテスト実行の後に、主要な演算子を突然変異させる(== → !=、+ → -、if x: → if not x:)そして、それをテストが検出できるか確認します。検出できないなら、コードではなくテストが弱いということです。
- ワークスペースを理解できない 「Goサービスのバグを直して」とエージェントに頼むと、エージェントは次を知りません:
go.modはある?モジュール名は?
go test ./... が正しいコマンド?それとも go test -run=TestXxx ./...?
go mod tidy が必要な外部依存はある?
それは単一パッケージ?それともマルチモジュールのワークスペース?
この文脈がないと、エージェントは(誤った)推測をするか、(うるさい)質問をするかのどちらかになります。どちらも許されません。
機能するもの:計画が始まる前にプロジェクト構造をスキャンする「ワークスペース・オラクル」
検出:/src/go.mod にGoモジュールあり(module: myapp)
検出:/src/cmd/、/src/internal/
テストコマンド:go test ./... -v
依存関係:標準ライブラリのみ
これは当然に聞こえます。ですが、ほとんどのエージェントはこれを適切にやれていません。
- ロールバックがない ファイルを変更して失敗したエージェントは、ワークスペースを壊れた状態のままにします。これは机上の話ではなく、複数ステップの修復中には常に起きます。 解決策は恥ずかしいくらい簡単です:実行のたびにgit stashし、ロールバック時にgit stash pop、成功時にgit stash drop。 実行前: git stash create ← スナップショット 実行中: agent がファイルを変更 テスト失敗時: git stash pop ← きれいな状態に復元 テスト成功時: git stash drop ← 変更を受け入れる すべてのエージェントがこれをすべきです。ほとんどはしません。
- LLMプロバイダの不安定さ 単一のLLMプロバイダに依存して構築すると、信頼性上の負債になります。レート制限、日次クォータ、APIエラー——これらはいずれも、タスクの途中でエージェントを殺します。 カスケードの方がうまくいきます: プロバイダ1 → レート制限 → プロバイダ2 → 日次制限 → プロバイダ3 → … ただし重要な細部があります。いったんのレート制限(30秒待ってリトライ)と、日次で使い切ったクォータ(このセッション中はこのプロバイダを完全にスキップ)を区別すること。同じ扱いにすると時間を無駄にします。
ベンチマークの問題
現在のコーディングエージェントのベンチマークは「最終出力が動いたか」を測ります。これは重要なことを全部見落とします:
何回の試行で到達したか?
どれくらいのコンテキストを消費したか?
解決策は決定的か?もう一度実行して同じコードが得られるか?
生成されたテストは回帰(退行)を捕捉できるか?
「合格率85%」というベンチマークスコアには、まったく異なる意味があり得ます:
良い:最初の1回で85%、残りは構造化された修復、すべてのテストにミューテーションカバレッジあり
悪い:5回試行して85%、テストは退屈な内容、実行のたびに別のコードになる
最も重要な指標は、合格率ではありません。修復率です。平均修復回数が0.1でタスクの95%を通すエージェントは、平均修復回数が2.3で95%を通すエージェントより役に立ちます——見出しの数字が同じに見えてもです。
決定性:欠けている性質
コーディングエージェントで最も過小評価されている性質は「決定性」だ、と私は主張したいです。
同じタスクを2回走らせて、同じ結果が得られるでしょうか?
ほとんどのエージェントでは、いいえ。LLMは設計上非決定的です(temperature > 0)。コンテキストが変わる可能性もありますし、ツール呼び出しが変動するかもしれません。
なぜそれが重要なのか?
デバッグ:失敗した場合、再現できません。なぜ失敗したのか理解できません。
CI/CD:非決定的なエージェントをパイプラインに入れられません。ある実行では通り、次の実行では失敗します。
信頼:開発者は予測できないツールを信頼しません。
機能するアプローチの1つ:録画/リプレイ。エージェントがタスクに成功したら、LLMのやり取り全体——入力、出力、推論——を記録します。その後の実行では、LLMを呼び出すのではなく、記録したやり取りをリプレイします。
これにより得られるのは:
繰り返しタスクでのLLMコストがゼロ
100%の決定的な出力
監査可能な履歴(「3月3日にエージェントが実際に何をしたか?」)
記録された軌跡(トラジェクトリ)は、学習データにもなります——ただしそれは別の記事の話です。
良いアーキテクチャはどう見えるか
すべての失敗と反復の後に、実際に信頼できる結果を生み出すアーキテクチャはこうなります:
┌─────────────────────────────────────────────────┐
│ Goal Parser │
│ 言語・依存関係・ワークスペースの種類を検出 │
└─────────────────────────┬───────────────────────┘
│
┌─────────────────────────▼───────────────────────┐
│ Workspace Oracle │
│ プロジェクト構造をスキャンし、テストコマンドを見つける │
└─────────────────────────┬───────────────────────┘
│
┌─────────────────────────▼───────────────────────┐
│ Scaffold Engine │
│ 環境を準備する(venv、node_modules など) │
└─────────────────────────┬───────────────────────┘
│
┌─────────────────────────▼───────────────────────┐
│ LLM Planning (Cascade) │
│ 構造化されたコマンド計画を生成する │
└─────────────────────────┬───────────────────────┘
│
┌─────────────────────────▼───────────────────────┐
│ Executor + Snapshot │
Gitのstashのロールバック保護付きでコマンドを実行
└─────────────────────────┬───────────────────────┘
│
┌───────────┴───────────┐
│ │
✅ テストは通過 ❌ テスト失敗
│ │
変更を受け入れる 失敗を分類
スナップショットを削除 │
修復プロンプトを作成
│
修復(最大3回)
│
まだ失敗している?
│
ロールバック+レポート
各ボックスはそれぞれ別の懸念事項です。それぞれは独立して失敗し得ます。それぞれは独立してテストできます。
実務上の要点
エージェントを作る、または評価するなら:
作る:
生のエラーフォワーディングではなく、構造化された失敗分類
突然の変異(ミューテーション)テストの強制 — 任意にしない
ワークスペースを認識したテスト検出
Gitスナップショットのロールバック — 常に
複数プロバイダーのLLMカスケード(クォータ追跡付き)
測る:
成功したタスクあたりの平均修復回数(目標:< 0.3)
ロールバック率(目標:< 10%)
生成されたテストのミューテーションスコア(目標:100%)
決定性:同じタスクを3回実行し、出力を比較
避ける:
単一プロバイダーのLLM依存
ロールバック保護なしでファイルを変更するエージェント
最終的な合否しか測らないベンチマーク
デモ動画への信頼
これからどうなるか
勝つエージェントは、最も強力な基盤モデルを持つものではありません。信頼できる実行レイヤーを最も備えたものです。モデルはコモディティです — GPT-4、Claude、Llama、Qwen — どれも十分に使えます。差別化要因はモデルの周りにあるすべてです。
信頼性、決定性、監査可能性、ロールバック — これらは派手なエンジニアリング課題ではありません。派手なデモにもなりません。ですが、開発者が実際に信頼して毎日使うツールにするのは、まさにここです。
ベンチマークは最終的に追いついてきます。それまでは、本当に重要なタスクでエージェントを動かし、実際の修復率を測り、自分自身の失敗から回復できないものは捨ててください。
私はこの種のシステムを作る細部について、進めながら書き続けています。もし同様のものに取り組んでいる、またはエージェントのアーキテクチャについて考えがあるなら、ぜひ — コメントをください。
タグ:ai rust プログラミング開発ツール machinelearning
カバー画像の提案:テスト結果が表示されるターミナル — 緑の合格、1つの赤い失敗、次に修復、そしてまた緑。




