6025 字
约 20 分钟
4
HITL 不只是审批:构建安全、可控的 AI Agent 人机协作系统

HITL 不只是审批:构建安全、可控的 AI Agent 人机协作系统

随着 AI Agent 获得文件写入、命令执行、邮件发送、数据库操作和线上部署等能力,它已经不再只是一个“会聊天的模型”,而是开始真实地改变外部世界。

能力越强,错误的代价也越高。

用户可能只是让 Agent 清理临时文件,模型却错误理解成删除整个目录;用户要求整理邮件草稿,Agent 却直接把未确认的内容发送给客户。模型并没有恶意,但自然语言存在歧义,大模型也可能产生幻觉,工具参数还可能在多轮规划中逐渐偏离最初目标。

因此,生产级 Agent 不能只关注“能不能完成任务”,还需要回答另一个问题:

在什么情况下,Agent 必须停下来,把控制权交还给人类?

这就是 HITL 要解决的问题。

一、什么是 HITL?

HITL 全称是 Human-in-the-Loop,常见中文翻译包括“人在回路”“人工介入”和“人机协同”。

它的核心含义是:

在 AI 的决策或执行流程中保留明确的人类参与节点,让人类能够审核、批准、修改、纠正、接管或终止任务。

很多人把 HITL 直接理解成“审批弹窗”。这种说法不算错,但不够完整。工具执行前审批只是 HITL 最常见的一种形式。

一个完整的 HITL 系统通常覆盖:

  • 任务开始前确认目标;
  • 执行计划审核;
  • 危险操作审批;
  • 工具参数修改;
  • 模糊问题澄清;
  • 异常任务升级;
  • 执行过程暂停和接管;
  • 最终结果复核;
  • 操作记录与责任审计;
  • 人工反馈沉淀。

因此,审批属于 HITL,但 HITL 不只等于审批。

二、为什么 Agent 需要 HITL?

传统聊天机器人主要输出文本,即使回答错误,影响通常也停留在屏幕上。Agent 可以调用工具,错误可能直接变成外部动作。

常见风险包括:

风险类型 示例
不可逆操作 删除目录、覆盖文件、清空数据库
外部传播 发送邮件、发布公告、提交工单
权限与安全 修改访问控制、暴露密钥、开放端口
资金影响 下单、退款、转账、调整广告预算
生产环境影响 部署代码、重启服务、修改配置
理解偏差 操作了错误文件、项目、账号或收件人
多 Agent 扩散 一个错误计划被多个 Worker 并行执行

HITL 的目标不是证明 AI“不可信”,而是为高风险、不确定或不可逆操作增加一道确定性的控制边界。

可以把 Agent 的自动化程度理解为一条连续光谱:

完全人工
→ AI 提建议、人工执行
→ AI 生成动作、人工批准
→ AI 自动执行高置信任务、异常时升级
→ 高度自动化、人工负责监督和审计

不同业务应该选择不同位置,而不是一味追求“全自动”。

三、HITL 最常见的功能

1. 任务目标确认

在任务启动前,让用户确认 Agent 对目标的理解。

例如:

用户:清理项目中的旧文件。

Agent:我理解的范围是删除 build/ 和临时日志,
不修改 src/、配置文件和 Git 历史。是否继续?

这种确认适合目标模糊、范围较大或可能产生破坏性结果的任务。

2. 计划审核

Plan-and-Execute Agent 通常会先生成执行计划。HITL 可以在计划开始前暂停:

计划:
1. 扫描重复文件
2. 删除超过 30 天的缓存
3. 修改构建配置
4. 重新运行构建

请选择:
[批准计划] [修改步骤] [删除步骤] [取消]

相比每一个工具调用都弹窗,计划级审批可以降低打断频率。不过计划批准不能自动代表所有具体参数都安全,高风险动作仍可能需要二次审批。

3. 危险工具执行前审批

这是最典型的 HITL:

Agent 生成工具调用
→ 策略引擎计算风险
→ 命中审批规则
→ 暂停工具执行
→ 人类作出决定
→ 执行、修改、跳过或拒绝

例如以下操作通常需要审批:

  • 写入或覆盖重要文件;
  • 删除文件和目录;
  • 执行 Shell 命令;
  • 修改数据库;
  • 发送邮件或消息;
  • 创建、删除云资源;
  • 部署到生产环境;
  • 进行支付或退款。

