コーディングエージェントはなぜ動き、なぜ壊れるのか

同じモデルだ。Webチャットでhallucinateしていたあのモデルが、Claude Codeでは200行の機能を一発で仕上げる。Codexの/goalはイシュー一つをまるごと解決する。モデルが急に賢くなったわけではない。変わったのは構造だ。

なぜ動くのか

対話型AIのループはこうだ:

LLM → 人間 → LLM → 人間

フィードバックがすべて自然言語だ。確率的生成に確率的評価が続く。精度が積で劣化する。

コーディングエージェントのループは違う:

LLM → コード生成 → ファイル保存 → テスト実行 → pass/fail → LLM
LLM → コード修正 → ビルド → 成功/失敗 → LLM
LLM → 型チェック → エラーメッセージ → LLM

ループの中に決定論的ゲートが挟まっている。ファイルシステムは書いたとおりに保存する。テストはpassかfailだ。コンパイラは間違っていれば間違っていると言う。これらが意図せずラチェットの役割を果たしている。

LLMはunreliable componentだ。しかしunreliable componentの上にreliable protocolを載せるのは工学の基本だ。TCPはunreliable networkの上でreliable deliveryを実現する。RAIDはunreliable diskの上でreliable storageを実現する。ECCはunreliable memoryの上でreliable computationを実現する。

コーディングエージェントが動く理由は同じだ。unreliable LLMの上にdeterministic verifier(テスト、ビルド、リンター、型チェッカー)を載せたからだ。モデル性能ではなくtopologyが成功の原因だ。

ではなぜ壊れるのか

動くと言った。しかし時折壊れる。なぜか。

ラチェットが偶然挟まっていることと、意識的に設計されていることは違うからだ。

ラチェットのない区間が存在する

テストのないコードをエージェントが修正するとどうなるか。ビルドは通り、リントも通り、しかし機能は壊れている。決定論的ゲートのない区間では、LLMが確率的に判断し、確率的判断は積で劣化する。

200エンドポイントのうち180にはテストがあり20にはない。エージェントは180を完璧に処理し、20で静かにバグを仕込む。「ほぼできているのにどこかおかしい」が生まれる理由だ。

フィードバックの情報量が足りない

1000語をソートする実験をした。CPUは0.08msで100%。LLMは438秒で97.7%。それ自体驚くべきことだ――純粋な認知で97.7%とは。しかし本当の発見は別のところにあった。

同じ結果に対してフィードバックのレベルだけを変えてみた:

フィードバック結果
なし6個のエラー (99.4%)
「エラーがある」10個のエラー (99.0%) ── 悪化
「23個のエラーがある」1個のエラー (99.9%)
「6個、ここにある」0個のエラー (100%)

「間違っている」とだけ伝えると、過剰修正でかえって悪化する。エラーの個数を伝えると目標値が生まれ、執拗に探し出す。位置まで伝えると完璧に直す。

今のエージェントは大半が二番目のレベルに留まっている。テストが失敗すれば「何かが間違っている」とは分かるが、なぜ間違っているかの構造的理由までは伝えない。エラーメッセージはあるが、それは原因ではなく症状だ。

死角が存在し、反復では解決しない

ソート実験でLLMはR2で6個のエラーを残した。R3で「エラーなし」と報告した。R4bでも「エラーなし」と報告した。同じ6個を同じ方法で見落とした。

ヒントなしでは何度繰り返しても99.4%で収束した。「6個残っている」と伝えて初めて100%を達成した。

コーディングエージェントでも同じことが起きる。エージェントがバグを作り、self-reviewで「問題なし」と判断し、もう一度直せと言っても同じ箇所を見落とす。retryが解決策にならない理由だ。死角はモデルの確率的特性から来る構造的限界であり、努力不足ではない。

スケールで掛け算が作動する

97.7%精度のステップを2回チェインすると0.977² = 95.4%。3回なら93.2%。10回なら79.2%。

エージェントがファイル1つを修正するのは得意だ。しかし100ファイルにまたがるリファクタリングを任せるとどうなるか。各ステップが97%でも、100ステップを経ると0.97¹⁰⁰ = 4.8%。事実上、失敗が保証される。

これが「vibe codingが200エンドポイントで崩壊する」の数学的説明だ。小さなプロジェクトではチェイン回数が少ないから確率が持ちこたえ、大きなプロジェクトでは掛け算が破滅的に作動する。

何が必要か

動く理由と壊れる理由が同じところを指している:決定論的検証ゲートの有無だ。

今のエージェントは偶然挟まっているラチェット(テスト、ビルド、リンター)に依存している。これを意識的に設計すればもっと強くなる。

ラチェットを意識的に設計するということ:

第一に、ラチェットのない区間を特定する。テストのないコード、スキーマのないAPI、型のないデータ。エージェントが確率的に判断しているすべての箇所が脆弱点だ。

第二に、フィードバックの情報量を高める。pass/failだけ返すと過剰修正を誘発する。「どこで、なぜ、何が期待と異なるのか」を構造化して伝えなければならない。

第三に、チェインの途中に決定論的ゲートを挟む。10ステップを一度に回すと掛け算が破滅的だが、毎ステップごとにラチェットで固定すれば劣化がリセットされる。

LLMは驚くべき生成器だ。1000語を純粋な思考で97.7%正確にソートする。人間にもできないことだ。しかし100%でないものはすべて、反復すれば崩れる。0.977を二乗すれば0.954だ。

コーディングエージェントが動くのはモデルが賢いからではない。ループの中に決定論的ゲートが挟まっているからだ。壊れるのはそのゲートが抜けているからだ。

生成は確率的でよい。検証は決定論的でなければならない。


関連記事