AIエージェントに本番UPDATEをさせる前に置くべき「承認ゲート」設計

AIエージェントに本番UPDATEをさせる前に置くべき「承認ゲート」設計

AIエージェント(Claude Code や Cursor など)に実務フローを任せ始めると、ある日必ず「本番DBへの書き込みまでやってほしい」という要求にぶつかる。集計結果の反映、フラグの一括更新、特定期間のレコード修正——こうした破壊的操作(UPDATE / DELETE)は、人手でやれば数分の作業だ。だがエージェントに丸ごと委ねた瞬間、リスクの性質がまったく変わる。

本記事では、AIエージェントに破壊的操作を含むフローを任せるにあたって、私が「承認ゲート」と呼んでいる多段の防御設計を、再現可能なパターンとして整理する。特定の事故や案件の話ではなく、一般論として書く。

なぜAIエージェントの破壊的操作は危険か

人間のエンジニアがUPDATEを打つとき、私たちは無意識に多くの前提を確認している。「今つないでいるのは本番か検証か」「WHERE句の対象範囲は意図どおりか」「この期間指定で本当に合っているか」。これらは経験と緊張感に支えられた、暗黙のチェックだ。

AIエージェントはこの暗黙のチェックを持たない。指示の曖昧さを、それらしい推測で埋めてしまう。「先月分を更新して」という一言から、エージェントが想定する「先月」「対象種別」「絞り込み条件」が、あなたの想定と一致している保証はどこにもない。しかも自然言語で流暢に「更新しました」と報告してくるため、取り違えに気づくのが遅れる。

破壊的操作の怖さは、失敗が可逆でない点にある。SELECTなら間違えてもやり直せる。だがUPDATEで対象を取り違えれば、上書きされた元の値は戻ってこない。エージェントの「もっともらしさ」と、操作の「不可逆性」が掛け合わさったとき、被害は静かに、そして確実に広がる。

承認ゲートの多段設計

対策の中心は、「承認が下りるまで破壊的操作を絶対に実行させない」ことだ。ただし単に「最後に確認する」だけでは足りない。フローを複数のゲートに分割し、各ゲートが異なる役割を担う多段構成にする。私は便宜上 Gate A/B/C/D のように呼んでいる。

  • **Gate A(対象の確定)**: 何を、どの範囲で操作するのかを、エージェント自身の推測ではなく人間との対話で確定させる。対象DB・期間・種別といったパラメータを、この時点で明示的に固定する。
  • **Gate B(影響のプレビュー)**: 実際に書き換える前に、まず読み取り専用でヒットする対象件数やサンプルを提示する。「これから何件・どのレコードを触るのか」を、実行前に人間が目視できる状態にする。
  • **Gate C(承認)**: 提示された対象に対して、人間が明示的にGoを出す。ここを通過するまで、いかなる書き込みも走らせない。承認は「はい」の一言ではなく、対象の要約を添えた確認とする。
  • **Gate D(限定実行と記録)**: 承認された範囲に厳密に一致する操作だけを実行し、何をしたかを記録として残す。

重要なのは、各ゲートが「前のゲートで確定した内容」を入力として受け取り、勝手に広げないことだ。Gate A で「対象は特定期間の特定種別」と固定したなら、Gate D の実行はその範囲を1ミリも超えてはならない。

WHERE句固定・対象限定という防御

多段ゲートを支える技術的な要が、「対象を限定するWHERE句をあらかじめ固定する」という発想だ。

エージェントに自由にクエリを組み立てさせると、絞り込み条件が状況次第で揺れる。そこで、暴走の余地がある部分——接続先の識別、対象期間、対象種別といった軸——を、エージェントが動的生成する対象から外し、フロー側で固定値として与える。エージェントに委ねるのは「固定された枠の中での作業」だけにする。

-- 悪い例: 条件をエージェントの推測に委ねる
UPDATE target_table SET status = 'done' WHERE <エージェントが自由に生成>;

-- 良い例: 危険な軸を固定パラメータとして外から与える
UPDATE target_table
SET    status = :approved_status
WHERE  db_scope   = :fixed_scope      -- 接続対象を固定
  AND  period     = :fixed_period     -- 対象期間を固定
  AND  category   = :fixed_category   -- 対象種別を固定
  AND  id IN (:preview_confirmed_ids) -- Gate Bで確認済みの対象のみ
;

ポイントは、preview_confirmed_ids のように「プレビューで人間が確認した対象そのもの」を実行時のキーにすることだ。こうすれば、Gate B と Gate D の間で対象がずれる余地がなくなる。「見せたものと違うものを更新する」という最悪の乖離を、構造的に潰せる。

オーケストレータと原子スキルで危険を分解する

もう一つの柱が、フローの組み立て方だ。「本番を更新する」という一枚岩の危険な操作を、そのままエージェントに持たせない。

親となるオーケストレータが全体の段取りを管理し、実際の個々の操作は、責務を絞った小さな「原子スキル」として切り出す。たとえば「対象を数える」「サンプルを取得する」「承認を受け取る」「限定された更新を実行する」を、それぞれ独立した部品にする。

この分解には二つの効果がある。第一に、危険な操作(限定更新の実行)が単独の小さな部品に閉じ込められるため、レビューと権限管理の対象が明確になる。第二に、オーケストレータが「承認を受け取る部品を通過していなければ、更新を実行する部品を呼べない」という順序制約を強制できる。危険なスキルは、前段のスキルが成功したという条件下でしか起動しない。

エージェントに「全部よしなにやって」と一枚岩で渡すのではなく、「安全な部品を、安全な順序でしか呼べない構造」を先に作る。これが分解の狙いだ。

注意点

最後に、運用で効かせるための注意をいくつか。

まず、ゲートは「面倒だから省く」誘惑に常にさらされる。順調なときほどプレビューや承認を飛ばしたくなるが、事故はまさにその省略から起きる。ゲートは仕組みとして強制し、人間の自制心に頼らないことが肝要だ。

次に、承認は「儀式」にしないこと。要約を読まずに反射的にGoを出す承認は、ゲートが存在しないのと同じだ。プレビューは、人間が数秒で異常に気づける粒度で提示する。

そして、これらの設計は特定の失敗の再発防止として導入されることが多いが、目的は「誰かを責めないための構造」にある。人は疲れれば対象を取り違える。だからこそ、取り違えても本番に届かない経路を先に用意しておく。承認ゲートとは、エージェントを縛る仕組みであると同時に、人間の一瞬の油断を受け止める仕組みでもある。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください