正解ひとつで採点したテストのスコア、測り直したら半分になった

AIが生成したテストを正解実装ひとつだけで採点すると、品質は水増しされる。複数の有効・無効な実装で測り直すと、最も優秀なモデルでさえ59.67%から28.00%まで落ちた。
← 목록으로
온
온틀 리서치
2026년 10월 10일 更新 2026.10.16 読了 13分 閲覧 2

コーディングエージェントはコードを書くだけではない。そのコードが正しいかを確かめるテストも一緒に作る。テストがグリーンになれば「パス、完了」。開発の現場では、このグリーンのランプが信頼の証だ。

問題は、このグリーンが点く仕組みのほうだ。ふつうは「正解実装ひとつ」に対してテストを走らせ、パスすれば合格とみなす。ところが、同じ要件を満たす正しいコードはたいてい複数ある。もっともらしく間違ったコードも複数ある。正解をひとつ見ただけで、そのテストを信じてよいのだろうか。

最近のある研究は、まさにこの問いを携えてテストを採点し直した。正解ひとつではなく、複数の実装にまんべんなく走らせてみたのだ。最も成績のよかったモデルの合格率が大きく落ち込んだ。テストは一文字も変えていない。測り方を変えただけである。

なぜ正解ひとつでは足りないのか

良いテストは二つのことをやってのける。バグのあるコード(修正前)では失敗してバグをあぶり出し、きちんと修正したコードではパスする。業界の慣行は、この二つの条件を「正解ひとつ」に対して確認する。修正前は失敗、正解実装(gold solution)ではパス。それで合格。これを単一リファレンス評価(single reference evaluation)と呼ぶ。

ここに落とし穴がある。採用試験を、模範解答一部だけに合わせて出題する場面を思い浮かべてほしい。その模範解答のスタイルにだけ合う問題になってしまうと、同じく正解を書いたのに別の解き方をした応募者を落としてしまう。逆に、もっともらしく間違った応募者はふるい落とせずに通してしまう。テストも同じだ。前者は特定の実装のやり方に必要以上に縛られて、別の正しいコードを壊してしまうこと。後者は、求められた挙動を実際には検査できていないことだ。どちらにも単一リファレンス評価は「合格」のハンコを押してしまう。

だから本当に問うべきはこれだ。このテストは、実装が変わっても信頼できるのか。複数の正しい実装にはまんべんなく通りつつ、仕様に反した実装には敏感でなければならない。この研究の核心は、この古くからある要求を評価指標そのものに組み込んだ点にある。

より厳しく測る方法:実装パネル

やり方は単純だ。テストを正解ひとつではなく「実装パネル」に対して採点する。課題ごとにパネルを組む。基準となるリファレンス1個、やり方は違うが正しい実装4個、間違った実装5個。課題300個にそれぞれ10個の実装があるので、ラベル付きの実装は3000個になる。有効と無効がちょうど半々だ。テストを作るときは、このパネルを隠す。エージェントは要件だけを見てテストを書き、採点はパネル全体に対して行う。

注目したいのは、間違った実装の作り方だ。コードに人為的な傷をつけて偽の欠陥を量産する(変異)のではなく、能力がまちまちな複数のモデルが実際に解いて出した誤答を集めた。本当にやらかす間違いに近づけようという選択だ。似た実装ばかりが集まってパネルが易しくなりすぎないよう、互いに十分に異なるものだけを残すフィルターもかけている。

採点は四つの数字に分かれる。

  • RAR:従来方式のスコア。正解ひとつに対して測った成功率だ。
  • VAR:別の正しい実装をどれだけ受け入れるか。
  • IRR:間違った実装をどれだけふるい落とすか。
  • JSF:この三つを一度に要求する。修正前のコードで失敗し、選ばれた正しい実装をすべて通過させ、間違った実装をすべて拒否して初めて1点。一つでも外れれば0点。オール・オア・ナッシングだ。

この設計の賢さは別のところにある。パネルをリファレンス1個に減らせば、JSFはちょうど昔のスコア(RAR)へと戻る。従来方式は間違っているのではなく、新しい物差しの最もゆるい特殊ケースなのだ。そしてJSFは構造的にRARを超えられない。両者の差こそが、「正解ひとつは通過したが、別の実装の前で崩れたテスト」の取り分である。

数字で見ると差は明らかだ。1位の構成でさえ、従来スコア(RAR)は59.67%だったが、JSFは28.00%だった。正解ひとつには60%近く通っていたテストが、条件を足したとたんに半分以下へ落ち込んだわけだ。ファミリー別の最高構成のJSFは、その28.00%から11.33%まで散らばっている。先行するモデルでも「実装が変わっても信頼できるテスト作り」は、まだ解けていないということだ。