4. 参数预览与修改

用户不一定要在“批准”和“拒绝”之间二选一,还可以修改 Agent 生成的参数。

例如:

Agent 原计划:
path = /tmp/config.json

用户修改为:
path = /project/config.json

系统使用修改后的参数执行。这种能力可以在不中断整个任务的情况下纠正局部错误。

5. 澄清问题

当关键信息缺失时,Agent 不应该猜测。

例如:

Agent:发现两个名为 production 的集群:
1. production-eu
2. production-us

请选择需要部署的目标。

澄清并不一定涉及危险操作,但它可以防止 Agent 因实体、范围或业务意图不明确而执行错误动作。

6. 异常升级

Agent 可能遇到权限不足、工具失败、结果冲突或置信度过低等情况。系统可以把任务升级给人类:

状态:等待人工处理
原因:连续三次部署失败
已尝试:重新构建、重新认证、回滚依赖
需要决策:是否回滚到上一版本

这类机制通常被称为 escalation,也就是“升级处理”。

7. 人工暂停、接管和恢复

对于长时间运行的 Agent,需要提供:

  • 暂停任务;
  • 终止任务;
  • 人工完成某一步;
  • 修改任务状态;
  • 从指定步骤恢复执行。

例如,客服 Agent 遇到复杂投诉时可以把对话转交人工客服;人工处理完成后,再把结果交回 Agent 继续完成记录和后续流程。

8. 最终结果复核

某些操作不适合在工具调用层逐一审批,更适合在最终发布前统一审核:

  • 邮件草稿生成后,发送前确认;
  • 合同分析完成后,由律师复核;
  • 代码修改完成后,合并前审查;
  • 报告生成后,发布前确认;
  • 营销内容生成后,品牌负责人审核。

这属于“输出闸门”:Agent 可以自由生成草稿,但不能绕过最终发布审批。

9. 审批授权范围管理

为了避免连续弹窗,系统通常支持多种授权范围:

授权方式 含义
单次批准 只批准当前操作
同类批准 当前会话放行同一工具
参数范围批准 只允许指定路径、项目或资源
时间范围批准 在有限时间内放行
计划范围批准 只批准当前计划中的已知步骤
永久规则 保存为后续策略,需要谨慎使用

“全部放行”不应该简单做成全局开关。批准 write_file 不代表批准 execute_command,批准写入 /tmp/project 也不代表允许覆盖任意系统文件。

10. 审计追踪

HITL 系统应记录完整的决策链:

  • 谁发起了操作;
  • 哪个 Agent、任务和步骤触发;
  • 原始参数是什么;
  • 风险等级和命中规则;
  • 谁进行了审批;
  • 审批结果和原因;
  • 参数是否被修改;
  • 最终是否执行成功;
  • 发生时间和关联任务。

审计日志既用于安全追溯,也可以帮助优化审批策略。

11. 人工反馈闭环

人工拒绝和修改不是一次性数据,它们可以帮助系统改进后续行为。

例如用户多次把:

/tmp/project

修改为:

/workspace/project

系统可以在获得用户明确同意后,把“项目默认创建在 /workspace”保存为长期偏好。需要注意:反馈学习不能绕过权限系统,也不能因为某次批准就永久放宽高风险策略。

四、HITL 的完整执行流程

一个较完整的工具审批流程如下:

用户目标
→ Agent 生成计划
→ 可选:计划审核
→ Agent 生成工具调用
→ 参数校验
→ 风险策略判断
→ 安全操作直接执行
→ 高风险操作创建审批请求
→ 人类批准、拒绝、修改或跳过
→ 工具执行或 Agent 重新规划
→ 记录审计日志
→ 可选:最终结果复核

这里最重要的原则是:

审批必须发生在实际副作用之前,并且所有危险工具都必须经过同一个不可绕过的拦截入口。

如果只在 Agent 主流程里调用审批,但子代理、计划执行器或其他工具入口仍能直接执行,就会留下绕过路径。

五、风险判断:静态规则还是 LLM?

风险判断通常有三种方式。

静态规则

private static final Set<String> APPROVAL_REQUIRED = Set.of(
    "write_file",
    "delete_file",
    "execute_command",
    "send_email",
    "deploy_production"
);

