AI でのデバッグが最もうまくいくのは、隣の席の同僚に渡すものをモデルに渡したときです。エラー全文、エラーを出したコード、期待したこと、実際に起きたこと、すでに可能性を否定したこと。モデルはプログラムを実行することもデータを見ることもできないので、バグについて知っていることはすべて、あなたが貼り付けたものから来ます。いちばん役に立つ習慣は1つ、修正より先に原因を尋ねることです。
エラーだけでなく、すべてを貼り付ける
下の2つのタブは同じバグを説明しています。Excel から書き出した CSV ファイルを読むスクリプトが、ファイルには明らかに email の列があるのに、KeyError: 'email' でクラッシュします。
KeyError は、辞書に 'email' というキーがないことを意味します。.get() を使えば、エラーを出す代わりに None が返るので、エラーを避けられます。
email = row.get("email")
あるいは、先に確認します。
if "email" in row:
email = row["email"]
1つ目の返答は KeyError が何かについては正しいのですが、ここではそのアドバイスは有害です。row.get("email") にするとクラッシュは消え、すべてのメールアドレスが None になります。プロンプトが説明していたのはそれだけだったので、モデルはそのエラーの最もよくある版に答えたのです。
完全な報告がうまくいったのは、2つの行のおかげです。「最初の列だけが失敗する」と「Excel から CSV UTF-8 で保存した」がバイトオーダーマークを指す手がかりで、どちらもエラーメッセージには含まれていません。自分の書いた細部のどれが手がかりになるのかは、めったにわかりません。だからすべてを貼り付けるのです。
含めるべき5つのこと
- エラー全文。言い換えではなく、トレースバックやコンソール出力のすべてです。行番号と呼び出しの連鎖が失敗の始まった場所を示し、それはエラーが表に出た場所から数フレーム離れていることがよくあります。
- エラーを出したコード。失敗している関数と、それを呼び出しているコードです。エラーが特定の行に触れているなら、その行が貼り付けたものに含まれているか確かめてください。
- 期待と実際。それぞれ1文で。エラーがまったく出ないバグ(出力が違う、ページが真っ白、クエリが遅い)では、これがバグ報告のすべてです。
- 環境。言語のバージョン、OS、関係しうるならフレームワークとライブラリのバージョン。文字コード、パス、日付のバグは、プラットフォームに依存することがよくあります。
- すでに試したこと。モデルが同じことを再び提案するのを防ぎ、各試みの結果が証拠になります。「email の部分を消すと動く」が、CSV のバグを1つの列に絞り込みました。
修正より先に原因を尋ねる
修正を頼むと、モデルはエラーが消えるまでコードを変えようとします。原因を頼むと、エラーがなぜ起きるのかを推論させることになり、修正はそこから導かれます。確かめ方つきの原因の短いランキングを頼み、確認は自分で実行してください。このテンプレートがそれをします。
TypeError: Cannot read properties of undefined (reading 'map')function UserList() {
const [users, setUsers] = useState();
useEffect(() => {
fetch("/api/users")
.then((res) => res.json())
.then((data) => setUsers(data));
}, []);
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}- データが存在する前にコンポーネントが描画されている。
useState()はundefinedから始まり、React はエフェクトを実行する前にコンポーネントを一度描画するので、users.mapがundefinedに対して呼ばれます。これだけで、読み込みのたびにまさにこのエラーが出ます。確認:returnの直前にconsole.log(users)を加えます。undefinedが出てすぐにエラーが続くなら、これが原因です。 - API が配列以外のものを返している。
{ users: [...] }のようなオブジェクトを返していたら、エラーは別のもの(users.map is not a function)になるので、貼り付けられたエラーの原因ではありません。ただし、原因1を直したあとで次の問題になる可能性はあります。確認:2つ目の.thenの中でconsole.log(data)。 - リクエストが失敗している。まだ関係していません。最初の描画で例外が投げられるので、React はエフェクトを実行せず、リクエストは送られてさえいません。確認:ネットワークタブに
/api/usersのリクエストがないことで、原因1も確かめられます。
この返答は、修正を先に出す答えが飛ばすことをしています。原因を否定する理由として、その原因なら貼り付けたものとは違うエラーが出るはずだから、あるいはコードがそこまで進まないから、と示しています。エラーの正確な文面が重要なのもこのためです。答える前に原因を挙げさせるのは、軽い形の Chain-of-Thought プロンプティングです。推論が先に来て、結論はその上に成り立ちます。
最小の再現コードを作る
最小の再現コードとは、まだバグが起きる最小のプログラムです。データベースの呼び出しの代わりにハードコードしたデータ、モジュール全体の代わりに関数1つ。これを作るうちに、誰かに尋ねる前にバグが見つかることもよくあります。取り除いた部品の1つ1つが、バグを残す(関係なかった)か、バグを消す(関係していた)かのどちらかだからです。見つからなかったとしても、再現コードは理想的なプロンプトになります。モデルがすべての行を読める短さで、間違った問題を追いかけさせる無関係なコードもありません。
バグがデータに依存するなら、それを引き起こす数行を含めてください。モデルは [{"id": 1, "name": null}] については推論できますが、「本番のいくつかの行」については推論できません。
修正が効かなくなったとき
モデルの3つ目の修正が同じように失敗したら、4つ目の修正を頼んでもうまくいく見込みは薄いでしょう。もっと役立つことが2つあります。
- 新しい証拠を渡す。 失敗する地点で実際の値を表示する print やログの行を加えて実行し、出力を貼り付けます。モデルの仮説と矛盾する証拠こそ、より良い仮説への最短の道です。
- 新しい会話を始める。 長いデバッグのスレッドは、捨てた仮説や古い版のコードでいっぱいになり、モデルはそれらを土台にし続けることがあります。現在のコード、エラー、証拠、「すでに否定したもの:X と Y」という1行を持った新しいチャットは、1回の返答でもっと先に進めることがよくあります。
ライブラリの動作についての自信ありげな答えには注意してください。モデルは存在しないオプションや関数を説明することがあります。確かめ方は AI のハルシネーションを参照してください。コードが壊れているわけではなく、なぜそう動くのかがわからないだけなら、コードを説明してもらうためのプロンプトのほうが適した道具です。
よくある質問
ChatGPT や Claude にコードを直してもらうにはどう頼めばいいですか?
エラーメッセージ全文とエラーを出したコードを貼り付け、短い3行を加えます。期待したこと、実際に起きたこと、すでに試したことです。修正を頼む前に、最も可能性の高い原因とその確かめ方を尋ねてください。「直して」だけでは、そのエラーの最もよくある版に対する修正が返ってきますが、それはあなたのケースではないかもしれません。
プロジェクト全体を AI に貼り付けるべきですか?
いいえ。エラーが起きている関数、それを呼び出しているコード、受け取るデータのサンプルを貼り付けてください。さらに良いのは、問題が再現する最小のプログラムまで削ることです。関係のないファイルは答えを遅くし、存在しない問題を探す場所をモデルに増やしてしまいます。
AI の修正でエラーは消えたのに、プログラムがまだ動かないのはなぜですか?
修正が症状だけを治したからです。たとえば row["email"] を row.get("email") に置き換えれば KeyError は止まりますが、上流のバグのせいでキーがないのだとしたら、今度はすべてのメールアドレスが黙って None になります。先に原因とその確かめ方を尋ねれば、問題を隠すだけの修正を避けられます。
AI が効かない修正ばかり提案してくるときはどうすればいいですか?
修正を頼むのをやめて、代わりに証拠を渡してください。それぞれの試みで何が変わったかを報告し、実際の値を表示する print やログの行を加えて、その出力を貼り付けます。会話が長くなっているなら、コード、エラー、証拠、すでに否定された修正をまとめた要約を持って、新しい会話を始めてください。