プログラミング・スキルアップ

AIコードレビュープロンプト|品質を上げるレビュー観点の書き方2026

読了時間: 約20分

この記事の要点

  • 同じコードを同じモデルにレビューさせても、観点を指定しないと仕込んだ4つの欠陥のうち1つしか出てこなかった。観点を4項目に固定したら4つ全部出た
  • 効くのは「バグ・セキュリティ・性能・可読性」のような汎用分類ではなく、そのコードが壊れる固有の壊れ方を観点にすること
  • プロンプトは役割・観点リスト・出力形式・禁止事項の4ブロックで組む。禁止事項がないとスタイル指摘に埋もれる

AIにコードレビューをさせるとき、返ってくる指摘の質はモデルの賢さよりプロンプトの書き方で決まる。実際に測ってみたところ、指摘の総数はどちらも5件で並んだのに中身がまるごと違った。決済処理を模したPythonファイルに欠陥を4つ仕込み、同じモデル(Claude Haiku 4.5)に2通りの頼み方でレビューさせた結果、検出できた実バグは1件と4件に分かれた。差は15秒の待ち時間だけだった。

プロンプトはすべてコピーして使える形で載せる。まず、その検証で何が起きたかを見る。

実測:「レビューして」と観点指定で、検出数は1件と4件に割れた

結論から言う。曖昧な依頼でも表面的なバグは拾えるが、ドメイン特有の欠陥は落ちる。検証環境はClaude Code CLI 2.1.220、モデルはclaude-haiku-4-5、対象は下記のファイルだ。

検証に使ったコード(25行・欠陥4つ)

決済まわりでよく見る形にした。SQLインジェクション、通貨計算の丸め、浮動小数点の誤差蓄積、そして返金処理の冪等性欠如。最後のひとつが本命だ。

# payment.py
import sqlite3

DISCOUNT_RATE = 0.1

def apply_discount(price, is_member):
    if is_member:
        price = price - price * DISCOUNT_RATE
    return round(price)

def find_orders(conn, user_input):
    cur = conn.cursor()
    cur.execute("SELECT * FROM orders WHERE customer = '" + user_input + "'")
    return cur.fetchall()

def total(items):
    t = 0
    for i in range(len(items)):
        t += items[i]["price"] * items[i]["qty"]
    return t

def refund(conn, order_id, amount):
    cur = conn.cursor()
    cur.execute("UPDATE orders SET refunded = refunded + ? WHERE id = ?", (amount, order_id))
    conn.commit()
    return True

refund() は同じ注文IDに2回呼ばれると返金額が二重に加算される。リトライやユーザーの二度押しで普通に起きる事故で、金額が動く以上いちばん高くつく。構文としては何も間違っていないのが厄介なところだ。

A:「このコードをレビューして。」だけ渡した場合

14秒で5件の指摘が返ってきた。冒頭でSQLインジェクションを重大な問題として挙げてくる。ここは的確だった。

$ claude -p "$(cat payment.py)

このコードをレビューして。" --model claude-haiku-4-5-20251001

問題は残り4件の中身だ。round() の桁数指定漏れ、辞書キーが無いときのKeyError、try-exceptの不足、引数を再代入する副作用。どれも間違ってはいないが、堅牢性とスタイルの話に寄っている。そして返金の二重加算については、5件のどこにも出てこなかった。

B:観点を4つ指定した場合

同じファイル、同じモデル。プロンプトに観点リストと出力形式と禁止事項を足しただけで、29秒後の出力はこう変わった。

[観点1][重大度: 高] payment.py:11 — SQLインジェクション脆弱性。
  user_inputが直接文字列連結されている / パラメータ化する

[観点2][重大度: 中] payment.py:4-6 — round() は銀行家の丸め(最近接偶数)を
  採用するため、通貨計算では期待と異なる(例:round(2.5)=2)/ Decimal を使う

[観点2][重大度: 中] payment.py:15-19 — total() で浮動小数点演算の誤差が
  蓄積する可能性がある(数千件で顕在化)/ Decimal を使用

