メインコンテンツへスキップ

vibe coding はなぜ最後の 1 割で詰まるのか

·
数学 ソフトウェア開発 確率 クーポンコレクター問題 本番化 vibe coding AI
KONDO Kenji
著者
KONDO Kenji
目次

vibe coding は、最初は速い。

意図を投げれば動くコードが返ってくる。ハッピーパスはすぐ通る。主要な機能もそれなりに動く。週末に思いついたアイデアが、その晩のうちにデモ可能なところまで来てしまう。

しかし、そこから本番品質に近づけようとすると急に遅くなる。

体感では「9 割できているのに、最後の 1 割で同じ時間がもう一度かかる」、ひどいときには「半分の時間で 9 割まで来たのに、残りの 1 割に倍以上かかる」。 vibe coding を経験した人なら、誰でもこの非対称性に覚えがあるはずだ。

この現象を、簡単な確率モデルで書いてみた。すると、構造として面白いインサイトが得られた。前半が速いほど、後半の遅さは際立つ。これは構造の問題として言い換えられる。

ついでに白状しておくと、こんなことを書きたくなったのは、最近カントの『道徳形而上学の基礎づけ』を読んでいたからだ。形而上学観がどこに反映されているかは、あとでわかる。

非理想点の集合
#

システムには、本来修正されるべき「非理想点」が有限個あると仮定する。なお「非理想点」というのは僕の造語である。

$$ D = \{d_1, d_2, \dots, d_n\}. $$

冒頭で予告した形而上学的なところは、まさにここである。実物を見たこともない $D$ を、いきなり有限集合として書き下してしまっている。そのあたりはまあ、目をつぶる。

ここで $d_i$ は、狭義のバグだけではない。

  • 仕様と違う挙動
  • UI の違和感
  • ボタン位置の悪さ
  • エラーハンドリング不足
  • レイテンシ
  • 文言の不自然さ
  • 運用上の不便さ

などを含む。つまり $D$ は、理想状態からのズレの集合である。

システムを試すことを「試行」とみなす
#

システムを 1 回試すことを、1 回の試行とみなす。 vibe coding の文脈で言えば、生成されたコードを動かしてみる、デプロイしてみる、ユーザーに触ってもらう、その一回一回が試行である。各試行では、ある非理想点 $d_i$ に遭遇するかもしれない。

まず単純化して、各試行で $D$ のうちひとつに等確率で遭遇するとする:

$$ P(d_i \text{ に遭遇する}) = \frac{1}{n}. $$

これはかなり粗いモデルだが、まずは本質を見るには十分である。

未発見の非理想点
#

時点 $t$ で、すでに発見済みの非理想点集合を $C_t \subseteq D$ とする。未発見集合は

$$ U_t = D \setminus C_t, $$

その個数を $|U_t| = m$ とする。

次に新しい非理想点を見つける確率
#

1 回の試行で、新しい非理想点に遭遇する確率は

$$ P(\text{新しい非理想点に遭遇}) = \frac{m}{n} $$

である。全体 $n$ 個のうち、未発見が $m$ 個あるからだ。

次の発見までの待ち時間
#

未発見が $m$ 個ある状態で、次に新しい非理想点を見つけるまでの試行回数を $X_m$ とする。各試行で新しい非理想点に当たる確率は

$$ p_m = \frac{m}{n} $$

である。各試行は独立で、当たる確率も毎回 $p_m$ だから、初めて当たるまでの試行回数 $X_m$ は幾何分布に従う。すなわち、

$$ P(X_m = k) = (1 - p_m)^{k-1} \cdot p_m = \left(1 - \frac{m}{n}\right)^{k-1} \cdot \frac{m}{n}, \quad k = 1, 2, 3, \dots $$

期待値は

$$ \begin{aligned} E[X_m] &= \sum_{k=1}^{\infty} k \cdot (1 - p_m)^{k-1} p_m \\ &= \frac{1}{p_m} \\ &= \frac{n}{m}. \end{aligned} $$

全部見つけるまでの期待試行回数
#

