工具调用的重试与幂等

工具调用的重试与幂等
主题插图 · AI 辅助生成

连接断开不等于远端没有执行,用稳定的操作身份处理重复请求与未知结果。

一次请求发出后连接断开了。界面没有收到成功消息,远端却可能已经保存了记录。这时直接重试,究竟是在补做一次工作,还是在重复做一次工作?

这个问题在普通表单里就会出现,加入 Agent 后也不会自动消失。本文设计一个“把阅读笔记加入清单”的小接口,练习如何表达意图、记录结果,并在不确定时恢复。

给操作一个稳定身份

AWS Builders’ Library 关于幂等 API 的文章讨论了让重试更安全的设计。这里借用请求身份这一思路,下面的字段和状态划分是本文的小项目方案。

对于同一个“添加笔记”的意图,客户端在重试时复用同一个操作编号。若用户真的要再添加一份内容,那是一个新的意图,应当使用新的编号。仅根据文本是否相同来猜测意图,很容易把用户希望保留的重复记录吞掉。

type AddReadingNote = {
  operationId: string
  notebookId: string
  sourceUrl: string
  note: string
}

服务器还需要把操作编号和参数摘要联系起来。相同编号却带来了不同内容时,应当明确报告冲突,而不是随机采用最后一次请求。这个检查同样要在真正执行写入的一侧完成。

把记录与写入放进一个边界

在这个练习里,操作记录和业务笔记保存在同一个数据库中,便于放入同一事务。若它们位于不同系统,就需要另外设计恢复流程,不能只画一个事务框便声称解决了全部问题。

当前状态再次收到同一操作应当做什么
尚未处理正常请求校验并尝试写入
已完成参数一致返回已保存结果
已完成参数不同报告冲突
处理中或结果未知重复请求查询实际状态,再决定下一步

这张表的重点是“结果未知”。网络错误只说明调用方没有拿到完整结果,不能直接证明远端什么都没做。

为失败安排不同的路

参数不合法,通常不应该原样重试。连接暂时不可用,可以在预算内等待后再尝试。结果已经存在,则应当读取原结果,而不是重新执行副作用。把所有错误都塞进同一个重试循环,会让日志越来越长,行为却越来越难解释。

可以先人为制造两种故障:写入完成后丢弃响应,以及写入之前断开连接。用同一操作编号重试,检查最终是否只有一条业务记录,并且能看到一次清楚的恢复过程。

发布需要更明确的状态

当工具涉及发布、发送或其他对外动作时,我会把“准备内容”和“正式执行”分成不同阶段。准备阶段生成可审阅结果,执行阶段记录具体确认与结果。是否需要确认取决于用户授权和实际产品流程,而不是每次都增加一个空泛的弹窗。

一个可靠的小助手,不一定永远不出错。它需要在出错以后留下足够的信息,让人知道工作停在哪里,已经发生了什么,以及重复一次会不会造成新的问题。

工具调用的重试与幂等 · LovelyCat · 2026-10-21

个人学习与创作札记 · 设计参考 Yohaku