Dance with Agents

読む速さを、書く速さが追い越したとき——エージェントとの大規模開発で学んだこと

エージェントとの開発は速い。管理人がひとりで進めている個人開発のWebサービスは、1年経たないうちにプルリクエストが500本を超えた。フロントエンド・計算エンジン・管理システムの3コンポーネント構成で、設計文書は170本を超えている。専門的な知識体系を扱うサービスで、中身の詳細はここでは伏せるが、規模感だけ伝えたくてこの数字を挙げた。ひとりの人間が趣味の時間で開発していて、この量になる。

この速さは、はっきり言って楽しい。だがある時点で、認めざるを得ない事実に突き当たった。

自分はもう、書かれていくものを読み切れていない。

AIエージェントとの開発は、次のような不安がつきまとう。「本当に、自分が思っている通りに作られているのだろうか」「コードを全て読み切れていないが、大丈夫なのだろうか」。エージェントにお任せで開発したことがあれば、必ずついて回る課題だ。しかもこれは一時的な問題ではない。エージェントのコーディング速度は上がり続け、人間の読む速さは上がらない。差は開く一方で、この不安は放っておけば深まる一方だ。

この記事は、その不安への答えを探して転びながら学んだことの記録だ。先に結論を言ってしまうと——読む速さで追いつくことは、目標にしてはいけなかった。 信頼の根拠を「読むこと」ではない別の場所に移す必要があった。順を追って書く。


起きたこと① エージェントは「すでにあるもの」を見落とす

ある日、新機能の設計を頼んだら、エージェントは立派な設計を返してきた。問題はひとつだけ。その機能は、1,200行を超える実装がすでにリポジトリの中に存在していた。 エージェントはそれを見ずに、ゼロから設計を始めていた。同じ日に、進行中のプルリクエストと丸かぶりの提案をもう一度やられた。1日2回である。

なぜ起きるか。エージェントは基本的に、毎回まっさらな状態で会話を始める。リポジトリの全体像は、調べるよう仕向けられなければ調べない。そして「すでにあるかもしれない」という疑いは、作る勢いの前では簡単に忘れられる。

再発を止めた対策:着手前サーベイの儀式化。 「既存実装を検索したか」「進行中の作業と衝突しないか」を、設計を始める前に必ず通すチェックリストにして、エージェントの作業手順そのものに組み込んだ。ポイントは、人間が毎回「気をつけてね」と言うのではなく、手順として固定すること。注意は消耗品だが、手順は消耗しない。

起きたこと② テストが全部緑なのに、本番で落ちる

外部サービスと連携する部分を作ったときのこと。エージェントは実物のレスポンスを一度も見ないままコードを書き、モック(偽物の応答データ)を相手にしたテストを添えてきた。テストは全部通った。本番に投入したら、即死した。

あとで分かったが、正解は仕様書にちゃんと書いてあった。読んでいなかっただけだ。

この事故の本当の怖さは、落ちたこと自体ではない。テストを書いたのも同じエージェントだったことだ。実装が何かを誤解しているとき、テストも同じ誤解のもとで書かれる。つまり緑のチェックマークが保証しているのは「実装とテストが同じ誤解を共有している」ことでしかない。自分で自分を採点させている構図に、テストの本数をいくら増やしても意味はない。

再発を止めた対策:「外部の真実」との照合を義務化。 モックではなく、実物のAPIレスポンス・既知の正解データ・現実の記録と突き合わせるテストが1本もない実装は、マージしないことにした。答え合わせの相手は、必ず「エージェントの外」に置く。

起きたこと③ 同じ計算が3か所にあり、1つだけズレていた

サービスの核になる計算——円環状の数え上げで、1始まりと0始まりの数え方が混在しやすい種類のもの——が、いつのまにかリポジトリの3か所に別々に実装されていた。そして1つだけ、答えが1つズレていた。

たちが悪いことに、どの実装も単体ではテストに通っていた。ズレは、実装同士を突き合わせたときにしか見えない。

