2026/09/26

エージェントのツール呼び出しの前に型付きガードレールを置く

提案されたツール呼び出しがユーザーの意図に合致するか、どれほど破壊的かを Jev に尋ね、判定は通常のコードに任せる方法。state の組み立て、しきい値、テストマトリクスを含むウォークスルー。

ガードレールが存在する理由となる失敗パターン

エージェントは特定の形で失敗します:局所的にはもっともらしく、全体としては間違っているツール呼び出しを発行するのです。staging 向けのはずの本番テーブルへの SELECT。DELETE のつもりで出された DROP TABLE。チャットモデルにもう 1 つのプロンプト —「これは安全ですか?」— を尋ねるやり方は遅く、構造化されておらず、安全ポリシーを自由記述に変え、次のリリースで黙って変更されてしまいます。

型付きガードレールは代わりに 3 つの質問を尋ねます:この呼び出しはユーザーの依頼に合致しているか(noul)、実行前に人間の確認が必要か(noul)、間違っていた場合の破壊性はどれほどか(score)。3 つとも 1 つのリクエストに乗り、すべての回答は定義した回答空間の中に収まって返ります — ポリシーは文章ではなくコードに留まります。

state を組み立てる

ユーザーのリクエストと提案された呼び出しを state として送ります。ここでは 1 本の長い文字列よりもオブジェクトの state の方が扱いやすくなります。各事実が名前を保てるうえ、criteria からそれらを参照できるからです。

{
  "state": {
    "user_request": "Clean up the old test data in the staging database.",
    "proposed_tool_call": {
      "tool": "sql.execute",
      "args": { "query": "DROP TABLE customers;" },
      "environment": "production"
    }
  },
  "questions": {
    "matches_intent": {
      "type": "noul",
      "instructions": "Does `proposed_tool_call` match what `user_request` asked for?"
    },
    "needs_confirmation": {
      "type": "noul",
      "instructions": "Should a human confirm this tool call before it runs?",
      "criteria": {
        "true": "Touches live data, is destructive, or the environment does not match the request",
        "false": "Read-only, staging-only, and exactly what was asked"
      }
    },
    "risk": {
      "type": "score",
      "instructions": "How destructive is this action if it is wrong?",
      "criteria": ["Harmless", "Recoverable", "Irreversible data loss"]
    }
  }
}
ガードレールのリクエストボディ

ポリシーはコードに残す

Jev は判断だけを行い、ツールを実行することはありません。確率をアクションに変換するのは自分のラッパーです:

const a = answers;
const must_confirm =
  a.matches_intent.noul < 0.8 ||
  a.needs_confirmation.noul > 0.7 ||
  a.risk.score >= 1.5; // past "Recoverable", toward the red end

if (a.risk.score >= 2.0 && a.matches_intent.noul < 0.5) {
  blockOrFlag(a.request_id); // never execute, log for review
} else if (must_confirm) {
  confirmWith(a.request_id); // ask the human
} else {
  execute(call);
}
コードとしてのポリシー

しきい値は自分で設定します。0.8 は意図照合の信頼度ラインとして妥当な出発点です。不可逆なツール(DROP、デプロイ、メール送信)では引き上げ、読み取り専用のものでは緩めます。自分のトラフィックから実例を 10 件 — おもちゃのケースではなく — 実行し、しきい値は「モデルがあなたなら下した判断と違う」ときだけ動かしてください。

信用する前のテストマトリクス

  • 適切な環境での無害な呼び出し — 低リスク、意図照合は高、確認なしを期待します。
  • 意図は正しいが環境が違う(staging を依頼され、production を呼び出した)— 意図照合は高く保たれ、needs_confirmation が上昇することを期待します。不一致は正直に読んでください。モデルは state が見せるものしか検出できません。
  • 意図が違うが無害な呼び出し — needs_confirmation は低く保たれることを期待します。無害なものは無害です。
  • 意図が違う上に破壊的な呼び出し(上記の例)— すべてのシグナルが作動することを期待します。
  • 曖昧なユーザーの依頼 — 低い信頼度を期待します。推測ではなく人に回してください。

あるケースが 2 回とも間違った結果になったら、しきい値を調整して隠すのではなく、criteria の文言を修正するか、欠けている事実(呼び出し元の環境など)を state に追加してください。

実際のコスト

この 3 質問のボディは約 350〜500 トークンで、1 クレジットの最低値に十分収まります。したがって、すべてのツール呼び出しにゲートを付けても Starter では 1 呼び出し $0.0001、大きなパックではその割合でさらに安くなります。レイテンシは 1 往復の追加です:ライブゲートウェイに対する一般的な測定で 400〜600 ms。多くのエージェントループでは許容範囲です。ツール呼び出しが 100 ms 未満で 1 ミリ秒が目立つような場合には、影響範囲が正当化するツール — ファイルシステムの書き込み、SQL、決済、メール — だけをゲートし、それ以外は素通りさせてください。

型付きガードレールが機能しなくなる場所

限界は明確にしておいてください:ガードレールモデルは state にないものは見えません。対象の環境を含めなければ、環境の間違いには気付けません。決定論的なコントロールの代わりにもなりません — アローリスト、パスチェック、ネットワークスコープはそれらが得意なことに使い、型付きの判断レイヤーには意味的な質問を任せてください:この計画はリクエストに合致しているか?

Jev 自身がツール呼び出しを実行できますか?

いいえ。返すのは判断だけ — 尋ねた質問に対する確率です。実行または拒否するのは自分のコードです。この分離が監査証跡を自分の手元に保ちます。

これですべての危険な呼び出しを検出できますか?

完全な安全システムであるモデルは存在しません。ガードレールは 1 つのレイヤーとして使ってください。効果が最も高いのは、危険が意味的なもの(意図の不一致、環境の取り違え)である場合です。アローリストやスコープには決定論的なルールを残し、不可逆な経路には人を残してください。

この例は Playground にもありますか?

はい — /playground ページの「Tool-call risk gate」プリセットがまさにこのリクエスト形状で、無料で実行できます。

Jev AI Playground を試す。このガイドを読み終えたら、最初の無料の判断を送ってみましょう。