周三夜里,你的服务接到一笔订单。

订单服务调用了一个AI接口,用来判断风险等级。接口没返回明确结果,连超时还是拒绝都分不清。你的第一反应很自然:重试一次。

打开网易新闻 查看精彩图片

于是系统又发了一次同样的请求。两头都安静了——没有报错,也没有成功。但第二天对账的时候你发现,这笔订单被处理了两次。

不是因为AI接口重复返回了结果,而是因为你重试的那一次,被当成了一个全新的业务动作。

这不是假设。任何一个请求,如果在第一次响应不明确之后被再次发送,而第二次发送和第一次尝试之间没有任何关联标记,那么同一个业务动作就有机会被发起两次。这一条,恰恰是AI接口接入前最容易被忽略的坑。

先别谈重试,谈谈可观测的请求历史

很多团队在接入AI API之前,会认真讨论一个问题:要不要做重试?重试几次?间隔多久?

这个问题本身没有错,但它不是最优先的。

更该提前想清楚的问题是一个更基础的设计:每一次重试,系统能不能让这次重试和第一次尝试建立起可见的联系?这串联系,在工程上叫可观测的请求历史。

请求历史不是一句空话。它至少包含四样东西:幂等键、处理状态、原始结果、重试结果。

在这样的结构下,测试阶段就能验证一件最关键的事:测试集里的每一次重试,最终都对应到一条记录,并且这条记录带着一个看得见的状态。而不是重试发出去了,日志里却只留下两段互不相干的请求记录,谁也说不清它们是同一次业务动作。

重试的前提:你得能讲清楚这次重试在追哪件事

先往前推一步。为什么重试会和重复执行业务动作扯上关系?

因为AI接口的响应存在一种中间状态:既不是明确成功,也不是明确失败。响应不完整,超时,内容含混,或者返回了无法解析的数据。面对这种不明确的结果,系统如果决定重发请求,就必须让第二次请求知道自己是在"接着问同一个问题",而不是在"问一个全新的问题"。

一个最简单也最常见的错误是:不明确的结果没有被记录下来,直接就发了重试。结果第二次请求没有得到任何上下文佐证,被下游当成了新的业务请求来对待,于是同一笔订单、同一条消息、同一次扣款动作,被触发了两遍。

一句话:如果不把这次"不明确"记录下来,后面任何一个新决策都没有依据——它会假装自己面对的是一个干净的、全新的请求。

一条记录该长什么样

在一个请求进入系统之前,就预先为它定义好一条可观测的记录。这条记录不需要花哨,但字段得够用。

原文给出的字段设计是这样的:请求标识、重试键、处理状态、原始结果、重试结果,以及一个未解决状态。

逐项拆开看:

请求标识,是这次业务动作的身份证。后续所有重试都挂在同一个标识下面,这样不管发了多少次请求,它们都指向同一个原始动作。

重试键,这是幂等性的核心。不是随便生成一个随机串就算完——这个键要能表达"我是我自己的重试",让下游看得出这次请求和之前某次请求的关联关系。

处理状态,记录当前这轮处理走到哪一步了。是刚收到请求,还是已经返回结果,还是卡在不明确的状态里。

原始结果,也就是第一次请求拿到的响应原文。哪怕这个结果含糊不清,也要原样保留。

重试结果,每次重试拿到的响应,统统追加在这一条记录里。

未解决状态,最后一个字段最容易被忽视。它专门用来标记那种既不成功也不失败、但又不能继续自动重试的情况。这个状态存在的意义,是让不确定性的东西有一个安放的位置,而不是被下一次重试冲走。

记录的目的:不是宣布重试安全,而是让重试有迹可循

有人可能会问:把这些字段都存下来,是不是就证明重试是安全的了?

不是。

这套记录结构的目的,从来不是为了宣布"重试是安全的"。它要做的事情更朴素:在业务动作被重复发起之前,让重试请求先和那条已经存在的记录绑定。

换句话说,检查的对象不是某个单独的响应好不好看,而是一次业务尝试的完整历史。

这是整篇文章里第一个重要的观念转变:重试不再只是一个传输层面的细节,它变成了一个决策对象。

围绕这次重试,系统需要回答三个问题:

第一,在发出这次重试之前,我们已经知道了什么?

第二,重试之后,情况发生了什么变化?

第三,如果原始结果和重试结果对不上,这个差异应该由谁来排查?

这三个问题,每一项都要落到那条记录上,才算真正有了答案。

边界同样重要:记录不能证明动作只执行了一次

有一条界限需要划清楚:一条记录的存在,并不等于这次业务动作真的只执行了一次。

记录能做到的,是让下一次决策有据可依。它把"这个请求到底发生了什么"摆到桌面上,而不是让系统在黑暗中猜测。

所以,在动手设计重试机制之前,先确认一件事:你是否能回答"这次重试在追哪件事"?如果答不上来,那么重试按钮越方便,重复执行业务动作的风险越大。

自动化该在哪里停下

这套日志机制最宝贵的时刻,恰恰不是结果明确的时候,而是结果不明确的时候。

当原始结果和重试结果对不上,或者两者都是模糊状态,系统面对一个选择:继续自动重试,直到拿到明确答案;还是停下来,把这条记录交给人工判断。

两种选择都有代价。继续重试,可能让同一个业务动作第三次、第四次被触发;停下来,意味着响应时间变长,需要人介入。

关键在于:不管选哪条路,那条记录都必须先存在。因为只有把不明确的结果固定下来,后续无论走自动还是人工,才不会把一个悬而未决的问题伪装成一次干净的成功。

这,才是接入AI之前真正需要定下来的事。