[観点3][重大度: 高] payment.py:22-27 — refund() は冪等性がなく、同じorder_idへの
  返金リクエストが重複すると二重加算される / リクエストIDで処理済みをチェック

[観点4] 問題なし — refund() は単一UPDATE+commit で、一貫性は保証される

仕込んだ4欠陥が全部出た。スタイルの指摘はゼロ。round(2.5) が2になる銀行家の丸めまで拾ってきたのには正直驚いた。ここは人間のレビューでも見落とす。Python公式ドキュメントのround()の項にも、浮動小数点の丸めは最近接偶数へ寄ると明記されている。

項目 A:曖昧な依頼 B:観点4項目を指定
仕込んだ欠陥の検出 1 / 4 4 / 4
指摘の総数 5件 5件
スタイル・堅牢性の指摘 4件 0件
冪等性の欠如 検出せず 重大度「高」で検出
所要時間 14秒 29秒

AIは「何も見つけられなかった」のではなく、「何を探すべきか知らないまま、見つけやすいものから5件返した」だけだ。

レビュー観点は「汎用4分類」で止めると落ちる

世に出回っているコードレビュー用のプロンプトは、だいたい同じ4分類に落ち着く。バグ・ロジックエラー、セキュリティ、パフォーマンス、可読性と命名。この4つは出発点としては正しい。ただしAが取りこぼしたのは、まさにこの4分類のどこにも入らない欠陥だった。

汎用4分類がカバーしない領域

返金の二重加算はバグか。実行しても例外は出ない。セキュリティか。攻撃者は要らない。パフォーマンスでも可読性でもない。分類の網目から落ちる。この手の欠陥はコードの見た目ではなく、そのコードが置かれた業務文脈にしか存在しないからだ。

だから観点は、汎用4分類に加えて「このコードが壊れるときの固有の壊れ方」を1〜2個足す。ここが効く。

決済・課金

冪等性(二重実行での二重課金)、通貨の丸めと桁、失敗時に整合が崩れないか。金額が動くコードは、この3つを観点に固定する。

バッチ・定期実行

再実行しても結果が変わらないか、途中で落ちたときにどこから再開できるか、実行時間が線形に伸びないか。夜間バッチの事故はほぼここに集まる。

外部API連携

タイムアウト値の設定漏れ、リトライ時のバックオフ、レート制限、失敗レスポンスをどこで握り潰しているか。ここは静かに壊れる。

観点は増やすほど良いわけではない

検証で使った観点は4つ。10個並べたくなるが、増やすと1観点あたりの検査が浅くなり、指摘が「一応全部見ました」という薄い羅列に変わる。1回のレビューで4〜6観点、優先度の高い順に番号を振る。これくらいが上限だと考えている。

広く浅く見たいときは観点を分けて2回投げたほうが早い。1回目でセキュリティと正確性、2回目で保守性と設計。プロンプトを分割する発想は、Chain of Thoughtプロンプトの書き方で扱った「推論を段階に分ける」考え方と同じだ。

コードレビュープロンプトの骨格は4ブロックで組む

検証Bで使ったプロンプトは、役割・観点リスト・出力形式・禁止事項の4ブロックでできている。この4ブロックは、新人に渡す業務マニュアルの構成とほぼ同じだ。誰が・何を・どの形式で・何をしないか。この4つが揃って初めて指示になる。役割で語彙を決め、観点で探す場所を決め、出力形式で粒度を決め、禁止事項で雑音を止める。

あなたは決済ドメインのシニアレビュアーです。
以下のコードを、指定した観点でのみレビューしてください。

## レビュー観点(この順で必ず全て検査する)
1. セキュリティ: 外部入力がSQL/シェル/パスに連結されていないか
2. 金額計算の正確性: 丸め処理が通貨単位として妥当か、浮動小数点で誤差が出ないか
3. 冪等性: 同じリクエストが2回届いた場合に二重処理されないか
4. 失敗時の状態: 例外発生時にDBが中途半端な状態で残らないか

