
"人在回路"最容易被实现成一件事:在高危操作前面弹一个确认框。
这种做法在低风险场景里够用,但一旦真的出事,你会发现它什么都没解决——确认框弹出来的时候人不在,操作超时了怎么办?人点了"同意"但看到的是三分钟前的快照,怎么办?审批超时之后任务是继续还是回滚?
HITL 本质上是任务状态机里的一条分支,不是界面上的一个弹窗。它要回答的是四个工程问题:什么时候停、停下来之后存什么、谁来恢复、等不到人怎么办。
同步确认:任务挂起等答复,答复后立刻继续。适用:秒级可决策、操作者就是审批人。
异步审批:任务挂起、落库、通知审批人,审批后从断点续跑。适用:审批人是另一个人、可能几小时后才看到。
事后复核:操作先执行,标记为"待复核",复核不通过再走补偿。适用:不可阻断的低延迟链路。
三种的代价完全不同:同步确认影响吞吐,异步审批要处理状态持久化,事后复核要依赖补偿能力。先按影响面选形态,再谈实现。
一是阻塞连接。 把"等人点按钮"实现成一个挂起的 HTTP 请求,是最常见的错误。用户去开会了,连接就挂在那里,网关超时、任务被重试——而重试意味着这个待确认的操作被提交了第二次。
二是超时后的默认行为说不清。 超时了是拒绝还是放行?很多实现里这个分支根本没写,结果是异常抛出去,任务失败——但失败的动作可能已经部分执行。
三是审批人看到的不是当时的现场。 审批界面渲染时重新去查了一遍数据,而这几分钟里数据已经变了。人批的是 A,系统执行的是 B。
三者的共同修法是同一件事:把确认做成一个持久化的"待决策"状态,而不是一个阻塞调用。
异步的骨架是这样:
第 1 步和第 4 步各有一个容易错的点。
快照必须是完整的、不可变的。 审批人点"同意"时,系统执行的必须是快照里那份数据。如果恢复时重新读库,你审批的和执行的就可能不是同一件事。这也是审计的基本要求:半年后追查,你要能还原"当时他看到了什么才批的"。
恢复时必须校验前置条件是否还成立。 三小时过去了,订单可能已经被取消、库存可能已经没了。所以续跑的第一步不是执行,而是重新检查前置条件——不成立就走"审批作废"分支,而不是硬着头皮执行。
这里和状态持久化是同一套机制:待审批本质上是一种特殊的不确定态,恢复时靠校验和回查,而不是无脑重放。
审批超时之后走哪条路,是所有 HITL 设计里唯一不能拍脑袋的地方。
只有两个选项,而且必须显式选一个:
选择依据不是偏好,是两种错误的代价对比:默认拒绝的代价是业务卡住,默认放行的代价是错误执行。哪个更贵,选另一个。
真正要避免的是第三种状态:超时后没人知道发生了什么。任务悬在那里,既没执行也没终止,几天后靠人发现。这比选错方向更糟。
这是最容易被技术上忽略、但直接决定闸门是否有效的一环。
审批界面上只放一句"确认执行删除操作吗?",结果是审批人一律点同意——因为他没有判断依据。闸门就此退化成一个仪式。
最小上下文包应该包含三样:
这三样齐了,审批人才可能真的拒绝一次。而"真的拒绝过"是闸门有效的唯一证据——如果上线三个月没有人拒过任何一次,那不是系统安全,是闸门失效了。
不建议把所有高危操作都做成人工审批。
审批是有成本的,而成本会转化为疲劳。当一个人每天要批 50 次,他会开始无条件点同意——这时闸门的效果比他根本不看还差,因为它给了系统一个"已被人审核"的假象。
我倾向于按影响面分档,只有最高一档走人工,中间档用"可撤销 + 事后抽检",低档全自动。宁可只守住 5% 的操作但每次都是真审,不要 100% 都过一遍手却全是走过场。
人在回路的价值不在于"加了一道人工确认",而在于在自动化的链路上留出一个可以反悔的地方。要让这个地方真的有用,它得是可持久化的、能恢复的、审批人看得懂在批什么的,以及超时之后有人负责的。
四条缺一条,它就只是一个点过就算的按钮。
同系列:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。