細部には興味深い非対称がある。6構成のうち5構成が、有効の受け入れ(VAR)よりも無効の拒否(IRR)のほうが得意だった。間違った実装をふるい落とすのはやさしいが、別の正しい実装を「これも正解」と受け入れるほうが難しい、ということだ。ある構成は無効の拒否が86.33%と最も高いが、有効の受け入れ(50.33%)とJSF(11.33%)は最下位だった。ふるい落としが得意なだけでは、良いテストにはなれない。逆に、ある構成は有効の受け入れが77.00%とよく受け入れるが、無効の拒否(66.00%)は相対的に鈍かった。

一つはっきりさせておこう。JSFは「選ばれたそのパネル」に対するスコアだ。世の中のすべての正しい・間違った実装に対する絶対保証ではない。実際に課題を絞ってパネルを拡大してみたところ、リファレンスだけを立てたときに平均49.33%だったスコアが、有効・無効の実装を交互に9個足すと24.33%まで下がった。テストはそのままだ。パネルが厳しくなるほどスコアは削られる。「JSF 28%」を絶対的な等級ではなく、この構成での測定値として読むべき理由がここにある。

テストはどこで崩れるのか

抽象的な分類よりも、実際の場面のほうが早い。論文が挙げた二つの例がくっきりしている。

ポーカーハンドを判定するコードがある。あるテストは、「エースロー・ストレート」と「スリーカード」を突き合わせるケースを一度も入れていなかった。その比較が抜けているせいで、エースロー・ストレートをハイカードと誤って分類する間違った実装が、堂々と通ってしまう。テストがその挙動をまったく通らなかったわけだ。これをカバレッジの空白と呼ぶ。カバレッジとは、テストが関連するコード行を実際に通ったかどうかを指す。

括弧パーサー(括弧の対応が取れているかを解析するコード)のテストは、毛色が違う。対応の取れない括弧は入力として入れていた。ところが、結果の「個数」だけを確認していた。そのせいで、有効な括弧グループを丸ごと捨ててしまう実装まで「個数は合っているのでパス」と受け入れてしまう。コードには到達したのに、判定を誤ったわけだ。これを誤った検査と呼ぶ。ここでいう「検査」とは、テストが結果を正しい/間違いと判別する、あの一行のことだ。

どちらのテストも、修正前のコードでは失敗し、正解実装ではパスする。従来方式は平然とグリーンを点ける。パネルを付けた瞬間に、はじめて欠陥があらわになる。

ここで数字を当てはめると、意味がくっきりする。失敗したテスト286件を専門家が分類したところ、いま見た「誤った検査」が50.0%で最も大きかった。「カバレッジの空白」が34.6%、テスト自身のバグが15.4%だった。三つ目はこんな具合だ。テストの中に関数を仕込んで呼び出すうちに、引数が一つ余計に紛れ込み、正解実装でさえテストが壊れてしまう。

ここで押さえておきたい点。失敗の半分は、コードには到達したのに判定を誤ったケースだ。カバレッジは「関連するコードに到達したか」を見るだけで、「到達してきちんと判定したか」までは保証しない。カバレッジの数字だけを見て完了のハンコを押すと危ない理由が、ここにある。

より賢く作る方法:互いに突き合わせて直す

測る物差しを立てたので、スコアを引き上げる側も見てみよう。研究陣が示した生成・検証の手順は、核心を一文で言える。テストを一度作って終わりにせず、別々に作ったもの同士を突き合わせて直せ。三つのパートで回る。

第一に、互いに異なる探索戦略を受け取った複数のエージェントが、それぞれテストを作る。戦略をわざと別々にするのは、失敗する道が一つではないからだ。別の角度から突かなければ、別の欠陥に触れられない。

第二に、あるエージェントが作ったテストを、別のエージェントが直したコードに走らせてみる。自分のテストが他人の正常なコードを間違いだと言うなら、それはそのテストが特定の実装に過度に縛られているサインだ。その反例を使ってテストを直す。さらに、要件だけを見た独立のレビュアーが、判定が正しいかを別途点検する。

第三に、こうして磨いた「生成戦略」そのものを、訓練用の課題でもう一度手入れしたうえで、その戦略を凍結して本番の試験に投入する。

最も興味深い結果は、部品を一つずつ外して寄与度を測る実験(アブレーション)から出てくる。テストを1セットから3セットに増やすだけでは、スコアはほとんど動かなかった。ところが、その3セットを互いに突き合わせて直す交差検証をオンにすると、スコアが一気に跳ね上がった。どちらの場合も、課題あたりに使える計算量(推論予算)は同じに固定してあった。つまり、利得は「より多く生成」ではなく「互いに検証」から出たのだ。完成形の手順は、モデルが既定で使っていたやり方より8.67〜9.00%ポイント、最も単純な1セット構成より11.67〜12.00%ポイント高かった。基準の異なる二つの数字なので、足し合わせて読んではいけない。

