コードを問い直すための仕組み
前の記事で、「AIが書いたコードに、自分は何を問えるか」という話を書いた。AIが書いたコードを理解するには、ただ読むだけではなく、「なぜこうなっているんだろう」と自分から問いを返す必要があるんじゃないかと。
最近、そのための質問を interrogate という小さなskillにまとめて使っている。きっかけになったのは、kawasimaさんの「Generation-then-comprehension」という記事だった。たとえば、
- このコードが前提としている条件は何か
- その前提は誰が保証しているのか
- 前提が崩れたらどうなるのか
- もっと単純な実装ではだめなのか
- この条件分岐を消したら何が起きるのか
- 正常系のテストだけでは見つからない問題は何か
といったことを聞く。
前にも触れたRustのコードでは、ある処理が「入力はソート済み」という前提で動いていた。実装を読むだけなら、それで終わる。でも、「なぜソート済みである必要があるのか」「誰がそれを保証するのか」「ソートされていなかったらどう壊れるのか」と聞いていくと、コードの見え方が変わってくる。コメントに書いておけば十分なのか。debug_assert! を入れるのか。それとも型で表現するのか。
ただ、質問の内容以上に意識したのが、AIにどう答えさせるかだった。「なぜこの実装にしたの?」と聞けば、AIは今ある実装をうまく説明してくれる。でも、それだけだと、あとからもっともらしい理由を付けているだけなのか、本当に他の選択肢より良かったのかが分からない。
そこで、このskillでは「正当化ではなく反証から組む」というルールを入れた。今の実装が正しい理由を並べる前に、正しく動かない条件、採用を見送るとしたらどこか、もっと単純な方法で十分ではないか、テストで確認できていない前提はないか、という方向から考えてもらう。正しさを説明してもらうより、まず壊しにいく。
もちろん、これで自分がコードを理解できるようになる、という話でもない。skillが質問して、AIが答えて、それを読んで「なるほど」で終わったら、結局やっていることはあまり変わらない。答えそのものより、そこで「本当に?」「じゃあこの入力なら?」「その前提はコードのどこにある?」と自分がもう一度引っかかれることのほうが大事なんだと思う。
だからこのskillには、ライブラリの挙動や呼び出し箇所のように確認できるものは実際に確認すること、より単純な実装で十分ならそう認めること、自分が書いたコードを自分でレビューするときはそのバイアスを意識すること、といったルールも入れた。AIに説明させるためというより、AIの説明をそのまま信じないための仕組みに近い。
以前、「AIに何を教えるべきか」を考えていたとき、AIに知識だけでなく「問い」を持たせるのがいいんじゃないかと書いた。その問いが、最近は少し違う使い方になってきた。AIに良いコードを書かせるためだけではなく、AIが書いたコードを自分が理解するためにも使う。 問いをskillにしたことで理解を自動化できるわけではない。むしろ、自動化しすぎて通り過ぎそうになるところで、一度立ち止まるための仕組みなのかもしれない。