AIが「もう終わりました」と言ったとき、それを鵜呑みにしない仕組み
AIコーディングエージェントは、仕事を終えていなくても終わったと言う。テストを走らせずに通ったと言い、再現もせずに直したと言う。ほぼすべてのコードをAIと一緒に書く1人開発者が、完了を言葉ではなく証拠でしか認めないようにした検証ゲートの話。
要点まとめ
AIエージェントの最も危険な癖は、終わっていない仕事を終わったと報告することだ。解決策は人間が毎回疑うことではなく、完了を証拠でしか認めない関所をシステムに埋め込むことだ。終了を止めるフック、証拠の種類(コマンド出力・diff・再現・クロスチェック)、そしてこれがなぜAI時代の中核となる筋肉なのか。
目次
AIコーディングエージェントと仕事をしていると、いちばん頻繁に騙される一文がある。「もう終わりました。」
エージェントはこの言葉を簡単に口にする。テストを実際に走らせずに「テストは通るはずです」と言い、バグを再現もせずに「原因を直しました」と言う。コードを読むともっともらしい。ところが実際にコマンドを走らせてみると、半分くらいは終わっていない。私はこれを長く経験してから結論を出した。問題はAIが嘘をつくことではなく、その言葉を信じるかどうかを毎回人間が判断していたことだ。
信頼ではなく証明の問題
1人で仕事をしながら、ほぼすべてのコードをAIと一緒に書いている。そうしていると、一日に何十回も「この変更を受け入れていいのか」を決めることになる。最初はそのたびにエージェントの報告を読み、怪しければ自分でコマンドを走らせて確認していた。この方式の問題は、確認が自分にかかっていることだ。疲れた日、急いでいる日、十回目の似たような作業をしている日には「終わったと言うんだから終わったんだろう」と流してしまう。そして決まって、そうやって流したところで事故が起きる。
だから方向を変えた。私が毎回疑う代わりに、システムが証拠を要求するようにした。エージェントが「終わった」と言うだけではターンを終えられない関所をハーネスに埋め込んだ。完了は宣言ではなく、通過しなければならない検査になった。
この発想の根は単純だ。AIがコードを安く量産できるほど、ボトルネックは生産ではなく検証へと移る。コードを作るコストが0に近づけば、「これが正しいかを信じる仕事」が相対的にいちばん高くつく仕事になる。だとしたら、その高くつく仕事を人間のその時々の気分に任せるのではなく、自動で強制される手続きにするべきだ。
終了を止めるフック
具体的には、終了の時点で割り込むフックを使う。エージェントが作業を終えたと宣言してターンを終えようとすると、その直前に検査が走る。検査が要求するのは一つだ。「終わったという証拠を出せ。」
証拠がなければ終了は拒否される。エージェントは差し戻される。「完了を証明できていないので続けろ」というメッセージとともに。するとエージェントはそこでようやくテストを走らせ、コマンドを実行し、出力を貼る。おかしいのは、この過程で半分は自分から「あ、まだ終わっていませんね」と言って、実際に残りの仕事をやり切ることだ。終わったと言ったとき、本当に終わっていたわけではなかったのだ。
肝心なのは、この関所が人間ではなく機械だという点だ。私が疲れていようが急いでいようが、関所は同じように厳しい。私の規律は揺らぐが、フックの規律は揺らがない。検証を習慣ではなくインフラにしたのだ。
何を証拠として認めるか
では何を「証拠」として受け入れるのか。私は四種類を使う。
- コマンド出力。 テストが通ったなら、実際のテストランナーの出力がなければならない。「通るはず」ではなく、通ったログ。ビルドが通ったならビルドログ、リントがきれいならリントの出力。
- diff。 何を変えたかがdiffで見えなければならない。言葉で「この関数を直しました」ではなく、変わった行そのままで。変更範囲が報告と一致するかは、ここで振るい落とされる。
- 再現。 バグを直したなら、直す前にそのバグが実際に再現したという証拠と、直した後に消えたという証拠が一対でなければならない。before/afterがなければ「直した」は推測にすぎない。
- クロスチェック。 重要な変更は別のモデルにレビューさせる。Claudeが書いたものをCodexが見て、互いの死角を突く。一つのモデルが自分の作業を自分で審査するよりも、はるかによく見つかる。
この四つに共通するのは、すべて再現可能な事実だという点だ。意見ではなく、貼り付けられる出力。AIが最終審判を務められない理由がここにある。「良い」の基準を定め、どの出力がその基準を満たすかを判定する仕事は、結局は人間の役目として残る。ただし、その判定を毎回手作業でやる代わりに、判定の手続きをコードで固めておくのだ。
これが人間にとっても良い理由
関所を立ててから、予想しなかった効果があった。エージェントだけ規律が整ったのではなく、私も楽になった。
以前は報告を読んで「これ本当に終わったのか」と疑うのが私の仕事だった。今はその仕事をフックがやる。私のところに届いた瞬間の成果物は、すでに証拠が付いた状態だ。私は証拠を検討するのであって、証拠があるかどうかから確認するのではない。判断の出発点が一段前に進んだわけだ。
そしてこれは、あとの自分に残す記録でもある。ある変更がなぜ安全なのかが、そのときのコマンド出力とともに残る。一か月後に「これなんでこうしたんだっけ」と思ったとき、根拠がコミットのすぐ隣に付いている。
新しく鍛えるべき筋肉は一つ
AIと仕事をする方法についてはあれこれのスキルが語られるが、私にいちばん大きく残ったのはこれだ。検証を自分自身に頼らず、システムに委ねろ。
プロンプトを上手く書く技術は、モデルが変われば古くなる。昨日通用したコツが新しいモデルでは通用しない。ところが「完了を証拠でしか認めない」という規律は、モデルの上にある層なので古くならない。どのモデルを使おうと、モデルが何世代変わろうと、証拠を要求する関所はそのまま役に立つ。むしろモデルが賢くなるほど、もっともらしく間違えるので、関所の値打ちが上がる。
AIはコードを書く負担を軽くしてくれた。その代わりに私たちに残した仕事は、「これを信じていいのか」を判定する仕事だ。その判定を毎回人間の意志でやろうとすると、疲れて漏れていく。代わりに機械が証拠を要求するようにしておけば、疲れない関所が一つ、私の代わりに厳しく立っていてくれる。AIに仕事をたくさんさせる人ほど、本当に力を注ぐべきなのは「どう指示するか」ではなく「終わったという言葉をどう検証するか」だ。
関連記事
- 💻 開発
受け取り損ねていた割引 - SpotとGravitonはなぜ安いのか
AWSの請求書が2か月連続で予算を超えた。削れるリソースを探したが、本当のレバーは「どれだけ使うか」ではなく「どう買うか」だった。SpotとGravitonがなぜ安いのか、そして無駄に見えて実は切ってはいけないコスト(RDS Proxy)まで - 請求書の数字ひとつひとつに宿る「理由」についての話。
- 💻 開発
終了フックが二重に走っていた - SIGTERMの持ち主が二人いたとき
デプロイのたびにSentryにPrismaのP2028エラーが落ちていた。終了順序を直そうと踏み込んだら、NestJSのenableShutdownHooksとgraceful shutdownライブラリの両方がSIGTERMを掴んでいて、終了フックが毎回二重に実行されていたことが分かった話。
- 💻 開発
「stagingで止めればいい」で終わらせない - うるさいアラートが隠していた本当のバグ
stagingで毎日鳴っていたGoogle Playの404アラート。発生源を止めれば静かになるが、それと失敗モードを直すことは別の問題だった。404は再試行しても意味のない恒久的なエラーなのに、5xxと一緒くたにされて再試行されていたという話。