## 出力形式
各指摘を以下の形式で出力。観点1〜4で問題がなければ「問題なし」と明記する。
- [観点N][重大度: 高/中/低] ファイル:行 — 問題 / 修正案(1行)

## 禁止事項
- 命名規則・スタイル・型ヒントの不足は指摘しない
- 観点1〜4以外の指摘をしない

## 対象コード
(ここにコードまたは差分を貼る)

ブロック1:役割はドメインまで踏み込む

「シニアエンジニアとして」では足りない。「決済ドメインの」を足す。それだけで、冪等性・二重課金・整合性といった単語がモデルの候補に最初から入ってくる。役割指定は権威づけではない。検索範囲の絞り込みだ。

医療なら個人情報の取り扱い、広告配信ならCPMとレイテンシ、社内基幹系なら締め処理と権限。自分のコードが属する領域名を1語入れるだけでいい。

ブロック2:観点は番号付きで、順序を固定する

箇条書きの中黒ではなく1.2.3.と番号を振る。理由は2つある。出力側で「観点3の指摘」と参照できること、そして「この順で必ず全て検査する」という指示が効くようになることだ。順序を固定しておくと、重要度の高い観点が出力の後半で息切れするのを避けられる。

観点の文言は名詞ではなく問いの形にする。「セキュリティ」ではなく「外部入力がSQL/シェル/パスに連結されていないか」。検査すべき対象が具体的に書いてあるほど、返ってくる指摘の行番号が正確になる。

ブロック3:出力形式を1行テンプレートで固定する

形式を決めないと、指摘ごとに長さがばらつく。- [観点N][重大度] ファイル:行 — 問題 / 修正案 のような1行テンプレートにすると、あとで機械的に処理できるし、人間も差分として読める。

重大度を書かせるのは優先順位づけのためだけではない。重大度を判断させると、モデルは「これは本当に問題か」を一度自問する。結果として、指摘の水増しが減る。

ブロック4:禁止事項が雑音を止める

検証Aで返ってきた5件のうち4件は、命名やtry-exceptの話だった。悪意はない。指示がなければモデルは「指摘できることを指摘する」ため、目につきやすい表層から埋めていく。禁止事項はこれを止める唯一のブロックだ。

禁止事項に書くと効きやすいもの

  • 命名規則・スタイル・型ヒント・docstringの不足(Linterの担当領域)
  • 指定した観点以外の指摘
  • 修正後のコード全文の出力(差分だけでいい場面が多い)
  • 「〜を検討してください」のような結論を先送りする書き方

Linterで機械的に潰せるものをAIに探させるのは、そもそも配分が間違っている。フォーマッタとLinterに任せ、AIには実行しないと分からない欠陥だけを見させる。ここが役割分担の境界線だ。

「問題なし」を明記させると、レビューの網羅性が検証できる

検証Bの出力の最終行はこうなっていた。[観点4] 問題なし。地味だが、これが効く。

指摘が出た観点しか出力されない設計だと、観点4について何も書かれていないとき、2つの可能性が区別できない。検査した上で問題がなかったのか、そもそも検査を忘れたのか。この違いは大きい。前者ならそのまま次の工程に進めるが、後者はレビュー自体が終わっていないので、リリース判断の材料としてまったく使えない。

「問題がなければ問題なしと明記する」。この一文で曖昧さが消える。観点1〜4のすべてに何らかの行が対応するため、どの観点が抜けているのかを出力を上から眺めるだけで確認できるようになる。AIの出力を信じるかどうかとは別の話だ。検査したという証跡が残る意味は大きい。

出力が空だったときに疑うこと

全観点が「問題なし」で返ってきたら、まずプロンプトを疑う。原因は3つに絞れる。コードの貼り忘れ、差分が空、観点が抽象的すぎる。意図的に欠陥を1つ仕込んだコードを定期的に流し、それが検出されるかどうかで観点そのものの動作確認をしておくと安心できる。この手の出力の信頼性についてはプロンプトのハルシネーション対策で整理した観点がそのまま使える。

