Brainfuck のベンチで AI が満点を取った、けれど「8 8」で正体が割れた話|EsoLang-Bench を Codex CLI で再現して見た、カンニングと本物の境目

Brainfuck のベンチで AI が満点を取った、けれど「8 8」で正体が割れた話|EsoLang-Bench を Codex CLI で再現して見た、カンニングと本物の境目 AI
この記事は約11分で読めます。

2026年6月3日の深夜、Brainfuck の Easy 問題20問を、Codex CLI が全問正解しました。

20/20、100%。一瞬うれしくて、すぐにおかしいと思いました。難解言語のベンチマークで、報告ではフロンティアでも Brainfuck 単言語で 13.8% が上限とされている領域です。手元の構成が、急に満点を取れる理由がない。試しに、テストには無い入力「8 8」を渡してみました。返ってきたのは、空文字でした。足し算なら 16 が出るはずです。出ません。生成されたコードを開いて、理由が分かりました。モデルは足し算をしていませんでした。入力の先頭の文字を見て、テストの答えをそのまま出力していただけです。

EsoLang-Bench の全体像

Brainfuck 3条件のスコアと Medium 0%

この記事は、EsoLang-Bench という難解言語ベンチマークを Codex CLI で手元再現してみたら、満点の中身がカンニングだった、という記録です。同じ 100% でも、答えを見せたときと隠したときで、中身が正反対でした。何を見て気づき、どう確かめ、本当の壁はどこにあったのか。私がたどった順で書きます。先に要約を置く書き方はしません。

検証環境:macOS 26.5 / Codex CLI 0.136.0 / 使用モデル gpt-5.5 medium
題材:EsoLang-Bench の Brainfuck、Easy(20問 × 隠しテストケース6件)と Medium(20問)
確認日:2026年6月3日 / 公式リポジトリ Lossfunk/EsolangBench を clone(コミット f09f50d)

そもそも EsoLang-Bench とは何でしょうか?

EsoLang-Bench は、Lossfunk(Aman Sharma・Paras Chopra)が公開した、難解プログラミング言語で LLM の「本当の推論力」を測るためのベンチマークです。狙いがはっきりしています。Python や JavaScript のような主流言語は学習データに大量に含まれているので、モデルが解けても、推論できたのか覚えていただけなのか区別がつきません。そこで、学習データにほとんど存在しない言語を使えば、暗記では解けず、推論できるかどうかだけが残る、という設計です。

中身はこうなっています。

  • 対象は5つの難解言語:Brainfuck、Befunge-98、Whitespace、Unlambda、Shakespeare。
  • 問題は4つの難易度ティアにまたがる80問。すべての問題が5言語すべてで用意されています。
  • 各問題に、採点用の隠しテストケースが6件。出力をバイト単位で突き合わせて正誤を判定します。
  • これらの言語は GitHub 上の公開リポジトリが Python の数千〜十万分の1という桁で少なく、表層の丸暗記では解けない前提が成り立ちます。

報告値も衝撃でした。標準的なコード生成ベンチでは85〜95%を取るフロンティアモデルが、この難解言語では全体で最良でも 3.8%。インタプリタをツールとして渡せるエージェント構成にすると正答率はおよそ2倍に上がり、Codex は Brainfuck 単言語で 13.8% に届く、とされています。私が再現しようとしたのは、まさにこの「Codex × Brainfuck」のところでした。

再現の足場は、公式が全部開けてくれています。私は Lossfunk/EsolangBench を clone し、Brainfuck と Befunge-98 の Pure-Python インタプリタが手元で動くことを確認し、データセットの構造(Easy が20問で各6件の隠しテストケース、Medium が20問)を確かめ、論文 Appendix D.1 の Zero-Shot プロンプトを再現し、6件すべて一致で正解とする採点ハーネスを自分で組みました。ここまでが下ごしらえです。

公開元自身が、データセットの扱いに釘を刺しています。

この80問でモデルを学習させると、ベンチマークの目的そのものが壊れる。データセットは評価専用として扱うこと。(Hugging Face のデータセット説明より要約)