最初は未発見が $n$ 個。そこから $n-1, n-2, \dots, 1$ と減っていく。したがって、全部見つけるまでの期待試行回数 $E[T_n]$ は

$$ \begin{aligned} E[T_n] &= \sum_{m=1}^{n} E[X_m] \\ &= \sum_{m=1}^{n} \frac{n}{m} \\ &= n \sum_{m=1}^{n} \frac{1}{m}. \end{aligned} $$

つまり

$$ E[T_n] = n H_n, $$

ここで $H_n = \sum_{m=1}^{n} \frac{1}{m}$ は調和数である。近似すると、 $H_n \approx \log n + \gamma$ なので、

$$ E[T_n] \approx n \log n + \gamma n. $$

つまり、 $n$ 個ある非理想点を全部見つけるまでに、平均して $n \log n$ 程度の試行が必要になる。

後半が遅くなる理由
#

非理想点が $n$ 個あるなら、単純に $n$ 回試せば全部見つかるわけではない。期待値は $n \log n$ オーダーになる。これは、発見済みのものに何度も遭遇するからである。

未発見が $m$ 個のとき、次の発見までの期待試行回数は $\frac{n}{m}$ である。例えば $n=100$ とすると、

未発見数 $m$次の発見までの期待試行回数
1001
502
1010
520
1100

最後の 1 個は、平均して 100 回試さないと見つからない。最後の 1 つが重いという感覚は、こうして並べてみると、まあそういうものなのだろう、と納得できる。

vibe coding がこの現象を際立たせる理由
#

ここまでの話は、ソフトウェア開発全般に当てはまる。それでも vibe coding でこの非対称性が体感的に強く出るのには、理由がある。

vibe coding は、前半の生産性を桁違いに上げる。意図を投げれば動くコードが返ってくる。未発見が多いうちは、試せばたいてい新しい非理想点に当たり、最初の数試行で次々と潰れていく。

ここまでは速い。

ここで、非理想点をユーザーが踏みうるルートのように見立ててみる。修正済みのものは、もう「ふつうに動く」だけのルートだ。すると、未発見が減るにつれて、システムを試してもすでに直したルートばかりを通ることになる。残った未発見は少ないから、ランダムに選んでも辿り着くのは、直し終えた理想点ばかりだ。

ここで vibe coding ならではの事情が効いてくる。生成されたコードは、書いた本人ですら細部を把握しきれていないことが多い。だから自分が踏んでいない経路は、人間のレビューではショートカットできない。残った非理想点に出会うには、ひたすら試行を増やすしかない。

しかも、前半が速いことそのものが、後半の遅さの感じ方を増幅する。同じ「未発見が 1 個残った状態」でも、そこに至るまでが 1 時間なら、最後の 1 個に 100 試行かかることが致命的に遅く感じられる。前半の速度は、後半の遅さの感覚的な分母になる

要するに、 vibe coding はこの構造的な遅さを解消するわけではない。解消するどころか、前半の急加速によって後半の遅さを露わにする

まとめ
#

本番化とは、既知のタスクを順番に消化する作業ではない。未発見の非理想点に確率的に遭遇するまで、試行を繰り返す作業だ。 vibe coding で「もう動いてるじゃん」と思ったあとに、もう直したところを何度もなぞるあの時間は、その試行回数を定義通り消化しているだけである。

ここまで来てようやく言えるのだが、これはまさにクーポンコレクター問題の構造そのものだ。 $n$ 種類のおまけを全部集めるのに $n H_n$ 回くじを引く、あの古典的な問題である。一言でいえば、

vibe coding の本番化とは、非理想点のクーポンコレクター問題である。

そして、最後が重いのは、最後だから重いのではなく、引いても引いても直し終えたルートばかりを通るから重いのである。

おわり

関連記事

これが最小になる値はな〜んだ?」問題 〜最適化問題を考える〜
AI 最適化 数学
混合行列、適合率、再現率、F値、MCC
技術 AI 数学
スライドパズルの数理
技術 数学 アルゴリズム AI