智能体面试准备(六十三):智能体人在回路(HITL)与审批流工程——中断、审批、回滚与可审计闭环
智能体面试准备(六十三):智能体人在回路(HITL)与审批流工程——中断、审批、回滚与可审计闭环
引言
前面(六十二)讲了工具沙箱与执行安全,把"智能体能做什么"关进了笼子;前面(五十五)讲了工程化交付。但生产里还有一类更现实的问题:有些动作不能让智能体自己拍板——发邮件、改数据库、批准报销、调用付费 API、对外发布。这些必须有人确认。这就是人在回路(Human-in-the-loop, HITL)。
HITL 不是"加个弹窗"那么简单。它要的是:在正确的节点停下来等人、把上下文讲清楚让人能决策、人决策后能从断点续跑、人拒绝后能安全回滚、全程可追溯可审计。本文讲一套工程上能落地的审批流设计,含状态机、断点续跑、回滚、审计。结尾给速答。
一、为什么 HITL 是生产智能体的刚需
不需要 HITL 的: 需要 HITL 的:
只读查询(搜文档) 写操作(发邮件/改库)
低风险生成(草稿) 对外发布/付费调用
可回滚的试探 不可逆动作(转账/删除)
内部分析 涉及隐私/合规/他人
核心判据:动作是否不可逆、是否涉及他人、是否花钱、是否合规敏感。任一命中就进审批。这和(六十二)沙箱的"默认拒绝 + 白名单"是互补的:沙箱管"能不能执行",审批流管"要不要先问人"。
二、审批流的状态机
把一次需要审批的工具调用建模成状态机,是工程上最清晰的做法:
工具调用审批状态机
plan
|
v
[pending] -- 自动白名单 --> [executed] --ok--> done
| |
需审批 被拒/失败
| |
v v
[awaiting_human] [rolled_back] -> done
|
人批准 -> [executed]
人拒绝 -> [rolled_back]
人改参 -> [pending](新参数)
要点:
- pending 是计划态,尚未产生副作用。
- awaiting_human 是阻塞态,智能体线程挂起,不能继续往下走(否则会出现"人还没批,它已经发了下一封邮件"的事故)。
- 任何"已产生副作用"的状态都要能对应一个 rollback 动作。
三、中断与续跑:把执行拆成可恢复步骤
智能体不能一次性跑完再问人。要把流程拆成"步骤 + 检查点",在检查点阻塞。工程上用一个持久化的执行上下文(checkpoint)保存:当前到第几步、每步输入、已产生副作用列表。
执行上下文(检查点)结构
{
run_id, step_index,
plan: [step0, step1(需审批), step2],
side_effects: [ {step:0, kind:"db_update", undo:"UPDATE ... SET old"} ],
status: "awaiting_human",
human_decision: null
}
续跑:人批准后在 step_index 处 resume,加载上下文继续;不丢历史、不重算已过的步骤。这呼应(二十二)长时任务断点续跑——审批流是断点续跑的一个特例。
代码(阻塞式审批桩):
import json, time
def request_approval(ctx, step):
ctx["status"] = "awaiting_human"
ctx["pending_step"] = step
save(ctx) # 持久化, 等待人
# 真实系统: 发消息给审批人(IM/工单), 然后阻塞或返回
decision = block_until_human(ctx["run_id"])
ctx["human_decision"] = decision
if decision["action"] == "approve":
ctx["status"] = "executing"
return True
if decision["action"] == "reject":
rollback(ctx) # 回滚已产生副作用
ctx["status"] = "done"
return False
if decision["action"] == "modify":
step["args"] = decision["new_args"] # 人改参数后重跑该步
return True
四、回滚:副作用必须可撤销
不可逆动作(转账、删除)原则上不应进智能体自动链路;必须做也要"预扣 + 确认 + 限时"。对可回滚动作,每条副作用记 undo 脚本:
side_effect 记录
kind: db_update
do: UPDATE account SET balance=balance-100 WHERE id=1
undo: UPDATE account SET balance=balance+100 WHERE id=1
kind: email_send
do: send(to, body)
undo: 撤回(若服务商支持) 或 标记"待确认未发"
kind: file_write
do: write(path, content)
undo: write(path, backup) # 先备份原文件
拒绝或超时时按 side_effects 倒序执行 undo。关键:undo 本身可能失败,要有"补偿 + 告警 + 人工兜底",不能假设回滚一定成功。
五、审批人体验:让人能决策
人不会点"批准"如果看不懂要批什么。审批消息必须把决策所需信息给全:
【待审批】智能体想执行: 发送邮件
收件人: zhang@corp.com
主题: 关于 Q3 报销的确认
正文摘要: ...(前200字)
影响: 对外、不可逆程度=低、预估成本=0
[批准] [拒绝] [修改参数] [查看完整上下文]
信息密度原则:默认给"做了什么、影响谁、能否撤销、完整上下文链接"。否则人只能盲批,HITL 退化成形式。
六、可审计:留痕是合规底线
审计日志(每条审批)
run_id, step, actor(智能体/人), action,
decision_by, decision_at,
before_hash, after_hash,
side_effects, rollback_status
审计要防篡改(append-only + 哈希链),能回答"谁在什么时候批准了什么、产生了什么后果"。这在金融/医疗/政企场景是合规硬要求(呼应六十安全合规)。
七、降级与超时
- 审批人离线:设超时策略——超时拒绝(保守)或转交备用审批人(生产)。默认"超时拒绝 + 告警"。
- 高优路径:把不可逆/高成本动作默认设为"必须审批",低风险动作走白名单自动过,平衡效率与安全。
- 批量审批:同类低风险动作合并成一次审批("允许接下来 10 分钟发送最多 5 封同类邮件"),降低人负担。
八、和(五十八)多智能体编排的关系
在 DAG/状态机编排里,审批节点是一个特殊节点:它把"自动边"变成"人工边"。编排引擎要支持"human node"作为一等公民——可挂起、可恢复、可超时、可回滚。否则 HITL 只能塞在单智能体里,多智能体流程一碰到人工就断。
面试速答
问:HITL 和沙箱(六十二)什么关系?
答:沙箱管"能不能执行"(默认拒绝+白名单),审批流管"要不要先问人"(不可逆/花钱/合规敏感动作)。一个管权限,一个管决策。
问:审批流核心状态机?
答:pending → awaiting_human →(批准)executed /(拒绝)rolled_back /(改参)回到 pending。阻塞态不能继续往下跑。
问:回滚为什么不能假设一定成功?
答:undo 本身可能失败(如邮件已读无法撤回)。要补偿+告警+人工兜底,并留审计。
高频追问清单
- 哪些动作必须进审批?判据是什么?
- 智能体在 awaiting_human 时线程怎么处理?能继续别的任务吗?
- 断点续跑的上下文要持久化哪些字段?
- 不可逆动作(转账/删除)怎么在智能体链路里安全处理?
- 回滚失败怎么办?补偿事务怎么设计?
- 审批消息要包含哪些信息才不至于让人盲批?
- 审计日志为什么要用 append-only + 哈希链?
- 审批人离线/超时,策略怎么定?
- 批量审批怎么设计既安全又不烦人?
- 多智能体编排里 human node 如何作为一等公民支持挂起/恢复?
更多推荐

所有评论(0)