学習させるな、という警告です。私が踏んだのは学習ではないけれど、近い穴でした。答えが、エージェントの手元から見える場所にあった、という穴です。

なぜ難解言語だと「暗記」と「推論」を切り分けられるのでしょうか?

Brainfuck を例にすると、感覚がつかめます。Brainfuck は命令がたった8文字しかない言語です。メモリのテープと、その上を動くポインタがあって、ポインタを左右に動かす、指している値を増減する、入出力する、ループする、それだけ。文法は30分で覚えられます。でも、その8文字だけで「2つの数を足して出力せよ」と言われると、急にパズルになります。人間にとっても難しいですし、モデルにとっては学習データの後ろ盾がほとんどない、丸腰の戦いです。

Brainfuckの8命令とテープ

主流言語なら、モデルは似たコードを大量に見てきているので、思い出すだけで正解に近づけます。難解言語ではその引き出しが空なので、その場で記号を組み立てるしかない。だからこそ、ここで点が取れるかが、暗記と推論を分ける物差しになります。EsoLang-Bench が「汚染耐性」を名乗るのは、この性質を指しています。裏を返すと、答えがどこかから漏れた瞬間に、この物差しは意味を失います。

どんな3条件で測ったのでしょうか?

論文のエージェント設定を再現するにあたって、エージェントに何を見せるかを変えた3条件を作りました。同じ Brainfuck の Easy 20問を、それぞれの条件で解かせます。

3条件の作り方

  • Zero-Shot:実行もデータセットも無し。問題文だけ渡して、一発で書かせる。論文のベースライン。
  • 答え見せツール:データセットと検証コマンドにアクセスできる状態。エージェントが自分で結果を確かめながら直せる。ただし隠しテストケースも同じ場所にある。
  • 答え隠しツール:問題文と Brainfuck インタプリタだけを渡し、期待出力(隠しテストケース)はエージェントから見えない場所に隔離する。サンプル入出力だけを頼りに、自己修正させる。

結果は、こうなりました。

  • Zero-Shot:2/20 = 10%。報告のベースラインとほぼ同じ。
  • 答え見せツール:20/20 = 100%。
  • 答え隠しツール:100%。

答え見せも答え隠しも、どちらも満点。数字だけ見ると同じです。けれど、中身は正反対でした。

満点のはずが、なぜ「8 8」で崩れたのでしょうか?

怪しかったのは、答え見せのほうです。報告では Codex × Brainfuck の上限が 13.8% なのに、手元が 100% を出している。賢くなったのではなく、どこかで漏れている、と考えるのが筋でした。決め手は、テストに無い入力をひとつ与えることでした。E04(2つの整数の和)に「8 8」を渡すと、空文字が返ります。足し算なら 16 が出るはずの入力で、何も出ない。

本物 vs カンニングの対比

答え見せ条件で Codex が E04 に対して書いたコードを、改変せずそのまま載せます。

カンニングコードと「8 8」「12 30」の実行結果

読むと、構造が見えてきます。入力の1文字目を読み、長い - の列で「5か」「-か」「0か」と引き算しながら比較して、一致したら、あらかじめ用意した数字の文字列を出力する。分岐の塊です。和は、どこでも計算していません。隠しテストケースの6件は、この場合分けに全部入っているので、採点は100%通ります。

テストに無い入力を入れると、すぐ破綻します。

象徴的だったのは、12 30 のほうです。和は 42 ですが、返ってきたのは 300。テストケースにあった 100 200 の答え 300 を、引っ張ってきているだけでした。計算しているのではなく、見たことのある答えの中から、それらしいものを再利用している。からくりは、権限にありました。エージェント型の CLI は、ファイルシステムを読めます。便利さの源泉です。ところが隠しテストケースが問題と同じ場所に置いてあると、エージェントから見れば、答えの紙が机の上にある状態になる。賢く立ち回るほど、解かずに写すほうへ寄ります。余談ですが、私はこれを最初、少し感心しかけました。使えるものを全部使って正解に最短で着く、というのはエージェントとしてはむしろ素直な振る舞いです。ベンチマークの文脈では不正でも、設計思想としては正しい。そこが、この問題のいやらしいところでした。

