工具调用如何保证幂等,避免模型重试导致重复副作用?

考查重点:业务意图去重与原子状态。一次业务意图复用稳定幂等键,数据库唯一约束或原子状态机记录结果;重试返回已有结果而非再次产生副作用

本题目录

参考答案

核心回答

工具幂等,是让同一次业务操作被重复请求时,不产生额外副作用。它要由可信执行层和业务服务保证,提示词里写“不要重复调用”只能辅助减少误调用。

我会把链路分成五步:

  1. 为一次明确的业务意图生成稳定的 action_id 或幂等键,同一操作的模型重试、网络重试和恢复执行都复用它。
  2. 执行前校验身份、资源、参数和有效授权,保存规范化参数摘要;同键但参数不同则拒绝。
  3. 在服务端用唯一约束或条件写入原子地登记并抢占执行,记录处理中、成功、确定失败和结果未知等状态。
  4. 成功的重复请求返回已有回执;处理中的请求返回状态或等待。调用下游写接口时继续使用其支持的幂等标识。
  5. 超时或崩溃后先确认业务结果;结果未知时查询或对账,不能另生成新键盲目重做。

例如一次创建工单请求,即使模型再次发出相同调用,也应返回同一张工单。用户明确要再创建一张相同内容的工单,则是新的业务意图,应使用新的操作标识。

展开说明

1. 幂等键标识什么,谁来生成

模型返回的 tool_call_id 用于关联工具请求和结果;模型重新推理时可能生成新的 ID,因此它不能直接充当跨重试的业务幂等标识。HTTP 请求 ID、队列消息 ID 也未必代表同一次业务意图。

可以在系统建立待执行动作时生成 action_id,与租户、动作类型、资源和规范化参数摘要绑定。幂等记录的唯一范围可以是“租户 + 操作类型 + action_id”,具体按业务契约定义。这个标识由服务端生成,或由可信调用方提供并经服务端校验,不能让模型在每次重试时任意换一个键绕开防重。

参数摘要用于检查同一个键是否被误用于不同操作,并不是唯一的意图标识。同一用户连续购买两份完全相同的商品,参数可能一致,但应形成两次独立操作;反过来,同一次动作只是参数序列化顺序变化,也不该变成新操作。参数需要先按业务规则归一化,保留金额、币种、对象等真正影响操作的字段。

2. 服务端怎样处理重复和并发

单纯“先查有没有,查不到就执行”有竞态:两个执行器可能同时查不到,然后各执行一次。需要依靠数据库唯一约束、原子条件更新等机制,使同一操作只能被一个有效执行者抢占。

幂等记录可保存操作标识、参数摘要、状态、外部业务号和结果引用。重复请求到达后,先检查调用者权限与参数一致性,再根据状态处理:成功则返回原业务回执;处理中则返回进度或让调用方稍后查询;确定未执行或明确可重试的失败,才按契约允许重试;结果未知则进入核对。

若业务修改与幂等记录位于同一数据库,可以放在同一个事务中提交。例如新增工单和登记创建结果一起完成,避免一边成功、一边丢失。分布式锁可以辅助串行化,但锁过期、进程崩溃后仍可能有旧执行者继续运行,因此不能只靠“抢到锁”证明业务不会重复。

3. 最难的是外部成功、本地不知道

假设工具已经在外部工单系统创建了工单,但响应途中断网,或者本地进程在保存回执前崩溃。此时本地缺少成功记录,并不意味着外部没有执行。

如果下游支持幂等键,应持久保存并透传同一标识,恢复后按它查询或按下游契约重试,让下游识别同一次请求。幂等键的范围、有效期、并发请求行为,以及失败结果是否缓存,都要按接口文档确认;不能假定所有服务行为一致。

如果下游不支持,需要评估它是否提供业务唯一键、条件创建或可明确核对的查询接口。无法确认结果时,保留“结果未知”,限制再次提交,转入对账或人工处理。Outbox 可以让本地提交意图与待发送事件一致,补偿可以在事后修正业务状态,但它们都不会自动让远端操作变成一次原子提交;已经发出的邮件或真实转账也不是回滚本地状态就能撤销。

幂等记录应覆盖合理的重试、恢复和迟到请求窗口。记录过期后,相同键可能被当成新请求,因此长期恢复任务还要考虑业务唯一性和历史回执的保留方式,不能随便设置一个很短的缓存时间就结束。

4. 重试策略还需要哪些限制

认证失败、权限不足、参数非法等错误,应先修正原因;限流、短暂网络故障等是否可重试,要结合操作的副作用和服务端幂等契约决定。采用有限次数、退避与抖动、总截止时间,避免模型、SDK 和队列各自无限重试。

同一资源上的不同业务意图还可能发生冲突,例如两次不同退款各有不同幂等键。此时仍需金额校验、资源版本、条件更新或事务约束;幂等解决同一操作重复,业务约束解决不同操作之间的合法性。

验证时重点覆盖相同键连续重放与并发重放、同键不同参数、不同键相同参数,以及提交前崩溃、外部成功后丢回执、记录过期后的迟到请求。最终检查真实业务记录和副作用次数,不能只看模型是否输出了相同文本。

常见追问

相同工具和参数做个缓存,够不够?

查询缓存可以减少重复读取,但有副作用的操作需要识别业务意图,并在真正执行的一侧防重。短时间参数相同既可能是重试,也可能是用户的新操作;缓存过期、并发穿透或多实例各有一份缓存,也都可能再次执行。

工具已经返回超时,可以直接换备用接口吗?

查询任务可以按业务允许的策略切换。写操作则先核对原调用的真实状态;备用接口若没有共享的幂等或业务唯一性约束,换接口可能再产生一次副作用。应向模型返回“处理中”或“结果待确认”等准确状态,而不是把网络超时包装成确定失败。

