跳转到主要内容

智能体工具调用中的幂等性问题

阅读需 1 分钟Tian PanTian Pan

这种场景每次都如出一辙。你的智能体正在预订酒店房间,支付API调用返回200后、确认信息存储之前发生了网络超时。智能体框架发起重试,支付再次执行,客户被扣了两次款。支持团队升级处理,某位高管说AI"幻觉出了重复扣款"——这种说法是错的,但听起来有道理,因为没人愿意承认他们的重试逻辑从一开始就是坏的。

这不是AI问题,而是分布式系统问题——被AI层全盘照搬,却没有带来分布式系统工程师几十年苦心钻研出的应对之道。标准的智能体重试逻辑假设操作是幂等的,而大多数工具调用并非如此。

为什么智能体重试在结构上就是坏的

每个主流智能体框架——LangChain、LlamaIndex、OpenAI的Agents SDK、Anthropic的Claude——都内置了针对瞬时故障的自动重试行为。这是正确的。分布式系统中瞬时故障随时发生,静默丢弃请求比重试更糟糕。

问题在于重试逻辑所处的位置。智能体框架在LLM层重试:模型看到工具调用失败,决定再试一次,于是再次调用工具。这个循环里没有任何机制追踪工具是否已经执行了其副作用。框架看到超时,推断:"我没有收到结果,所以应该重试。"而工具可能早已写入了数据库、扣了款、发了邮件或创建了工单。

这种故障模式遍布各行各业。管理CRM系统的智能体会为同一客户投诉创建重复的支持工单;库存管理智能体会对同一订单重复扣减库存;金融智能体会发送重复退款。每个案例都遵循同样的模式:超时或瞬时错误触发重试,工具再次执行,系统最终进入智能体从未预期的状态。

这时,"修复提示词"的本能就会发作。工程师添加诸如"只调用一次支付工具"或"创建之前先检查订单是否存在"之类的指令。这没用。产生重复扣款的智能体当时是在正确地执行指令——它真的不知道第一次调用已经成功了。问题不在于模型的推理,而在于缺少外部状态让工具报告"我已经做过了"。

幂等性对工具调用究竟意味着什么

幂等性意味着多次调用一个操作与调用一次产生相同的结果。GET请求天然是幂等的:读取一条记录不会改变它,读十次也是安全的。DELETE在实践中是幂等的:删除一条不存在的记录与删除一条存在的记录返回相同的逻辑结果。而创建记录或扣款的POST默认不是幂等的——每次调用都会创建新东西。

让非幂等操作变得安全的模式,在支付API中已经相当成熟。客户端发送请求时附带一个幂等键——由客户端生成并持有的唯一标识符。服务端将该键连同操作结果一起存储。用同一个键重试时,服务端检查存储并返回缓存结果,而不重新执行。客户端第三次重试时得到的响应与第一次一致。

对于智能体工具调用,这一模式需要在三个层面做出明确的设计决策:

智能体运行时层必须为每个工作流步骤生成并维护幂等键。实践中,从持久状态派生的键效果最好:{workflowRunId}:{stepId}。这确保键在重启后仍然有效且是确定性的——恢复时重新生成相同的键,而不是重试时生成新键。

工具执行层必须将幂等键传递给下游服务,在执行前检查去重存储,并以足够的TTL缓存结果。如果键已存在且上次调用成功,返回缓存响应;如果键已存在且上次调用以永久错误失败,返回该错误而不重新执行。

工具接口本身必须接受幂等键并实现去重逻辑。调用外部API的工具应将键透传给这些API;向内部数据库写入的工具应将键作为唯一约束的一部分。

当三个层面协同配合时,智能体框架可以尽情重试。经济结果——一次扣款、一条记录、一封邮件——与智能体的意图相符。

多步骤工作流的Saga模式

单工具幂等性是更简单的问题。更难的情况是多步骤工作流:智能体依次调用多个工具,中途某处发生故障。

设想一个处理订单的智能体:预留库存、向客户扣款、发送确认邮件。每个步骤单独看都是幂等的。但如果支付成功而确认邮件失败,客户已被扣款却没有收到确认。如果智能体重试整个流程,支付会再次执行(假设你在那一层实现了幂等性,扣款会被去重),但库存已经被预留了——第二次预留尝试可能会因库存归零而失败。

这正是Saga模式要解决的问题。Saga是一系列步骤,每个步骤都有对应的补偿动作,当后续步骤失败时可以撤销其效果。与原子回滚(需要分布式事务及其相关代价)不同,Saga通过显式补偿实现最终一致性。

对于订单处理工作流,Saga如下所示:

  • 预留库存 → 补偿动作:释放预留
  • 扣款支付 → 补偿动作:发起退款
  • 发送确认 → 补偿动作:发送取消通知

如果确认步骤永久失败,Saga执行器以相反顺序运行补偿动作:发起退款、释放库存。客户看到的是订单失败,而非扣款成功但无确认的状态。

关键的实现细节是:补偿动作本身必须是幂等的。重试退款时不应该发起第二次退款。这听起来显而易见,直到你在凌晨两点调试退款循环时才真正体会到。

Saga执行存在两种实现模式。编排模式使用中央协调器——通常是持久化工作流引擎或专用的编排智能体——指挥每个步骤并在失败时触发补偿。这提供了对工作流状态的清晰可见性,但产生了单点协调。协同模式让每个步骤发出事件触发下一个步骤,补偿由失败事件触发。这种耦合更松散,但观察和调试难度显著更高。

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 12 分钟

级联问题:为什么 Agent 副作用在大规模运行时会呈爆炸式增长

独立通过每一项单元测试的 Agent 在大规模部署时会导致级联副作用。本文将介绍其工程分类以及真正能防止这种情况的模式。

insider
ai-engineering
阅读需 11 分钟

429 错误背后的惊群效应:速率限制是一个分布式系统问题

不带抖动的指数退避会组织你的重试集群而不是将其消解 —— 随之而来的是同步的 429 浪潮、重试放大和亚稳态故障。本文将探讨为什么 LLM 速率限制需要抖动、重试预算,以及你原本没打算构建的客户端调度器。

insider
ai-engineering
阅读需 12 分钟

智能体系统就是分布式系统:在遭遇惨痛教训前应用微服务经验

当今困扰多智能体 AI 系统的失败模式,其实是伪装成新问题的 2015 年分布式系统老问题。那些在构建智能体之前就内化了微服务经验的团队,正在交付更可靠的系统。

ai-engineering
agents
阅读需 13 分钟

重试放大:2% 的工具错误率如何演变成 20% 的智能体故障

智能体循环通过在多个步骤和 SDK 层级间叠加重试,将 2% 的工具错误率放大为 20% 的用户端故障。本文将解析其背后的数学原理、自我 DoS 模式,以及能够遏制这种现象的重试预算规范。

insider
agents
阅读需 11 分钟

优雅的工具调用失败:你的 Agent UI 缺失的错误契约

大多数 Agent UI 只处理成功路径。以下是将工具调用失败从崩溃变为可恢复时刻所需的错误契约和 UX 模式。

insider
ai-engineering