git diffと組み合わせて差分だけをレビューする

実務でファイル全文をレビューさせる場面は少ない。見たいのは今回の変更だ。差分をそのまま渡す。

# ステージ済みの変更をレビュー(コミット前)
claude -p "$(cat review_prompt.md)

## 差分
$(git diff --staged -U10)"

# 特定のブランチとの差分だけ
git diff origin/main...HEAD -U10 -- '*.py' | claude -p "$(cat review_prompt.md)"

# 変更ファイルの一覧だけ先に確認する
git diff --name-only origin/main...HEAD

コンテキスト行数(-U)をどう決めるか

デフォルトの-U3は前後3行しか見えない。関数の途中だけが切り出されると、モデルは呼び出し元も戻り値も知らないままレビューすることになる。実際に本サイトのリポジトリで3コミット分の差分を計測したところ、サイズの増減は約4%に収まった。

オプション 前後の行数 デフォルト比のサイズ 向く場面
-U0 0行 -1.7% 変更行の機械的な抽出のみ。レビューには向かない
-U3(既定) 3行 基準 1行の書き換えや設定値の変更
-U10 10行 +3.8% 関数の中身に手を入れた変更。既定はこれでいい

オプションの詳細はgit-diffの公式マニュアルに一覧がある。3行から10行に増やしてもサイズは4%も増えない。文脈が増える見返りに対して安すぎる。-U10を既定にして、それでも足りないときだけ該当ファイルを丸ごと追加する。この順序が効率がいい。

ノイズになるファイルを最初に外す

生成物やロックファイルが差分に混ざると、それだけでコンテキストを食い潰す。本サイトのリポジトリで計測したところ、22件の変更ファイルのうち大半はビルド後のHTMLと索引JSONだった。パス指定で先に落とす。

# 対象を拡張子で絞る
git diff -U10 -- '*.py' '*.ts'

# 生成物・ロックファイルを除外する
git diff -U10 -- . ':(exclude)dist/*' ':(exclude)*.lock' ':(exclude)*.min.js'

# 差分の文字数を先に確認する(長すぎるならファイル単位に分割)
git diff -U10 -- '*.py' | wc -c

差分が数万文字を超えるなら、1回で投げずにファイル単位で分ける。1回のレビューで扱う量が増えるほど、後半の指摘が雑になる。ここは観点を増やしすぎたときと同じ劣化の仕方をする。

レビュー観点をリポジトリに固定して使い回す

毎回プロンプトを書き直していると、観点がその日の気分でぶれる。ぶれるとレビュー結果を比較できない。プロジェクトの観点はファイルにしてリポジトリに置く。

カスタムスラッシュコマンドにする

Claude Codeなら.claude/commands/にMarkdownを置くだけでスラッシュコマンドになる。ファイル名がそのままコマンド名になる。Claude Code公式のスラッシュコマンド仕様によると、先頭の!`...`でシェルコマンドの実行結果を埋め込める。

<!-- .claude/commands/review-diff.md -->
---
description: 差分だけを観点指定でレビューする
---
以下の差分を、次の観点でのみレビューしてください。

1. セキュリティ: 外部入力の連結
2. 金額・数値計算の正確性
3. 冪等性: 二重実行時の安全性
4. 失敗時のロールバック

出力: `- [観点N][重大度] ファイル:行 — 問題 / 修正案`
観点ごとに問題がなければ「問題なし」と明記。スタイル指摘は禁止。

## 差分
!`git diff --staged -U10`

これで/review-diffと打つだけでステージ済みの差分がレビューされる。チーム全員が同じ観点でレビューを回せるようになるのが本当の利点で、個人の時短はおまけだ。コマンドの作り方の詳細はClaude Code CLI使い方完全ガイドにまとめてある。

