跳转到内容

Agent 人工干预安全网关

Agent 人工干预安全网关

1. 问题定义

在 Agent 工具调用场景中,某些操作具有不可逆性或高风险(如删除文件、发送消息、执行系统命令)。如果让 Agent 自主执行所有工具调用,可能导致安全事故。人工干预安全网关的目标是:在工具执行前,根据策略决定是直接执行、跳过还是暂停等待用户审批。

2. 核心架构:7 阶段干预检查流水线

干预检查不是简单的”允许/拒绝”二元判断,而是一个多阶段的纵深防御体系。每个阶段按优先级依次检查,一旦某个阶段做出决定,后续阶段不再执行。

Phase 1:全局 Resolver(安全黑名单)

全局 Resolver 对所有工具调用统一检查,最典型的是安全黑名单——匹配已知危险的命令模式(如 rm -rfDROP TABLE)。

// 伪代码:安全黑名单 Resolver
const DEFAULT_SECURITY_BLACKLIST = [
{ command: /^rm\s+(-rf?|--?\S*)?\s/i, policy: "always" },
{ command: /^mkfs\./, policy: "always" },
{ command: /^curl.*\|\s*(sh|bash)/, policy: "overridable" },
];

全局 Resolver 的 policy 分为两种:

  • always:无条件阻止,即使在 headless 模式下也跳过该工具
  • overridable:可覆盖的阻止,允许用户在知晓风险后手动批准

为什么需要全局 Resolver? 因为某些危险操作无论用户配置如何都不应自动执行。

Phase 2:Headless 模式

Headless 模式用于异步自动化任务(如定时 cron 任务),此时无人在场审批。策略是:

  • always 阻止的工具:直接跳过
  • 其他工具:全部直接执行

陷阱:headless 模式下跳过的工具不会通知用户,可能导致任务部分完成但用户不知情。应在任务完成报告中记录跳过的工具。

Phase 3:动态策略 Resolver

动态 Resolver 允许根据工具参数实时判断是否需要干预。例如:

// 伪代码:动态 Resolver
{
dynamic: {
type: "file-write",
default: "never", // 默认不需要干预
policy: "always", // 匹配时总是需要干预
resolver: (args, metadata) =>
args.path.includes("/etc/") || args.path.includes(".env")
}
}

动态 Resolver 的优势是上下文敏感——写普通文件不需要审批,但写入系统配置文件则需要。

设计权衡:动态 Resolver 的复杂度随规则数量增长,建议限制 Resolver 数量(如 5 个以内),并在配置文件中文档化每个 Resolver 的触发条件。

Phase 4:Always 策略匹配

工具自身的 manifest 可以声明 humanIntervention: "always" 或匹配规则。这些规则覆盖 auto-run 模式——即使用户选择了全自动模式,always 标记的工具仍需审批。

典型场景:发送外部消息(邮件、IM)、修改账户配置等不可逆操作。

Phase 5-7:用户配置模式

模式行为适用场景
auto-run所有工具直接执行高信任环境、低风险工具
allow-list仅白名单中的工具直接执行受控环境,明确知道哪些工具安全
manual(默认)使用工具自身的 manifest 配置通用场景,信任工具作者的判断

未知工具守卫(Phase 5.5)

当工具不在 toolManifestMap 中时,manual/allow-list 模式下要求干预。这是防止未知工具被静默执行的安全兜底。

陷阱:在 auto-run 模式下不启用此守卫,因为选择 auto-run 的用户已经接受了未知工具的执行风险。

3. Turn-scoped 范围守卫

一个关键的安全陷阱是 stale pending tool messages。当用户发起工具审批但从未点击”批准/拒绝”时,这些 pending 状态的 tool message 会被加载回 state.messages。如果不做作用域限制,它们会在后续每个 tool_result 阶段劫持循环,导致 Agent 永远卡在 waiting_for_human 状态。

解决方案是 turn-scoped 范围限制:只检查与当前 assistant turn(最近的发出工具调用的 assistant 消息)相关的 pending tool messages。

// 伪代码:turn-scoped 范围守卫
private getCurrentTurnPendingToolMessages(state) {
// 找到最近发出工具调用的 assistant 消息 ID
let currentAssistantId = findLatestAssistantWithToolCalls(state.messages);
// 只返回 parentId 匹配该 ID 的 pending tool messages
return state.messages.filter(
m => m.role === "tool"
&& m.pluginIntervention?.status === "pending"
&& m.parentId === currentAssistantId
);
}

4. 三种审批交互模式

模式说明Agent 指令类型
Approve用户批准或拒绝单个工具调用request_human_approve
Prompt用户输入文本反馈request_human_prompt
Select用户从多个选项中选择request_human_select

5. 安全纵深总结

6. 参考来源

  • OWASP Top 10 for LLM Applications — LLM-05: Supply Chain Vulnerabilities
  • LobeHub GeneralChatAgent.checkInterventionNeeded — 7 阶段干预检查的完整实现
  • LobeHub InterventionChecker.shouldIntervene — 静态策略判断逻辑