AI 智能体需要可替换,同时不丢失已批准的业务操作
AI agents need to be replaceable – without losing your work
The New Stack 刊文讨论 AI 智能体崩溃后如何安全接替工作:应用在派发退款前先把金额、授权、幂等键和状态写入事务型存储,替换智能体继承原操作而非重新推理。文章指出 LangGraph、Temporal 等持久执行框架能恢复进度,但无法判断支付方是否已提交请求,因此需在工具边界校验持久记录,并用 Langfuse 与 ClickStack 的 MCP 服务只读排查结果不明的调用。
正文 · AI 翻译
一个智能体获得批准去处理一笔部分退款。它把请求发送给支付 API,随后进程崩溃了。支付服务可能已经完成了退款,也可能请求根本没发出去。一个替补智能体启动后,发现一条操作记录被标记为已派发,却没有写入任何结果。
这种模糊性并非智能体独有。任何分布式工作进程在变更操作中途崩溃都会面临同样的问题。但传统工作进程会从上一个检查点恢复预定的工作流。而智能体做的事情更危险:它自行推理。面对同样的客户请求且没有结果记录,它可能想出不同的方案、选择不同的参数,或者决定发起一笔新的退款,而不是继续那笔已经获批的退款。
“智能体做的事情更危险:它自行推理。”
如果原始退款已经成功,第二次尝试就会向客户退款两次。该笔扣款仍有足够的剩余余额来覆盖另一次部分退款,因此没有任何机制能阻止它。
替代者必须继承原始操作,而不是重新解释它。
操作必须比智能体存续得更久
智能体的进程、它的内存变量、它短暂的推理上下文:全都是可丢弃的。业务操作则不是。退款、它的审批、它的参数、它的当前状态。一个长时间运行的智能体可以在其运行期间保留有用的状态。要求是:任何关键操作都不应依赖于原始执行仍然存活。
在派发退款之前,应用会向事务型存储提交一条持久化的操作记录。该记录包含已批准的金额、适用的授权、应用发送给支付提供方的幂等键、应用在提供方元数据中的操作标识符,以及一个状态。
“智能体的进程、它的内存变量、它短暂的推理上下文:全都是可丢弃的。业务操作则不是。”
随着请求发出,状态从“已创建”变为“已派发”,并且只有在收到提供方响应后才会变为“已确认”或“已失败”。如果智能体崩溃,替补者会检索这条记录及其关联标识符。一条卡在“已派发”状态的记录表明曾尝试发起调用,但结果从未被写入。
替补者继承已批准的操作,而不是重新生成它。
当替补者需要验证结果时,它可以列出针对原始扣款的退款记录,并匹配返回元数据中的操作标识符。
但持久记录不仅仅是给替补者提供上下文。应用在工具边界强制执行它:派发层会根据已提交的记录校验每一个出站请求。智能体可以提出下一步建议,但只有携带原始参数和身份的授权操作才能到达提供方。模型无法重新定义已批准的内容。
ClickHouse Managed Postgres 保存业务数据,包括定义替补者被允许执行哪些操作的权威操作记录。原生 CDC 将这些数据复制到 ClickHouse。应用遥测数据发送到 ClickStack,智能体追踪数据发送到 Langfuse,两者都配置为使用同一个 ClickHouse 服务作为其后端数据库。
因为业务数据、应用遥测和智能体追踪都落在同一个数据库中,所以将一次操作与派发它的智能体运行以及失败的 HTTP 调用关联起来,只需一次单标识符查询。无需跨三个工具进行对账。
两个条件。应用必须传播该标识符。操作 ID 必须出现在 Postgres 行中、Langfuse 追踪属性中以及服务的日志上下文中,因为没有任何东西会替你完成关联。并且替补者从 Postgres 读取记录,而不是从复制副本读取。CDC 存在数秒延迟。权威行是工具边界所强制执行的那一行。
重启执行并不等于安全地恢复工作
像 LangGraph 和 Temporal 这样的持久执行框架会记录执行进度,并在失败后恢复。两者都建议让副作用具备幂等性,因为恢复并不能解决副作用的问题。如果退款在该步骤仍处于待处理状态时已经完成,框架可以重启智能体,但它无法告知替补者支付提供方是否已提交原始请求。
持久操作记录为下一步并非预先确定的智能体实现了这一幂等性指导。
持久记录中的幂等键将替补者与原始请求关联起来。如果替补者使用同一个键重试,提供方就能识别出这是同一操作,而不是将其作为一笔独立退款来处理。即使原智能体在崩溃后才完成其进行中的请求,或者一个被认为已死亡的 worker 已恢复运行,这一点依然成立。AWS 的 Builders' Library 将这一模式正式化:调用方提供的标识符与变更操作原子性地一同记录。
但重试并不总是安全的。结果可能仍然不明确。Stripe 的文档指出,变更操作返回 500 响应仍可能产生外部影响。当结果未知时,替补者需要证据来进行调查。
Langfuse 可以显示前一个智能体的工具调用:一个使用已记录的幂等键派发的退款请求。ClickStack 可以补充运维方面的情况:一次发往支付服务的出站 HTTP 请求随后发生连接失败,从而缩小了故障窗口。
两者都可直接供替补智能体使用。Langfuse MCP 服务器让它按操作 ID 查询前一个智能体的追踪记录,ClickStack MCP 服务器让它搜索同一时间窗口内的服务事件。只给替补智能体提供读取工具。它可以缩小排查范围,但工具边界仍然控制着替补智能体能够做什么。
两条追踪记录都不能证明支付提供方已执行退款。而缺失的追踪记录也不能证明请求从未发出,因为 Langfuse 是异步传输追踪数据的,崩溃可能导致数据未能送达。支付提供方仍是外部结果的权威记录系统。执行遥测能缩小调查范围,但不能替代权威确认。
继续工作,不要从头开始
替补智能体拥有持久记录,并在结果不明时拥有执行证据。现在它需要采取行动,但不是重新决定该做什么。
替补智能体遵循应用定义的恢复协议,而不是凭自己对客户处境的判断行事。
如果提供方确认退款已完成,替补者就记录结果并继续推进。如果提供方显示退款仍处于待处理或进行中,替补者就等待。重试可能会造成重复退款。如果退款已明确失败且没有产生外部影响,替补者会在发起新的授权尝试之前重新校验前置条件。如果结果仍不明确,替补者会升级处理,而不是猜测。提供方记录缺失并不能证明退款从未被处理。提供方可能尚未最终完成该交易。
“已存储的批准是历史证据,而不是当前采取行动的权限。”
即便已经确定了外部结果,替补者仍必须核实外部环境没有发生变化。可退款余额可能已经变动。人工客服可能已通过另一个界面处理了一笔单独的退款。客户的账户状态可能已经改变。有人可能已经撤销了原始授权。
已存储的批准是历史证据,而不是当前采取行动的权限。
真正的工程问题在于,新的智能体能否确定这项工作当前的目标、未履行的义务和不确定的影响,然后安全地继续推进,而不把前任的记忆当作权限。
智能体是可替换的。工作不是。
文章《AI 智能体需要可替换,同时不丢失已批准的业务操作》首发于 The New Stack。