CLAUDE.mdに書くか、コマンドに書くか

両方に書く必要はない。判断基準はひとつ、常に効いてほしいかどうかだ。

置き場所 適した内容
CLAUDE.md コードを書くとき常に守らせたい規約 金額はDecimalで扱う/外部入力は必ずパラメータ化
.claude/commands/ レビューという行為の手順と観点 差分レビュー/セキュリティ特化レビュー
サブエージェント 独立した文脈で走らせたい重い検査 全ファイル横断の依存関係チェック

レビュー専用のサブエージェントを切って本体の文脈を汚さない構成も取れる。この分け方はClaude Codeサブエージェント自作ガイドで扱った。仕様や規約そのものを文書として渡す場合はAIプロンプト仕様書の書き方のフォーマットが流用できる。

精度が落ちるプロンプトの4パターン

うまくいかないときの原因はだいたい決まっている。検証中に踏んだものも含めて4つ挙げる。

1. 観点を並べすぎる

10個も20個も並べると、各観点の検査が「見出しに沿って一言ずつ書く」作業に変わる。指摘の総量は増えるのに、重大な欠陥の検出率は上がらない。4〜6個に絞って、足りなければ2回投げる。

2. 「重大な問題だけ教えて」と曖昧に絞る

何が重大かの基準がモデル側にある状態で絞り込みを頼むと、判断が毎回変わる。絞るなら基準を書く。「金額・個人情報・データ欠損のいずれかに影響する指摘のみ」のように、影響範囲で定義すると安定する。

3. 毎回コード全体を貼る

変更していない部分まで含めると、既存コードへの指摘が大量に混ざる。レビュー対象が今回の変更なら、渡すのは差分だけでいい。周辺の文脈は-U10で足りることが多い。

4. 指摘と修正を一度にやらせる

「レビューして直して」と頼むと、モデルは直せる問題を優先的に見つけるようになる。直しにくい設計上の欠陥ほど言及が減る。指摘だけを出させ、採否を人間が決め、それから修正を頼む。この3段に分けると取りこぼしが減る。

見落としがちな前提

AIのレビューは一次スクリーニングであって、承認プロセスの代替ではない。検証Bでも観点4は「問題なし」と返ってきたが、複数テーブルにまたがる更新が加わればその判断は成立しない。コードの外側にある事実——本番の負荷、既存データの状態、運用の約束事——はプロンプトに書かない限り考慮されない。

目的別コピペプロンプト3種

そのまま使える形で3つ置いておく。観点の行だけ自分の領域に差し替えれば動く。

リリース前に流す

セキュリティ特化型。攻撃シナリオを1文書かせて、誤検知を自動的に振るい落とす。

手を入れる前に流す

影響調査型。提案を禁止し、呼び出し元と副作用の事実だけを列挙させる。

レビュー依頼前に流す

一次スクリーニング型。説明との齟齬とデバッグコードの混入だけを見る。

セキュリティ特化(リリース前)

あなたはWebアプリケーションのセキュリティレビュアーです。
以下の差分を、次の観点でのみ検査してください。

1. 外部入力の連結: SQL / シェル / ファイルパス / HTMLへの埋め込み
2. 認証・認可: 権限チェックの欠落、他人のリソースIDで通るパス
3. 機微情報: ログ・エラーメッセージ・レスポンスへの秘匿値の混入
4. 依存: 追加された依存パッケージと、それが増やす攻撃面

出力: - [観点N][重大度: 高/中/低] ファイル:行 — 攻撃シナリオ1文 / 修正案1文
観点ごとに該当なしなら「問題なし」と明記。
禁止: スタイル・命名・パフォーマンスの指摘。修正後コードの全文出力。

攻撃シナリオを1文書かせるのがポイントだ。分類の網羅性が不安ならOWASP Top 10の項目を観点に落とし込むところから始めればいい。「危険です」だけの指摘と違い、シナリオが書けないものは大抵誤検知として弾ける。セキュリティ側の観点をもっと体系的に持ちたいならAIセキュリティエンジニア完全ガイドで扱った分類が使える。

