当一个AI代理派发一个动作——发消息、订时段、切换设置——它需要知道这个动作到底成没成。问题在于,不是每个后端给出的答案质量都一样。

有的后端会明确告诉你发生了什么;有的给你足够的信息让你自己推断;还有的,什么都不给。如果代理对所有后端一视同仁,那么当某个服务商沉默不语时,它就会做出错误判断。解法是在派发之前就把能力等级显式建模,而不是等派发之后再想办法。

这套模型把后端能力分成四档,用一个枚举类型声明:

  • FULL(完全确认):服务商返回确认结果。你既知道投递发生了,也知道动作被接受了。带写入接口的日历服务、带送达回执的消息平台属于这一档。
  • RECONCILABLE(可对账):派发时没有直接确认,但你可以在事后查询服务商状态,并与派发前的快照做比对,差异会告诉你什么变了。
  • PARTIAL(部分确认):服务商确认收到,但说不清动作是否真的被执行。你知道它到了,但不知道它有没有落地。
  • BLIND(全盲):发出去就不管了。没有回执,没有可查询的状态。你派发了,仅此而已。

等级决定了你的对账策略应该长什么样,而这个决定必须在派发之前做出,不能等到你已经在等一个永远不会来的响应时才想。

代码里用一个派发策略结构体承载这个判断:等级、对账键、最早可对账时间、是否需要人工核验。四档对应四种组合——FULL 不需要对账键,立即可对账,不需要人工;RECONCILABLE 生成对账键,但要等过一个一致性窗口才允许对账,不需要人工;PARTIAL 同样生成对账键、同样等窗口,但需要人工核验;BLIND 没有对账键,最早可对账时间被设成 Instant.MAX,并且需要人工核验。

那个一致性窗口被写死为 30秒。它的作用是强制记录达到最小年龄之后,对账任务才能碰它,用来抵御复制延迟带来的误判。

这些信息最终要落到动作记录里。动作记录本身携带投递状态和接受状态,能力等级和派发策略就挂在旁边一起存。对 BLIND 服务商来说,最早可对账时间是 Instant.MAX,意味着这条记录永远不会进入自动对账流程,它会一直停留在 DENIED_UNRESOLVED,直到有人类或更高层级的信号来把它了结。

规则只有一条:在注册时建模等级,而不是在失败时建模。等到派发已经悄无声息地失败,再决定怎么处理就已经晚了。代理打交道的每个服务商都要声明一个等级,每条动作记录都携带该等级所隐含的策略。下游的对账与确认处理只读记录,不需要知道自己在跟哪个服务商打交道。

这套东西属于一个系列的一部分:第一部分讲两轴状态模型与 DENIED_UNRESOLVED,第二部分讲上下文传播与置信阈值,第三部分讲迟到的确认竞态与终态检查,第四部分就是这里的能力等级。