正直な妥協も一つある。戦略を磨くとき、肝心の看板指標であるJSFではなく、旧指標のRARを目標に据えた。JSFが厳しすぎて、学習の信号がほとんど立たないからだ。測る目標と上げる目標がずれている、という点は研究陣も認めている。

ONTLE の QA に当てはめるなら

この研究が他人事に読めないのは、ONTLE の働き方がまさにこの構図だからだ。

一つの場面を最後まで追ってみよう。ある顧客プロジェクトで、AI PM が決済の返金計算機能を担当した。AI がコードを書き、同じ流れでそのコードを検証するテストを作り、テストがグリーンになると「返金計算 完了」と顧客に報告する。このグリーンこそ、正解ひとつ分の採点だ。いま見たとおり、その品質は体系的に水増しされている可能性がある。顧客に手渡した「完了」バッジが、実は同じく正しい別の実装を壊したり、微妙に間違った実装を見逃したりするテストでありうる、ということだ。

だから手を入れるべき場所は、ONTLE パイプラインのレビュー・QA ゲートだ。完了のハンコを押す前に、小さな手続きを一つ挟む。

  1. 完了の直前に、機能を書いた本体とは別のモデルで「正しい代替実装を二〜三個」と「意図的に壊した実装を二〜三個」を作る。ONTLE にはすでに段階ごとに別のモデルを使うルーティングがあるので、代替の生成を本体と別のモデルに任せるのは、追加の設備なしでできる。
  2. 生成したテストを、そのパネル全体に走らせる。代替実装をすべて通過させ、壊した実装をすべてふるい落として初めて、通過とみなす。
  3. カバレッジが高いからといって終わらせない。エッジな入力を入れて、判定が欠陥を実際に捕まえるかを確認する。
  4. 何が正しく何が間違っているか(パネルのラベル)は、要件だけを見た独立のレビューが確定する。人がやろうと、別のエージェントがやろうと。このラベルがいい加減なら、ゲートもいい加減になる。
  5. すべての課題にかけるわけではない。誤った「完了」の代償が大きいところ、お金が動く計算やデータを変更する機能から、狭くかける。

性急な同一視は戒めるべきだ。この研究が扱ったのは「エージェントが生成したテスト」の品質を測る問題だ。ONTLE のすべての完了判定が、この構造とそっくり同じわけではない。人が手で書いたテストや、顧客がすでに持っているテストまで同じ数字でくくって語る根拠はない。コストもタダではない。実装を一つ増やすたびに、テストを最初から走らせ直さなければならない。だからパネルは小さく、ゲートは狭く、というのが正しい。顧客の画面には相変わらず「完了」しか見えないとしても、その裏でゲートが正解ひとつではなく複数の実装で検証を終えたかどうかが、信頼の実体になる。

よくある質問

では、テストカバレッジのツールはもう役に立たないということですか?

いや、そうではない。カバレッジは JSF と正(+)の相関を示した。関連するコードに到達することは、確かに役に立つ。ただし「到達」と「正しい判定」は別物だ。カバレッジは必要条件であって十分条件ではない、ということだ。カバレッジを捨てるのではなく、その上に「到達したうえで判定が正しいか」を測る一枚を重ねるほうがよい。

間違った実装を変異で作らず、実際の誤答で集めると、何が良くて何が物足りないのですか?

利点は現実性だ。人やモデルが実際にやらかす間違いに近い欠陥の分布が得られる。物足りない点は、その分布が結局、誤答を出したモデルたちの間違いの傾向をなぞってしまうことだ。彼らがあまり出さない種類の欠陥は、パネルに入りにくい。複数の公開ベンチマークから課題を引いてきている分、それら原本のバイアスも一部引き継ぐ。

小さなチームで、代替実装をいくつも作る余力がない場合、どこから始めればいいですか?

いちばんよく壊れる機能を一つ選べばいい。新しい実装を作る必要すらなく、過去のバグ報告で実際に間違っていたコードを「無効な実装」として再利用し、昔の正しいリファクタリング版を「有効な実装」として使うところからが出発点になる。パネルは二〜三個あれば十分だ。肝心なのは規模ではなく、正解ひとつを離れた検証を一度でも走らせてみることだ。

テストが通っても信じられないなら、では何を信じてデプロイするのですか?

完璧な保証など、そもそも存在しない。パネルは「絶対安全」を与えるものではなく、グリーンの根拠を正解ひとつから複数へと広げる仕掛けだ。信頼を 0 か 1 かで見るのではなく、検証の幅をリスクの高さに合わせて調整するダイヤルとして見るほうが、実務に合う。お金のかかった機能にはパネルを広く、軽微な変更には狭く。

参考資料