LLMにバグ修正をやらせる仕組みを作っていて、最初はプロンプトで「migrationファイルは触らないで」「自信がなければ直さないで」と書いていた。当然のように守られないことがある。数を捌いていると、たまに関係ないファイルまで書き換えたPRが出てくるし、情報が足りないチケットにも無理やり答えを返してくる。
結局、守らせたいことはプロンプトではなくコード側で弾くことにした。モデルの出力を信じる前提をやめて、出てきたものを機械的にチェックして落とす。今は3か所で止めている。
触っていいパスの外なら、出力ごと捨てる
モデルが「このファイルを直す」と言ってきても、対象が許可の外なら、その修正提案はまるごと捨てる。migration、.env系、生成物(dist/、node_modules/)、ロックファイルあたりは最初から除外している。
DENY = ("db/migrations/", ".env", "dist/", "node_modules/", "package-lock.json")
def is_touchable(path: str) -> bool:
return not any(p in path for p in DENY)
プロンプトに「触るな」と書くのも一応やる。ただ最後の砦はこっちで、モデルが何と言おうと is_touchable がFalseなら差分を作らせない。
特定できなければ、PRは作らない
「どこを直すか絞れたか」をモデル自身に言わせて、絞れていないときは素直に止める。再現手順がない、対象ファイルが特定できない、というのはよくある。そういうときに無理して出したPRより、「情報が足りませんでした」とチケットにコメントして終わるほうがいい。
ここを甘くすると、それっぽいけど的外れなPRが量産される。レビューする人からすると、これが一番きつい。時間を取られた挙句、最初から自分で調べ直すことになるからだ。「作らない」という判断をちゃんと持たせるのが、地味に効く。
月の上限で勝手に止める(事故対策)
アカウントごとに、月のAI呼び出し回数に上限を置いている。超えたら処理そのものを受け付けない。
if used_this_month >= plan.limit:
raise BudgetExceeded # ここで処理を始めない
従量課金にしていると、バグやリトライのループで一晩に何百回も回る事故が普通に起きる。上限は「使いすぎ防止」というより、事故で請求が跳ねないための保険に近い。
作ってみて思ったのは、AIに任せる部分より「任せない範囲をどう固定するか」のほうに時間を使ったということ。生成の精度を上げるより、変なものが出ても外に漏れない作りにしておくほうが、運用はずっと楽になった。
この仕組みは、BacklogのチケットからGitHubのDraft PRのたたき台を作るツールで動かしている。
https://keros.repocarta.jp/example