はじめに: AIレビューが「使えない」と感じる理由
「AIコードレビューは使えない」--以前の私も、同僚もそう言っていました。CopilotやClaude Codeにレビューを投げても、的外れなコメントばかりで結局自分で見直す。
転機は、AIコードレビューのハーネス(制御システム)を構築し始めたときでした。レビュー観点のチェックリストに「並行処理の制御」を追加しようとして手が止まった。Mutex、デバウンスくらいは書ける。でも「全パターンを網羅しているか」と聞かれると答えられない。観点が定義されていなければ、AIが的外れな指摘を返すのは当然です。
そこからレビューの仕組みやAIが理解しやすい評価方法を学び、少しずつ運用に組み込んでいきました。まだ試行錯誤中ですが、AIからの的外れな指摘は格段に減り、デグレや動作確認時の失敗も目に見えて減っています。
この改善の土台になったのが、LLM研究の世界で体系化されているLLM-as-a-Judgeの設計原則です。
LLM-as-a-Judgeとは何か
LLM-as-a-Judgeは、LLMの出力をLLM自身で評価する手法です。
「LLMでLLMを評価するなんて、自分の答案を自分で採点するようなものでは?」と思うかもしれません。しかし、重要な違いがあります。
生成と評価は別のタスクです。
生成LLMは「自由回答の小論文を書く」仕事。評価LLMは「採点基準に沿って○×をつける」仕事。後者の方がはるかに簡単で、精度も高い。
コードレビューに当てはめると:
この非対称性が、LLM-as-Judgeを実用的にしています。
コードレビューで使える4つの評価パターン
パターン1: PASS/FAIL判定
Hamel HusainとGergely Oroszの共著記事(Pragmatic Engineer)の実証データによると、点数評価よりPASS/FAIL二値判定の方が精度が高いことが分かっています。
# ❌ 点数評価(精度が低い)
「このコードのセキュリティスコアは4/5点です」
# ✅ PASS/FAIL判定(精度が高い)
「このコードにSQLインジェクションの脆弱性があります: FAIL」
なぜ二値の方が良いのか。LLMは「3点と4点の違い」のような微妙な差を一貫して判定するのが苦手です。一方、「脆弱性がある/ない」は明確で、判定のブレが少ない。
パターン2: 観点別分離評価
1回のレビューで「セキュリティも可読性もパフォーマンスも見て」と投げると精度が落ちます。
# 観点を分離して個別にジャッジさせる
review_aspects = [
{"aspect": "security", "prompt": "SQLインジェクション、XSS、認証バイパスの脆弱性はあるか?"},
{"aspect": "concurrency", "prompt": "排他制御、デッドロック、レースコンディションのリスクはあるか?"},
{"aspect": "error_handling", "prompt": "エラーハンドリングは適切か?例外の握りつぶしはないか?"},
]
1観点1ジャッジ。人間のレビューでも「セキュリティレビュー」「パフォーマンスレビュー」を分けるのと同じ発想です。
パターン3: ペアワイズ比較
2つのコード変更を比較して「どちらが優れているか」を判定させます。
変更A: tryブロックで例外を握りつぶしている
変更B: 例外を適切にログ出力してから再スローしている
→ 変更Bの方がエラーハンドリングが優れている
リファクタリングのBefore/After比較に有効です。
パターン4: 基準付き直接スコアリング
評価基準を明示的に定義して、それに沿って判定させます。
## 評価基準: エラーハンドリング
- PASS: 全ての外部API呼び出しにエラーハンドリングがある
- PASS: タイムアウト設定がある
- PASS: リトライロジックにバックオフが実装されている
- FAIL: 上記のいずれかが欠けている
基準が明示的なほど、LLMの判定はブレません。
AIレビューが失敗する「3つの溝」
Hamel HusainとShreya Shankar(O'Reilly「Evals for AI Engineers」共著者)は、AIレビューの失敗を3つの溝で説明しています。
1. 理解の溝(Gulf of Comprehension)
開発者がデータとモデルの挙動をスケールで把握できないギャップ。
「AIレビューが何を見落としているか」を全件確認することは不可能です。100件のPRを流しても、11件目で見逃した脆弱性に気づけない。
対策: トレース(AIの推論過程の記録)を定期的にサンプリングして手動レビューする。
2. 仕様の溝(Gulf of Specification)
プロンプトと意図のギャップ。「セキュリティを見て」というプロンプトでは、LLMは何をチェックすべきか推測するしかありません。
対策: 「SQLインジェクション」「XSS」「認証バイパス」など、具体的なチェック項目を列挙する。
3. 汎化の溝(Gulf of Generalization)
完璧なプロンプトを書いても、未知のパターンでは失敗する。
対策: 本番データでの継続的バリデーション。新しい失敗パターンを発見したら、評価基準に追加してループを回す。
実践: AIコードレビューの構築ステップ
Step 1: 決定論的チェックを先に
LLMに全てを任せない。まず決定論的なツールで自動チェックできるものを潰します。
決定論的チェック(リンター/SAST):
- ESLint, Semgrep, Bandit → 既知パターンの脆弱性検出
- 型チェック → 型安全性
LLM-as-Judge(上記で拾えないもの):
- ビジネスロジックの妥当性
- 設計パターンの適切さ
- ドキュメントとコードの整合性
OpenAIのハーネスチームも「決定論的カスタムリンター + LLMベースのエージェント」の併用を実践しています(Birgitta Böckeler, martinfowler.com)。
Step 2: 観点を定義する
レビュー観点を洗い出します。
| カテゴリ | チェック観点 |
|---|---|
| セキュリティ | SQLi, XSS, 認証, 暗号化, シークレット管理 |
| 並行処理 | Mutex, Semaphore, デッドロック, レースコンディション |
| エラー処理 | 例外握りつぶし, リトライ, Circuit Breaker |
| 可読性 | 命名, 関数長, コメント, 型定義 |
Step 3: PASS/FAIL基準を明文化する
各観点について、何がPASSで何がFAILかを明示的に書きます。曖昧さはLLMの判定ブレの原因になります。
Step 4: CI/CDパイプラインに組み込む
FAILがあれば人間にエスカレーション。OpenAIの実践では「agent-to-agentレビュー」で回し、人間は本当に判断が必要な場面だけ介入しています。
Step 5: 失敗をフィードバックする
「AIレビューが見逃した脆弱性」を発見したら、その事例を評価基準に追加します。
Mitchell Hashimoto(HashiCorp共同創業者)の言葉(意訳):
エージェントがミスしたら、二度と同じミスをしないよう環境を改善する
これが「ハーネスエンジニアリング」の本質です。
まとめ: 「AIレビューが使えない」のはAIのせいではない
| 問題 | 原因 | 対策 |
|---|---|---|
| 的外れなレビュー | レビュー観点が未定義 | 観点をすべて列挙 |
| 判定がブレる | 点数評価を使っている | PASS/FAIL二値判定に変更 |
| 見落としがある | 1回で全観点をチェック | 観点別に分離評価 |
| 新しいパターンに弱い | フィードバックループがない | 失敗事例を評価基準に追加 |
AIコードレビューの品質は、モデルの性能ではなく評価設計の品質で決まります。
LLM-as-Judgeの設計原則を理解し、ハーネスを構築すること。これが、AIレビューを「使えない」から「手放せない」に変える方法です。
皆さんのチームでは、AIコードレビューの観点をどう定義していますか? うまくいった設計やハマった落とし穴があれば、ぜひコメントで教えてください。
参考
- LLM-as-a-Judge for Software Engineering(arxiv)
- A pragmatic guide to LLM evals for devs(Pragmatic Engineer)
- LLM-as-a-judge: a complete guide(Evidently AI)
- Harness engineering(OpenAI)
- Harness engineering for coding agent users(Birgitta Böckeler, martinfowler.com)
- Judge Reliability Harness(RAND Corporation)
この記事で紹介した評価パターンと3層モデルの実装を体系的にまとめました。観点定義からCI/CD統合まで、AIコードレビューの仕組み化を1冊で解説しています。
📕 AIコードレビューを仕組み化する技術: レビュー時間60%削減の3層モデル(Amazon Kindle)
