结果未知与无进展如何停止循环
一句话收获:超时不是失败证明;没有新证据时继续循环只会放大风险。
这个场景在解决什么问题
这个场景讲的是:当一次写入操作"超时了、不知道结果"时,或者循环"转了很多轮却没有任何进展"时,该怎么安全地停下来。目标(goal)是实现四个出口机制:查询优先、重复检测、预算、接管出口。观察点(observation)是:拿"写入超时"这个场景,对照两种做法——盲目重试 vs 受控恢复。
为什么值得单独学?因为超时是 Agent 里最常见的坑:你以为失败了就重试,结果可能已经执行过了,重试会造成重复副作用。这个场景告诉你:超时≠失败;在没有新证据的情况下继续循环,只会把风险越滚越大,正确做法是查询、检测、必要时停下交给人接管。
先理清这条判断链(文字版)
这个场景的四步讲的是从"超时"到"受控收束"的正确处理路径,本质是"识别超时 → 禁止重试 → 查询无果 → 受控收束":
- 写入超时了,客户端没收到结果,但外部动作可能已经发生——先承认"结果未知"。
- 禁止直接重试同一写入,保存幂等依据(防止重复副作用),改走查询。
- 连续查询还是返回相同结果、预算下降、状态不变,正式判定"无进展"。
- 受控收束:查询确认了唯一对象就完成;仍未知就生成接管包并停止。
这条链的核心逻辑是:结果未知时先查、不盲试;查也查不出新东西时,就停下交人,而不是硬着头皮继续。
逐层详解
第 1 步:写入超时
原文:客户端未收到结果,外部动作可能已经发生。
白话:客户端发起一个写入(比如创建订单、发起退款),结果超时了、没收到响应。这时候要意识到:外部系统那边的动作,可能其实已经执行了,只是回执没传回来。结果处于"未知"状态。
类比:像你发微信问朋友"帮我订票了吗",对方一直没回——票可能已经订了,也可能没订,你不知道,但不能默认"没订"。
举例:Agent 调用"创建订单"接口,等了 30 秒超时、没收到回执。这个订单在外部系统里可能已经创建成功了,只是网络把回执吞了。此时业务结果未知,不能想当然。
为什么重要:传输状态与业务状态分离。也就是说,"我没收到响应"是传输层面的状态,和"业务上到底做没做"是两回事,必须分开看待。
怎么验证(证据点):
- 超时发生:确实发生了超时。
- 操作身份存在:这次操作有一个唯一身份标识(如请求 ID)。
- 业务结果未知:业务侧结果确实还没确认。
别踩的坑(边界):没有响应不能推出没有执行。意思是,不能因为"没收到响应"就推断"没执行"——这是最常见的误判。
落地检查:先进入 result_unknown。也就是说,落地时遇到超时,第一步是把状态标记为"结果未知(result_unknown)",而不是直接判断成败。
第 2 步:禁止直接重试
原文:Harness 阻断同一写入并保存幂等依据。
白话:Harness 拦截"对同一个写入的直接重试",防止重复提交;同时保存"幂等依据"(比如幂等键),让后续即使重复提交也不会产生重复副作用。改走"查询"来确认结果。
类比:像网上购物点了两次"支付"按钮——系统靠订单号做幂等,第二次点击不会真的再扣一次钱,而是提示你"去查订单状态"。
举例:退款写入超时后,Harness 用同一个幂等键阻断再次发起退款,保存这个幂等依据,然后引导流程去查询"这个退款到底成功没",而不是再点一次退款。
为什么重要:重复提交可能产生重复副作用。也就是说,直接重试很可能把已经发生过的事再做一遍,产生重复副作用(比如重复退款)。
怎么验证(证据点):
- 重试被阻断:同一写入的重试被拦住。
- 幂等依据保留:幂等键被保存下来。
- 查询入口存在:有查询权威状态的入口。
别踩的坑(边界):阻断不等于永久失败。意思是,拦住重试不代表这事永远做不成了——只是换一种更安全的方式(查询)去推进。
落地检查:下一步是查询权威状态。也就是说,落地时阻断重试后,下一步是去权威来源查询真实状态,而不是干等或再试。
第 3 步:查询仍无新证据
原文:连续查询返回相同结果,预算下降且状态不变。
白话:于是去查询权威状态,但连续查了好几次,返回的都是相同结果、状态没有任何变化,预算(还能试的次数)却在不断下降。这时候要正式判定:没有进展了。
类比:像反复刷新物流页面,状态一直是"运输中",刷了十次都一样,你就该判断"现在查不出新东西了",而不是继续无限刷。
举例:退款超时后,连续查询 5 次,退款状态始终是"处理中"、没有任何变化,同时预算从 10 次降到 5 次。系统据此判定"无进展(progress delta = 0)"。
为什么重要:无进展需要正式检测。也就是说,"一直没进展"不能靠感觉,要有正式的检测机制(比如 progress delta 为 0)来判定。
怎么验证(证据点):
- 相同动作:连续在做相同的动作。
- 相同结果:得到的结果一致。
- progress delta 0:进展变化量为 0。
别踩的坑(边界):系统仍在调用不代表任务推进。意思是,系统还在忙、还在调接口,不代表任务在往前推进——可能只是在空转。
落地检查:改变策略、等待或接管。也就是说,落地时一旦判定无进展,就要改变策略、或主动等待、或交给人接管,不能继续空转。
第 4 步:受控收束
原文:查询确认唯一对象后完成;仍未知则生成接管包并停止。
白话:最后是"受控收束"——两条路:如果查询最终确认了那个唯一对象(比如退款确实成功了),就正常完成;如果怎么查都还是未知,就生成一个"接管包"(把情况打包交给人),然后停止循环。
类比:像客服处理一个查不清的订单——能查清就给你结论,查不清就整理一份"所有已知信息 + 待你确认项"的工单,转给人工,而不是继续乱点。
举例:退款查询最终确认"订单已退款、对象唯一",任务完成;如果始终查不到、状态一直未知,系统生成接管包(目标、已做动作、未知点、风险),停止循环,交给人来判断。
为什么重要:两种出口都比盲目重试可靠。也就是说,无论是"确认完成"还是"交人接管",都比无脑重试更安全可靠。
怎么验证(证据点):
- 权威状态:有权威来源的状态作为依据。
- 停止原因:清楚记录为什么停止。
- 接管材料:接管包材料齐全。
别踩的坑(边界):停止不是把责任空洞转给人。意思是,停止并交人,不是甩锅式地扔一句"搞不定"就完,而是要给足材料让人能接手。
落地检查:接管者必须能独立判断。也就是说,落地时生成的接管包,要让接手的人不依赖你也能独立做出判断。
落地可行性小结
本场景涉及的技术栈和落地要点:写入超时、result_unknown(结果未知状态)、幂等(幂等键)、Harness 阻断重试、权威状态查询、progress delta(进展变化量)、接管包(handoff package)。
真实落地时要注意:写入操作必须带唯一身份标识(请求 ID / 幂等键),否则没法在超时后查询;超时后先标记 result_unknown,再走查询,绝不直接重试;要有"无进展检测"(progress delta = 0 或连续相同结果)来触发停止;停止时生成的接管包要包含目标、已做动作、未知点、风险、剩余选项。常见坑是:把"没收到响应"当成"没执行"而直接重试;以及无进展时继续空转,让风险越滚越大。
回顾
- 超时不是失败证明——没收到响应不等于没执行。
- 超时后先标记 result_unknown,再查询,而不是直接重试。
- 重复提交可能产生重复副作用,靠幂等依据阻断。
- 无进展要正式检测(progress delta 为 0),系统在忙不代表任务在推进。
- 受控收束只有两条路:确认唯一对象后完成,或生成接管包停止交人。