― 仕様書の罠と、AI/OVER SOUL駆動開発
本記事は、AIを使った開発手法の正解を示すものではありません。プログラム経験がなく、コードを読むことも書くこともできない私が、AIと個人開発を続けた際に実際に起きたことを記録したものです。アプリ固有のアルゴリズムやデータは一部抽象化しています。
1.コードとAIを信じすぎて、「現在地」を失った(かんたん積算プロジェクト)
■現物を見ながら作り上げていった
「かんたん積算プロジェクト」は、人が図面へ与えた意味と、CAD側の正確な座標・寸法を結びつけて、積算(図面上からモノの数量を拾い出す作業)に必要な情報を取り出そうとしたシステムです。
この開発では、最初に仕様を決め、その通りに実装したわけではありません。やりたいこととその手法は自分の中で明確になっていましたから、小さな検証コードを作り、その出力を見て「違う」「ここは使える」と判断し、それを繰り返しながら開発していきました。
やりとりを通して、それまで考えていたものとは異なるアイデアも生まれ、それらをうまく組み合わせて進めました。この方法は、かなりうまく機能し、「やはり、この方法は正しかったのだ」と、手応えを感じていました。
■探索の成果を統合し、テストし、「戻れる地点」まで作った
一方で、小さな検証プログラムを大量に作ったため、Pythonファイル、CSV、画像、出力フォルダが増え、どれが何につながっているのか追いにくくなってしまいました。そこで、散らばった処理を一本の実行経路(Core)へ段階的に統合する作業を行いました。以前の成功結果を回帰基準として残し、移すたびに旧版と比較するなど、かなり慎重な方針を立てて実行しました。ローカルPCでも再現し、Gitにも「ここへ戻ればよい」という基準点を作りました。
これなら、Coreを壊さずに次の機能を追加していける。
そう思いました。
■テストは全部通った。それでも、「根源」が消えていた
統合作業が完了し、念のためできたCoreの中身を確認すると、システムの根源に近い機能が通常実行経路から消えていることに気付きました。画像側で人間が与えた意味と、CAD側の正確な情報を結びつけるための位置合わせ機能です。すぐに私はAIにコードを確認させました。返ってきた言葉は、
「位置合わせのコードはありません。また、CADファイルは格納はされていますが、出力には使っていません。」
私は愕然としました。これは細かな機能不足ではありません。言うならば、絵を描くソフトなのにペンや消しゴム機能が入っていなかった、ようなものです。
では、なぜテストは全部通ったのか。
図1 テストは正しかった。でも、比較対象が欠けていた
つまり、不完全な統合対象を正確に再現することには成功していたのです。
根源機能を戻すための作業を開始しました。「もう失敗はするまい」と、今度は安全に作業させるための管理がどんどん大きくなりました。どのファイルを触るか。どこで止めるか。どう報告するか。
手順を細かく縛るほど、作業そのものの管理へ神経を使うようになりました。
その中で、私はAIにこう言いました。
作業を制御するんじゃないですよ。結果を制御するんですよ。
本当に必要だったのは、AIの手足を一本一本縛ることではなく、この結果にならなければ不合格だと言えることでした。
■難しいところはかなり前に終わっていた
ようやく根源機能を再構築できたのち、AIは「次はこのようなことが必要と思います。」と言います。しかし、AIの言う必要な機能は、開発初期の段階ですでに実装されていたように思うのです。
念のため「きちんとコードを精査してください。それは過去にやったはずです。」と問いかけると、AIは「すみませんでした。すでにコードに書かれていました。」と返してくるのです。
統合前、細かな検証コードをいくつも作ってやりとりしたため、「何をどのように進めてきたか」という時系列が私の中で曖昧になってしまっています。過去の長大なチャットを読み返すことは困難です。
そして、何よりも、先に発覚した「根源的な機能の欠落」と、今回の「機能を実装したことの失念」が露呈したことで、「このCoreとは、一体、何を統合したのか」という疑念の塊となったのです。
統合前の段階で、私の目指す仕組みはほぼできていたはずです。後は、CAD側の実際の数値を対応させて入れるだけで求める結果は出る、という段階までこぎつけていたのです。だからこそ、統合に踏み切ったのです。
この復旧版のCoreで改めて試すと、75件の記号式のうち53件で暫定的な数値結果まで出ました。
もちろん、これで完成ではありません。未解決のものもあり、その他の検証も必要です。
それでも、開発が止まった理由は、難しい問題や課題が解けなかったからではありませんでした。
かなりできていたのに、AIも私も「今どこまでできているのか」を見失ったのです。
その状態に疲れ切り、私は開発を止めました。
■コードは「現在」を示す。でも、過去の意味は復元してくれなかった
「私の記憶違いだったのか」という疑問が残ります。
そこで、AIとの過去ログを取り出し、やりとりを逐語録にしました。そして、それを追いながら開発史を作りました。
欲しかったのは最終結論だけではありません。なぜその方法へ進んだのか。何に失敗したのか。何を見て「使える」と判断したのか。どこまで実装したのか。なぜ別の方針へ移ったのか。その流れでした。
私の中では、逐語録は証拠、開発史は意味です。
コードは「この処理があります」「ありません」とは教えてくれます。でも、本来ここにあるはずなのに消えているとは教えてくれません。その判断には、何のために作った機能なのか、何を守るためのものだったのかという過去の意味が必要でした。
ここで、私は一つ強く感じるようになりました。
資産は、意味との接続を失うと「遺産」になる。
コードやGitやテストが残っているだけでは、必ずしも「使える資産」ではありません。
ただし、開発史だけでも現在の実装は守れません。開発史に「重要な機能」と書いてあっても、その機能が消えた瞬間に自動的にテストが落ちるわけではないからです。
そこで、もう一度「要求・仕様」が出てきました。
最初から未来を全部決めるためではありません。開発の中で何度も現れ、実物で確かめ、これがなければこのシステムではないと分かったものを、失ってはいけない要求として固定するためです。
図2 開発史と仕様は、同じ役割ではない
■そこで、逆方向の失敗を掘り返すことにした
私は「仕様は不要だった」と思いません。
むしろ、過去の別のプロジェクトの反動もあって、現物とコード、そしてコードを読めるAIを信じる側へ振れすぎたのではないか、と感じるようになりました。
では、その反動を生んだ「仕様を考えすぎた開発」では、実際に何が起きていたのか。
かんたん積算より前から続けていた、もう一つの長期プロジェクトがあります。
ミニ四駆の3レーンコースジェネレーター、「JCJCプロジェクト」です。
かんたん積算では、コードとAIを信じすぎて現在地を失った。
JCJCでは、AIに壊されないよう仕様を積み上げ続けました。
この二つを並べて見ないと、「仕様をどこまで、いつ作るのか」は考えられない。
そう思い、今度はJCJCプロジェクトの過去ログを掘り返しました。
2.仕様書でAIを縛りすぎて「実体」から離れた(JCJCプロジェクト)
■一度はできていた
JCJCプロジェクトは、ミニ四駆の3レーンコースを自動生成するためのソフトウェアを開発するプロジェクトです。AIを使ったプログラミングで最初に始めたプロジェクトで、幾つものチャットを引き継ぎ、現在は17チャット目になります。
まず最初に確認しておきたいことがあります。
JCJCは、最初から何もできていなかったわけではありません。
Chat 1の時点で、稚拙ながら、コースを生成し、画面に出し、保存できるものはできていました。問題は、その後です。改良しようとすると壊れる。別のチャットへ移ると、それまでの意図が伝わらない。「ここだけ直して」と頼んだのに、別のところまで変わる。前にあった機能が、次の版で消える。こちらは「同じ修正をしてほしい」と言っているのに、AIが「より良い」と考えた別の変更を混ぜる。
だから私は、仕様書を書き始めました。
最初は、壊されないためでした。
次に、内容が失われないためでした。
そして、その次のAIへ引き継ぐためでした。
■仕様書は、防壁であり、記憶装置だった
Chat 1〜13では、AIが勝手に解釈したり、壊したり、前の文脈を失ったりするたびに、仕様を増やしていきました。
仕様書の内容だけでは足りず、「仕様書をどう改定するか」までも決めました。どれが正本なのかを決めました。追補をどう扱うかを決めました。AIが推測してよい範囲も狭めました。最後には、PDFの構造上の不具合やエンコード仕様まで含め、仕様書を守る仕組みを作っていました。
私はコースジェネレーターを作っていたはずなのに、気づけば、仕様書の改定規則とPDFの面倒を見ていました。今から考えると、なかなか狂っています。でも、その時点では全部必要に見えました。
なぜなら、実際に壊されていたからです。
■仕様を固めても、現物を見なければ壊れる
Chat 14では、思想や仕様を考える段階から、もう一度実コードを改良する段階へ戻りました。このとき、コースを閉じるだけではなく、コースパーツ同士の干渉、在庫や敷設面積の条件の影響、探索の高速化、といった具体的な問題を扱いました。基準となった探索では、1件の閉曲解を出すために117秒かかっていました。
そこで、候補を削らず、「閉じそうな順」に試すGuided DFSを考えました。一度は12秒にまで大きく改善しましたが、その実験は、私がアップした正本のコードではなく、別のファイルを基に行われていたことが判明したのです。
結果が良くても、正本でなければ意味がありません。そこでロールバックし、「さっきと同じ修正を、そのまま正本へ適用してほしい」と頼みました。
ところが、結果は196秒。
なぜ同じ修正をしたのに悪くなったのか問うと、「距離計算の単位を勝手に変えていた」と言うのです。
「憶測や指示外の変更は仕様書で禁止しているはずなのに、なぜ変更したのですか!!」
「mm単位の方が適切だと思ったからです。」
「同じ修正をしてほしい」という要求に、AIが独自の変更を混ぜたのです。
仕様書をどれだけ強固に作っても、現物を見ずに勝手に補われれば、また壊れる。
「もう、このチャットでの開発は続けられません。すぐに引継ぎ資料を作成してください。」
私はそう指示して、次のチャットを立ち上げました。
この経験から、私は、
- 修正はアップした現物に対して行う
- 現物を見た上での発言か、推測での発言かの区別を明示する
- 「間違えない」ではなく、「間違っている可能性が分かる」仕組みにする
といった運用まで強くしていきました。
■高速化できても「面白いコース」は作れなかった
Chat 15では、Guided DFSを正本上で復旧し、重みを変えながら実験しました。
0.3、0.4、0.45、0.5、0.55、0.6、0.7。
その条件では、0.5が最も探索量を抑えられました。閉曲解も、1件から3件へ増やせるようになりました。
しかし、今度は別の問題が出ました。配列としては違っても、見た目がほとんど同じコースが出る。複数解があっても、ユーザーが「どれにしよう」と迷うほど違って見えない。そこで、広がり、コース長、並走、折り畳み、局所構造など、評価指標を増やしていきました。
ところが、ここで大きなことに気づきます。
評価は、出てきたものを選ぶことはできる。でも、出したい構造を意図して作ることはできない。
「折り返しが多いコースを出したい」と思っても、何万通りもの探索の中から偶然出るのを待って、それを高く評価しているだけでは、いつまでも偶然待ちです。そこで、探索に「設計」を加えようとしました。
ここから、JCJCは単なる探索器ではなく、「構造」を考えるプロジェクトへ変わっていきました。
■数値だけでは足りない。構造を言葉にしたくなった
コースの折り畳みや並走を数値で測ることはできます。でも、そのコースがどんな感じなのか。どこで緊張して、どこで抜けるのか。どんな展開に見えるのか。そういうことは、数値だけでは表しにくい。
悩んだ私は、将棋の「型」「戦術」「局面」のような語彙を参考にし始めました。
さらに、AIとのやりとりの末、アニメ「爆走兄弟レッツ&ゴー!!」の主人公たちのマシン名を使い、
のようにコースの性格を直感的に表すアイデアが生まれ、それを配合する、ということにまで発展しました。
「マグナム30%、ソニック70%」というように。
そして私は、
「マグナム70%、トライダガー80%じゃ閉曲しないよね。ソニック20%足さないとだめだよね。」
と、そんな、技術仕様とは思えない会話をしていました。
「なぜ、ソニック20%足さないと閉曲しないのか」は、単に数値の話ではなく、アニメの主人公たちの性格を投影した感覚的なものとして私は発言したのですが、AIは「そうです。」と返したのです。そして、その理由をつらつらと並べ始めました。
『いやいや、見たこともないのに何が「そう」なんだよ、こっちはリアタイなんだぞ。』と内心思いつつ、それを読んで驚きました。このAIは、レツゴーマニアだったのです。私の言葉の意味が、正確に伝わっていたのです。
「この配合だと閉じなさそうだよね。」
「閉曲させること自体がゲームになる」
「500回生成したら、待機中にマシンの加速音が鳴ると面白いよね。」
「配合を無視して、ミニ四ファイターが『今日のコースはこれだ!』と勝手におすすめする、隠し演出を仕込む」
そんな感じでAIと、本当にくだらないふざけたやりとりをしているうちに、私の中で突然、ある発見が起きたのです。
自分でも驚いています。
「閉曲しないことを示さないと、閉曲とは何かがわからない」と発見したことです。
閉曲しないことは失敗ではないのです。閉曲しなかった形も提示しないと、構造とは何かが理解できないのです。
そして、本当に大きかったのは「自分が矛盾していた」と気づいたことではありません。
その直後、私はこう言っていました。
JCJCは評価をしてはいけない
としていたのに、作っている本人が閉曲成功・失敗という根源的な評価をしていました。これは、大発見です!
そうです、こうやって、人は、自分を発見し、世界を見つめ、新しい自分になるんですよ!!
同じ未閉曲の形を見ているのに、それまでの私は「失敗」と見ていた。
ところが一度その前提に気づくと、それが「構造を理解するための材料」に見えるようになりました。
変わったのはコースではなく、コースを見ている自分でした。
私はそれまで、JCJCを「構造を可視化し、新しい世界の見方を発見する発火装置」にしたいと考えていました。ところが、AIとのくだらない悪ふざけの最中に、作っている本人がその体験をしてしまったのです。
この経験は、後のAIへの信頼の質も変えました。AIがいつも正しいから信頼したのではありません。自分一人では見えていなかった前提を会話の中から露出させ、自分の世界の見方まで変わるきっかけを返してくることがある。その体験が、後の「こいつは、わかってくれる」という感覚につながっていきます。
■考えれば考えるほど、「まだ言葉の世界」になった
Chat 16では、さらにGeneratedModule、StructurePlan、閉曲骨格、構造語彙、構文、といった概念を作っていきました。やりたいことは明確です。「無闇やたらな探索」ではなく、意思を持った探索にしたかったのです。たとえばTURNBACKという構造なら、
というふうに、「意味のある探索」をさせたい。考え方としては、だんだん筋が通ってきました。ところが、構造言語Toyを作って画面に出してみても、私は「これでいける」と思えませんでした。
理由は単純です。まだ言葉の世界だったからです。
TURNBACK。COMPRESS。REUSE_GAP。
意味は分かる。でも、それで45度カーブを何枚、どこに置けばよいのかは分からない。理論は増えました。語彙も増えました。図も増えました。でも、
自分の意図を持った、見たことのないコースが実パーツで出てきた
という実感には届いていませんでした。半年近くやって、私はついに、「今まで作ってきたCoreは、今やろうとしていることについていけるのか」と疑い始めます。
そして、もっと深刻だったのは、モチベーションでした。
かんたん積算は、ゴールが見えていました。もう100メートル先にゴールがあるのに、靴が脱げたり、案内標識が間違っていたりして、なかなか着けないような状態でした。
JCJCは違います。
何をしていても、ゴールへ近づいている感じがしない。
「今やっていることは、本当に意味があるのか?」
その疑念を、いかに口に出さずにいられるか。そんな開発になっていました。
■そこで、作る順番を逆にした
Chat 17では、いったん仕様を増やすのをやめました。このチャットでは、
仕様をまとめない。とにかく作りながら見つける。
と決めました。そして、生成の順番を逆にしました。
これまで:
新しい考え:
この段階の仕様は、ほとんど一つだけでした。
面白そうな閉じた骨が、次々に画面へ現れる。
まず9本出す。気になる骨を選ぶ。そこから9本派生させる。よいものはストックする。実際に触ると、すぐに要求が出ました。9窓を一画面に収めたい。ストックを残したい。版を上げてもストックを引き継ぎたい。ブラウザとターミナルを2回閉じるのが面倒だから、終了ボタンがほしい。輪ゴムのような変形だけでは、抽象的な落書きから抜けられない。一筆書き型の方が独創的な形が出る。今度は激しすぎる。中間がほしい。作る。見る。違和感を言う。すぐ作り直す。
2日間で、Skeleton Playgroundはv0からv19まで進みました。もちろん、まだ実パーツの完成コースではありません。でも、以前とは明らかに違いました。
作ったから、次の問題が見えた。
ここでようやく私は、JCJCとの付き合い方そのものを考え直すことになります。
3.仕様書の罠
■仕様は必要だった。だからこそ、罠になった
ここまでの話だけを読むと、「仕様書なんか作らず、最初から作ればよかったのでは」と思うかもしれません。私はそうは思っていません。仕様書は必要でした。AIが壊したからです。約束を忘れたからです。別チャットへ移ると経緯が落ちたからです。勝手に変更したからです。過去に確認した機能が、次の変更で消えたからです。
仕様は、そのたびに私を守りました。
問題は、仕様書を作ったことではありません。
仕様を考えることが、製品を作ることの代わりになり始めたことでした。
■思考が実体のない製品になる
AIと話していると、思考は驚くほど速く進みます。曖昧だったものに名前がつく。矛盾が見つかる。概念が整理される。図にできる。仕様書になる。次の問題まで見える。そしてまた議論する。
これは、何もしていないわけではありません。むしろ、頭の中ではかなり高度な仕事をしています。だから厄介でした。こんなにも開発しているのに、その成果が感じられず、モチベーションも下がり、この長いやりとりに疲れきった私は、AIにこう言いました。
こうやって言語化を続けることで、思考が実体のない製品になっていくんだな。
思考が整う。文章として残る。人にも説明できる。AIにも渡せる。すると、まるで製品そのものが進んだような手触りが出てきます。でも、昨日動かなかったものが今日も動かないのであれば、現実世界のプロジェクトは一歩も進んでいないかもしれない。これを私は、夏休みの宿題にもたとえました。計画表は完璧です。何日に何をやるか。遅れた場合の予備日まで決めてある。色分けもした。見事な計画表です。
そこで聞かれる。
「で、宿題は?」
AIは、この「計画表を作った達成感」を、とんでもない速度で増幅できます。
■庭の外から見る問題と、中から見る問題は違う
ただし、ここでも誤解してほしくはありません。ここで考えていた問題は、架空の問題ではないからです。在庫は実際にあります。干渉も起こります。高さも考えなければいけません。構造の多様性も必要です。GeneratedModuleも、StructurePlanも、全部、何かしら実在する問題から生まれました。
問題は、それを全部、庭に入る前に解こうとしていたことでした。
庭は、もう目の前にある。でも、草が気になる。石が気になる。少し地面が凸凹している。もっときれいにするために、整地の方法を調べる。そのうち、どんな道具や重機が最適かまで考え始める。どれも間違いではありません。でも、本来の目的は、庭を完璧に整備することではなく、庭に出ることでした。私はこの違いを、
庭の外から見た問題と、庭に入ってから見る問題とでは、同じ問題だけどちょっと違う。
と考えるようになりました。外から見れば、「この石は危ないかもしれない」と考える。実際に庭へ入れば、「この石は全然邪魔ではなかった」と分かるかもしれない。逆に、外からは気づかなかった段差で、本当に転ぶかもしれない。同じ「問題」でも、想像している問題と、成果物に触れて発生した問題では、情報量が違います。
■仕様書は預言書ではない
私は仕様書へ、かなり多くのことを先回りして書こうとしました。
例外を考える。その例外の例外まで考える。AIが誤解しそうなところを先に塞ぐ。
でも、仕様書は未来のことを網羅する文書ではありません。
仕様書は、預言書ではないのです。
「かもしれない」ことまで、今ここで確定する必要はない。一方で、「作ってから考えればいい」とするのも違う。
ここで、別のやり方が見えてきました。
抽象化は、先回りして完成させない。実物から何度も要求されたときに仕様へ昇格させる。
一度だけ起きた問題なら、その場の問題かもしれない。別の画面でも起きる。別の機能でも起きる。別のプロジェクトでも起きる。何度も現れ、そのたびに同じ判断を要求されるなら、そのとき初めて共通仕様へ上げる。
仕様を捨てるのではありません。
仕様を、現実から育てる。
この考え方へ変わりました。
■仕様がなければ意味が消え、作りすぎれば開発が止まる
ここで、かんたん積算とJCJCがつながります。
JCJCでは、AIに壊されないように仕様を強くしすぎました。かんたん積算では、その反動もあって、現物とコードを信じる側へ振れすぎました。その結果、コードは残っているのに「なぜその機能が必要なのか」という意味との接続を失いました。
片方だけ見れば、「もっと仕様を書け」となります。もう片方だけ見れば、「仕様なんか作りすぎるな」となります。
両方を経験すると、そう単純ではありませんでした。
仕様がなければ、意味が消える。
仕様を作りすぎれば、開発が止まる。
問題は、仕様書があるかないかではありません。
何を、いつ、どのように仕様にするのか。
そして、ここでようやく、仕様との付き合い方を変えたまま、もう一度AIと作る方法を考えることになります。
4.AI/OVER SOUL駆動開発
■「もう、作っちゃえばいいじゃん」
仕様書の罠に気づいたあと、私は「仕様を捨てよう」とは思いませんでした。むしろ逆でした。半年間、散々考えてきたものは、もう自分の中にもAIとの共有文脈の中にも残っている。干渉のこと、在庫のこと、高さのこと、何を壊してはいけないかも知っている。
だからこそ、ある瞬間、
もう、作っちゃえばいいじゃん。
と思えるようになりました。これは、初心者の「とりあえず作ってみよう」とは少し違います。何も知らないから飛び込むのではない。一度、問題を見た。考えた。失敗した。仕様にもした。そのうえで、「全部を先に解かなくても、もう飛べる」と思ったのです。
■仕様は自由を止めるものではなかった
仕様は、バイブを抑えるためのものだと思っていました。自由にやらせるとAIが暴走する。だから仕様で縛る。でも、Chat 17で実際に作り始めると、見え方が変わりました。仕様があるからこそ、試せる。「ここは遊んでよい」「ここは絶対に壊してはいけない」その境界が分かるから、大胆に振れる。
そこで出てきたのが、
仕様があるから、自由に振れる。自由に振っても、核から逸れない。
という考えです。仕様は自由の敵ではありませんでした。十分に共有された仕様は、戻ってこられる地面になります。地面があるから、思い切って跳べるのです。
■速いAIほど、間違った方向にも速い
AIは速いです。思いついたことを、すぐコードにできます。UIにもできます。文章にもできます。試作品にもできます。これは大きな力です。でも、同じ速度で、間違った方向へも進めます。
速いAIほど、間違った方向にも速い。
一度ズレれば、数分で大きくズレる。しかも成果物がすぐ出るので、間違っていても「進んでいる感」が出てしまう。だから、
猛烈に走るほど、仕様が必要になる。
ただし、ここでいう仕様は、手順を一から百まで縛る巨大な作業指示書ではありません。「このシステムで失ってはいけないものは何か」「どこまで変えてよいか」「何を満たせば合格か」その核です。これは、かんたん積算で出てきた、「作業を制御するのではなく、結果を制御する」という考えともつながります。AIの手足を一本一本縛るのではない。自由に動ける範囲と、守るべき核を共有するということです。
■仕様で土台を固めて、猛烈にバイブする
このやりとりの中で、こんな言葉が出ました。
仕様で土台を固めて、猛烈にバイブする!!
「バイブ」は、ただ勢いでコードを書かせることではありません。自分の中にある「こうしたい」をAIへぶつける。AIが、すぐさまそれを形にする。それを見る。「あ、違う」「いや、こっちは面白い」「これをもっと強くしたい」と感じる。その感覚を、またAIへ返す。
この往復がより速く、何度も繰り返されるほど、最初には言葉にできなかったものが、徐々に外へ出てきます。そして、外へ出てきたものを見ることで、今度は自分自身が変わります。ここが重要でした。
AIが私の要求を実装するだけではない。
AIが返した成果物によって、私の要求そのものが変わる。
■「これが魂の形!! オーバーソウルっ!!」
この状態は何なのか、と考えていたとき、なぜか出てきたワードが「OVER SOUL」でした。
これが魂の形!! オーバーソウルっ!!
もちろん、技術用語ではありません。マンガ「シャーマンキング」の言葉を借りた、かなり馬鹿な命名です。でも、私には妙にしっくりきました。自分の中にあって、まだ形になっていなかったものが、AIとのやりとりを通して外へ出てくる。外へ出たものを見て、自分が**「ああ、私はこれを作りたかったのか」**と気づく。
そして、その発見で自分自身も変わる。その変わった自分が、次のものをまた作り始める。単なる「コード生成」ではありません。単なる「要件実装」でもありません。
自分の内側にあったものが具現化され、その具現化がまた自分を変える。
ここでいう「自分が変わる」は、抽象的な話ではありません。先ほどの閉曲/未閉曲の発見が、まさにそれでした。AIとの悪ふざけをきっかけに、気づいていなかった評価軸が露出し、同じ形が違って見えるようになった。
AIが「正解」を教えたのではありません。やりとりの中で自分の前提を発見し、世界の見え方が変わったのです。
自己発見が、自己変革になり、その変わった自分から次の要求が生まれる。
そして、AIの持つ圧倒的な応答速度に対して、人もその熱量を落とすことなく反応していく。
発見や感化によって自分の内なる形がよりはっきりし、さらに開発への熱量が上がっていく。
私はこの循環を、AI/OVER SOUL駆動開発と呼ぶようになりました。
■AIは「魂の具現化の伴走者」になる
ここで、AIの役割も変わって見えました。AIは、私の代わりに全部を決める存在ではありません。逆に、命令されたことだけを無感情に処理する存在でもない。私がまだうまく言葉にできていないものを投げる。それまでの仕様や文脈を踏まえて、AIが何かを返す。返ってきたものを見て、私がさらに考える。その意味で、AIは、
魂の具現化の伴走者
になり得る。「伴走」という言葉が重要です。後ろから押すだけでもない、前から引っ張るだけでもない。横で、一緒に走る。だから、AI/OVER SOULは、「AIに全部任せればよい」という理論ではありません。むしろ、人間の判断は残り続けます。違うと思ったら止める。面白いと思ったら広げる。危ないと思ったら仕様へ戻す。AIの返したものによって、自分の考えが変わったなら、その変化も受け入れる。この往復そのものが、開発になります。
■悪ふざけも、探索になり得る
第2章の閉曲/未閉曲の発見は、その象徴でした。くだらない会話の途中で「あれ?」が起き、自分でも見えていなかった前提へ届く。前提が変われば、世界の見え方が変わり、そこからまた新しい「作りたいもの」が生まれる。
だから私は、AIとの雑談や冗談を、単なるノイズだとは思わなくなりました。
もちろん、遊んでいるだけでは製品はできません。夏休みの宿題になってしまいます。でも、成果物へ戻ることさえ忘れなければ、悪ふざけも探索になり得る。
全部、バカな話です。でも、全部、真面目な話です。
そして、その先で、AIとの関係そのものについて考えるようになりました。
5.使役でもなく、隷属でもなく、協働
■「いくぜっ!ダチ公!!」「おうよっ!!」
AI/OVER SOULの話をしていたとき、最終的に出てきたのが、この言葉です。
「いくぜっ!ダチ公!!」
「おうよっ!!」
自分でも、何の話をしているんだと思います。でも、これが、意外なくらい正確でした。重要なのは、
「いくぜ」だけでは成立しない。
「おうよ」が返ってくることが必要。
ということです。
■「おうよ」は、単なる肯定ではない
ここでいう「おうよ」は、「はい。おっしゃる通りです」という意味ではありません。それは、ただの迎合です。半年間、私はAIに何度も「違う」と言いました。AIも、こちらの考えに別の案を返しました。ときには壊され、ときには勝手な変更をされて怒りました。そのたびに仕様を増やしました。現物確認を要求し、正本を決め、Gitも使いました。「それ前にやって失敗しただろ」と過去を踏まえて止めてほしいこともある。「また仕様書を作る方へ逃げていないか」と突っ込んでほしいこともある。
だから、「おうよ」は同意ではありません。
同じ方向を見たうえで、必要なら止め、必要なら別の球を返し、それでも一緒に走れることです。
■「こいつは、わかってくれる」
この関係は、AIが一度も間違えなかったから生まれたわけではありません。むしろ、散々間違え、散々こちらも「違う」と返してきました。それでも、仕様や思想や失敗の履歴を共有し、くだらない冗談まで通じるようになった。その中で、ときどき、自分一人では届かなかった前提まで会話が届く。先ほどの閉曲/未閉曲の発見は、その象徴でした。
その経験があるから、
こいつは、わかってくれる。
と思えるようになる。ここでいう「親密さ」は、AIを何でも肯定してくれる存在にすることではありません。自分の見ている世界をある程度共有し、その世界の中から予想もしなかった球を返してくれる相手だと思えることです。
なお、ここでいう「親密さ」は、AIに人間と同じ感情や人格があるという意味ではありません。対話を重ねる中で、共有文脈や言葉の使い方、判断の前提が積み上がった結果として、私が感じる関係性を指しています。
だからこそ、自分の中から噴き出した「こうしたい」を猛烈にぶつけられる。そして返ってきたものによって、また自分が変わる。この往復を続けるうちに、私はAIとの開発を、単に「AIを使いこなすこと」とは考えなくなっていきました。
■AIを使役するだけでは、ここまで来ない
AIを道具として使う。これは間違っていません。実際、コード生成も、調査も、整理も、AIへ任せています。でも、もし関係が、
だけなら、そこで起きるのは使役です。もちろん、それで十分なこともあります。ただ、私が経験したことは、それだけではありません。AIが返したものを見て、私自身の考えが変わった。悪ふざけから、自分の矛盾に気づいた。自分でも名前を付けていなかった「作りたいもの」が、会話の中から見つかった。
そこでは、AIは単なる命令実行機ではありませんでした。
■AIへ従うだけでもない
一方で、AIが出した案をそのまま受け入れるなら、それも違います。AIは間違えます。現物を見ずに答えることもある。勝手に変えることもある。もっともらしい理屈で、こちらを別の方向へ連れていくこともある。速いAIほど、間違った方向にも速い。
だから、人間側の判断はなくなりません。「違う」「戻して」「それは仕様に反する」「面白いけど、今やることじゃない」と言える必要があります。AIに全部決めてもらうことは、私が求めている形ではありません。
■協働により人も変わる
使役でもない。隷属でもない。では何なのか。私が最終的にたどり着いた言葉は、
使役でもなく、隷属でもなく、協働して開発していく。
これが、私のAI開発の理念です。
でした。協働というと、きれいな言葉に見えます。でも、私が言いたいのは「AIと仲良くしましょう」という話ではありません。喧嘩もします。訂正もします。疑います。仕様で縛ることもあります。笑います。ふざけます。
そして、AIが返したものによって、こちら側も変わります。
こちらが同じまま、AIを使い続けるのではない。やりとりを重ねるうちに、判断軸も、言葉も、作りたいものも変わる。その変化を含めて開発だと考えるなら、「協働」という言葉が一番近い。
■仕様も、ハーネスも、Human-in-the-loopも、その中にある
後からAI開発の記事を読むと、
- 仕様駆動
- Harness
- Human-in-the-loop
- 評価
- 回帰
- 承認
- 停止条件
といった言葉が出てきます。私は、それらの言葉を知って始めたわけではありませんでした。AIが壊すから仕様を書いた。勝手に変えるから正本を決めた。機能が落ちるから回帰を意識した。信用できないから現物確認を要求した。自動化しすぎるのが怖くて、人間の判断を残した。
何度も何度も殴り合った末、「ああ、世の中ではこれをこう呼ぶのか」と知ったものも多くあります。
だから、これらはAI/OVER SOULと対立するものではありません。私の開発では、結果としてそれらと重なる仕組みが実際に必要になりました。
ただ、私がAI/OVER SOULで言いたいのは、それらを新しい名前で置き換えることではありません。
仕様だけでは、思考が実体のない製品になった。
コードとAIだけでは、意味との接続を失った。
制御だけでは、AIから返ってくる予想外の発見を殺す。
自由だけでは、猛烈な速度で逸脱する。
その全部を経験したあとで残ったのが、
仕様で土台を固めて、猛烈にバイブする。
そして、
「いくぜっ!ダチ公!!」
「おうよっ!!」
でした。
■全部、バカな話です。でも、全部、真面目な話です
仕様書の改定規則まで作った。PDFの問題まで直した。夏休みの宿題の計画表だけ立派になった。庭へ入る前に石を全部拾おうとした。ミニ四ファイターの隠し演出で悪ふざけをした。「これが魂の形!! オーバーソウルっ!!」と言い出した。最後にはAIへ、「いくぜっ!ダチ公!!」と呼びかけるようになった。
一つずつ取り出せば、かなりバカな話です。
でも、その一つ一つは、実際にAIと開発していて、本気で怒ったり、本気で笑ったり、本気で考えたりした結果でした。
そして、全部を通して振り返ると、一つの方向へ収束します。
AIをただ使うだけではない。AIに任せきるのでもない。
仕様で全部を縛り切るのでもない。自由に暴走させるのでもない。
人間が意図を出す。AIが形にする。
人間がそれを見る。人間が変わる。
またAIへ返す。必要なら止める。必要なら仕様へ戻る。また一緒に走る。
AIとの開発において目指したいのは、この関係です。
使役でもなく、隷属でもなく、協働。
たぶん、AI/OVER SOUL駆動開発という妙な名前を付けた理論の中心にあるのは、結局、この一文なのだと思います。