审批通过后,执行前还要校验上下文
文章用 Python 示例将审批绑定到动作与上下文的哈希快照,执行前重新计算指纹。若订单状态或消息等信息变化,就退回复审;执行时另传入幂等键以控制重复操作。
AI 深度解读
下午 4 点,审核员批准了 AI 起草的退款;4:05,系统准备执行,但客户刚刚发来「不用了,找到了」。审批没有出错,执行却可能已经不合时宜。问题出在:批准时的条件变了,系统还在沿用旧决定。
作者给出的办法很直接:审批绑定具体快照,执行前重新检查,条件变化就退回审核。这套做法适合需要人工确认的 AI 工作流,但它解决的是审批过期,完整的执行安全还需要更多保障。
审核员批准的,应该是哪个版本
「同意给客户 X 退款」太宽泛。客户消息、订单状态、退款金额发生变化,都可能让原来的批准失去依据。
作者建议把动作和关键上下文一起生成指纹(fingerprint),也就是用一串摘要标识这次审批对应的内容:
import hashlib, json
def fingerprint(action, context):
payload = {"action": action, "last_msg_id": context["last_msg_id"],
"order_status": context["order_status"], "amount": action.get("amount")}
return hashlib.sha256(json.dumps(payload, sort_keys=True).encode()).hexdigest()
def request_approval(store, action, context):
fp = fingerprint(action, context)
store.save(action_id=action["id"], fingerprint=fp, status="pending")
return fp
重点看 payload:它包含整个 action、last_msg_id、order_status 和 amount;sort_keys=True 则让字典键顺序不影响序列化结果。这里的 SHA-256 用于比较内容是否变化,不能证明业务判断正确。
审批绑定的应该是动作及其决策条件,而不只是一个动作 ID。
字段选择决定这套机制是否好用。漏掉关键条件,变化后仍会放行;塞入每个时间戳,又会让无关更新频繁触发复审。作者的原则是:只纳入会改变决定的信息。不过,示例直接放入整个 action,实际接入时还需要检查里面是否混有无关字段。
执行前再查一次,重试也要防重复
保存指纹只是第一步。真正执行时,系统还要读取最新上下文,与审批时的指纹比较:
def execute_if_still_valid(store, action, load_context, run):
record = store.get(action["id"])
if record.status != "approved":
return "not_approved"
if fingerprint(action, load_context(action)) != record.fingerprint:
store.update(action["id"], status="needs_review")
return "stale_back_to_reviewer"
run(action, idempotency_key=action["id"])
store.update(action["id"], status="done")
return "done"
要看的是 load_context(action) 这一行:校验需要重新加载上下文。拿审批时缓存的数据再算一次,发现不了后来的变化。
状态不是 approved 就停止;指纹不同,就改为 needs_review,返回 stale_back_to_reviewer;校验通过才执行,成功后标记 done。
这里还有另一道保障:idempotency_key=action["id"]。它用于避免重试造成重复退款,但前提是执行端确实支持并落实幂等处理,传入参数本身不会自动获得这种能力。
退回复审时,作者还建议明确解释原因,例如「客户在批准后发送了新消息」。指纹只能告诉系统内容变了,要告诉审核员具体变在哪里,还得保存旧值、版本或变更记录;示例没有实现这一部分。
我的判断
作者抓住了人工审批里一个容易被忽略的问题:人确认的是当时的信息,系统执行时却可能已经进入另一个业务状态。相比只检查 approved,增加执行前校验有明确价值。
但原文没有给出实测数据、吞吐量或方案对照,不能据此判断复审会增加多少,也不能认定摘要方案优于数据库版本号。若关键状态已经有可靠的版本字段,直接比较版本也可以;跨多个来源拼上下文时,指纹更便于统一比较。
示例还有一个边界:检查通过到 run 执行之间,状态仍可能变化。 对退款这类有实际后果的操作,还需要结合执行端的条件校验、事务或其他并发控制缩小这个窗口。
另外,从 pending 变成 approved 的过程没有展示。审核页面是否显示对应快照、批准时是否核对版本,原文都没说清。这段代码适合作为流程骨架,不能直接当作完整退款系统。
能拿来做什么
- 给现有 AI 审批流程列一份「哪些变化会推翻批准」的字段清单,再据此选择指纹字段,避免直接对整个业务对象求摘要。
- 在前端审核页面展示本次审批对应的动作和关键条件,并在退回复审时显示具体变化,让审核员知道为什么需要再次确认。
- 在 Node 等后端的实际执行入口重新加载上下文,同时让执行端按稳定的动作 ID 落实幂等处理,覆盖超时重试和重复提交。
- 验证流程时,至少检查批准后收到新消息、金额变化、订单状态变化和执行后重试这些情况,分别确认复审与防重复机制有效。