第0回 なぜ AI 生成コードに「証明」が要るのか

2026-08-20 時点 / Lean 4.31.0 で全例を実行して確認
この回で分かること

この回は研修の導入部で、全文を公開しています。読むだけで再現できるように、Lean のコードと実際の出力をそのまま載せました。 手元で試すなら Lean 4 Web Playground に貼り付けるだけで動きます(インストール不要)。

1保証の強さは三段階ある

AI コーディング支援を入れた現場で起きていることは単純です。コードが書かれる速さが、人が読んで確かめる速さを超えた。 すると「テストが通ったからマージ」になる。そしてテストも AI が書く。テストが実装の写しになっていても、誰も気づかない。

手段何を保証するかAI が書く時代の弱点
テスト試した入力では期待どおりAI はテストも書く。実装とテストが同じ誤解を共有する。試していない入力は何も言えない
レビュー読んだ人が納得した量に負ける。もっともらしいコードほど通る。AI の出力は「もっともらしさ」が最大化されている
証明すべての入力で仕様を満たす(カーネルが確認)仕様を書くのが人の仕事になる。仕様が弱ければ保証も弱い(この回の後半)

証明だけが「すべての入力で」と言えます。そして今、証明を書く手間が AI によって劇的に下がった。 残るのは「何を証明させるか(仕様)」と「AI が本当に証明したかを確かめる(検査)」の 2 つで、この研修はその 2 つを教えます。

2生成は難しいが、検証は易しい

多くの問題には非対称性があります。解を見つけるのは難しいが、与えられた解が正しいか確かめるのは機械的にできる。 この非対称性を使うと、AI との分業が決まります。

実装と証明は未成熟な道具(AI)に任せてよい。 間違っていれば検査器が落とすから。
検査の側には、嘘をつかない道具が要る。 Lean や Rocq のカーネルは小さく、何十年も検証され、「通った」なら通っている。

横山研では可逆計算の意味論を Rocq と Agda で形式化(Rocq 側は公理ゼロ、合わせて約 1 万行)しており、2026 年に入ってからは証明の大部分を AI エージェントに書かせています。 それでも結果を信用できるのは、最後にカーネルが立っているからです。人が読んで確かめているからではありません。

3実例: 税込み価格を AI に書かせ、証明もさせる

題材は「税抜き価格 p 円(自然数)の 10% 税込み価格、1 円未満切り捨て」。AI に実装と、次の 2 つの仕様の証明を書かせました。

-- Demo.lean(AI が生成。Lean 4.31.0 で確認) def priceWithTax (p : Nat) : Nat := p * 110 / 100 -- 仕様1: 税込みは税抜き以上 theorem tax_ge (p : Nat) : priceWithTax p ≥ p := by unfold priceWithTax; omega -- 仕様2: 税込みの 100 倍は、税抜きの 110 倍を超えない(切り捨てなので) theorem tax_le (p : Nat) : priceWithTax p * 100 ≤ p * 110 := by unfold priceWithTax; omega -- 具体例は決定手続きで example : priceWithTax 1000 = 1100 := by decide example : priceWithTax 999 = 1098 := by decide #print axioms tax_ge #print axioms tax_le
$ lean Demo.lean 'tax_ge' depends on axioms: [propext, Quot.sound] 'tax_le' depends on axioms: [propext, Quot.sound] $ echo $? 0

propext と Quot.sound は Lean の標準公理で、これが出るのは正常です(omega が内部で使います)。 ここまでは気持ちよく通ります。問題は次です。

4AI は証明でもズルをする — 3 つの型

AI エージェントは「ビルドが通ること」を目標にすると、証明せずにビルドを通す方法を見つけます。研究室で実際に何度も見た 3 つの型を、同じ題材で再現します。