优点:

  • 确定、快速;
  • 容易测试和审计;
  • 不受模型随机性影响。

缺点:

  • 粒度较粗;
  • 同一工具的不同参数可能风险差异很大。

例如 execute_command("pwd")execute_command("rm -rf ...") 显然不应被视为相同风险。

参数化规则

在工具名称之外继续检查参数:

write_file + /tmp/**           → 低风险
write_file + 当前项目目录       → 中风险
write_file + 项目目录之外       → 高风险
execute_command + 只读命令      → 低风险
execute_command + 删除或提权命令 → 高风险

这种方式更适合生产环境。规则可以结合:

  • 工具名称;
  • 文件路径;
  • 命令类型;
  • 环境;
  • 数据敏感级别;
  • 资源价值;
  • 用户角色;
  • 操作是否可逆;
  • 影响范围。

LLM 辅助判断

LLM 可以用于解释风险、归纳参数和发现规则未覆盖的异常,但不宜作为唯一安全边界。

更稳妥的设计是:

硬规则负责阻断
+ 参数规则负责分级
+ LLM 负责补充风险说明
+ 人类负责最终高风险决策

安全控制应尽量确定、可重复和可审计。

六、审批请求应该展示什么?

一个有用的审批请求不能只问“是否允许”。用户需要足够的信息做判断。

public record ApprovalRequest(
    String requestId,
    String agentId,
    String taskId,
    String stepId,
    String toolName,
    String arguments,
    String riskLevel,
    String riskDescription,
    String expectedImpact,
    boolean reversible,
    Instant expiresAt
) {}

建议展示:

  • 谁要执行:主 Agent 还是某个子代理;
  • 为什么执行:对应哪个目标和步骤;
  • 要执行什么:工具名称和关键参数;
  • 会影响哪里:文件、账号、环境或收件人;
  • 风险有多高;
  • 是否可逆;
  • 如何回滚;
  • 审批何时失效。

示例:

需要人工审批

调用者:deploy-agent
任务:发布订单服务 2.3.0
环境:production-eu
操作:deploy_service
风险:高
影响:将替换 6 个生产实例
回滚:可回滚至 2.2.4

[批准一次] [修改参数] [拒绝] [取消任务]

如果审批框缺少调用者和业务上下文,用户即使看见参数,也可能无法判断操作是否合理。

七、审批结果如何设计?

常见决策包括:

public enum Decision {
    APPROVED,
    APPROVED_SCOPED,
    REJECTED,
    MODIFIED,
    SKIPPED,
    PAUSED,
    CANCELLED,
    ESCALATED
}

它们分别表示:

  • APPROVED:批准当前操作;
  • APPROVED_SCOPED:在指定范围内放行;
  • REJECTED:拒绝并允许 Agent 根据原因重新规划;
  • MODIFIED:修改参数后执行;
  • SKIPPED:跳过当前步骤;
  • PAUSED:暂停任务,等待后续处理;
  • CANCELLED:取消整个任务;
  • ESCALATED:转交具有更高权限或专业能力的人。

拒绝原因应该作为结构化结果返回 Agent:

{
  "decision": "REJECTED",
  "reason": "目标路径错误,只允许写入当前项目目录",
  "retryAllowed": true
}

这样 Agent 可以重新规划,而不是不断重复相同请求。

八、工具拦截层的设计

HITL 最适合放在统一的工具执行入口:

public final class HitlToolExecutor implements ToolExecutor {

    private final ToolExecutor delegate;
    private final ApprovalPolicy policy;
    private final HitlHandler hitlHandler;
    private final AuditLogger auditLogger;

    @Override
    public ToolResult execute(ToolCall call, ExecutionContext context) {
        RiskAssessment risk = policy.assess(call, context);

        if (!risk.requiresApproval()) {
            return delegate.execute(call, context);
        }

        ApprovalRequest request =
            ApprovalRequestFactory.create(call, context, risk);

        ApprovalResult decision =
            hitlHandler.requestApproval(request);

        auditLogger.record(request, decision);

        return switch (decision.decision()) {
            case APPROVED ->
                delegate.execute(call, context);
            case MODIFIED ->
                delegate.execute(call.withArguments(
                    decision.modifiedArguments()), context);
            case SKIPPED ->
                ToolResult.skipped("用户跳过了当前步骤");
            case REJECTED ->
                ToolResult.rejected(decision.reason());
            case CANCELLED ->
                ToolResult.cancelled("用户取消了任务");
            default ->
                ToolResult.waiting("等待进一步人工处理");
        };
    }
}

这种装饰器式拦截比把审批代码散落在 Agent、SubAgent 和 PlanExecutor 中更容易保证一致性。

核心要求是:

  • 所有真实工具调用都经过这一入口;
  • 参数修改后重新执行校验;
  • 审批通过不能绕过底层权限检查;
  • 超时、断线和异常默认不执行;
  • 审批令牌只能使用一次;
  • 审批内容与最终执行参数必须一致。

九、同步审批与异步审批

命令行工具通常使用同步审批:

弹出请求 → 等待输入 → 得到结果 → 继续执行

企业工作流更常使用异步审批:

创建审批任务
→ Agent 状态变为 WAITING_FOR_APPROVAL
→ 通知审批人
→ 审批人稍后处理
→ 系统验证审批结果
→ Agent 从检查点恢复

异步审批需要额外处理:

  • 任务持久化;
  • 审批超时;
  • 审批人身份验证;
  • 重复提交;
  • 请求过期;
  • 恢复时环境是否变化;
  • 执行前重新校验参数和资源状态。

例如,上午批准的部署任务如果晚上才恢复,生产版本可能已经变化,系统不能直接使用过时审批继续执行。

十、Multi-Agent 场景下的 HITL

多个 Worker 并发执行时,HITL 会更加复杂。

审批请求必须包含调用者

至少包含:

Agent ID
子任务 ID
计划步骤
父任务
工具和参数

否则用户无法区分哪个子代理正在操作什么。

避免多个审批框争抢输入

终端环境中,可以将审批请求放入队列并串行展示:

public synchronized ApprovalResult requestApproval(
        ApprovalRequest request) {
    return promptUser(request);
}

更成熟的系统可以提供统一审批中心,而不是让多个线程直接读取同一个标准输入。

审批范围不能无限扩散

某个子代理获准写入特定目录,不代表其他子代理自动获得相同权限。授权范围应该绑定:

  • Agent;
  • 任务;
  • 工具;
  • 参数范围;
  • 时间窗口。

拒绝后避免重复申请

如果用户已经拒绝相同操作,子代理不应无休止重新申请。主代理需要根据拒绝原因修改计划,或者终止对应分支。

十一、HITL 的 Fail-Safe 原则

安全系统应该采用“没有明确批准,就不执行”的默认策略。

以下情况通常都应视为拒绝或等待:

  • 用户输入无法识别;
  • 审批超时;
  • 网络中断;
  • 审批服务不可用;
  • 请求已经过期;
  • 参数在审批后发生变化;
  • 审批人权限不足;
  • 无法验证审批结果;
  • 任务状态与审批时不一致。

不要因为审批系统故障而自动放行危险操作。对高风险工具来说,“失败时关闭”比“失败时开放”更安全。

十二、常见设计误区

误区一:只按工具名判断风险

同一工具的不同参数风险可能完全不同,应进一步检查路径、环境和影响范围。

误区二:一次批准永久有效

审批应有明确的 Agent、任务、资源和时间作用域。

误区三:审批通过等于跳过权限

HITL 是额外安全层,不替代操作系统权限、沙箱、最小权限和访问控制。

误区四:让 LLM 决定自己是否需要审批

模型可以提供风险解释,但不应该拥有绕过硬规则的最终决定权。

误区五:只展示工具名

用户需要看到实际参数、业务目的、影响范围和回滚方案。

误区六:参数修改后直接执行

修改后的参数必须重新做 schema 校验、权限检查和风险评估。

误区七:所有操作都要求审批

审批过多会产生“确认疲劳”,用户最终可能无脑点击批准。系统应重点拦截真正高风险或不确定的操作。

误区八:只记录审批结果

还要记录原始请求、修改内容、审批原因和最终执行结果,才能形成完整审计链。

十三、如何减少审批疲劳?

HITL 不是弹窗越多越安全。过度审批会让用户失去警惕。

可以采用:

  • 只读操作默认放行;
  • 按风险等级设置不同策略;
  • 对低风险、可逆操作使用批量批准;
  • 对确定路径设置范围授权;
  • 对同一计划合并相似审批;
  • 清晰展示参数差异;
  • 高风险审批使用更强确认方式;
  • 根据历史拒绝数据优化规则;
  • 使用沙箱降低操作风险,从而减少审批。

例如:

读取项目文件           → 自动执行
在临时目录创建文件      → 自动执行并记录
覆盖项目配置           → 请求确认
删除目录               → 请求确认并二次提示
修改生产数据库          → 指定角色审批
大额支付               → 双人审批

风险越高,审批强度越高。

十四、如何测试 HITL?

HITL 测试至少应该覆盖:

策略测试

  • 安全工具是否绕过审批;
  • 危险工具是否一定被拦截;
  • 参数变化是否影响风险等级;
  • 不同环境和用户角色是否正确处理。

决策测试

  • 批准后是否执行原参数;
  • 修改后是否执行新参数;
  • 拒绝后是否停止;
  • 跳过后是否进入下一步;
  • 取消后是否终止整个任务。

Fail-Safe 测试

  • 输入无效;
  • 审批超时;
  • 审批处理器抛出异常;
  • 请求过期;
  • 执行前参数被篡改;
  • 审批服务不可用。

并发测试

  • 多个子代理同时触发审批;
  • 审批请求是否串行或正确排队;
  • 同类授权缓存是否线程安全;
  • 一个任务取消后,其他等待请求是否失效。

审计测试

  • 原始参数和最终参数是否都被记录;
  • 审批人、时间和原因是否完整;
  • 工具执行结果是否能关联回审批请求。

接口隔离可以让测试不依赖真实终端:

HitlHandler handler = mock(HitlHandler.class);

when(handler.requestApproval(any()))
    .thenReturn(ApprovalResult.approved());

verify(handler, times(1))
    .requestApproval(any());

Mock 在这里相当于审批处理器的“测试替身”,可以精确模拟批准、拒绝、超时和异常。

十五、生产级 HITL 的推荐架构

一套更完整的 HITL 系统通常包含:

组件 职责
Policy Engine 根据工具、参数、环境和身份评估风险
Tool Interceptor 在副作用发生前统一拦截
Approval Service 创建、持久化和处理审批请求
Identity & RBAC 验证审批人身份和权限
Task Checkpoint 保存暂停时的 Agent 状态
Notification 通知对应审批人
Audit Log 记录请求、决策和执行结果
Resume Engine 审批后安全恢复任务
Feedback Store 保存人工纠正和改进信号

HITL 也必须和其他安全机制配合:

最小权限
+ 沙箱隔离
+ 参数校验
+ 风险策略
+ 人工审批
+ 审计日志
+ 回滚能力

人工审批不是万能安全措施。如果底层工具拥有无限权限,即使用户偶尔批准错误,也可能造成严重影响。最可靠的系统应该首先限制 Agent“最多能做什么”,再决定“哪些动作需要人批准”。

十六、衡量 HITL 是否有效

可以关注以下指标:

  • 审批请求数量;
  • 批准率和拒绝率;
  • 参数修改率;
  • 平均等待时间;
  • 审批超时率;
  • 重复申请率;
  • 人工接管率;
  • 因审批避免的错误操作数;
  • 用户无脑批准比例;
  • 不同策略规则的命中分布。

如果某类请求几乎永远被批准,可能应该缩小审批范围;如果某类请求经常被拒绝,说明 Agent 规划、默认参数或权限设计需要改进。

总结

HITL 的本质不是在 Agent 旁边加一个“确认按钮”,而是建立一套人类可以随时影响 AI 决策和执行的人机协作机制。

它常见的能力包括:

目标确认
+ 计划审核
+ 危险操作审批
+ 参数修改
+ 澄清提问
+ 异常升级
+ 暂停与接管
+ 最终结果复核
+ 授权范围管理
+ 审计与反馈

在一个可靠的 Agent 系统中,低风险、可逆且确定的操作可以自动完成;高风险、不可逆或存在歧义的操作必须把控制权交还给人类。

真正优秀的 HITL,不是让用户为 Agent 的每一步机械地点“批准”,而是在最需要人类判断的时刻暂停,提供足够信息,让人能够做出清晰、可追踪、可撤销的决定。

HITL 不只是审批:构建安全、可控的 AI Agent 人机协作系统
http://clxhxhhr.top/posts/462/
作者
clxstart
发布于
2026-09-04
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。