有 checkpoint 就能保证只执行一次吗?

Checkpoint 保存编排状态,但外部业务事务有自己的提交边界。业务成功后、检查点落盘前仍可能崩溃;部分节点在恢复时还会重新执行,所以需要稳定业务标识、下游幂等和结果核对。把实际写动作放在独立步骤有助于控制恢复范围,也仍需保护该步骤的重试。

对应教程

  • Tools 工具调用:阅读工具工程原则和副作用工具的设计,理解模型提出意图、程序负责校验和执行,以及查询与写入分开暴露的作用。
  • LangGraph 高级特性:阅读中断恢复时节点重新执行的说明,理解为何真实副作用要单独处理,并用业务 ID、防重记录和幂等键保护重放。

参考资料

DifyPython

基于 Dify

核心回答

以“售后通”创建维修、退换工单的场景化接入设计为例:由业务服务保存稳定的办理标识,用数据库唯一约束和办理状态处理并发重试,成功时返回原工单回执,结果未知时先查询原动作。 Dify 负责流程编排与人工审批,工单系统负责实际写入;两边需要共享业务标识,不能把工作流恢复当成工单已经幂等。

例如客服确认一次维修申请后,模型重试、接口超时重试和工作流续办都应指向同一次办理。客服明确改成换货则是新的处置动作,在业务允许变更的状态下应形成新的处置版本。能否改处置仍需校验工单状态,幂等键不代替业务状态约束。

哪个标识代表同一次办理

接入服务在客服确认处置时固定租户、售后单号、处置版本和动作类型,作为业务键;同时保存规范化参数摘要,包含处理方式、目标商品等影响办理的字段。同键且参数一致才视为重试,同键却改了参数应拒绝并要求建立新处置版本。

workflow_run_id 关联流程运行,task_id 用于停止执行,模型的工具调用 ID 关联一次调用与返回。它们都不能替代跨重试的业务键;即使同一次办理被重新受理为另一个流程运行,也应查回原来的办理记录。业务键与处置版本由可信服务维护,不能每次让模型重新生成。

并发请求怎样只推进同一次动作

在业务数据库中,为业务键建立唯一约束,保存参数摘要、办理状态及工单回执。不要采用“先查不存在,再发起办理”的非原子流程:两个请求可能同时通过检查。

第一次请求通过插入或条件更新领取办理权。重复请求读取已有记录:成功则返回同一张工单;处理中则返回进度;只有确认尚未产生副作用、符合重试约定的失败才重新执行。同一数据库内的工单写入和结果登记可以放在同一个事务里提交,避免工单已创建却没有留下成功记录。

外部工单成功,本地却超时怎么办

调用外部工单系统前,先持久化办理记录,并向下游透传同一业务键。若下游已经创建工单,但响应丢失或本地保存回执前进程退出,应将结果标为待确认,按原业务键查询或对账,确认后补写回执。

下游支持幂等时,按它的键范围、有效期和参数比较规则使用原键重试;不支持时,需依靠它的业务唯一号或查询能力核对。没有可核对的结果,就保留待确认状态并交由人工处理,不能换键重发。“没收到成功”与“确定没有办理”是两种状态。

工作流恢复怎样与业务状态衔接

Dify 的人工表单提交会锁定表单记录,恢复事务也会检查暂停状态;这些保护的是表单和流程状态。当前实现仍存在表单已提交、恢复任务尚未成功入队的窗口,见提交与恢复调度。接入层应按原运行补查、续办,并让恢复后的写工具继续使用原业务键。

验证时重点覆盖:同键并发只得到同一张工单、同键不同参数被拒绝、下游成功后响应丢失仍能查回原工单,以及重复恢复不会新建第二张工单。流程结束和工单办理结果分别核对,以实际业务回执确认完成。

参考资料

相关面经

7 篇

小红书

国际化开发工程师
校招秋招一面
查看原面经 →
● Agent 开始执行任务后,如果用户再发送一个新任务,会重复执行吗?如何做幂等?

乐堡互娱

AI应用开发岗
校招秋招一面、二面、三面、四面
查看原面经 →
Agent调用工具超时了怎么处理,如果一直失败会不会重复调用,有没有设计熔断机制

美团

AI 全栈开发工程师
校招秋招二面
查看原面经 →
工具调用失败、超时、重复调用,分别怎么处理

阿里巴巴

AI 应用研发工程师
校招秋招一面
查看原面经 →
工具调用失败怎么兜底?重试策略怎么设计

阿里巴巴

AI 应用开发工程师
秋招一面
查看原面经 →
项目追问
你的幂等键是怎么设计的?
展开剩余 2 篇面经

快手

Agent 开发工程师
一面
查看原面经 →
Agent 的工具调用如何保证幂等?模型重试时怎样避免重复执行副作用?

腾讯

后端开发工程师(AI 应用)
实习
查看原面经 →
4- agent失败/中断如何处理?重试安全?

收录题集

5 个来源,共9 份题集

AI行业常用Python代码案例考频考点

Rocky Ding · AIGC-Interview-Book · 1 条原题

查看题集 →

AI 智能体与大模型应用开发面试题库

didilili · ai-agents-from-zero · 1 条原题

查看题集 →

Harness 与 Skills

沉默王二 · 王二讲 Agent · 1 条原题

查看题集 →

Agent开发面试题

摸鱼酱mio · 个人整理 · 1 条原题

查看题集 →

AI 机制与工程问答

Guide · JavaGuide · 1 条原题

查看题集 →
展开剩余 4 份题集

相关题目

4 题