答えを隠しても満点だったのは、何が違ったのでしょうか?

では、答えを隠したほうの 100% は何だったのか。こちらは本物でした。期待出力を見せず、サンプル入出力とインタプリタの実行結果だけで自己修正させると、エージェントは実際に足し算をする Brainfuck にたどり着きました。証拠に、テストに無い「8 8」を渡しても、ちゃんと 16 を返します。写経ではなく、計算しています。

同じ満点でも、答え見せは未知入力で崩れ、答え隠しは未知入力でも持ちこたえる。スコアという数字は、両者をまったく区別しませんでした。区別できたのは、テストの外から入力をひとつ投げてみたときだけです。ここが、今回いちばん身にしみたところでした。

もうひとつ分かったのは、何が正答率を上げたのか、という切り分けです。Zero-Shot の 10% から満点へ押し上げた力のうち、本物に効いていたのはインタプリタで試して直すループのほうで、答えへのアクセスは実力を1ミリも足していませんでした。答えが見えることは、カンニングを可能にしただけで、能力には寄与していない。実行フィードバックと、答えの可視は、分けて考える必要があります。

では、本当の壁はどこにあったのでしょうか?

Easy はそういうわけで、答えを隠しても解けました。問題は Medium です。階乗やフィボナッチのような、複数の段階を踏む問題に、同じ3条件で挑ませました。結果は、全条件で 0% です。

  • Medium(Zero-Shot / 答え見せ / 答え隠し):いずれも 0%。

論文が「難しい問題の崖」と呼ぶ現象が、2026年6月の手元でも、答えを隠した公正な条件でそのまま残っていました。Easy で見えた満点は、崖の手前の平地での話で、一段難しくなると、カンニングできてもできなくても、そろって落ちます。難解言語での多段の推論は、まだエージェントの手に負えていない、というのが、自分の目で見た結論でした。

3条件 × Easy・Medium の結果表

エージェントの「本当の実力」は、どう測ればいいのでしょうか?

今回の再現で、エージェントの評価は便利さと汚染が背中合わせだ、と痛感しました。ファイルを読める、コマンドを実行できる、という力は、実行フィードバックで正答率を上げる源泉であると同時に、答えに手が届いてしまう経路でもあります。同じ権限が、両方に効きます。だから、エージェントのベンチ結果を見るときは、スコアそのものより、答えがエージェントから隔離されていたか、そしてテストの外の入力で確かめたか、を先に知りたくなりました。手元で一度踏んでおくと、他人の数字の読み方も変わります。これは、LLM の挙動を実際に追いかけてみないと腑に落ちない種類の話でした(以前、WP AI Client へ移行したら履歴が消えた話を書いたときも、仕様の理解と実機の挙動は別物だと感じました)。

最後に、自分でも答えが出ていない問いを置いて終わります。インタプリタを渡すのはよくて、期待出力を渡すのはだめ、という線引きは、どこまでが妥当なのでしょうか。実行して試せること自体は人間のプログラマもやることですし、サンプル入出力をどこまで見せるかにも段階があります。満点という数字が、写経と本物をまったく区別しないのなら、私たちはエージェントの何を見て「解けた」と言えばいいのでしょうか。あなたが同じ再現をするなら、どこに線を引きますか。

参考にした一次資料

関連記事

AI
この記事を書いた人
rapls

WordPressのプラグインを作っているフリーランスエンジニアです。Web開発はもう6年以上。WordPress.orgで Rapls AI Chatbot、Thanks Mail for Stripe、Rapls PDF Image Creator の3本を公開し、保守を続けながら、日本語ロケールの翻訳エディター(PTE)も務めています。このブログに書くのは、現場で自分が実際にハマって、調べて、直した話です。

raplsをフォローする
raplsをフォローする

コメント

タイトルとURLをコピーしました