← ブログに戻る

AIでのコーディングには、標準的なツールでは解消されない懸念がある

AIによる無秩序なコード変更と、AITM の構造化されたアプローチを対比したイラスト

現在のAIは、関数やコンポーネント、さらにはエンドポイント全体でも、数秒で書き上げることができます。問題が現れるのは、多くの人が想定する場所、つまり構文や速度ではありません。AIが既存のシステムに手を入れなければならなくなった瞬間に現れます。数十のファイル、積み重なった意思決定の履歴、そして開発者たちの「頭の中」以外にはどこにも書かれていないビジネスルールです。この問題を体系的に防ぐ方法こそ、このシリーズ全体のテーマであり、順を追って辿り着くツールの名前が AITM です。

そこへ進む前に、AIエージェントを使うチームが遅かれ早かれ、手軽な方法か高くつく方法のどちらかで答えを出すことになる問いを考えておく価値があります。エージェントが「完了」として返してきた結果が、見た目だけでなく本当に正しいと、どうすれば分かるのでしょうか。答えはこの記事の最後に示します。ただ、その前に、この問いがそもそもなぜ自明ではないのかを見ていきましょう。

実際にはどうなるか

典型的なシナリオを考えます。AIエージェントに1つの関数の修正を依頼します。エージェントは修正しますが、その関数が他の3か所から、それぞれ異なる前提で呼び出されていることを忘れています。あるいは、論理的に思えたという理由でコードの構造を「改善」し、そのせいで、見てもいなかった下流のロジックを壊してしまいます。

これらは単発のバグではなく、構造的な問題です。AIエージェントはシステム全体のコンテキストを持たず、プロンプトに収まる範囲と、全文検索で読み取れた範囲しか把握していません。判断の根拠は言葉であって、ビジネスロジックではありません。ドキュメントが利用できる場合でも、与えられたプロンプトと無関係な部分まで含めて全内容を読み込んでしまうことがよくあります。これは利用可能な最強のモデル(Opus、Fable、Astra など)にも当てはまります。モデルが賢くないのではなく、個々の作業の合間に、この知識を体系的に保存しておく場所がないのです。

ソースコードの行数が増え、ビジネスロジックが複雑になり、個々のモジュールやクラスの結びつきが強くなるほど、この検索の精度は落ちていきます。修正と無関係なデータがAIに流れ込み、その結果、技術的には正しく書かれているものの、誤ったビジネスロジックに従ったコードができあがります。完成した機能が壊れていたり、そもそも誰も触ってほしくなかったコードが「修正」されたりします。

どこで行き詰まるのか

根本的な障害はハルシネーションであり、これを排除するのは非常に困難です。2つ目の問題はプロンプトの品質で、これはユーザーとしてある程度は改善できます。しかし両者の上には、さらに厳しい制約が控えています。コンテキストの制限です。利用可能な最大級のモデルでも、扱えるのはおよそ100万トークンです。一方、扱う環境には数十万行のコードがあります。

経験上、スキルや md ファイル内のヒントといった基本的な手段では足りなくなる実用的な閾値は、およそ15万行あたりです。30万行前後になると、環境は本格的に複雑になり、日常的な状態が崩れ始め、何もしなくても物事が壊れるようになります。ここで想定しているのは、OOPで構築され、複雑な論理条件を持ち、メッセージやイベントの仕組みなどを介して各部分がつながっているソフトウェアです。そのようなコードでは、呼び出しとその処理との対応関係が常に明白とは限らず、AIはこの部分を非常に苦手とします。あるメソッドに結びついたコードをすべて発見できない可能性が高いのです。

さらに別の層があります。AIエージェント自身が、プロンプトに基づいて独自のサブエージェントを生成することがよくあり、そのサブエージェントの生成自体がAIの制御下にあるため、新たな誤りの原因が加わります。文法上の流れのためだけに文に入れた単語(指示ではないもの)にAIが高い重みを付けると、その単語に基づいて、まったく意図していない処理を行うサブエージェントを生成することがあります。しかもサブエージェントは自分の誤りを他のエージェントへ次々に引き継げるため、個々のハルシネーションが連鎖の中で伝播し、積み重なっていきます。

すべてが仕様どおりに行われたかを検証する役割のチェック用エージェントがあれば解決しそうに思えます。しかし「検証」とは実際に何を意味するのでしょうか。別のAIがタスクを処理したときと同じやり方で評価するなら、得られるのは同じ判断の確認であり、独立した検証ではありません。異なる、より優れたLLMをチェックに使って初めて、誤りを見つける確率が実際に高まります。しかしそれは誰かが意図的に選ぶべき選択であり、「チェックが行われた」ことから自動的に得られる結果ではありません。

もう1つの道が残っています。アプリケーションや既存のテストを実行し、ログからエラーを読み取り、テストが通るように修正することです。ただしここでも、実際に何が修正されたのかという疑問は残ります。本当にバグなのか、それとも前のステップが意図せず行ったビジネスロジックの変更によって生じたエラーなのか。修正自体は多くの場合明快で、エラーも消えますが、その過程でコードの別の部分を壊してしまうことがよくあります。コードの複雑さと依存関係によって、結果は大きく左右されます。

比較的単純なもの、たとえば編集機能、入力後のバリデーション、ビジネスロジックを介したデータ保存を備えたWebフォームであれば、通常は大した負担ではなく、成功する確率は99%近くになります。より複雑な構造では、コードの構造が崩れ始め、バグが次々に連鎖する状態に実際に陥ることがあります。テストやE2Eテストを繰り返し実行すれば徐々に修正できますが、本当に複雑なシステムでは何度も試行が必要になることがあり、その1回ごとにコストがかかります。

冒頭で約束した答え

冒頭の問いに戻ります。結果が見た目だけ完成しているのではなく、実際に正しいと、どうすれば分かるのか。プロンプトとその後のチェックだけでは、確実には分かりません。その理由はこれまで見てきたとおりです。限られたコンテキスト、サブエージェント間で伝播するハルシネーション、最悪の場合は同じ誤りを追認するだけのチェック、そして本物のバグと副作用を区別できないログ駆動の修正です。

これらはプログラマーが現在一般的に使っている手法であり、単純な変更であれば十分に通用します。次のレベルはAIを使ったオーケストレーションです。システムに関する一定のデータを準備して最新の状態に保ち、より良い情報をAIに渡すことで、AIが依頼とは別のことをする余地を狭めます。AITM — AI Task Manager が作られた目的はまさにここにあります。コードを書くエージェントが依頼に取りかかる前に、システムが対象領域のコントラクト(文書化された振る舞い)、DOMマップ、ビジネスロジックを取り込み、その知識を踏まえて初めてタスクを組み立てます。単一のエージェントに直接頼るのではなく、パイプライン全体と、より良い結果を得るために AITM が使うその他の手法に基づいています。

今後の記事では、AITM で実際にこれが具体的なプロンプト、エージェント、パイプラインのステップとしてどう見えるのか、そしてなぜこれがプレーンなコンソールから慣れ親しんだAIの使い方とは異なる作業方法なのかを示していきます。