Industry & PracticeTools & Frameworks
Inspect 工具 审批: 人 审、 自动 放行 和 桥接 智能 体
审批模式打开后,没有被策略处理的工具调用会被拒绝。桥接智能体连续三次被拒绝的回复会终止样本。远程 MCP(execution=remote)在审批策略活动时不能用来生成。

In this piece
工具审批
UK AI Security Institute。Tool Approval。文档页无单独发布日期(检索于 2026-11-02)。许可证:MIT License,Copyright (c) 2024 UK AI Security Institute。
概述
Inspect 的审批模式(approval mode,工具调用在执行前先过一道决定)让你为模型发出的工具调用(tool call,模型请求执行某个工具并带上参数)制定细粒度策略。例如,下面这些都支持:
- 全部工具调用由人类操作者批准。
- 选出的一部分工具调用由人类操作者批准(其余不经批准就执行)。
- 自定义审批器(approver,决定批准、拒绝或交给下一个审批器的函数)决定批准、拒绝,或升级给另一个审批器。升级(escalate)是不自己做最终决定,而是把这一次调用交给链上的下一个审批器。
自定义审批器很灵活,可以实现多种决定方案,包括非正式的启发式规则,以及由模型来评估。它们也可以支持在远程系统上用自定义界面做人工批准(批准通过消息队列发送和接收)。
审批器可以设在评测级,也可以设在任务级。下面的例子演示评测级审批器。任务级见任务审批器。
人工审批器
最简单的审批策略是:所有工具调用都由人交互式批准。用 CLI 选项 --approval human(或传给 eval() 的参数 approval = "human")打开这一策略:
inspect eval browser.py --approval human这个例子给模型内置的网页浏览器工具,并让它打开一个网页做搜索。
人工审批器默认提供批准、拒绝和终止(human_approver(choices=...) 可以改这些选项)。它不能提供修改,因为操作者没有办法录入一次修改后的工具调用:如果 choices 里包含 "modify",会丢掉并给出警告;如果 "modify" 是唯一选项,human_approver() 会报错。
自动审批器
一旦打开审批模式,所有工具调用都必须以某种方式被处理(否则会被拒绝)。但是逐个批准每一次调用会很烦,也不是每一次调用都值得人来盯。
可以把 human 和 auto 审批器串成一条审批策略(approval policy,按顺序尝试的审批器列表),只批准选中的那些调用。例如,这里的策略只对交互式网页浏览器工具调用要求人工批准:
approvers:
- name: human
tools: ["web_browser_click", "web_browser_type"]
- name: auto
tools: "*"导航类网页浏览器工具调用(例如 web_browser_go)由链末尾兜底的 auto 审批器自动批准。在策略里列出审批器时,用一个 glob 或一组 glob 标明它处理哪些工具。这些 glob 按前缀匹配,所以 web_browser_type 同时匹配 web_browser_type 和 web_browser_type_submit。
要用这条策略,把策略 YAML 文件的路径当作审批器传入。例如:
inspect eval browser.py --approval approval.yaml也可以匹配工具参数(对会分发多种动作类型的工具)。例如,下面是计算机工具的审批策略:允许打字和移动鼠标,但对组合键(例如 Enter 或快捷键)和打字要求批准。原文代码块前面单独有一行文件名 approval.yaml,匹配模式按页面原文没有闭合括号:
approval.yamlapprovers:
- name: human
tools:
- computer(action='key'
- computer(action='left_click'
- computer(action='middle_click'
- computer(action='double_click'
- name: auto
tools: "*"因为这是前缀匹配,而且后面还可能有别的参数,工具匹配模式的末尾不加括号。
在代码里写审批器
上面演示了用 YAML 审批策略文件配置审批器。也可以直接在代码里给出策略(需要更动态时有用)。下面是上一节例子的纯 Python 版本:
from inspect_ai import eval
from inspect_ai.approval import ApprovalPolicy, human_approver, auto_approver
approval = [
ApprovalPolicy(human_approver(), ["web_browser_click", "web_browser_type*"]),
ApprovalPolicy(auto_approver(), "*")
]
eval("browser.py", approval=approval, trace=True)任务审批器
创建 Task 时,可以用 approval 参数在任务级指定审批策略。例如:
from inspect_ai import Task, task
from inspect_ai.scorer import match
from inspect_ai.solver import generate, use_tools
from inspect_ai.tool import bash, python
from inspect_ai.approval import human_approver
@task
def linux_task():
return Task(
dataset=read_dataset(),
solver=[
use_tools([bash(), python()]),
generate(),
],
scorer=match(),
sandbox=("docker", "compose.yaml"),
approval=human_approver()
)和其他 Task 选项一样,评测级定义的 approval 策略会覆盖任务级审批策略。
上下文管理器
可以用 approval() 上下文管理器(context manager,进入一段代码时换上新设置、离开时恢复旧设置的对象),在一次正在跑的评测里临时覆盖审批策略。当求解器或智能体对某一段工具调用需要不同的审批策略时,这很有用:
from inspect_ai.approval import approval, ApprovalPolicy, human_approver, auto_approver
async def my_solver(state):
# Use human approval for a critical section
with approval([ApprovalPolicy(human_approver(), "*")]):
# tool calls within this block require human approval
...
# Outside the block, previous approval policies are restored
...上下文管理器在其持续期间替换当前审批策略,退出时恢复之前的策略。支持嵌套:每一层嵌套的 approval() 上下文设置自己的策略,退出时正确恢复外层策略。
execute_tools() 函数和 react() 智能体也为方便接受 approval 参数,在工具执行期间应用审批策略:
from inspect_ai.model import execute_tools
from inspect_ai.approval import ApprovalPolicy, human_approver
result = await execute_tools(
messages, tools,
approval=[ApprovalPolicy(human_approver(), "*")]
)from inspect_ai.agent import react
from inspect_ai.approval import ApprovalPolicy, human_approver
agent = react(
tools=[bash(), python()],
approval=[ApprovalPolicy(human_approver(), "*")]
)桥接智能体
通过智能体桥接入的智能体自己跑工具循环,所以 Inspect 从不执行它们的工具调用。桥接智能体(bridged agent,工具循环在智能体自己那边、Inspect 只看到模型回复的智能体)的审批策略改为作用在每一次模型回复里的工具调用上,在把该回复交回智能体之前。这同时覆盖 agent_bridge() 和 sandbox_agent_bridge(),以及它们支持的每一种 API 方言。
评测级和任务级策略会自动生效。也可以把策略直接限定在一座桥上:
async with sandbox_agent_bridge(
state,
approval=[
ApprovalPolicy(human_approver(), "bash"),
ApprovalPolicy(auto_approver(), "*"),
],
) as bridge:
...对沙箱桥来说,这个参数是从智能体内部设置策略的唯一可靠办法:桥接生成跑在沙箱服务任务里,看不到在智能体函数体里进入的 approval() 上下文管理器。
各种决定的行为如下:
| 决定 | 对桥接智能体的行为 |
|---|---|
| approve | 这次调用交给智能体,由它照常执行。 |
| modify | 修改后的参数交给智能体。把调用改成另一个函数会使样本以错误失败。没有修改后调用的 modify 当作拒绝。 |
| reject | 这次调用从不交给智能体。模型被告知被拒绝,并被要求重新生成;智能体只看到替换后的回复。 |
| terminate | 样本被终止。 |
| escalate | 交给链上的下一个审批器,和其他地方一样。 |
有两种行为是桥接智能体特有的:
- 一次拒绝会丢掉同一条回复里的每一次工具调用。 每一次调用都会得到一条结果,说明发生了什么;本身没有被拒绝的那些调用会被告知是哪一次调用导致的,这样模型可以单独再发出它们。这和 Inspect 自己执行的工具不同,后者每次调用独立处理。
- 连续三次被拒绝的回复会终止样本。 没有这一条,一个不断提出被拒绝调用的模型会无限重试。
因为 Inspect 不执行这些工具调用,不会为它们记录工具事件。记录里显示的是审批决定,而不是一次带有审批的工具调用。读日志时由此有两点:
- 调用按顺序审批,评测在第一次拒绝处停下。因此,紧挨在被拒绝的兄弟调用之前、已被批准的那一次,即使从未运行,也会记下一次审批。桥接智能体的审批决定记录的是这次调用被允许,不是它已经被执行。
auto审批器的自动批准完全不显示。如果想让每一次决定都有可见记录,就用auto以外的审批器。
modify 决定在日志里保留原来的调用:记录下来的模型输出和审批事件显示模型提出了什么,审批事件的 modified 字段显示被替换成了什么。
对带有桥接工具的沙箱桥,决定还决定智能体能在宿主上执行什么。桥接工具只对模型在一次桥接生成里提出的调用运行,每个提议一次,参数是批准后的参数(因此 modify 决定授予的是修改后的调用,不是原来的);没有匹配提议的 tools/call 会被拒绝,智能体把错误交给模型,由模型重新提议。没有配置审批策略时也是这样。用 BridgedToolsSpec(require_proposal=False) 注册的服务器放弃这种对应关系:它的工具对智能体发出的任何 tools/call 都会运行。见执行契约。在 Codex CLI 的代码模式下,模型只提议运行其脚本的那一次 exec 调用,所以策略审查的是这次调用;脚本发出的宿主工具调用不由任何策略审查(而且要能运行,需要 require_proposal=False)。
远程 MCP 服务器
远程 MCP 服务器(execution="remote")的工具在生成期间由模型供应商调用,所以 Inspect 无法批准那些调用。审批策略处于活动状态时,带远程 MCP 服务器去生成会报错,而不是把服务器发给供应商。这对任何策略都适用,包括只点名其他工具的策略,因为没有策略匹配到的工具调用会被拒绝。传给 react()、agent_bridge() 和 sandbox_agent_bridge() 的策略也一样。用 execution="local",服务器的工具调用就会和其他工具一样被审批。
自定义审批器
Inspect 带两个内置审批器:human 在终端做交互式批准,auto 自动批准或拒绝指定工具。也可以自己写审批器,实现几乎任何能想到的方案。
自定义审批器是返回 Approval 的函数。Approval 由一个决定和一段解释组成。下面是 auto 审批器的源代码,它只是把初始化时给定的决定原样返回:
@approver(name="auto")
def auto_approver(decision: ApprovalDecision = "approve") -> Approver:
async def approve(
message: str,
call: ToolCall,
view: ToolCallView,
history: list[ChatMessage],
) -> Approval:
return Approval(decision=decision, explanation="Automatic decision.")
return approve有五种可能的审批决定:
| 决定 | 说明 |
|---|---|
| approve | 工具调用被批准 |
| modify | 工具调用在修改后被批准(修改后的调用放在 Approval 的 modified 字段) |
| reject | 工具调用被拒绝(向模型报告这次调用被拒绝,并附上解释) |
| escalate | 工具调用应升级给链上的下一个审批器。 |
| terminate | 由于这次工具调用,当前样本应被终止。 |
modify 决定必须在 modified 里带上修改后的调用。没有的话,这个决定当作拒绝:工具不运行,模型被告知选了修改,但没有提供修改后的调用。审批事件仍然记录 modify 决定。
modify 决定只能改工具调用的参数。如果修改后的调用点了另一个函数,两个工具都不运行,样本以错误失败,因为这是审批器里的缺陷,而不是要报告给模型的事。对修改后的调用,工具事件记录实际运行的参数,模型输出和审批事件保留模型提出的调用。
下面是一个更复杂的自定义审批器,为 bash 命令实现允许列表。设想这个审批器写在名为 evaltools 的 Python 包里。原文函数体在做出决定处用省略号,这里照样保留:
@approver
def bash_allowlist(
allowed_commands: list[str],
allow_sudo: bool = False,
command_specific_rules: dict[str, list[str]] | None = None,
) -> Approver:
"""Create an approver that checks if a bash command is in an allowed list."""
async def approve(
message: str,
call: ToolCall,
view: ToolCallView,
history: list[ChatMessage],
) -> Approval:
# Make approval decision
...
return approve假定已经按 Inspect 扩展正确注册了审批器,就可以在审批策略里使用它:
approvers:
- name: evaltools/bash_allowlist
tools: "bash"
allowed_commands: ["ls", "echo", "cat"]
- name: human
tools: "*"这些审批器对它们被配置来处理的每一次工具调用,会做出下面三种决定之一:
- 允许这次工具调用(依据各项已配置的选项)
- 不允许这次工具调用(因为在所有条件下它都被认为危险)
- 把这次工具调用升级给人工审批器。
人工审批器放在最后,并且绑定全部工具,所以来自 bash 和 python 允许列表审批器的升级,最终会提示人工审批器。
在 Python 包里发布审批器的更多细节,见审批器扩展。
工具视图
默认情况下,一次工具调用拿来给人批准时,会打印工具函数和它的参数。对有些调用这够用,但有些工具可以从增强的呈现里受益。例如:
- 网页浏览器工具的交互功能(点击、打字、提交表单等)引用一个
element_id,但这个 ID 本身的上下文不够用来批准或拒绝这次调用。作为补偿,网页浏览器工具提供一些额外上下文(正在交互的element_id周围的一段页面)。
示例
可以这样为 bash 工具实现一个自定义代码块查看器。原文在文档字符串后以省略号结束:
from inspect_ai.tool import (
Tool, ToolCall, ToolCallContent, ToolCallView, ToolCallViewer, tool
)
# custom viewer for bash code blocks
def bash_viewer() -> ToolCallViewer:
def viewer(tool_call: ToolCall) -> ToolCallView:
code = tool_call.arguments.get("cmd", tool_call.function).strip()
call = ToolCallContent(
format="markdown",
content="**bash**\n\n```bash\n" + code + "\n```\n",
)
return ToolCallView(call=call)
return viewer
@tool(viewer=bash_viewer())
def bash(timeout: int | None = None) -> Tool:
"""Bash shell command execution tool.
...ToolCallViewer 收到 ToolCall,返回 ToolCallView。后者提供 context(帮助理解这次调用的额外信息)和 call(这次调用的另一种渲染)中的一个或两个。对 bash 工具,这里给出要执行的 bash 代码的 markdown 代码块渲染。
context 通常用于有状态的工具,它们需要呈现当前状态里的一些上下文。例如,网页浏览工具提供当前已加载页面的一个片段。
出处:UK AI Security Institute,Tool Approval,文档页无单独发布日期(检索于 2026-11-02),https://inspect.aisi.org.uk/approval.html ,MIT License(Copyright (c) 2024 UK AI Security Institute)。
Found it useful? Pass it on
Scan with WeChat to open it on your phone and forward it.