人工审批与幂等执行:让 Agent 安全创建工单 @ Lin | 2026-05-27T10:00:00+08:00 | 3 分钟阅读 | 更新于 2026-09-12T10:00:00+08:00

把审批绑定到具体命令,用业务幂等和结果对账处理超时后的不确定执行状态。

本文于 2026-09-12 补充整理,按 2026-05 专题归档。示例为方案设计,参数用于说明方法,不代表已上线项目或实测成果。

审批需要绑定一件确定的事

员工说“可以”,可能指同意摘要,也可能指同意创建工单。要避免歧义,系统先生成提案:项目、环境、标题、正文和影响范围都明确展示,然后把确认绑定到这个具体版本。

提案应由服务端保存,至少包含 proposalIdtaskId、参数摘要、工具版本、有效期和提案哈希。审批记录关联该提案。修改任何影响业务结果的字段,都应让旧审批失效。

审批与幂等解决不同问题

审批回答“允许不允许做”;幂等回答“重复请求会不会重复做”。用户确认了创建工单,仍可能因为网络重试创建两张。因此两个机制必须同时存在。

PREPARED → WAITING_APPROVAL → APPROVED → EXECUTING
                                          ├─ SUCCEEDED
                                          ├─ FAILED
                                          └─ OUTCOME_UNKNOWN

OUTCOME_UNKNOWN 表示下游可能已执行,只是当前没有拿到结果。这不是普通失败,不应直接重发写请求。

幂等键如何生成

幂等键应绑定一次逻辑业务操作,例如由服务端为提案生成稳定操作 ID,并加入租户和操作类型作为唯一范围。同一提案重试沿用原键;用户明确发起新的工单,即使正文相同,也应使用新键。

只对参数做哈希会把两次合法的相同操作合并;每次网络重试生成新 UUID 又会失去去重作用。参数哈希适合验证“同一键是否对应同一内容”,不适合独自定义业务身份。

建议建立操作账本:

unique(tenant_id, operation_id)
proposal_hash
status
downstream_request_id
downstream_resource_id
attempt_count
updated_at

相同键携带不同参数时返回冲突,而不是覆盖旧操作。

超时后先查结果

如果工单 API 支持幂等键和按键查询,执行器可以用同一键安全重试或核实结果。若不支持,则优先通过下游请求编号查询;不能可靠关联时,进入人工核对,明确保留不确定状态。

在本地表插入“处理中”并不能保证外部系统恰好执行一次。进程可能在下游成功之后、本地记账之前崩溃。只有本地数据库的锁无法填补这个跨系统窗口。

事务 Outbox 模式有助于可靠传递执行事件,但消费者仍需处理重复。它也不会自动使一个外部写接口获得幂等能力。

审批执行时还要重新检查

等待期间,用户可能失去项目权限,提案可能过期,工具契约可能升级。执行器应核对当前身份权限、审批状态和提案哈希,在原子状态转换中抢占执行资格。

审批撤销与执行开始可能竞争。系统需要定义线性化边界:执行器成功将状态从 APPROVED 转到 EXECUTING 后,撤销不再承诺阻止已开始的外部动作,而是展示当前状态并按业务规则补偿。

故障注入比正常路径更有价值

让测试工单服务成功创建后故意丢弃响应,再让工作进程重启。验收要求:账本保留操作 ID;系统先对账;最终只出现一张工单,或者明确停在待核对状态。

同时测试重复点击确认、同一键不同参数、审批后修改正文和审批过期。能够解释这些边界,才说明写操作已经从聊天演示进入业务系统设计。


查看系列导读与阅读路线

© 2019 - 2026 Lin 的博客

Powered by Hugo with theme Dream.

avatar
关于我

Lin 的 ❤️ 博客

技术专题:Java Agent 工程化:从知识库问答到可靠业务执行。围绕 RAG、工具治理、任务恢复与 Java 平台架构整理设计思路和验证方法。

记录一些 🌈 生活上,技术上的事

  • 🛠️ 技术阵地: 深耕 Java 开发 ,目前向 AI 应用领域探索与拓展。这里主要记录我从后端架构到 AI 赋能的进阶之路、技术思考以及日常的 debug 血泪史。始终致力于写出优雅且没有 bug 的代码(尽量)。
  • 🌈 生活侧写: 偶尔脱下极客的外衣,我也会在这里分享生活中的灵光一现。不管是好用的效率工具,还是周末的一场骑行,都是构成我真实生活的一部分。