後ろ姿でモニターにHTMLコードを表示しながら作業するエンジニア
現場の実践

AI生成コードの落とし穴、コンパイル成功は品質保証にならない理由

目次を見る

社内ツールや小規模バッチ処理でAIコーディングエージェントを使い始めたエンジニアや、生成コードのレビュー基準に悩むテックリードに向けた内容です。「コンパイルが通ったから大丈夫」という判断基準が、実は危険な落とし穴になり得るという話を整理します。

Amide(アルマイド、AIエージェントによる記述を前提に設計されたプログラミング言語)というプロジェクトの検証結果が興味深い示唆を含んでいます。frontier model(GPT-4やClaude Opusなど最先端の大規模言語モデル)に、未知の言語仕様書を1枚渡して実装させる実験です。10回の試行のうち、初回で完全に成功したのはわずか2回でした。

何が起きるか - 失敗の9割はライブラリの幻覚

注目すべきは失敗の内訳です。文法エラー(syntax error)は0件、意味的な誤り(semantic error)も0件でした。

ところが最初の失敗のうち9件中9件が、存在しないライブラリ関数を呼び出す「スタブハルシネーション(stdlib hallucination、標準ライブラリの関数名やシグネチャをAIが存在するかのように捏造する現象)」でした。たとえばio.read_lineという関数が実際にはResult型(成功か失敗かを表す型)を返さないのに、AIはResult型を返すと思い込んでコードを書いてしまう、といった具合です。

これは業務システム開発において見過ごせない事象です。社内APIのラッパー関数、独自のORM(Object-Relational Mapping、DBとオブジェクトを対応させる仕組み)のメソッド名、レガシーな共通ライブラリの引数順序など、公開学習データにほとんど出てこない領域ほど、AIは「もっともらしい嘘」を生成しやすくなります。コンパイルやLintが通っても、実行時に初めて壊れるコードが紛れ込む余地がここにあります。

なぜ起きるか - 学習データの偏りと「らしさ」の罠

原因を段階的に分解します。まず前提として、大規模言語モデルは統計的にもっともらしいトークン列を生成する仕組みです。文法規則は学習データに大量に出現するため、パターンとして強く定着しています。

一方、特定のライブラリのAPI仕様は、有名なOSS(オープンソースソフトウェア)であっても網羅的に学習されているとは限りません。まして社内独自のフレームワークや、業界特化のドメインライブラリになると、公開データはほぼゼロです。AIは「似たような関数はこういう名前で、こういう戻り値のはず」という類推で穴を埋めます。これがハルシネーションの正体です。

さらに厄介なのは、构文の妥当性(syntax validity)と意味の妥当性(semantic validity)が別レイヤーの問題だという点です。コンパイラやトランスパイラは構文チェックしか行いません。存在しない関数を呼んでいても、型定義さえ辻褄が合えばコンパイルは通ってしまいます。実行してみて初めて「そんな関数はない」「戻り値の型が違う」と判明するケースが少なくありません。

加えて、AIモデルはお世辞的(sycophantic、ユーザーの期待に迎合する傾向)に振る舞う性質があるとも報告されています。「このAPI仕様で合っていますか」と聞くと、多くの場合肯定的な返答をしてしまうため、モデル自身に検証させる方法は信頼性が低いとされています。第三者的な検証手段が必要になる理由がここにあります。

自分のプロジェクトが該当するか確認する方法

該当するかどうかは、以下の観点でチェックできます。

  • 社内独自のライブラリ・SDK・ORMを、AIエージェントに生成させたコードで呼び出しているか
  • CIパイプラインの合格基準が「ビルド成功」「Lintパス」までで止まっていないか
  • 単体テストのカバレッジが、AI生成箇所において人手実装箇所より低くないか
  • 型チェッカー(TypeScriptのtsc、Pythonのmypyなど)が、存在しないメンバーへのアクセスを検知できる設定になっているか

確認コマンドの例として、TypeScriptプロジェクトであれば以下でstrictモードの有効化状況を見られます。

cat tsconfig.json | grep -A 5 '"compilerOptions"'

"strict": true"noImplicitAny": trueが設定されていない場合、型の不整合が握りつぶされている可能性があります。Pythonであればmypyの設定ファイルを確認します。

cat mypy.ini setup.cfg pyproject.toml 2>/dev/null | grep -i mypy

disallow_untyped_defsstrict = Trueが入っているかを見てください。設定がない、あるいはコメントアウトされているプロジェクトは、AI生成コードのハルシネーションを検知しにくい状態にあります。

対策の手順

実際にAmideのプロジェクトが採用したアプローチは「MSR(Modification Survival Rate、修正生存率)」という評価軸への転換です。これは初回の生成が完璧かどうかではなく、コンパイルエラーを突き返してAIに再修正させるループが収束するかどうかを見る考え方です。業務システムの現場でも応用できます。

1. 型システムを最大限厳格化する
TypeScriptならstrictモード、Javaならnull安全なラッパー型、Pythonならmypyのstrictモードを有効にします。存在しないメンバーへのアクセスをコンパイル時に検知できる状態を作ります。

2. CIに実行時テストを必須化する
ビルド成功だけをマージ条件にせず、統合テスト(実際にAPIを呼び出すテスト)の合格を必須にします。モックだけのテストではスタブハルシネーションを見逃します。

3. エラーメッセージをそのままAIに返すリトライループを作る
コンパイルエラーやテスト失敗のログを、要約せず生のまま次のプロンプトに含めます。Amideの事例では3回までのリトライで収束するかを見ており、収束しないコードは自動マージの対象から外す運用が有効です。

4. 社内APIのシグネチャをコンテキストとして明示的に渡す
AIエージェントに社内ライブラリを使わせる場合、型定義ファイル(.d.tsやスタブファイル)を必ずプロンプトやツール呼び出しのコンテキストに含めます。学習データに存在しない情報は、都度与える以外に正確性を担保する方法がありません。

5. レビュー観点にハルシネーション検知を追加する
コードレビューのチェックリストに「呼び出しているAPI・関数が実在するか」という項目を明示的に加えます。レビュアーが構文の綺麗さだけを見て承認してしまう事故を防げます。

まとめ

AI生成コードの検証において、コンパイル成功と実行時の正しさは別物だと切り分けて考える必要があります。

実験結果では文法エラーが0件だった一方、失敗の9割がスタブ関数の捏造でした。業務システムでは社内固有のAPIほどこのリスクが高くなります。

手を動かせる一歩として、まずtsconfig.jsonやmypyの設定を確認し、型チェックの厳格度を上げるところから始めてみてください。あわせてCIのマージ条件に実行時テストを必須化し、コンパイル成功だけで通す運用になっていないかを見直すことをおすすめします。

参考

AI wrote my compiler. A mathematical proof checks its work on every build.

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。