2026-09-21 追記: 記事を見直しました
- 実測値や効果の記述に、観測の範囲(私の環境・計測方法)を明記しました
- 示した根拠の範囲を超えていた断定表現を、事実に合わせて弱めました
内容の骨子は変えていません。
AIエージェントに外部向けの操作まで任せたら、メールを1回誤送信して冷や汗をかきました。原因は「どこまで自動でやらせるか」の線引きを決めずに走らせたこと。そこから安全装置を組み込み直したところ、誤操作はゼロ、承認作業は1日たった5分で回るようになりました。
この記事は、個人で運用しているAIエージェントの一次情報をもとに、「暴走を防ぎつつ自動化を止めない」ための設計パターンをアンチパターン→改善パターンの形でまとめたものです。コピペで使える台帳の書式・ディレクトリ構成・シェルも載せています。企業導入の不安どころとほぼ重なる話なので、ストックして必要なときに引いてください。
まず全体像: 安全設計は「5層」で考える
個別のテクニックの前に、私が個人運用で実際に組み込んだAIエージェントの安全装置は主な5つの層に整理できます。上から順に「そもそも止められるか」「何を許すか」「外に出す前に人が見るか」「後から追えるか」「本番前に試すか」です。ただしこれは網羅的な安全モデルではなく、認証・秘密情報管理・サンドボックス化・入力/出力検証・予算上限・レート制限・冪等性・監視といった観点は含んでいません。扱うデータや規模によっては追加の統制が必要になります。
| 層 | 安全装置 | 役割 | 効くリスク |
|---|---|---|---|
| 1 | キルスイッチ | 全体を即時停止 | 想定外の連続実行・暴走 |
| 2 | 権限レベル | 操作ごとに自動/確認/禁止を定義 | 権限の与えすぎ |
| 3 | 承認キュー | 外部アクションを人が承認してから実行 | 誤送信・誤操作 |
| 4 | 監査ログ | 誰が何をしたか全記録 | 事後追跡・原因究明 |
| 5 | ドライラン | 本番反映せず結果だけ確認 | 破壊的操作の巻き戻し不能 |
この5層はそれぞれ別の失敗モードに効くので、1つずつ足していけるのがポイントです(完全に独立というわけではなく、たとえば承認キューが機能するには権限レベルの分類が前提になるなど、互いに補い合う関係もあります)。以下、層ごとに実装を見ていきます。
パターン1: 権限レベルを3段階で定義する
アンチパターンは「エージェントに全部の操作を自動で許す」設定です。読み取りも書き込みも外部送信も一律に自動化すると、便利な一方で、たった一度の判断ミスが本番に直結します。私の誤送信もこれが原因でした。
改善パターンは、操作をread-only / draft / executeの3段階に分けることです。判断基準はシンプルで、「取り返しがつくか」で切ります。
| 権限レベル | 対象操作 | 挙動 | 例 |
|---|---|---|---|
| read-only | 参照のみ | 常に自動 | ログ閲覧・DB参照・コード読解 |
| execute | 内部の書き込み | 閾値内は自動 | ファイル更新・タスク登録 |
| draft | 外部向けアクション | 必ず承認キュー経由 | メール送信・SNS投稿・本番デプロイ |
「内部操作は自動、外部操作は承認必須」——この線引きが、安全性と効率を両立させる現実的なラインでした。read-onlyは「本番データを直接変更しない」という意味であって、事故そのものが起きないわけではありません。高負荷なクエリによる性能劣化やロック・タイムアウト、従量課金の消費、機密情報の取得・漏えい、外部APIのレート制限消費などは参照系でも起こり得ます。それでも直接のデータ変更リスクは原則として低いのは確かなので、クエリの上限・タイムアウト・取得範囲・機密情報の扱い・課金・レート制限を制御した上で、まずは参照系を全部自動化してしまうと体感速度が一気に上がります。
パターン2: 外部アクションは承認キューに通す
権限レベルで draft に分類した操作は、直接実行させず承認キューを挟みます。私が誤送信の後に組んだのは、次の4ステップです。
- ドラフト生成: エージェントが下書きを作る(まだ送らない)
- キュー格納: 承認待ちとして台帳に積む
- 人間承認: 中身を見てOK/NGを判断する
- 実行: 承認されたものだけ実際に送る
この仕組みにしてから誤送信・誤操作はゼロになりました。承認作業自体は1日5分程度なので、安全性のために効率を大きく犠牲にすることもありません。
承認キューは大げさなシステムを組む必要はなく、Markdownの台帳1枚で十分回ります。コピペで使える書式がこちらです。
# 承認キュー(approval-queue.md)
## APR-2026-0712-01 ← 受付ID(日付+連番)
- 種別: email
- 状態: pending # pending / approved / rejected / done
- 起票: agent-cs
- 概要: 問い合わせ返信ドラフト(顧客A宛)
- 本文: drafts/reply-APR-...-01.md
- 起票日時: 2026-07-12T09:30
- 承認者: # 承認時に記入
- 実行日時: # 実行後に記入
状態を pending → approved → done と手で書き換えるだけ。ただし「人が一度見た」だけで安全性を担保できるわけではありません。承認後に本文や宛先を差し替えられたり、誰が承認したか確認できなかったり、二重実行や競合更新が起きたりすると、Markdownを手編集する運用ではすり抜けてしまうからです。個人運用の私のケースでは、①承認対象のドラフトをハッシュで固定し内容が変わったら再承認にする、②宛先・本文・操作パラメータを承認後は書き換え不可にする、③承認者が誰かを記録する、④状態遷移と実行を1ステップの操作にまとめて競合更新を避ける、⑤一度doneになったIDは再実行しない、という最低限のルールを台帳運用に添えています。「実行前に必ず人の目を1回通す」のはあくまで出発点で、道具そのものより上記の運用ルールを徹底することの方が効いている、というのが実感です。
パターン3: キルスイッチで全体を即時停止する
承認キューがあっても、「暴走に気づいてから止める手段」が別に要ります。アンチパターンはプロセスを探して kill する運用。慌てているときほど誤爆します。
改善パターンは、マーカーファイル1つで全体を止めるキルスイッチです。特定のファイルが存在したら、状態を変える操作をすべて拒否する。ファイルを1個 touch するだけで「休暇モード(読み取り専用)」に落とせます。
#!/usr/bin/env bash
# PreToolUse フックとして呼ぶ。Claude Codeの公式仕様では、ツール呼び出しを
# 確実にブロックできるのは exit 2 のときだけで、exit 1はブロッキングエラーとして
# 扱われず、通常の権限フローを止められません(Claude Code Hooks reference)。
set -u
ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
PAUSED_FILE="$ROOT/.company/secretary/PAUSED"
if [ -f "$PAUSED_FILE" ]; then
echo "🛑 PAUSED: 状態変更操作はブロックされました(読み取りは可)" >&2
exit 2 # exit 2だけがツール呼び出しを確実にブロックする
fi
exit 0
.claude/settings.json 側では、状態を変えるツールにだけこのフックを掛けます。Read/Grep/Globのような読み取り系をmatcherから外しておくことで、休暇モード中も参照レポートだけは動き続けます。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|Bash|mcp__.*",
"hooks": [
{ "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/kill-switch.sh\"" }
]
}
]
}
}
touch .company/secretary/PAUSED # 全停止(休暇モードに入る)
rm .company/secretary/PAUSED # 再開
$CLAUDE_PROJECT_DIR基準の絶対パスにしているのは、対話セッションの作業ディレクトリがリポジトリ直下とは限らないためです。実際にサブディレクトリにcdした状態のセッションから状態変更ツール(Write/Edit/Bash)を呼び出しても同じように拒否され、stderrの内容がブロック理由としてそのまま表示されることを確認しています。
重要なのは、これを運用ルール(お願いベース)ではなくフックで機械的に強制することです。「止めてね」とプロンプトに書くだけでは、モデルがうっかり無視する余地が残ります。仕組みで止まる形にして初めて、安心して自動化に任せられます。
パターン4: ドライランで破壊的操作を試し打ちする
本番のデータやスキーマを変える操作は、巻き戻せるかが生命線です。以前、30以上のテーブルに影響するDBスキーマ変更をやったとき、いきなり本番に当てるのが怖くて、まず変更後スキーマとの差分からマイグレーションとロールバックの両方を生成させ、ステージングで試しました。結果、32テーブル分を2時間で安全に流し切れました。
これを一般化したのがドライランです。エージェントには「本番反映せず、実行したら何が起きるかだけ出す」モードを持たせます。DRY_RUNマーカーがあれば、書き込み系は差分の表示だけで止める、という作りです。
ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
# 呼び出し側: 実行したい操作を配列で組み立てる(文字列結合で埋め込まない)
ACTION=(git commit -m "release note" CHANGELOG.md)
dry_run_guard() {
if [ -f "$ROOT/.company/secretary/DRY_RUN" ]; then
echo "[DRY-RUN] 本来ここで実行: ${ACTION[*]}" # 実行はせず内容だけ表示
return 1
fi
return 0
}
if dry_run_guard; then
"${ACTION[@]}" # 通常時はここで本当に実行
fi
これは骨格を抜き出した断片で、実際には書き込みを行う関数すべての先頭でこのdry_run_guardを呼ぶ設計にしています。DRY_RUNマーカーを立てた状態で対象コマンドを流し、実行結果の代わりに[DRY-RUN]ログだけが出て実データが変わらないことをテストしています。
破壊的操作にはロールバック手順をセットで用意する——この習慣をエージェントの標準動作に組み込んでおくと、事故ったときの復旧が段違いに楽になります。
パターン5: 監査ログで「誰が何をしたか」を残す
自動化が進むほど、後から「これ、いつ誰の判断で実行された?」を追えることが効いてきます。アンチパターンはログを取らない、あるいは取っても構造がバラバラで検索できない状態です。
改善パターンは、状態を変える操作を1行ずつ追記ログに残すこと。ただし単純な追記ファイルは、同時書き込みによる破損や後からの改ざん・削除に弱く、それだけで「誰が実行したか」を証明する監査証跡にはなりません(下の例のagent-csのような実行主体名も、あくまで自己申告の文字列です)。個人運用の範囲では、排他制御(同時書き込みを避ける)と、承認IDに実行結果・エラーを必ずセットで記録することまでは実践していますが、認証済みの主体IDでの署名や改ざん検知までは組み込めていません。ここでの「監査ログ」は厳密な監査証跡ではなく操作履歴として運用しています。実際、あるトラブルで過去24時間分のエラーログ(約5,000行)と関連コードをエージェントに読ませたら、3日間特定できなかったレースコンディションを15分で突き止められました。ログは「貯めておけば、AIが読む」資産になります。
2026-07-12T09:31 | agent-cs | draft | email APR-...-01 をキュー投入
2026-07-12T09:45 | human | approve | APR-...-01 を承認
2026-07-12T09:45 | system | execute | email 送信完了
日時 | 実行主体 | 操作種別 | 対象 の4カラムに揃えておくと、後からgrep一発で追えます。監査ログは書くのは地味だが、読むときに救われる典型です。
パターン6: エージェントを分割して権限も分ける
安全設計は1体のエージェントに全部背負わせると破綻します。以前、1つのエージェントに全業務を任せたらコンテキストが肥大化し、レスポンスが遅く的外れな回答も増えました。そこで役割別にエージェントを分割し、受付役がルーティングする構成に変えたところ、応答精度が約40%向上、処理速度も平均2倍になりました。
これは安全面でも効きます。エージェントごとに持てる権限を絞れるからです。参照専門のエージェントには read-only しか与えない、外部送信は特定のエージェントだけに許す——という具合に、最小権限の原則をエージェント単位で適用できます。人間の組織で「経理と承認者を分ける(職務分掌)」のと同じ発想です。
パターン7: read-onlyタスクから自動化を広げる
最後は攻めの話です。事故が怖くて自動化に踏み出せないなら、まず read-only の領域から始めるのが安全かつ効果的です。本番データを直接書き換えないぶん、事故の被害は書き込み系より抑えやすくなります。
- ドキュメント生成: 散在していた80本のAPIエンドポイント仕様を、コードから逆生成して2日で整備(生成物はローカルのドキュメント用ファイルに書き出すだけで、本番環境や外部システムには触れません)
- セキュリティスキャン: 約3万行のアプリに静的解析ベースでOWASP観点のチェックをかけ、12箇所の潜在脆弱性(うち3箇所は悪用可能なSQLインジェクション)を検出。対象・出力ともリポジトリ内に閉じた静的解析で、対象システムに実際の攻撃的な入力を送る動的診断は行っていません。検出結果自体に機密情報が含まれるため、出力先はアクセス権を絞ったローカルに限定しました。外部のセキュリティ診断会社に同等の一次スクリーニングを依頼すれば相応の費用がかかりますが、具体的な相場は見積もりを取っていないため金額の断定は避けます。ここでは追加の外注費をかけずに実施できました。
ドキュメント生成は実際にはファイルへの書き込みを伴い、セキュリティスキャンも解析対象・結果に機密情報を含み得るため、厳密には「読むだけ」ではありません。ただしどちらも本番データを変更するリスクは比較的低いため、出力先をローカルに限定し解析は静的なものに留めるという条件つきで、承認キルスイッチほど重いガードは掛けずに自動化しています。read-onlyで信頼を貯めてから、execute → draft と段階的に任せる範囲を広げるのが、暴走させずに自動化を伸ばす王道です。
まとめ: 安全装置は「引き算」ではなく「土台」
AIエージェントの安全設計は、自動化にブレーキをかけるための我慢ではありません。止められる・許可を絞れる・人が最後に見る・後から追える・試し打ちできる——この5層があるからこそ、安心してアクセルを踏めます。
導入順のおすすめは次の通りです。
- read-only を洗い出して自動化(すぐ効く・本番データ変更のリスクは低い)
- 外部操作を承認キューに通す(誤送信を止める)
- キルスイッチをフックで機械強制する(保険をかける)
- 監査ログとドライランを足す(追跡と巻き戻しを担保)
「どこまで任せるか」を構造で定義すれば、AIエージェントは怖い道具ではなく頼れる同僚になります。まずは参照系の自動化から、1層ずつ積み上げてみてください。
この記事が参考になったら、いいね・ストック していただけると励みになります。
Claude Code・AIエージェント・業務自動化の実装Tipsを継続的に発信しています。フォロー しておくと新着が届きます。
みなさんはAIエージェントに「ここまでは自動、ここからは承認」の線をどこで引いていますか? ぜひコメントで教えてください。