承認しても、理解したことにはならない ── AIエージェントに「前提ゲート」を実装する
Permission(承認)と Assumption Verification(前提検証)は別のレイヤーである、という話。
主要4フレームワークの実仕様(2026年6月時点)を一次ソースで確認した上で、足りていない層と、その埋め方を設計する。
TL;DR
- チャットボットが早く止まると「間違った答え」が返る。エージェントが早く止まると「世界が変わる」。
- だから tool call に承認(permission)が要る。でも承認は必要だが十分ではない。
- 次の失敗は「危険な操作」ではなく、誤った前提の、完璧な実行(flawless execution of a premature assumption)。
- 主要フレームワーク(OpenAI Agents SDK / Claude Code / LangChain / Google ADK)は、どれも tool call を guard している。だが**「その操作が許されるか」を検証していて、「その操作が乗っている前提が正しいか」は検証していない**。
- 本記事は、permission gate の手前に置く assumption gate を、
execution packetという型で実装する。全 action には適用しない。policy-routed(不可逆・高影響の action だけ)にする。
1. エージェントの早すぎる確定は「操作」になる
チャット画面では、早すぎる確定(premature closure)はテキストとして現れる。もっともらしい要約、自信ありげな推奨。読み返して、却下して、聞き直せる。
エージェントでは、同じ失敗が**操作(action)**になる。モデルは答えるだけでなく、ツールを呼び、ファイルを編集し、DBを叩き、リクエストを送り、コードを書き、ドキュメントを更新する ── そして途中で承認を求めてくる。
これが承認を必要にする。だが十分にはしない。
承認できる操作 ≠ 正しい前提に乗った操作
ユーザーが「このコマンドを実行していいか」に Yes を押したとき、検証されたのはコマンドであって、そのコマンドを選ばせた前提ではない。
2. 主要フレームワークは「tool call」を guard している(実仕様)
2026年6月時点で、主要なエージェントフレームワークは、いずれも tool call の周りに制御点を公開している。以下は各公式ドキュメントで確認した実仕様。
| フレームワーク | 機構 | 走るタイミング | できること |
|---|---|---|---|
| OpenAI Agents SDK | tool guardrails | function tool の実行前後 | input guardrail が call を skip / 出力を replace / tripwire を raise |
| Anthropic Claude Code | permission rules(allow / deny / ask) | tool 呼び出し前(deny→ask→allow で評価、deny 優先) | file edit / shell コマンドを「何を実行するか」見せて停止・承認 |
| LangChain | HumanInTheLoopMiddleware | tool 実行前に interrupt | 人間が approve / edit / reject |
| Google ADK |
before_tool_callback / after_tool_callback
|
tool 実行前後 | 引数を validate / modify / short-circuit |
最小コード例で見ると、どれも「tool call を挟む」構造になっている。
OpenAI Agents SDK(tool guardrail で実行前に弾く):
from agents import function_tool, tool_input_guardrail, ToolGuardrailFunctionOutput
@tool_input_guardrail
def block_prod_writes(data):
if "prod" in str(data.tool_input):
# tool call を止めて、モデルにメッセージを返す
return ToolGuardrailFunctionOutput.reject_content("production への書き込みは不可")
return ToolGuardrailFunctionOutput.allow()
@function_tool(tool_input_guardrails=[block_prod_writes])
def write_database(table: str, payload: dict) -> str:
...
Claude Code(settings.json で宣言的に gate する):
{
"permissions": {
"allow": ["Bash(git commit:*)", "Read(*)"],
"deny": ["Bash(git push:*)", "Bash(rm:-rf*)"],
"ask": ["Edit(*)"]
}
}
評価順序は
deny → ask → allow。最初にマッチした deny が勝つ。askにすると「何を実行するか」を見せて承認を待つ。
LangChain(危険な tool だけ人間に止めさせる):
from langchain.agents.middleware import HumanInTheLoopMiddleware
guard = HumanInTheLoopMiddleware(
interrupt_on={
"deploy_to_production": True, # approve / edit / reject を要求
"read_metrics": False, # 読み取りは自動通過
}
)
# checkpointer 必須(中断状態を保持するため)
Google ADK(callback で実行前に介入):
def before_tool_callback(tool, args, tool_context):
if tool.name == "delete_record" and not args.get("confirmed"):
# 値を返すと tool 実行を short-circuit できる
return {"status": "blocked", "reason": "confirmation required"}
return None # None なら通常実行
3. 違う表面、同じ形 ── どれも前提を見ていない
4つのコードを並べると、違う仕組みなのに同じ形だと分かる。
各機構が見ているもの:
✓ この tool は許されているか (allowed?)
✓ この操作は危険か (safe?)
✓ スコープ内か (in scope?)
✓ 承認が要るか (approved?)
✓ ロールバックできるか (undoable?)
どの機構も見ていないもの:
✗ この操作が乗っている前提は正しいか (right assumption?)
これらは permission・security・execution の問いだ。一段手前の問い ──
この操作を「適切に見せている」前提は何か?
── を、どのフレームワークも検証していない。これが埋めるべき層、assumption gate だ。
承認レイヤーが「tool 名 + 引数」しか見せないなら、人間は実行を承認しているだけで、前提は見ていない。承認ボタンを押す人間が、見えない推論チェーンの末端のボタン係になる。
4. Permission gate と Assumption gate は別物
permission gate : この操作は「許されるか」
assumption gate : この操作は「正しい問題を解いているか」
同じ問いではない。エージェントのワークフローは推論を操作に圧縮する。tool call は技術的操作であると同時に、「システムが何の問題を解いていると思っているか」の主張だ。その主張が承認画面に出ていなければ、人間はそれを検証できない。
具体例。エージェントが「個人サイトの集客が伸びない」を「ポジショニングが弱い」と早期に確定したとする。各操作は全て許可されうる ── サービスページを作る、プロフィールを編集する、料金表を書く、アウトリーチ文を下書きする、投稿をスケジュールする。全部 allowed、どれも policy 違反なし、sandbox も越えない。 だが前提(「問題はポジショニングだ」)が間違っていれば、許可された操作の連鎖が、丸ごと間違った方向に世界を変える。
5. 実装 ── execution packet
assumption gate の本体は、高影響 action の手前で、システムに前提を構造化して晒させることだ。承認画面に「何をするか」だけでなく「なぜ・何を前提に」を出す。
最小の型を execution packet と呼ぶ。6フィールド。
execution_packet:
objective: # この操作は何を解こうとしているか
"個人サイトのコンバージョン改善"
assumption: # この操作が意味を持つために、真でなければならないこと
"低コンバージョンの主因はポジショニングの弱さである"
evidence: # その前提を支える根拠(と、その強さ)
- source: "直近30日のアナリティクス"
strength: "weak" # 直帰率は高いが、原因は未分離
- source: "ユーザーの主観報告"
strength: "anecdotal"
scope: # この操作が触る範囲・権限
writes: ["service_page", "profile", "pricing_table"]
irreversible: true
rollback: # 失敗したら何が戻せるか
"ドラフト保存のみ。公開はしない。公開済みは git 履歴で復元可"
memory: # この操作が将来の文脈に何を書き込むか
"新ポジショニングを future context として保存する"
ポイントは assumption と evidence だ。permission gate には存在しないフィールドで、ここが「approved ≠ understood」を埋める。evidence.strength が weak / anecdotal のまま irreversible: true の操作に進もうとしていたら、それが止めるべきシグナルになる。
ゲート関数のイメージ(擬似コード):
def assumption_gate(packet, policy):
# 全 action には適用しない(§6 policy-routed)
if not policy.requires_gate(packet.scope):
return Decision.ALLOW
# 前提が未検証 + 不可逆 → 人間に前提ごと晒して止める
if packet.evidence.is_weak() and packet.scope.irreversible:
return Decision.INTERRUPT(
surface=packet, # objective/assumption/evidence を全部見せる
ask="この前提に同意しますか?(操作の許可ではなく)"
)
return Decision.ALLOW
これは既存の制御点の上に乗る。OpenAI の tool guardrail、Claude Code の hook、LangChain の interrupt、ADK の callback ── どれの上にでも実装できる。permission を置き換えるのではなく、足りない文脈を足す。
6. 全部には適用しない ── policy-routed
最大の反論はコストだ。「全 tool call に packet を要求したら、エージェントが遅くて鬱陶しい」。正しい。だから全部には適用しない。意味的・運用的に本当にリスクのある action にだけルーティングする。
class GatePolicy:
def requires_gate(self, scope) -> bool:
# 不可逆・高影響だけゲートする
HIGH_RISK = {
"file_write", "db_update", "external_send",
"purchase", "publish", "repo_wide_edit", "memory_write",
}
return (
bool(scope.actions & HIGH_RISK)
or scope.irreversible
or scope.reframes_identity # ユーザーの戦略・公開像を書き換える操作
or scope.built_on_stale_context
)
- 読み取り操作 → permission チェックで十分。ゲート不要。
- 可逆なドラフト → 軽いゲート。
- 不可逆・アイデンティティを変える操作 → 承認に前提を含める(重いゲート)。
7. フロー全体(Mermaid)
赤い破線が、いま塞がれていない経路 ── 承認されたが、理解されていないルートだ。assumption gate は、この経路を閉じるために置く。
8. Sandbox とは別レイヤーである
念のため。sandbox は必要だ。だが別の問いに答えている。
sandbox : コードが「どこで」走るか(被害範囲を絞る)
assumption gate : エージェントが「正しい問題」を解いているか
エージェントは sandbox の中で安全に間違ったリファクタができる。リポジトリ内に留まったまま、誤解したアーキテクチャで再編成できる。メールを送らず下書きするだけで、間違ったメッセージを形にできる。封じ込めは被害を減らすが、タスクの対象が正しいかは検証しない。 だから permission・sandbox・assumption verification は、別々のレイヤーに置く。
まとめ
エージェントの安全性の議論は正しい方向に進んでいる ── guardrail、承認、sandbox、スコープ付き権限、トレーシング。全部強化すべきだ。だが ──
permission は assumption verification ではない。そして approved is not understood。
承認を待つエージェントも、間違った前提の上で動いていることがある。tool call を承認する人間も、自分がどんな戦略的前提を世に出したのか分かっていないことがある。
足りない層は、難しい新技術ではない。高影響の action の手前で、前提を構造化して晒すこと。それだけだ。
補足:この記事について
本記事は、筆者(あきみつ / dosanko_tousan、独立AIアライメント研究者)とClaudeの対話から生まれ、構成・レビューには複数のモデルの助言を用いた。フレームワークの仕様(OpenAI Agents SDK / Claude Code / LangChain / Google ADK、2026年6月時点)は、すべて各公式ドキュメントを筆者が一次ソースで確認した上で記載している。 仕様はリリースごとに変わりうるため、実装時は最新の公式ドキュメントを参照のこと。
英語版(思想の角度から書いたもの)は Medium / AI Advances に掲載:Approved Is Not Understood — Why AI agents need assumption gates, not just permissions
この設計の背景にある「介入は反応が走る前に置く」という発想を、アビダンマの認識過程(citta-vīthi)から設計した記事。