LangGraph 修复人工审批答复错配隐患
LangGraph 1.2.20 为任务中的每次中断分配独立 ID,并新增拒绝过期答复的严格恢复模式。这些改动针对运行重试、重新规划后,旧审批答复可能按位置匹配到新问题的正确性风险。
AI 深度解读
人点了「同意」,Agent 却把这份同意用在了另一个问题上。原文讨论的是人工审批里一种隐蔽的错配:任务重试后,等待确认的操作变了,旧答案却仍被接收,系统还显示执行成功。
作者从 LangGraph 两个版本的发布说明出发,提出一个判断:审批必须绑定具体问题,恢复执行时必须拒绝错配的答案。这对正在给 Agent 接入人工确认的程序员很实用,但文中的故障案例是推演,并非复现报告。
为什么同一个「同意」会批准另一笔付款
LangGraph 用 interrupt() 暂停任务,等待人工回答。回答可能四分钟后到,也可能四十分钟后到,甚至拖到第二天早晨。在这段时间里,任务可能因为工具错误、重启或重新规划,再次走到暂停节点。
作者举了一个付款例子:Agent 最初询问,是否向供应商 A 支付 ₹4,00,000。用户看过后批准,但任务已经重试,新路径上的第一个审批问题变成了向供应商 B 付款。
如果恢复逻辑只认顺序,把第一个答案交给第一个暂停点,旧的「同意」就可能批准 B 的付款。系统没有抛错,审计记录甚至还能写着「用户已批准」。
审批顺序相同,不代表审批对象相同。
据原文转述,2026 年 11 月 5 日发布的 langgraph 1.2.20 包含两项变更:为一个任务里的每个 interrupt() 分配独立 id,以及增加拒绝过期中断答案的 strict resume 模式。
作者把两者看作配套机制:id 用来识别问题,严格恢复负责在答案与当前问题对不上时阻止继续执行。仅仅发现错配还不够;如果随后按位置回退,或者自行挑一个看似接近的问题,风险仍然存在。
审批记录为什么不能只有一个布尔值
一个 approved: true 只能证明有人表达过同意,无法证明他同意了什么。作者给出的记录设计,把问题、答案和身份放在一起:
approval_id appr_01J...
interrupt_id intr_7f3a... <- the question's identity
run_id run_55c1...
asked {"tool": "pay_vendor",
"vendor_id": "V-2291",
"invoice": "INV-88412",
"amount_paise": 40000000}
asked_sha256 9f2c...e4a1
decision approved
decided_by <user id>
decided_at 2026-11-10T11:49:08+05:30
要留意 interrupt_id 和 asked_sha256:前者标识问题,后者用于核对问题内容是否变化。恢复时,作者建议先匹配 id,再重新计算 asked 的哈希;任一不符就停止,让人重新检查。
这里保存的是「当时问了什么」。六个月后追查付款,才能核对供应商、发票和金额,而不是只找到一个孤立的批准结果。示例里的 amount_paise: 40000000 对应 ₹4,00,000,金额只是说明用途。
不过,原文没有交代 JSON 如何规范化后再计算哈希。对象序列化方式不同,可能影响校验结果,实际落地需要补齐这一约定。这份记录也是作者自己的设计,并非 LangGraph 规定的格式。
暂停状态同样需要被正确表达。据原文转述,2026 年 10 月 30 日的 langgraph 1.2.19 修复了 tools stream 把暂停中的工具报告为失败的问题。
等待人工处理应当与运行、失败区分。否则,上层系统可能把正常等待当成故障,触发重试、升级处理或回滚,而用户还在看审批内容。
我的判断
作者抓住的问题很准确:人工确认只能约束用户实际看过的操作。只按答案顺序恢复,无法证明这个约束成立;绑定问题身份与内容,比单独保存布尔值更适合追责和排查。
但这篇文章的证据边界也很明确。作者没有复现两种故障,没有报告维护者声明的修复动机,也没有给出对照数据。付款故事是风险推演,审批记录是个人实践,不能据此宣称旧版一定会发生误付款。
还有一个实现细节不能跳过:原文把 id 描述为能跨重试识别问题,但没有给出严格恢复的配置 API,也没有解释不同重启、重新规划路径下的身份规则。独立 id、跨重试匹配和内容校验分别能保证什么,单靠这篇文章还无法确认。
作者主张错配后停止并请人重看,我赞同它适合付款这类需要明确授权的操作。至于默认拒绝,它可能保护了资金安全,却没有解决审批错配及后续处置问题。团队仍需明确:任务停在哪里,用户如何看到原因,又如何重新审批。
能拿来做什么
- 给 Agent 做审批页面时,同时展示并保存用户实际确认的工具参数,让恢复执行能核对操作对象,而不只传回一个「同意」。
- 在 Node 服务的审批恢复入口,检查问题 id 和内容是否匹配;发现旧答案就停止执行,并把重新确认的原因返回界面。
- 把「等待人工」设为独立状态,检查任务调度器是否会对它自动重试,避免用户思考期间任务已经换了执行路径。
- 验证审批流程时,专门覆盖「发起审批后重试,待批对象发生变化」的场景,检查旧答案是否会被拒绝,以及记录能否还原当时的问题。