AIを使ったデバッグの方法は、最小の再現条件を固定する→エラー全文と関連コードと直前の変更をまとめて渡す→原因候補を複数出させて順位を付ける→1回に1つの要因を変えて検証する→原因と再発防止を記録する、という5段の手順です。エラーメッセージだけを貼って「直して」と頼む使い方が安定しないのは、AIが手元の実行環境や未提示の状態を確認できず、もっともらしい推測を修正案として返すことがあるためです。
AIは、渡した症状とコードから原因候補を広げ、各候補を確認する手順の下書きを作る作業に向いています。ただし、候補に漏れや誤りはあり得ます。「どれが本当の原因か」は、手元の環境で観測した結果から判断します。この記事では、その役割分担を前提に、仮説の順位付けの基準、仮説を出させるプロンプト、そして再現手順・仮説・実験結果を1枚に残すデバッグログのテンプレートを示します。
情報確認日:2026年7月28日(日本時間)
結論:AIには仮説を並べさせ、原因の確定は再現環境で行う
この記事の結論
- 再現できるなら最小手順を固定する。再現できない場合は、修正案より観測点の追加を先に検討する
- 渡すのはエラー全文・関連コード・直前の変更・環境の4点セット
- 原因は1つに絞らせず、3〜5件の候補と「それを否定する確認方法」を出させる
- 順位は確からしさだけでなく、確認にかかる手間との組み合わせで決める
- 検証は1回1変更。同時に2か所直すと、どちらが効いたか分からなくなる
- 症状を抑える暫定対応と、原因を取り除く恒久対応を分けて記録する
- 確定した原因は、可能ならテスト・検証・監視のいずれかへ変換する
先に再現条件を固定する
再現手順がないまま修正案を適用すると、「直ったのか、たまたま症状が出ていないだけなのか」を区別しにくくなります。再現可能なバグなら、まず同じ症状を繰り返し観測できる状態を作ります。本番でしか起きない、頻度が極端に低いなど再現が難しい場合は、無理に再現環境を作る前にログ・メトリクス・トレースなどの観測点を増やします。
期待結果と実際の結果を書く
「動かない」「エラーが出る」という表現は、それ自体には情報がありません。必要なのは、何をしたか(操作・入力)、何が起きると思ったか(期待結果)、実際に何が起きたか(実際の結果)の3点を分けて書くことです。とくに実際の結果は、エラーメッセージ・返り値・画面表示・ログ行のいずれかで、後から他人が同じものを観測できる形にします。
| 書きがちな表現 | 再現条件として使える書き方 |
|---|---|
| 保存が動かない | 新規フォームで件名を空のまま送信すると、HTTP 500 が返り、レスポンス本文が空になる |
| たまに落ちる | 同じ操作を10回繰り返すと2〜3回、KeyError: 'user_id' で処理が止まる |
| 本番だけ遅い | 一覧の2ページ目以降で応答が3秒を超える。1ページ目は0.2秒で返る |
| 集計がおかしい | 月次集計が実データより1件多い。月末23:59のレコードが当月と翌月の両方に入る |
| ログインできない | 大文字を含むメールアドレスで登録した利用者だけ、認証が401で失敗する |
右の列まで書けると、調べる範囲を狭められます。「大文字を含むメールアドレスだけ失敗する」と分かったなら、認証全体ではなく、正規化・比較・データベースの照合規則など、大文字小文字を扱う箇所から確認できます。AIへ渡す前に観測事実を具体化するほど、無関係な仮説を減らしやすくなります。
最小入力と発生頻度を残す
次に、再現する範囲で入力・手順・コードを削っていきます。削るたびに再現するかを確認し、再現しなくなった1つ手前が最小再現です。削った要素のうち、最後に削って再現しなくなったものは、原因に直接関わっている可能性が高い部分です。
あわせて発生頻度を記録します。次の3つに分け、断続的な場合は観測できた試行数と発生数を残します。
- 常に発生:同じ入力と状態で毎回発生する。入力・分岐・データ状態を追う手がかりになる
- 条件付きで発生:特定の入力・利用者・時刻・データ状態でのみ出る。条件の差分を調べる
- 断続的に発生(10回中3回など):タイミング、並行処理、キャッシュ、外部サービス、環境差、データ依存などを候補にする
どうしても再現しない場合は、AIに相談する前にログを増やす段階へ戻ります。観測できていない状態でAIに聞くと、症状に合いそうな一般論が返ってくるだけで、検証もできません。「いつから壊れたか」が分からないときは、git bisect が有効です。公式ドキュメントによれば、これは二分探索でバグを混入したcommitを特定するコマンドで、良いと分かっているcommitと悪いと分かっているcommitを伝えると、範囲を狭めながら判定を求めてきます。判定を自動化する git bisect run もあり、渡すコマンドは、良い状態なら終了コード0、悪い状態なら125を除く1〜127を返すよう作ります(125は判定不能としてそのcommitを飛ばす指定です)。
AIへ渡すコンテキストを整理する
再現条件が固まったら、AIが必要以上に推測せずに済む材料を揃えます。渡していない情報は推測で補われやすいため、回答中の事実と仮説を分けて確認します。
エラー全文・関連コード・直前変更を添える
基本になるのは次の4点です。すべて揃わない場合は、不明であることも明記します。
- エラー全文:最終行だけでなくstack trace(呼び出し履歴)全体。原因となった例外が別の例外に包まれている場合、その連鎖も含めて渡します
- 関連コード:例外が発生した行を含む関数、その呼び出し元、関係するデータ構造や型の定義。行番号を残したまま貼ると、指摘箇所を照合できます
- 直前の変更:直近のcommitの差分、依存パッケージ、設定・環境変数、投入データ、外部サービスなどの変更。「昨日まで動いていた」なら、コード以外の変化も確認します
- 環境:言語とversion、framework、OS、実行方法(ローカル・CI・本番のどれか)。versionが1つ違うだけで挙動が変わる領域は珍しくありません
逆に、渡さなくてよいものもあります。リポジトリ全体、無関係なファイル、過去の議論の経緯などは、判断材料を増やすというより、注目すべき箇所を薄めます。ツールによってリポジトリ全体を読ませられる範囲や差分の扱いは異なるので、その差は「AIコーディングツール比較」を参照してください。
秘密情報と個人情報を除去する
エラーログには、想像以上に多くのものが混ざります。認証トークン、APIキー、cookie、データベース接続文字列、内部ホスト名、そして実在する利用者のメールアドレスや氏名です。外部のAIサービスへ貼る前に、必ず取り除きます。
置換のコツは、構造は残して値だけを差し替えることです。行ごと消してしまうと、どこで何が起きていたかという手がかりまで失われます。
- トークン・鍵:
Authorization: Bearer <REDACTED_TOKEN>のように、ヘッダー名と形式は残す - 接続文字列:ホスト名・ユーザー名・パスワードを
<DB_HOST>のような一貫した仮名に置き換える - 個人情報:実在のメールや氏名は、架空だと明らかな値(
user001@example.com)へ。IDは連番の仮値へ - 置換は一貫させる:同じ値には同じ仮名を当てる。ばらばらにすると、同一人物かどうかの情報が壊れます
貼り付ける前に、組織のデータ取扱規程と利用するAIサービスの契約・設定を確認します。可能ならsecret scannerや定型のマスキング処理を通し、その後に Authorization、token、key、secret、password、メールアドレスなどを目視確認してください。文字検索だけでは、別名の資格情報や本文に埋まった個人情報を見落とすため、最終保証にはなりません。一般的な線引きは「AIの安全な使い方」にまとめています。
原因候補を複数出して順位付けする
原因候補を広げる作業は、AIを使いやすい場面です。ただし、質問の仕方によっては、もっともらしい断定が1つだけ返ることがあります。求めるのは「答え」ではなく「候補の一覧と、それぞれを確認する方法」です。
観測事実と推測を分けさせる
AIの出力では、推測が事実のような書きぶりで混ざることがあります。渡していない行番号、存在しない設定値、実際には呼ばれていない関数名が含まれていても、文章としては自然に読めます。出力形式で観測事実と推測を分けるよう求め、回答後に元資料と照合します。
次のプロンプトはそのままコピーして使えます。各ブロックに材料を貼り付けてください。
あなたはデバッグの補助役です。以下の情報だけを根拠に、原因の候補を挙げてください。
【症状】
- 操作/入力:
- 期待した結果:
- 実際の結果:
- 発生頻度: 常に / 条件付き(条件: ) / 断続的( 回中 回)
【エラー出力】(最終行だけでなく stack trace 全文)
【関連コード】(発生箇所とその呼び出し元・関係する型定義)
【直前の変更】(commit 差分 / 依存更新 / 設定変更 / データ変更)
【環境】言語とversion / framework / OS / 実行環境(ローカル・CI・本番)
【出力ルール】
- 原因候補を3〜5件挙げ、確からしい順に並べる
- 各候補について、次の5項目を必ず分けて書く
1. 仮説(何がどうなっていると考えるか)
2. 根拠にした観測事実(上に貼った情報から該当箇所を引用する)
3. 推測で補った部分(引用できない内容は必ずここに書く)
4. この仮説を否定する確認方法(1手順で、結果が yes / no で分かるもの)
5. 否定されたときに次に疑うもの
- 修正コードはまだ書かない
- 与えていない行番号・関数名・設定値を推測で書かない。
必要な場合は「確認が必要な情報」として質問の形で挙げる
受け取ったら、まず3の「推測で補った部分」を読みます。ここが長い仮説は、材料不足のまま組み立てられたものなので、順位を下げるか、不足している情報を渡し直します。2の引用が実際に貼った内容と一致しないものは、その場で捨ててください。
各仮説を否定できる確認方法を付ける
仮説には「否定されたと判断できる結果」を先に付けます。期待どおりの結果だけを探すと、別の要因による一致を根拠にしてしまうためです。ただし、確認手順そのものが不十分なら誤って否定することもあります。できるだけ小さく、結果の読み方が明確で、復元しやすい低リスクな確認から始めます。
| 仮説の型 | 1手順の確認方法 | 否定されたときの読み方 |
|---|---|---|
| 入力データが想定と違う | 例外発生の直前で、入力をそのまま出力する | 入力は正しい。処理側の変換を疑う |
| 設定値が読めていない | 起動直後に、実際に読み込まれた設定値を出力する | 設定は届いている。使い方や参照箇所を疑う |
| 依存versionの差 | ローカルとCIで依存一覧を出力し、差分を取る | 環境差ではない。コード側の変更を疑う |
| 並行処理の競合 | 同時実行数を1に落として再現するか見る | 競合ではない。データ依存やタイミング以外を疑う |
| キャッシュが古い | キャッシュを無効にして同じ操作を行う | キャッシュではない。生成側のロジックを疑う |
| 例外が握りつぶされている | catch節に一時的にstack traceの出力を入れる | 例外は出ていない。条件分岐の経路を疑う |
| 境界値の扱い | 境界の1つ内側と1つ外側の値で実行する | 境界ではない。値の範囲全体を疑う |
順位付けは、確からしさだけで決めません。確からしさ、確認コスト、変更の危険度を組み合わせます。確からしさが2番目でも、安全な読み取りで短時間に確認できるなら先に試せます。本番データの変更やサービス停止を伴う確認は、確率が高くても検証環境へ移すか、承認された手順に分けます。最終的な順序は、自分の環境と影響範囲を知る人が決めてください。
1回に1つの変更で検証する
候補が並んだら、検証順に試します。基本は、1回の検証で意図的に変える要因を1つにすることです。2つ以上を同時に変えて症状が消えると、どの変更が結果へ影響したかを切り分ける追加検証が必要になります。
ログ・テスト・debuggerで観測する
観測の手段は3つあり、状況で使い分けます。
- ログ出力:処理の経路と値の流れを追う。断続的なバグや、手元で止められない本番環境で有効
- debugger:実行を止めて周辺の状態をまとめて見る。ローカルで再現でき、停止による挙動変化が問題にならないときに向く
- テスト:再現をコードに固定する。修正の前に「落ちるテスト」を書いておくと、修正の効果がその場で判定できる
debuggerの入り口は言語ごとに用意されています。Pythonの pdb は公式ドキュメントで「対話的なソースコードデバッガを定義するモジュール」と説明されており、条件付きブレークポイントの設定、行単位のステップ実行、スタックフレームの調査、任意のPythonコードの評価ができます。Python 3.7以降は組み込みの breakpoint() が import pdb; pdb.set_trace() の代わりに使えます。JavaScriptでは debugger 文が、MDNの説明では「利用可能なデバッグ機能(ブレークポイントの設定など)を呼び出す。デバッグ機能が利用できない場合、この文は何もしない」と定義されています。Node.jsには node inspect myscript.js で起動する組み込みデバッガがあり、--inspect がデバッガ接続を待たずにコードを実行するのに対し、--inspect-brk はデバッガが接続され次第、最初の行で停止します。起動直後の処理を追いたいときは後者を使います。
ログを足すときは、レベルの意味を守ります。Pythonの logging では DEBUG(10)・INFO(20)・WARNING(30)・ERROR(40)・CRITICAL(50)が標準で、例外処理の中では logger.exception() が使えます。これはERRORレベルのメッセージへ例外情報を加えるメソッドで、exc_info=True を明示しなくてもtracebackが残ります。調査用ログには識別できる目印を付け、個人情報や資格情報を出さないようにします。原因確定後は、不要な一時ログを削除し、運用上必要なログだけを適切なレベルで残してください。
暫定対応と恒久対応を分ける
次のような変更は症状を抑えることがありますが、それだけでは原因を説明していません。
- 例外を
tryで囲んで握りつぶす - 値がnullのときだけ処理を飛ばす条件を足す
- 失敗したら再実行する(retry)を入れる
- 待ち時間を伸ばして通るようにする
- テストの期待値を、実際の出力に合わせて書き換える
これらは「なぜその値がnullになるのか」「なぜ最初の実行が失敗するのか」には答えていません。障害の影響を止めるために必要なら、暫定対応として採用する判断はあります。その場合も、回避している症状、残っている原因調査、解除条件、監視項目を記録します。恒久対応として採用するなら、変更で直る理由が観測事実と整合するかを確認してください。検証中の差分は、戻せる単位に分けます。
AIが提示した修正案をそのまま適用する前にも、同じ確認をします。差分の各行が、どの仮説に対応する変更なのかを言えるかどうかです。仮説と紐づかない行が混ざっていたら、それは「ついでの整形」か、AIが別の問題だと考えて足したものです。どちらもこの検証では邪魔になるので、分けて扱います。
原因と再発防止を記録する
ここまでの作業を1枚に残します。次のテンプレートは、最後にまとめて書くものではなく、最初の再現段階から順に埋めていくものです。埋まらない欄があるということは、その段階を飛ばしているという意味になります。
# バグ: <一行で症状>
## 1. 再現条件(先に固定する)
- 操作/入力:
- 期待した結果:
- 実際の結果:
- 発生頻度: 常に / 条件付き(条件: ) / 断続的( 回中 回)
- 最小再現手順:
1.
2.
- 環境: 言語 x.y / framework x.y / OS / 実行環境(ローカル・CI・本番)
- 直前の変更: commit / 依存更新 / 設定変更 / データ変更
## 2. 仮説(確からしい順・確認コストも書く)
| 順位 | 仮説 | 根拠にした観測事実 | 否定する確認方法 | 確認コスト |
|---|---|---|---|---|
| 1 | | | | 低 |
| 2 | | | | 中 |
| 3 | | | | 低 |
## 3. 検証ログ(1行 = 1変更)
| # | 変更した1点 | 期待 | 実際 | 仮説の判定 |
|---|---|---|---|---|
| 1 | | | | 否定 / 支持 |
| 2 | | | | |
## 4. 確定した原因
- 何がどうなっていたか:
- 症状が出る条件:
- なぜ今まで表面化しなかったか:
## 5. 修正と検証
- 修正内容(1変更 = 1コミット):
- 修正前に落ちたテスト:
- 修正後に通ったテスト:
- 戻した変更(症状を隠すだけだったもの):
## 6. 再発防止
- 追加した検知(テスト / lint / 起動時検証 / 監視):
- 同種のバグが残っていそうな箇所:
修正前後のテストを残す
可能なら、修正前に落ちるテストを書き、失敗を確認してから修正します。すでに修正したあとで回帰テストを書く場合は、修正前のcommitや失敗するfixtureに対して一度落ちることを確かめると、そのテストが対象のバグを検知しているか確認できます。
テストの入力には、最小再現手順を利用できます。ただし、削った要素が本番の条件を隠していないかも確認します。原因に関係する境界値、0件、NULL、重複などがあれば、同じ関数の別ケースとして追加します。テストケースの洗い出しをAIに手伝わせる手順は「AIでテストコードを生成する方法」で解説しています。
外部サービスへの依存やタイミングが絡んで、テストとして固定できない領域もあります。その場合は、実行時のassertion(前提条件の検査)や監視のアラートで代替します。何も残さずに済ませないことが目的です。
同種バグを検知する仕組みへ変える
最後に、確定した原因を「同じ型のバグを見つける仕組み」へ変換します。個別の修正で終わらせると、同じ原因のバグが別の場所で再発します。
| 確定した原因の型 | 変換先の仕組み |
|---|---|
| 型・null の取り違え | 型検査をCIの必須チェックに入れ、対象範囲を該当ファイルまで広げる |
| 設定・環境変数の漏れ | 起動時に必須設定の存在を検証し、欠けていたら即座に失敗させる |
| 例外の握りつぶし | 例外を捕捉した箇所でログ出力を必須にする lint(静的解析)規則を追加する |
| 境界値・時刻の扱い | 同じ関数に境界テストを追加し、タイムゾーンの前提をテストで固定する |
| クエリ発行の増殖 | 1リクエストあたりのクエリ数に上限を設け、テストで検証する |
| 外部サービスの応答変化 | 受信データのスキーマ検証を入れ、想定外の形を早い段階で弾く |
原因に合う再発防止策を追加できるか検討し、追加しない場合は理由を記録します。テストが難しい外部要因なら監視、設定ミスなら起動時検証というように、原因の型に合わせます。
よくある失敗
エラーの最終行だけを貼る
最終行には、例外の種類とメッセージだけが出ていることがあります。原因例外が別の例外に包まれている場合、stack traceを省くと発生箇所と呼び出し経路が失われます。秘密情報を除去したうえで、例外チェーンと関連するstack traceを省略せずに渡してください。
同時に複数箇所を直す
AIが3件の修正案を出すと、まとめて適用したくなります。しかし症状が消えたとき、効いたのがどれかは分かりません。無関係な2件が残り、そのうち片方が別のバグの原因になることもあります。1変更ずつ、判定を記録しながら進めてください。
再現しないまま修正案を試す
再現していない状態で修正を当てると、「しばらく症状が出ない」ことしか確認できない場合があります。緊急の影響緩和が必要なら暫定対応として分け、原因未確定であることを残します。並行してログやメトリクスを追加し、再現条件と解除条件を追跡してください。
よくある質問
再現できないバグはAIに相談しても無駄ですか?
原因の相談には向きませんが、「どこにログを足せば再現条件を絞れるか」を聞く使い方は有効です。症状と関連コードを渡し、観測点の候補を出させてください。仮説の検証は、再現できるようになってからです。
コードを全部渡したほうが精度は上がりますか?
多ければ必ず上がるわけではありません。発生箇所と呼び出し元、関係する型定義から始めると、注目点を絞れます。一方、初期化処理や横断的な設定が原因なら、より広い文脈が必要です。まず4点を渡し、仮説の検証に必要な範囲だけ追加します。
AIが出した修正で動いたら、原因を調べなくてもいいですか?
少なくとも、どの仮説に対応した修正か、修正前後で何を観測したかを確認してください。障害を止めるための暫定対応なら先に適用する場合もありますが、原因未確定として追跡し、解除条件と恒久対応を別に残します。
本番のエラーログをそのまま貼っても大丈夫ですか?
そのままは避けてください。トークン、接続文字列、cookie、実在する利用者の情報が混ざります。値だけを一貫した仮名に置き換え、構造は残す形で加工してから渡します。組織のルールで外部サービスへの送信が制限されている場合は、そのルールが優先です。
まとめ
AIを使ったデバッグは、エラーメッセージを渡して修正案を受け取る作業ではなく、再現・仮説・検証という手順のうち「仮説を並べる部分」をAIに任せる作業です。先に最小の再現条件を固定し、エラー全文・関連コード・直前の変更・環境の4点セットを渡し、原因候補を3〜5件、それぞれを否定する確認方法つきで出させます。
順位は確からしさ・確認コスト・危険度で決め、1回に1つの要因を変えて判定を記録します。症状を抑える暫定対応と、原因を取り除く恒久対応は分けます。確定した原因は、可能ならテスト・起動時検証・監視などへ変換します。この記事のデバッグログで空欄が出たら、未確認なのか、該当しないのかも含めて理由を残してください。