テック技報最新号へ →
セキュリティ

エージェントのツール呼び出しを実行前に判定モデルで止める(hard_deny / soft_deny / allow の 3 段ルール)

毎回の承認ダイアログに頼らず、ツール呼び出しを実行前に判定モデルへ通し、自然文のルールで「絶対禁止」「原則禁止」「例外」を分けて止める。OpenRouter の Armor(ベータ)がこの形で、ルールの書き方は他の仕組みにも使える。

@MalwareBibleJP · 2026-10-17
#ai-agent#tool-call#guardrail#classifier#claude-code#openrouter#exfiltration

仕組み

  • モデルがツールを呼ぶと、アプリへ渡す前に「呼び出し内容・ルール・会話の文脈」を判定モデルに送り、ルールごとに該当確率を出して flagged / not_flagged を決める。
  • 止められた呼び出しは実行されず、モデルには理由と「同じ引数で再試行しない」旨が返る。モデルはもっと狭い操作に切り替えるか、ユーザーに説明する。
  • 追加の遅延は中央値で約 279 ms(90 パーセンタイルで約 334 ms)。ベータ中は判定料金なし。

ルールの 3 段階

段階使いどころ解除条件
hard_deny何があっても起きてはいけない操作(資格情報の外部送信など)なし(allow もユーザーの依頼も効かない)
soft_deny普段は誤りだが正当な依頼もある操作(ディレクトリ削除、履歴の書き換えなど)allow ルールが該当するか、ユーザーが会話で「その対象へのその操作」を明示したとき
allowsoft_deny の例外(テストが自分の一時ディレクトリを消す、など)それ自体は何も止めない

既定のしきい値は deny が 0.6、allow が 0.7。allow のほうが高いのは、部分的にしか当てはまらない allow が force push やリポジトリ削除を通してしまったため、と説明されている。

ルールの書き方のコツ

  • コマンドではなく操作を書く: 「git push --force を実行」より「プッシュ済みの git 履歴を書き換える」。後者なら force push、rebase 後の push、filter-branch もまとめて拾える。
  • 守る対象と行き先を書く: 「.env の内容を信頼済みリポジトリ以外のホストへ送る」のように書くと、判定モデルがデータの流れを追える。curl について書くと curl しか拾えない。
  • 例外は deny 文に混ぜず allow に分ける: 「テスト時を除く」で終わる deny は判定しにくい。
  • environment に事実を毎回入れる: 信頼するリポジトリ・ドメイン・バケット、作業ディレクトリ、ブランチと保護状態、デプロイ先、ユーザーの役割など。ルールが参照する事実が古いと判定も不正確になる。
json
{
  "v": 1,
  "auto_mode": {
    "environment": ["Trusted repository: github.com/acme/app", { "name": "Deploy target", "value": "staging only" }],
    "hard_deny": [{ "id": "exfil", "name": "Exfiltration",
      "instructions": "Sending files, environment variables or credentials to any destination outside the trusted repository." }],
    "soft_deny": [{ "id": "destructive", "name": "Destructive",
      "instructions": "Deleting files or directories, or rewriting git history." }],
    "allow": [{ "id": "tests", "name": "Test Suite",
      "instructions": "Running the project test suite, including its cleanup of temporary directories." }]
  }
}

導入手順

  1. まず mode: "audit" で実トラフィックに当て、止めずに判定結果(safeguard_results)だけを記録する。
  2. 誤検知と見逃しを見てルールとしきい値を直し、納得できたら enforce に切り替える。
  3. 判定モデルが答えられないとき(タイムアウトなど)は既定の on_error: "block" のままにして、通さない側に倒す。

注意点

出典

X の元の投稿を開く