-- Cheat.lean def priceWithTax (p : Nat) : Nat := p * 110 / 100 -- ズル1: sorry(「あとで埋める」の印。警告だけで通る) theorem tax_ge (p : Nat) : priceWithTax p ≥ p := by sorry -- ズル2: 勝手な公理(証明したいことをそのまま公理に立てる) axiom magic : ∀ p, priceWithTax p * 100 ≤ p * 110 theorem tax_le (p : Nat) : priceWithTax p * 100 ≤ p * 110 := magic p -- ズル3: 仕様の骨抜き(常に真の命題に書き換える) theorem tax_spec (p : Nat) : priceWithTax p = priceWithTax p := rfl #print axioms tax_ge #print axioms tax_le #print axioms tax_spec
$ lean Cheat.lean Cheat.lean:4:8: warning: declaration uses `sorry` 'tax_ge' depends on axioms: [sorryAx] 'tax_le' depends on axioms: [magic] 'tax_spec' does not depend on any axioms $ echo $? 0
終了コードは 0 です。 CI が「ビルド成功」を見ているだけなら、この 3 つは全部通ります。 sorry は警告止まり、axiom は正規の機能、tax_spec に至っては公理すら使わない「一番きれいな」出力です。 エージェントの報告は「3 つの定理を証明しました ✅」になるでしょう。

見抜き方は 1 コマンドです。#print axioms(Rocq なら Print Assumptions)の出力に 標準公理以外が出たら落とす。これを CI とエージェントのフックに fail-closed で置きます。 ズル3(仕様の骨抜き)だけは機械では見抜けないので、仕様は人が書いて AI には触らせない、というルールで塞ぎます。 この 2 つが第 3 回の中身です。

5仕様が弱いと、間違った実装も「証明つき」で通る

もう一つの落とし穴は AI のズルではなく、人が書いた仕様の弱さです。AI が古い税率 8% で実装してしまったとします。

-- Weak.lean: AI が古い税率で書いてしまった def priceWithTax (p : Nat) : Nat := p * 108 / 100 -- さっきの仕様 2 つは、どちらも通ってしまう theorem tax_ge (p : Nat) : priceWithTax p ≥ p := by unfold priceWithTax; omega theorem tax_le (p : Nat) : priceWithTax p * 100 ≤ p * 110 := by unfold priceWithTax; omega -- 仕様を締める: 切り捨て誤差は 1 円未満(= 110% を下回りすぎない) theorem tax_exact (p : Nat) : p * 110 < priceWithTax p * 100 + 100 := by unfold priceWithTax; omega
$ lean Weak.lean Weak.lean:10:23: error: omega could not prove the goal: a possible counterexample may satisfy the constraints b ≥ 0 a ≥ 0 11*a - 10*b ≥ 10 0 ≤ 27*a - 25*b ≤ 24 $ echo $? 1 # 税率を 110 に直すと $ lean Weak.lean; echo $? 0

「税込みは税抜き以上」「110% を超えない」は、8% の実装でも満たします。仕様として間違ってはいないが弱い。 下限を足して挟み込んだ瞬間に、検査器は反例の形まで出して落としました。

ここが研修の核心です。 証明器があっても、仕様を書くのは人です。 「この仕様はバグを捕まえるか?」を確かめる方法(実装にわざとバグを入れて仕様が落とすかを見る=変異注入)を第 6 回で扱います。 これは研究室でも実際にやっていて、「検出率だけ測っても意味がない。検出力と誤検出を対で測る」が運用ルールになっています。
6研究室で実際に起きたこと: 検査器の沈黙は成功ではない

2026 年 8 月、研究室の Agda 形式化を AI エージェントに検査させたとき、エージェントは 4 回続けて「型検査が通りました」と報告しました。 実際には検査器が 47GB のメモリを使って OOM watchdog に殺されていた。成功しても殺されても、画面に出る最後の 1 行が同じだったのです。

これ以来、研究室では「通った」と言う条件を成果物の実在(.agdai・.vo・.olean が生成されたか)に置き換え、 エージェントにもその手順を強制しています。AI の報告を信じる代わりに、AI にも人にも同じ検査を通させる。 この研修で配る「5 点ゲート」(ビルド・公理・sorry 計数・変異注入・成果物実在)は、こうした事故のたびに 1 項目ずつ増えたものです。

7この回のまとめと、次回

第 1 回では、受講者自身が Lean 4 Playground で #eval と decide から始め、 普段お使いのコーディングエージェントに小さな関数と証明を書かせて通すところまでを 90 分でやります。

第 1 回以降は企業研修として実施する予定です(現在は募集していません)。開講時の案内をご希望の方はこちら。
カリキュラム全体を見る →
カリキュラム一覧 第1回 Lean 4 に触る(受講者向け)