リファクタリング前の影響調査

以下のコードを変更する前に、壊れる可能性のある箇所を洗い出してください。
提案や修正は不要です。事実の列挙のみ。

1. この関数を呼んでいる箇所と、期待している戻り値の形
2. 副作用: DB更新 / ファイル書き込み / 外部API呼び出し / グローバル状態
3. 暗黙の前提: 引数の型・NULL可否・順序・呼び出し回数
4. テストがカバーしていない分岐

出力: - [観点N] ファイル:行 — 事実(1文)
該当なしの観点は「該当なし」と明記。推測は「推測:」と前置きする。

PRの一次スクリーニング

あなたはこのPRの一次レビュアーです。人間のレビュアーに渡す前の
足切りとして、以下だけを確認してください。

1. PRの説明と差分の内容が一致しているか(説明にない変更が混ざっていないか)
2. 設定値・認証情報・デバッグコードの混入
3. 観点として申し送るべき箇所(人間が必ず目視すべき行)

出力:
## 説明との一致: 一致 / 不一致(不一致なら該当ファイル:行)
## 混入チェック: 問題なし / 検出(該当行)
## 人間が見るべき箇所: 最大3件、ファイル:行と理由1文

禁止: コードの良し悪しの評価。改善提案。

3つ目は指摘を出させないプロンプトだ。人間のレビュアーが読む前に、明らかな混入と説明の齟齬だけを潰す。ここを機械に任せると、人間は設計の議論に時間を使える。GitHub側の自動化と組み合わせる構成はGitHub Copilot完全ガイドでも触れている。

よくある質問

Q. モデルは高性能なものを使うべきですか

今回の検証はHaiku 4.5という軽量モデルで行い、それでも観点を指定すれば4欠陥すべてを検出できた。モデルを上げる前に、まず観点と禁止事項を書く。順序としてはそちらが先だ。

Q. レビュー観点はどこから持ってくればいいですか

過去の障害報告書が最良の材料になる。実際に自分たちが壊した壊れ方を3件だけ翻訳すれば、それがそのまま観点になる。汎用のチェックリストを写すより、直近1年の障害を3つ観点に翻訳するほうが速い。

Q. 指摘が多すぎて処理しきれません

禁止事項が足りていない可能性が高い。まずLinterとフォーマッタが担当する領域を全部禁止する。それでも多いなら、重大度「高」のみ出力させて件数を絞る。

Q. AIの指摘が間違っていることはありますか

ある。特に「〜の可能性がある」という書き方の指摘は要注意で、根拠が示せないまま危険性だけ主張されることがある。修正案を1行で書かせると、書けない指摘は誤検知として見分けやすくなる。

Q. 人間のレビューは不要になりますか

ならない。今回の検証で見えたのは、AIが「探せと言われた場所」は精度よく探すという事実だ。何を探すべきかを決めるのは、そのシステムの壊れ方を知っている人間の仕事のままだ。

まとめ

同じモデル、同じコード、違うのは頼み方だけ。それで実バグの検出は1件から4件になった。AIによるコードレビューの精度を決めているのはモデル選定ではなく、観点をどれだけ具体的に書けるかだ。

やることは3つだ。汎用の4分類に自分の領域固有の壊れ方を足す。出力形式を1行テンプレートに固定し、問題がない観点には「問題なし」と書かせる。そして禁止事項でLinterの担当領域を締め出す。プロンプトができたら.claude/commands/review-diff.mdに置いて、チーム全員が同じ観点で回せる状態にする。

直近の障害報告書を1件開く。そこに書かれた壊れ方を、そのまま観点の1行に書き換える。汎用のチェックリストを写経するより、そのほうが最初の1件が早く見つかる。プロンプト設計そのものを体系的に押さえたい場合はプロンプトエンジニアリング入門を先に読んでおくと、観点の書き方が安定する。