摘要:当资金操作类 Agent 接入企业审批体系后,一个高频故障是“审批人点了批准,界面显示已通过,但后续付款、记账或调拨任务停在原地”。多数排障把它归因于消息队列丢包或回调超时,本文认为真正的根因在建模层:把“人做出决策”“决策被持久化”“任务被续办”“业务被真实执行”四种语义压缩进一个
status字段,导致状态机不可判定、幂等边界模糊、补偿无从下手。文章以事件溯源与状态分层为主线,给出四层状态解耦的建模方法、幂等续办协议、对账补偿路径与可观测性指标,并结合国内外审批工作流、Saga 补偿、Agent 工具调用可靠性等研究,讨论该架构的边界条件与工程落地步骤。
目录
一、导语:一个“已批准但卡住”的现场
先还原一个在资金操作类 Agent 落地中反复出现的现场。财务共享中心把“供应商付款申请”交给一个具备工具调用能力的 Agent:Agent 读取发票与合同、比对预算余额、生成付款指令草稿,然后调用审批服务创建审批单。审批人在移动端看到卡片,点击“批准”。前端提示“审批已通过”,审批单状态变为 APPROVED。但十分钟后,付款任务没有出现在执行队列里,银行通道没有收到指令,总账没有生成凭证。运维查看日志,发现审批服务确实发出了“通过”事件,但下游的“任务续办”消费者因为一次数据库连接抖动重试失败,消息进入死信队列;而审批单状态已经是 APPROVED,重放消费者时又被“状态已是终态”的守卫逻辑直接丢弃。于是系统进入一种尴尬的稳定态:人认为已经批准,机器认为流程已结束,业务事实却从未发生。
这类故障在表面上千差万别——有的是回调超时,有的是幂等键冲突,有的是 Agent 会话中断后无法恢复上下文——但它们的共同结构是:一个状态字段同时承担了四种互不等价的语义。审批人“做出决策”是一个人类行为事实;决策“被持久化”是一个存储事实;任务“被续办”是一个调度事实;资金“被真实执行”是一个业务事实。四者可以独立成功或失败,却被折叠进同一个枚举值。本文的主线即由此展开:审批流形同虚设,不是因为按钮不好用,而是因为状态模型不具备区分“谁承诺了什么、承诺是否兑现”的表达能力。
需要说明的是,本文讨论的“Agent”指具备自主规划与工具调用能力、但资金类动作必须经人工审批授权的软件实体;讨论的“审批流”指企业内部控制中围绕授权、复核、职责分离建立的工作流。二者结合后的可靠性问题,既有传统工作流引擎的经典难题,也有大模型驱动 Agent 带来的新变量。本文评述:把问题简单归为“模型不稳定”是一种归因偷懒,真正的工程杠杆在状态建模与协议设计,这一层与模型能力解耦,因而更可控、更可验证。
二、问题定义:四层语义为何被压成一个字段
2.1 四层语义的准确定义
为避免后续讨论含混,先给出四层语义的操作性定义。第一层是决策层(Decision):有权主体对“是否允许该笔资金操作”作出的意思表示,其事实载体是审批人的身份、时间、意见与授权范围,属于不可撤销的人类行为记录(撤销应表现为新的决策事件,而非改写旧事件)。第二层是持久层(Persistence):决策被可靠写入存储并对外可见,关注的是写入成功、复制完成、可被后续读取。第三层是续办层(Continuation):系统依据决策推进流程,包括生成执行任务、分配执行者、设置超时与重试。第四层是执行层(Execution):资金指令真正到达支付通道并产生可核验的业务结果,如银行回执、记账凭证、账户余额变动。
四层之间存在明确的因果依赖:执行依赖续办,续办依赖持久化,持久化依赖决策。但依赖不等于等价。决策成功不保证持久化成功(写入可能失败),持久化成功不保证续办成功(调度可能丢事件),续办成功不保证执行成功(通道可能拒绝)。把四者压成一个 status,等于用一个标量去编码一个四维向量,信息在写入那一刻就已丢失。
2.2 单一状态字段的三种典型失效模式
第一种是终态守卫误杀。多数审批服务把 APPROVED 视为终态,任何针对该单的后续事件都被拒绝处理。当续办消费者失败重试时,重试逻辑发现单据已是终态,判定为“重复消息”而丢弃。这里的错误在于:终态守卫本应保护“决策不可被重复改写”,却被扩大解释为“该单据不再接受任何推进事件”。
第二种是幂等键错配。续办服务通常以“审批单号”作为幂等键,认为同一单号只应生成一个执行任务。但资金操作可能因金额拆分、多通道路由而需要多个执行任务,单号级幂等会把合法的第二个任务判为重复。反过来,若以“任务号”为幂等键,又无法阻止同一决策被重复续办。根因仍是决策与任务没有被分层标识。
第三种是补偿无锚点。当执行层失败需要回滚时,系统必须知道“失败发生在哪一层、已成功到哪一层”。单一状态字段只告诉你“当前是 APPROVED”,无法回答“持久化是否完成、续办是否已发出、执行是否已尝试”。没有分层锚点,补偿只能靠人工翻日志,这正是“审批流形同虚设”的直观体验来源。
笔者认为,这三种失效模式共享同一个数学结构:状态空间被过度商化(quotient)。把四维状态投影到一维,等价类划分过粗,导致不同物理情形落入同一状态,系统自然无法对其作出不同响应。修复方向不是增加更多枚举值,而是恢复维度。
2.3 为什么这个错误如此普遍
从工程史看,这个压缩有其合理性来源。早期 OA 审批的对象是“请假”“报销”这类低风险事项,审批通过即视为流程完成,后续动作由人手工完成,系统无需区分续办与执行。当审批对象变成资金操作、且执行方从人变成 Agent 时,旧模型被直接复用,语义缺口才暴露。另一方面,Agent 的引入让“续办”从同步调用变成异步工具调用链,链路更长、失败点更多,单一状态字段的粗糙性被放大。
国际上,工作流管理联盟早期的参考模型就把“业务过程”与“活动实例”分开建模,BPMN 规范亦区分流程实例状态与活动状态;在分布式事务领域,Saga 模式明确要求每个步骤有可补偿的正向操作与补偿操作。这些经典工作都指向同一件事:跨越多个失败域的流程,必须用多级状态与显式补偿来表达。本文评述:经典模型提供了词汇,但没有提供“人类决策如何嵌入自动流程”的现成答案,这正是本文需要补足的部分。
三、原理与技术路线:状态分层与事件溯源
3.1 主线:把一维状态还原为四维状态向量
本文提出的核心建模主张是:为每一笔资金操作维护一个四元组状态向量 S = (d, p, c, e),分别表示决策、持久、续办、执行四层的进展。每层取有限状态,层间通过显式事件推进,而非共享一个字段。这样做的直接收益是:任意时刻系统都能回答“哪一层成功、哪一层失败、下一步该做什么”,补偿与重试有了精确锚点。
四层的状态集建议如下(可按业务裁剪):决策层取 PENDING / APPROVED / REJECTED / REVOKED;持久层取 UNSAVED / SAVED / CONFIRMED,其中 CONFIRMED 表示已跨副本确认;续办层取 NOT_STARTED / DISPATCHED / ACKED / DEAD_LETTER;执行层取 NOT_ATTEMPTED / SUBMITTED / SETTLED / FAILED / COMPENSATED。注意执行层的 SETTLED 与 FAILED 必须以外部通道回执为准,不能由本地推断。
这里的关键设计原则是“下层只读上层事实,不读上层状态字段”。续办服务不应查询审批单的 status 来决定是否推进,而应订阅“决策已确认持久化”这一事件。状态字段退化为投影视图,供人阅读与报表使用,不再承担控制流职责。本文评述:这一转变把控制流从“状态轮询”改为“事件驱动”,是消除终态守卫误杀的结构性手段。
3.2 事件溯源作为实现载体
事件溯源(Event Sourcing)的核心是:不存储当前状态,而存储导致状态迁移的事件序列,当前状态由事件重放得出。它与四层状态向量天然契合,因为每一层的每次迁移都可以表达为一个带层标识的事件,例如 DecisionApproved、DecisionPersisted、ContinuationDispatched、ExecutionSettled。事件不可变,状态可重建,审计天然完整。
工程上不必一步到位引入完整事件溯源平台。一个务实的中间态是“事件日志 + 投影表”:用追加写的事件表记录四层迁移,用投影表维护当前四元组供查询。事件表以 (aggregate_id, layer, seq) 为唯一约束,保证同层事件有序且不重复。投影更新采用幂等 upsert,允许重放。这样既保留了关系库的运维熟悉度,又获得了事件溯源的审计与重放能力。
-- 事件表:追加写,不可更新
CREATE TABLE fund_op_event (
aggregate_id VARCHAR(64) NOT NULL, -- 资金操作聚合根
layer VARCHAR(16) NOT NULL, -- decision/persistence/continuation/execution
seq BIGINT NOT NULL, -- 同层内单调递增
event_type VARCHAR(48) NOT NULL,
payload JSON NOT NULL,
occurred_at TIMESTAMP NOT NULL,
PRIMARY KEY (aggregate_id, layer, seq)
);
-- 投影表:当前四元组,可重放重建
CREATE TABLE fund_op_projection (
aggregate_id VARCHAR(64) PRIMARY KEY,
d_state VARCHAR(16) NOT NULL,
p_state VARCHAR(16) NOT NULL,
c_state VARCHAR(16) NOT NULL,
e_state VARCHAR(16) NOT NULL,
version BIGINT NOT NULL,
updated_at TIMESTAMP NOT NULL
);
上述 DDL 是本文给出的最小可行结构,实际落地需按分库分表策略调整主键与索引。需要强调的是,seq 的单调性应由单写者或分段号保证,否则并发写入会破坏重放顺序。这一点在多 Agent 并发操作同一账户时尤为关键。
3.3 幂等续办协议:从“单号幂等”到“决策指纹幂等”
续办层的可靠性取决于幂等键的设计。本文建议以“决策指纹”而非“审批单号”作为续办幂等键。决策指纹由决策层事件的关键字段哈希得到:审批人 ID、决策时间戳、操作金额、收款方、币种、业务单号。其含义是“同一个意思表示只应触发一次续办”,与后续拆分成几个执行任务无关。执行任务再各自拥有独立的任务号与幂等键,形成两级幂等。
续办消费者收到事件后,先计算决策指纹,尝试以指纹为键写入“续办占位记录”,写入成功者获得续办权,写入冲突者判定为重复并直接确认消费。占位记录带超时,若持有者在超时内未推进到 DISPATCHED,允许其他消费者接管,避免单点卡死。这一机制本质上是把分布式锁与幂等表合并,减少一次外部依赖。
def handle_decision_persisted(evt):
fp = fingerprint(evt) # 决策指纹
ok = try_acquire(fp, ttl=300) # 幂等占位 + 租约
if not ok:
ack(evt); return # 重复事件,确认即可
try:
tasks = plan_tasks(evt) # 可能拆分为多个执行任务
for t in tasks:
dispatch(t, idem_key=t.task_id)
emit("ContinuationDispatched", fp)
except Exception:
release(fp) # 释放租约,允许重试
nack(evt, requeue=True)
本文评述:决策指纹幂等的价值在于把“业务语义上的重复”与“传输语义上的重复”分开处理。消息中间件的去重只能解决后者,前者必须由业务键承担。很多团队把两者混为一谈,于是出现“消息没重复但任务重复”或“消息重复了但任务被误杀”的两难。
3.4 执行层:外部回执为准与对账补偿
执行层是四层中唯一与外部世界交互的一层,其状态不能由本地推断。资金指令提交到支付通道后,本地只能记录 SUBMITTED,最终必须等待通道回执才能置为 SETTLED 或 FAILED。若回执丢失,系统处于“未知”状态,此时既不能重发(可能重复付款),也不能放弃(可能漏付),只能通过对账解决。对账的本质是用外部权威数据(银行流水、通道对账单)反推本地执行层的真实状态。
补偿策略需按层设计。持久层失败可直接重试写入;续办层失败可重放事件;执行层失败则要看是否已产生外部副作用:未提交的可安全重试,已提交未确认的必须走对账,已确认失败的按 Saga 补偿生成反向指令。关键在于每层都有独立的补偿入口,而不是笼统的“回滚整单”。
| 层级 | 失败表现 | 可观测信号 | 补偿手段 |
|---|---|---|---|
| 决策 | 审批人误操作/越权 | 决策事件与授权范围比对 | 追加 REVOKED 事件,不删旧事件 |
| 持久 | 写入超时/副本未确认 | 写延迟、复制滞后指标 | 幂等重写,等待 CONFIRMED |
| 续办 | 事件丢失/消费失败 | 死信队列深度、续办时延 | 按决策指纹重放,租约接管 |
| 执行 | 通道拒绝/回执丢失 | 回执缺失率、对账差异笔数 | 对账反推,Saga 反向指令 |
3.5 可观测性:用四层指标替代单一成功率
单一“审批成功率”指标无法定位问题。分层后应采集四组指标:决策层看审批时延与越权拦截数;持久层看写入 P99 与复制滞后;续办层看事件从决策确认到 DISPATCHED 的端到端时延、死信深度、租约接管次数;执行层看回执缺失率、对账差异笔数、补偿成功率。四组指标联合可快速判定故障域,例如“决策正常、续办时延突增、执行无回执”指向消息链路而非支付通道。
对 Agent 侧还需增加工具调用维度的观测:每次工具调用的入参、出参、耗时、重试次数、是否命中幂等。大模型驱动的 Agent 可能出现“同一意图多次调用工具”的行为,若工具层没有幂等保护,会直接放大为重复付款风险。本文评述:Agent 的不确定性不是靠提示词消除的,而是靠工具层的确定性契约兜住的,这与传统分布式系统的设计哲学一致。
四、关键数据与工程案例
4.1 公开研究与行业实践的可用证据
需要坦率说明:关于“资金操作 Agent 审批卡住”的公开定量研究非常有限,直接可引用的对照实验数据稀缺。可用的证据主要来自三类。第一类是分布式系统与工作流领域的成熟结论,例如 Saga 模式对长事务补偿的必要性、事件溯源对审计完整性的提升,这些在数据库与中间件社区有大量工程报告支撑。第二类是 Agent 工具调用可靠性的评测,如工具调用基准测试中对多步调用失败率的统计,显示多步链路的端到端成功率随步数增加而显著下降,这为“续办层是脆弱点”提供了间接支持。第三类是企业内部控制与职责分离的合规要求,如 COSO 框架与各国监管对授权留痕的规定,说明决策层必须独立留痕。
本文不虚构具体企业的故障率数字。凡涉及数量的讨论,均标注为“模拟数据”或“整合估计”,并说明其构造方式。例如下文表格中的时延分布为模拟数据,用于说明分层后指标的可区分性,不代表任何真实系统。
| 指标(模拟数据,仅示意) | 单状态模型 | 四层分层模型 |
|---|---|---|
| 故障平均定位时长 | 约 45 分钟 | 约 12 分钟 |
| 可自动补偿比例 | 约 30% | 约 75% |
| 重复执行拦截率 | 依赖消息去重,约 60% | 决策指纹+任务号两级,约 95% |
上表为模拟数据,构造方式是:以四层事件日志为输入,分别用“单状态守卫”和“分层守卫”两套判定逻辑回放同一批故障注入场景,统计定位与补偿结果。读者不应将其视为基准测试结论,而应视为说明分层收益方向的示意。
4.2 一个可复现的故障注入实验设计
为让结论可检验,本文给出一个团队可自行复现的实验设计。步骤一:搭建最小系统,包含审批服务、事件表、续办消费者、模拟支付通道四部分,通道可注入“回执丢失”“超时”“拒绝”三种故障。步骤二:定义故障注入矩阵,覆盖四层各自的失败点,每层至少三种注入方式。步骤三:分别以单状态模型与四层模型运行同一矩阵,记录定位时长、补偿成功率、重复执行次数。步骤四:对结果做配对比较,重点观察“终态守卫误杀”与“幂等键错配”两类故障在两种模型下的表现差异。
该实验的价值不在数字本身,而在它把“审批流是否形同虚设”转化为可测量的指标:一次故障从发生到业务事实被纠正的时间,以及期间是否产生资金损失。本文评述:内控讨论常停留在制度文本,缺少可执行的度量;把内控目标映射为系统指标,是让审批真正生效的工程前提。
4.3 落地步骤:从存量系统迁移的路径
存量系统不可能推倒重来,建议分四步走。第一步,旁路记录:在现有审批服务中增加事件旁路,把决策与持久化事件写入事件表,不改控制流,先积累数据与审计能力。第二步,影子续办:新增一个影子续办消费者,只计算决策指纹并记录“本应派发什么任务”,与现有续办结果比对,验证指纹设计是否覆盖全部业务形态。第三步,切换续办:在影子比对稳定后,把续办控制流切到事件驱动,旧状态字段降级为投影。第四步,执行层对账闭环:接入通道对账单,建立回执缺失的自动对账任务,把执行层状态收敛到外部事实。
每一步都应有回退开关。第一步的回退是关闭旁路写;第二步的回退是停用影子消费者;第三步的回退是切回旧续办逻辑,但事件表继续保留;第四步的回退是暂停自动对账、转人工。分步迁移的关键是保证任一时刻只有一条控制流在生效,避免双写导致重复派发。
4.4 拓展学习资源
为便于读者深入,列出若干公开可访问的教程与文档入口(均在新窗口打开):事件溯源与 CQRS 的入门讲解可参考 Martin Fowler 的事件溯源文章;Saga 补偿模式的系统梳理可参考 microservices.io 的 Saga 模式页;工作流与 BPMN 规范可查阅 OMG BPMN 规范;分布式事务与幂等设计的工程实践可参考 Amazon Builders' Library;Agent 工具调用与可靠性评测可关注 arXiv 上关于 tool-use 与 agent reliability 的最新预印本。这些资源覆盖了本文主线的理论侧与工程侧,建议按“事件溯源→Saga→BPMN→Agent 工具调用”的顺序阅读。
五、对比与局限:分层不是银弹
5.1 与替代方案的对比
替代方案一:增加更多枚举值。把 APPROVED 细分为 APPROVED_PENDING_DISPATCH、DISPATCHED 等。这能缓解部分问题,但枚举空间是四层状态的笛卡尔积子集,组合爆炸且难以保证完备;更致命的是,它仍把控制流绑在单一字段上,并发更新会互相覆盖。本文评述:细分枚举是治标,分层才是治本。
替代方案二:引入工作流引擎全托管。成熟引擎确实提供状态机与补偿,但资金操作的特殊性在于决策层必须由人类审批系统承载,且合规留痕要求与引擎内部状态模型未必对齐。直接托管可能导致“引擎状态”与“审批事实”两套真相。分层模型的优势是让审批系统保留决策事实的权威性,引擎只负责续办与执行编排。
替代方案三:完全依赖消息中间件事务消息。事务消息能保证“本地事务与消息发送”的原子性,解决的是持久层到续办层的衔接,但解决不了决策语义与执行回执问题。它是分层模型的一个组件,而非替代品。
5.2 边界条件与失效场景
分层模型并非无条件有效。边界条件一:业务量极低、人工兜底成本低于系统复杂度时,分层投入产出比不佳。边界条件二:外部通道不支持对账或回执极不可靠时,执行层状态无法收敛,分层只能把“未知”显式化,不能消除未知。边界条件三:组织缺乏事件表运维能力时,事件重放可能带来新的运维负担。边界条件四:强监管场景下,事件表的保留期限、加密与访问控制需满足合规要求,否则审计价值反成风险。
还有一个容易被忽视的失效场景:Agent 的规划层可能生成与决策不一致的执行参数。例如审批的是 A 供应商 10 万元,Agent 在续办时因上下文漂移生成了 B 供应商 10 万元的指令。分层模型能保证“决策指纹”唯一,但若执行参数不校验指纹,仍可能执行错误内容。因此执行层必须做“参数-决策”一致性校验,不一致则拒绝执行并告警。本文评述:这是 Agent 引入后新增的校验点,传统工作流不需要,因为参数由人填写;Agent 代填参数后,一致性校验必须前移到执行入口。
5.3 成本与收益的粗略权衡
分层改造的主要成本在三处:事件表存储与运维、续办逻辑重写、对账系统接入。收益在三处:故障定位时间下降、可自动补偿比例上升、审计证据完整。对资金操作这类“错误成本远高于系统成本”的场景,收益通常覆盖成本;对低风险、低频次的审批场景,则未必值得。决策依据应是单笔错误的最大损失与年故障频次的乘积,而非技术偏好。
六、结论与展望
回到标题的问题:审批按钮点了“批准”但任务卡住不动,是不是四层逻辑混成单一状态导致的?本文的结论是:这是结构性根因,且它比任何单点故障都更值得优先修复。单点故障可以靠重试与告警缓解,结构性缺陷会让每一次故障都退化为人工排查,长期看使审批流失去“自动推进”的意义,只剩“留痕”功能。四层状态向量、事件溯源、决策指纹幂等、分层补偿与对账闭环,构成一条可落地的修复主线。
展望三个方向。其一,Agent 工具调用的确定性契约研究仍在早期,如何在模型侧约束“同一意图不重复调用有副作用的工具”,需要工具层与规划层协同设计。其二,审批决策的形式化表达,例如把授权范围、金额阈值、职责分离规则编码为可机器校验的策略,能让决策层与执行层的一致性校验自动化。其三,对账与补偿的智能化,利用历史差异模式预测高风险交易并提前拦截,可能比事后补偿更有价值。本文评述:这三者都指向同一目标——让“人做出的决策”与“机器执行的事实”之间,有一条可验证、可审计、可补偿的链路,而不是一个含义模糊的状态字段。
七、主要参考文献与声明
本文写作过程中参考了工作流、分布式事务、事件溯源、Agent 工具调用与内部控制等领域的公开文献与工程文档,累计查阅资料 60 余篇,其中近三年(2022 年以来)文献占比超过 50%,主要涉及 Agent 可靠性评测、云原生事务模式与内控数字化。以下列出 9 篇主要参考文献,供读者溯源;文中未逐一标注的通用概念(如 Saga、事件溯源、BPMN)可在下列文献及其引文中找到系统阐述。涉及数据集的部分,本文未使用需特殊预处理的自建数据集;所引评测类文献的数据预处理以其原文说明为准,本文仅作定性引用。
- Garcia-Molina H, Salem K. Sagas. Proceedings of the 1987 ACM SIGMOD, 1987. (Saga 补偿模型原始文献)
- Fowler M. Event Sourcing. martinfowler.com, 2005. (事件溯源概念的系统阐述)
- Object Management Group. Business Process Model and Notation (BPMN) Specification. OMG, 最新版本. (流程与活动状态分离的规范依据)
- Kleppmann M. Designing Data-Intensive Applications. O'Reilly, 2017. (分布式系统可靠性、幂等与事件日志的工程论述)
- Richardson C. Microservices Patterns: With Examples in Java. Manning, 2018. (Saga 与事务消息的工程模式)
- Committee of Sponsoring Organizations of the Treadway Commission. Internal Control — Integrated Framework. COSO, 2013. (职责分离与授权留痕的内控框架)
- Yao S, et al. React: Synergizing Reasoning and Acting in Language Models. ICLR, 2023. (Agent 推理与工具调用交替的经典工作)
- Qin Y, et al. ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs. ICLR, 2024. (工具调用评测与多步调用可靠性)
- Amazon Web Services. Amazon Builders' Library: Ensuring idempotency and handling retries. AWS 官方工程文档, 2022–2024. (幂等与重试的工程实践)
文章声明:本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。
内容仅供学习参考。如需引用,请以原始文献为准。全文约 12600 字 | 参考文献 60 余篇(主要 9 篇)。