再発を止めた対策:正準実装をひとつに定め、再実装を禁止。 その計算はこのファイルのこの関数だけが行う、と宣言し、他の場所での手書き実装を禁じた。さらに、複数の実装がどうしても残る場合は、全パターンの入力で実装同士を突き合わせる「門番テスト」を置いた。冗長さは放置すれば事故の温床だが、相互検証に使えば防具になる。

起きたこと④ 手で書いた索引・目録は、全部腐った

設計文書が170本を超えたある日、棚卸しをして愕然とした。文書群の入口になるはずの「索引」が5本あり、5本全部が1年近く更新停止していて、リンク先の多くがすでに存在しなかった。 一方で、いちばん重要な設計文書のひとつが、どの索引からも辿れない場所に埋まっていた。地図が全部古くて、宝のありかだけ地図に載っていない状態だ。

原因は単純で、そして根深い。機械で導出できる事実を、人間の手で書き写した瞬間から、腐敗が始まる。 ファイル一覧、機能一覧、リンク集。書いた瞬間は正しい。だが実体は毎日変わり、書き写しは追従しない。エージェント時代は変化の速度が上がるぶん、腐る速度も上がる。

再発を止めた対策:「事実は生成し、意図だけを手書きする」。 一覧や索引のような「事実」はスクリプトで自動生成し、生成結果が古くなっていたらCI(自動チェック)が知らせる。人間とエージェントが手で書くのは「なぜそう決めたか」という理由だけ。理由は、コードが変わっても腐らない。 そして入口の索引は1か所に一本化した。2つあれば必ず片方が腐る。

起きたこと⑤ 何度訂正しても、「通説」に巻き戻る

これが一番深い事故だった。

扱っているドメインの専門用語に、成立条件の定義がある。ネットや一般向けの解説に流通している「通説」の定義と、その道で正確とされる定義が、微妙に——しかし決定的に——ズレていた。管理人はエージェントに正しい定義を伝えた。実装は直った。ところが後日、別のセッションでその周辺を触らせると、実装が通説側に巻き戻っていた。 訂正する。また巻き戻る。これを何度か繰り返した。

なぜ起きるか。LLMは学習データに含まれる通説を「知って」いる。会話で伝えた指示は、セッションが変わり文脈が薄れれば効力を失うが、モデルの事前知識は消えない。 知らないことを聞かれてでたらめを言うハルシネーションとは別種の、「自信のある間違い」だ。自信があるぶん、こちらのほうがしつこい。そして②で書いた通り、テストも同じモデルが書くので、放っておくと誤解がテストごと固定される。

再発を止めた対策:「答えが割れるテストケース」を人間が確認して固定する。 通説の定義と正しい定義とで、結果が異なる入力例を意図的に作る。その期待値だけを人間が確認し、テストとして永久に固定する。ここで大事なのは、両方の定義で答えが同じになるケースをいくら並べても、絶対に捕まらないということ。答えが割れる一点にこそ検証の価値が集中する。あわせて、実装前にエージェントに「今回採用する定義」をドメインの言葉で復唱させるようにした。人間はコードを読めなくても、自分の専門領域の定義の正誤なら数十秒で判定できる。


学んだこと:信頼は「読解」からではなく「構造」から得る

5つの事故を並べて、あるとき気づいた。「人間がもっと注意深く読んでいれば防げた」事故が、ひとつもない。

どれも、読解とは別の構造——手順の固定、外部の真実との照合、実装同士の突き合わせ、自動生成、答えが割れる一点の検証——で解決している。つまり「読み切れていないが大丈夫か?」という例の不安への答えは、こうなる。大丈夫かどうかは、読んだ量では決まらない。検証の構造が揃っているかで決まる。 具体的には:

  1. 意図が明文化されているか——守るべき原則が、書かれているか。書かれていない意図は、守られようがないし、検証のしようもない
  2. 機械検証があるか——違反したら自動で止まる仕組み(CI・チェックリスト・禁止フック)があるか
  3. 外部真実と照合しているか——答え合わせの相手がエージェントの外にあるか
  4. 挙動を確認したか——実際に動かして、目で見たか
  5. 抜き打ちがあるか——全部は読まない代わりに、時々どこか1点だけ深く読む。エージェントには毎回「今回いちばん自信のない箇所」を自己申告させる

