対象読者: AIにコードや文章を書かせていて、そのレビューもAIに任せられるか判断したい人
Node.js のエラー解説を集めたリポジトリで、コードと文章をAIに生成させ、それを別ベンダーのAIにレビューさせています。レビューを1回回すたびに、どの指摘を採用し、どれを誤検知として捨てたかを1ファイルに記録してあります。この記録が溜まったので、レビュアー側の精度を測ってみました。測るのはレビュアーの当たり外れで、指摘されたコードの側に何が多いかはAIに書かせたコードのレビュー指摘95件を全部分類したに分けています。
測定に使った記録
対象は、Node.js のエラーメッセージごとに解説記事を書き、各記事の「再現」と「修正」を Docker コンテナで機械検証しているリポジトリです。ここでは記事本文とサイト実装に対して、外部レビューを9回回してあります。
- レビュアーは異なるベンダーの3モデル: GPT-5.5(Codex CLI)/ Claude Opus 4.8(1M) / Gemini 3.5 Flash(Antigravity CLI)
- Gemini は9回中4回だけ参加しています
- 各回の成果物は「レビュー依頼のプロンプト」「モデルごとの生の指摘」「採否記録」の3点セット
採否記録には、指摘ごとに「一致したモデル」「一次情報や実機で裏を取った結果」「採用・保留・棄却の判断と理由」が残ります。精度の集計はここから取りました。
3つのうち Gemini だけが Flash、つまり小型・高速のティアです。 残る2つは旗艦モデルなので、同じ土俵の比較ではありません。Flash を選んだのは、1世代前の Pro(3.1)を回すより、新しい世代の小型モデルのほうが有利だろうという読みからです。**この読みは外れていました。**9回を終えたあとに Flash と Pro を同じ条件で回して比べ、Pro に切り替えています(後述)。あとでモデルごとの傾向に触れますが、そこをモデルの優劣として読まないでください。
指摘は散文で書かれていて、1つの指摘が複数の記事にまたがることもあります。件数は重複を統合したあとの指摘グループ単位の概算で、数え方によって±数件は動きます。
記録に残る名前は、モデルの自己申告
採否記録のモデル識別子は、レビュアー自身が名乗ったものを使っています。レビュアーを起動するランナーは、実際にどのバージョンが走ったかを知りません。CLI に「自分のベンダーとモデル識別子を書け」と指示して、返ってきた名前をそのままファイル名にしています。
これが1件ずれていました。Codex CLI の出力は自分を codex-gpt-5 と名乗りましたが、実際に走っていたのは GPT-5.5 です。上のモデル名は、CLI 側の設定と突き合わせて確かめた実際のバージョンに直してあります。
自己申告が当てにならないのは、この後で見る「確証あり」の欄だけではありません。自分が何者かという申告すら、そのままでは使えない。 集計に使うなら、記録された名前を実際の設定と照合する工程が要ります。
採用率は87%、誤検知は2%
| 区分 | 件数 | 率 |
|---|---|---|
| 採用(一部採用・検証後の採用を含む) | 約116 | 約87% |
| 保留・見送り・次の段階へ | 約14 | 約11% |
| 誤検知として棄却 | 3 | 約2% |
棄却したのは、明らかな事実誤りだけです。この後で見る失敗の型は誤検知に数えていません。結論は合うが理由づけが外れる、根拠を欠いた自己申告といった指摘は、採用したうえで裏取りの工程で直しています。2%は「捨てた指摘」の割合であって、残りがそのまま使えたわけではない。
同じ誤検知率は、別のリポジトリでも桁が近くなります。レビュー結果と対応記録だけが残っているリポジトリでは、棄却が34件中1件でした。ただし数え方は揃っていません。こちらの母数は重複を統合したあとのグループ、あちらは統合前の行そのままで、34件では1件の増減が3ポイントを動かします。再現性の裏づけというより、誤検知率の桁が合う程度に読んでおくのがいい。
数字だけ見れば、AIレビュアーはほぼ当たる、という話になります。しかしこの87%は、レビュアーの出力をそのまま採点した数字ではありません。
この87%を作っている工程
採否記録は、モデルの出力を受け取った直後ではなく、3つの工程を通したあとに書かれます。
flowchart TD
A[レビュー依頼<br/>範囲を明示: 機械検証済みの再現・修正は対象外] --> B1[GPT-5.5]
A --> B2[Claude Opus 4.8]
A --> B3[Gemini 3.5 Flash<br/>参加は9回中4回]
B1 --> C[突き合わせ<br/>3者一致 / 単独指摘 に仕分け]
B2 --> C
B3 --> C
C --> D[採用候補を一次情報・実機コンテナで裏取り]
C --> G[明らかな非該当は保留・対象外へ]
D --> E[採否記録<br/>ここで初めて採用・棄却が決まる]
G --> E
E --> F[87% / 2% はこの地点の数字]
レビュー依頼の時点で、対象範囲を絞っています。エラーの再現と修正はコンテナで自動検証済みなので、レビュー対象から外す。機械が保証している部分を人手のレビューに再確認させても、指摘の数が増えるだけで記事は良くなりません。
そのうえで、異ベンダーの複数モデルに同じ範囲を投げ、指摘を突き合わせる。最後に、採用しそうな指摘だけ一次情報とコンテナで裏を取る。棄却の3件は、この裏取りで落ちたものです。
87%は、レビュー出力の正確さではなく、この工程を通過した指摘の割合を表しています。工程を外して指摘をそのまま反映していたら、後述する失敗の型がそのまま本文に入っていました。
棄却より頻度が高い、5つの失敗の型
棄却は3件しかありません。それより頻度が高いのは「採用したが、そのままでは使えなかった」指摘で、これには繰り返し現れる型があります。
1. 結論は当たり、機構の説明が外れる
ある記事で、Node が出す Did you mean to import "./util.js"? というヒントについて、「読者の手元では出ないと書いてあるが、実際には出る」という指摘が Claude と Gemini から High で挙がりました。結論は両方とも正しい。
理由づけは両方とも外れていました。Claude は「Windows か Node のバージョンに依存する」と推測し、Gemini は「Windows のバグ」と書いた。実機で確かめると、ヒントが出るかどうかはカレントディレクトリ基準で決まります。当時の検証がサブディレクトリ構成で走っていたため、候補ファイルが探索範囲から外れていた、というのが真因でした。バージョンによって変わるのは表示形のほうで、Node 18 は引用符なしで親ディレクトリ側の候補を出し、20.11 以降は引用符つきで出ます。
結論だけ採り、機構は捨てる。指摘の「なぜ」は、指摘とは独立に検証する必要があります。
2. 自己申告の「確証あり」は根拠にならない
Python 記事のレビューで、Gemini だけが各指摘に 確証レベル: 確証あり という欄を付けてきました。プロンプトが要求した項目ではなく、そのモデルが自発的に足したものです。他2モデルは、確信が持てない箇所に「要確認」と書いていました。
「確証あり」が付いた指摘のうち2件は、示された根拠では裏が取れません。enable_mkldnn=False で例外を回避できるという主張は、根拠として挙げられた GitHub Issue にその記述がありません。降格先を 3.2.2 にすべきという主張の根拠は「複数報告を確認済み」だけでした。
そこで、単独モデルの確証は採らないという運用ルールに従い、両方を実機検証に回しました。結果、2件とも当たっていました。enable_mkldnn=False は降格せずに例外を消し、3.2.2 は正常に動きます。記事の解決策は、この2件を採用する形に書き直しています。
当たっていたから安心、とはなりません。同じ「確証あり」の欄が、根拠のある主張にも、示した出典では裏が取れない主張にも同じ顔で付きます。申告文からは見分けられない以上、自己申告の確信度は採否の入力として使えません。検証キューに入れる合図として扱うのが精一杯です。
3. 確認できない固有名が混じる
GPT-5.5 が、「現行の Node 公式ドキュメントは、CommonJS の名前付き export の検出に使うものを merve と呼んでいる」と書いてきました。記事が cjs-module-lexer という名前を無条件の現在形で書いているのは古びやすい、という指摘です。
他の2モデルはこの点に触れず、こちらでもその名前の実在を確認できませんでした。真偽の判定は保留しています。
一方、指摘の狙いである「内部実装名を断定して書くと将来ずれる」という点は、名前の真偽と関係なく成立します。本文は「Node が静的に解析する」を主文にして、実装名を主語から外す書き換えで対応しました。固有名の正誤に踏み込まずに済む逃げ方が、たまたまあった例です。
4. 参照先を取り違える
Gemini が、ある記事の74行目にある表現を、別の記事の74行目として引用しました。指摘された表現自体は実在し、指摘の中身も妥当です。引用先だけが違う。
file:line 付きで指摘が来ても、現行ファイルで再照合してから扱う。この一手間を省くと、指摘のない箇所を直すことになります。
5. severity が一致しない
同じ箇所に対して、GPT-5.5 が High、Claude が Low を付けた例があります。ESM 判定条件の表から、Node の構文自動検出の行が抜けている、という指摘でした。
Claude の言い分は、その記事の題材は require だけを含むファイルであり、自動検出は import や export があるときにしか発火しないので、表は題材の範囲では正しい、というもの。GPT-5.5 の言い分は、import と require が混ざったファイルは新しい Node で ESM 扱いになり、その経路を表が取りこぼしている、加えて姉妹記事の表と食い違う、というものでした。
どちらも事実としては正しく、severity の差は「記事単体で見るか、記事群の整合で見るか」の差でした。裁定は、題材内では事実誤りではないが不完全であり、記事群の整合として公開前に直す、としています。逆向き(Claude が High、GPT-5.5 が Medium)も出ます。EOL を迎えた Node のバージョンを移行先として推奨している箇所や、Blob がグローバルになったバージョンの記述が、その例です。
レビュアーが付けた High をそのまま作業順に使うと、記事群の整合のように、1記事だけを渡されたモデルには見えない軸が落ちます。severity は受け取ってから付け直すものとして扱っています。
一致は、正しさの代わりに使える並び替えの軸
3モデルが独立に同じ箇所を指摘したものは、9回を通してほぼ全件採用しています。一次情報で確認して覆ったものは、いまのところありません。
たとえば「グローバルの Blob が使えるのは 18.0.0 以降で、15.7 の追加時は require('buffer') が要る」は3者一致で挙がり、一次情報の確認を経てそのまま採用しました。
一致したから正しい、という因果を主張はできません。3モデルとも同じ学習データの偏りを持つ可能性は残ります。それでも、一致は突き合わせるだけで得られて、裏取りには時間がかかる。裏取りの順番を決める軸として、これ以上に安いものが見当たらないので使っています。
裏返すと、単独指摘は裏取りの前に採用してはいけない、という運用になります。棄却した3件は、すべて単独指摘から出ています。失敗の型のうち、機構の誤りや確認できない固有名も、単独指摘か単独の推測部分から出たものです。型5(severity の食い違い)だけは別で、これは2モデルが一致して、しかもどちらも正しいのに深刻度が割れる。合議では消えない軸なので、単独指摘を締めても防げません。
モデル別の傾向
9回、うち Gemini は4回という標本です。これはモデルの優劣を測ったものではなく、この標本で観察した傾向にすぎません。標本が小さく参加回数も揃っていないうえ、Gemini だけが小型ティア(Flash)で、他の2つは旗艦モデルです。条件がそろっていない以上、下の並びを能力の序列として読まないでください。挙げるモデル名は特定のバージョンを指していて、バージョンが変われば傾向も変わります。
- Claude Opus 4.8: バージョン依存の記述と事実照合で、単独 High が当たった事例が目立ちました。
crypto.randomUUIDの対応表が本文と矛盾している、fetchの実験的機能の警告が出るバージョンの範囲が違う、といった指摘です。キャッシュ再生成の副作用のような、変更の波及先を拾った例もあります。 - GPT-5.5: 構造と情報設計の単独指摘が当たった事例がありました。記事の中で「直し方」が出てくるのが遅い、といった読者の詰まり方に関わる指摘は、この1本だけから出ています。確認できない固有名の引用が1件ありました。
- Gemini 3.5 Flash: 採用された指摘もあります(
try/catchの適用範囲の限定、Blobのバージョン)。他の2本が拾わない指摘を出すことがあり、小型ティアという前提で見れば、想定より働いているというのが実感です。一方で振れ幅は3つの中でいちばん大きく、前述の自己申告2件と誤引用1件はこのモデルから出ました。その振れがモデルの性質なのか、小型ティアだからなのかは、この9回では切り分けられません。この点は9回のあとに、同じ枠を Pro に替えて比較しました(下記)。run.ps1で外せる補助枠にしているのは、当たり外れが読みにくいぶん、多様性の担保として置いているからです。
Flash と Pro を同じ条件で比べた(9回のあと)
ここまでの9回は、Gemini 枠をすべて Flash で回しています。9回を終えたあとに、同一プロンプト・同一記事・同日で Gemini 3.5 Flash と Gemini 3.1 Pro を並べ、3バッチぶんを比較しました(どちらも High ティア)。
| Flash | Pro | |
|---|---|---|
| 出力量 | 約20KB × 3 | 約10KB × 3(半分) |
| 一次情報での裏取り | なし | あり(スクリプトを書いて実行し、パッケージレジストリの API と標準ライブラリの差を実測) |
| 機構の主張の確認 | なし | あり(ビルドツールのバイトコード処理系や、警告フィルタの仕様書を引用) |
| 統合判断 | 結論のみ | 機構の違いから導出 |
| 指摘の重心 | 編集面(評価語・リンク欠落・表記ゆれ) | 事実・機構・規約違反 |
Pro は出力が半分で、中身が濃い。 Flash の 20KB は、同じ編集上の指摘を3記事ぶん繰り返して嵩んでいました。以後は Pro に切り替えています。
新しい世代の小型モデルより、1世代前の旗艦モデルのほうが良かった、というのが結論です。冒頭に書いた「新世代の小型のほうが有利だろう」という読みは、外れていました。
ただし Pro も過信はできません。Pro はある記事を「一次資料の実測値と完全に一致」と全面肯定しましたが、実際にはその一次資料自身が「断定するな」と書いていた箇所を、本文が断定していました。「確証あり」と言い切る癖は、ティアを上げても消えない。 前掲の型2は、そのまま残ります。
この比較は Gemini 枠の中の話で、標本は3バッチです。GPT-5.5 / Claude Opus 4.8 と Gemini の優劣を測ったものではありません。
運用に落ちたこと
このデータから、レビューの回し方に反映した点は5つあります。
- レビュー依頼の時点で範囲を宣言する。機械で検証済みの部分は対象外だと書く
- 単独指摘は、裏取りを通してから採否を決める
- モデルの自己申告は、確信度も身元も採否の入力にしない。記録したモデル名は、CLI 側の設定と照合して実際のバージョンを確かめる
- severity は受け取った値を使わず、自分で付け直す
- file:line 付きの指摘も、現行ファイルで再照合してから読む
この5点を含めた回し方(プロンプトの書き方、レビュアーの起動、intake の手順)は、2エージェント相互レビューの実運用に分けて書いています。
もう1つ、記録の側にも穴がありました。バージョン依存の記述を見たレビューでは、5本の記事に High が集中しました。原因は、記事ごとのサマリーに「裏取りが必要な項目」の欄がありながら、その確認結果を本文へ反映する工程が無かったことです。未検証リストは作られるが、消し込まれない。次のバッチから、各記事に「主張」「一次情報のURL」「確認日」を並べた sources.md を置いて、リストを閉じるところまでを工程に入れました。