この5つが揃っているなら、全コードを読んでいなくても、その信頼には根拠がある。逆に揃っていないなら、全部読んだつもりでも危ない。

そして人間の役割は、「読む人」から3つの役割に変わる。

  • 定める人——意図を、人間が全部読めるサイズの文書に外部化し続ける。実装が何万行になっても、意図は数百行に収まる
  • 触る人——人間はコードを読むのは遅くても、自分のドメインの真実を見抜くことにかけては現場最速だ。この非対称性を使い、検証を「人間が得意な境界」まで押し出す。完成物を触る。ドメインの言葉で書かれた定義と実例を確認する
  • 抜き打つ人——会計監査と同じで、全取引を読む監査人はいない。抜き打ちの存在自体が、品質の規律を保つ

「人間が単一障害点になっている」と自覚したときは、正直こたえた。だが役割をこう捉え直すと、ボトルネックだと思っていたものは、エージェントには決して代われない供給源——意図とドメイン真実の供給源——だったと分かる。

運用してみて効いた、細かい型

  • 「悪化だけ止める」方式(ラチェット)。大きくなったリポジトリの問題を一斉に直すのは無理。現状の問題数を基準線として記録し、増えたらCIで止める、減ったら基準線を締め直す。後退だけを防いで、前進は焦らない。大規模で現実的に回るのはこの形だった
  • 事故は「構造」に昇格させる。同じ事故の2度目は、運用ミスではなく構造の欠陥として扱う。危険な操作は実行前に物理的にブロックする、手書きを生成に置き換える、突き合わせテストを置く。検索プロセスの暴走でマシンが過熱し続けた件も、最後は「人が気をつける」ではなく常駐監視という構造で終わらせた
  • 人間が読むものは総量固定。報告や文書が増え続ける設計は、どんなに整理しても人間側が破綻する。全体は1枚のダッシュボードに集約し、あとは「前回から変わったこと」の差分だけを受け取る
  • 減らすことを、作ることと同格に扱う。文書もコードも機能も、総量は放っておけば増える一方で、増えたぶんだけ腐る候補が増える。「削除する作業」を定期的に、罪悪感なくやる

もし次の大規模開発をゼロから始めるなら

自分への引き継ぎを兼ねて、チェックリストにしておく。

  1. 意図の正本を最初に作る——守るべき原則を「1〜3行の鉄則+理由」の形で書き始める。プロジェクトの憲法。以後ここだけは人間が全文を把握し続ける
  2. 機能の登録簿(実装マップ)を最初から持つ——何を作ったか・削除したかを1か所に記録し、更新せずに機能を追加・削除するとCIが止める形にする。あとから作ると棚卸しが大仕事になる(なった)
  3. 「外部真実と照合しないテストは無効」を最初のルールにする——モックだけのテストは安心ではなく安心の偽装
  4. 通説とズレる用語・定義が見つかったら、その場で「答えが割れるケース」を固定する——巻き戻りは必ず起きる前提で
  5. 事故ったら、対策は必ず構造にする——チェックリスト、CI、禁止フック、生成化のどれかに落ちるまで再発防止を終わらせない
  6. 索引・一覧・目録を手で書かない——生成できないなら、そもそも持たない
  7. 人間が読むものを増やさない——ダッシュボード1枚と差分報告だけ。文書群はエージェントのための資料庫と割り切る
  8. 定期的に減らす——「削除するだけの日」をつくる

おわりに

エージェント時代の大規模開発は、もう「書く速さ」の勝負ではない。書く速さはエージェントが供給してくれる。勝負を分けるのは、意図を言葉にする力と、検証の構造を設計する力だ。

読み切れないことは、恐れなくていい。読み切れない前提で信頼が成立する構造を作ること。それが、この1年ぶんの授業料で買った答えだ。

エージェント利用実例の記事

エージェント利用実例のページへ →