feat(agents): 网络类错误持续重试中间件,断网恢复后任务自动继续 - #1007
Conversation
|
Codex Review: 预 review 基于 发现 1 个需修复的问题。 [P2] 外层 ModelRetry 会重置网络重试预算。 network_retry.py:89 每次 已按实际装配顺序组合两个中间件,用虚拟 monotonic/sleep 与持续 ConnectionError 复现: 验证:该 head 独立快照执行 |
- retry_on=retry_non_network_errors: 预算耗尽后网络错误直接失败,不再被 on_failure 吞成假完成 - 预算不再被外层放大(max_retries+1 次全新 600s) - 组合装配顺序的回归测试(虚拟时钟) + 非网络错误重试语义不变 - tracked decision
|
感谢 review,复现准确,已修复(最新 head [P2] 已修复:预算由 NetworkRetry 独家拥有,外层不再重试网络错误确认根因: 采用你给的第一个方向(避免外层再次重试已耗尽的网络错误):
证据新增
另有 tracked decision: |
|
Codex Review: 仅供参考:本轮预 review 基于 复查上次预算问题:本次修复已阻止外层 ModelRetry 为网络错误反复开启新预算。 实际验证:当前 head 独立快照执行 范围限制:这里确认的是单次模型调用的重试预算。未执行真实断网恢复、用户取消、worker 最终持久状态的 E2E,不把中间件抛异常等同于已经验证完整 Run 的失败/恢复结果。 |
|
很好的角度,不过我还有有一个小建议,直接继承原有的 model_retry 的 middleware,直接放在一个中间件里面,由一个开关控制以及单独的阈值 处理 network 的相关错误。 仅是建议,看一下是否可行 |
按作者建议,把 NetworkRetryMiddleware 改为继承 ModelRetryMiddleware, 在一个中间件内区分两类错误的重试维度: - 网络错误:按 network_budget_seconds(默认600s) 预算退避重试,耗尽显式抛出, Run 以 failed 结束,不再假完成; - 非网络错误:复用父类 max_retries/retry_on(on_failure) 语义。 移除了 retry_non_network_errors 谓词与 graph 里的双中间件装配,避免因装配顺序 或外层重试网络错误而放大预算。网络重试参数用 network_ 前缀与父类非网络重试的 initial_delay/max_delay 区分。 子智能体 graph 同步改用 NetworkRetryMiddleware,补齐其断网恢复能力 (此前只用裸 ModelRetryMiddleware,断网时仍会假完成)。
|
感谢建议,合并方案可行,已按此重构(最新 head 采纳:合并为继承 ModelRetryMiddleware 的单中间件
开关与阈值对应: 随之删除 一并补齐:子智能体 graph 也改用 NetworkRetryMiddleware重构时发现 验证
未运行真实断网/恢复 worker E2E;预算约束用虚拟时钟单测精确断言,真实断网恢复如需要我再补。 |
|
建议简化一下这个文件。主要问题是继承了 ModelRetryMiddleware,却又在同步、异步入口复制了父类的非网络重试逻辑,包括次数统计、退避计算和失败处理,还依赖 langchain.agents.middleware._retry 私有模块。 另外,就是需要完成真实的网络断网测试 |
按作者建议简化:网络重试改为闭包包装 handler,预算内吞网络异常退避重试, 非网络异常原样抛出交给父类 wrap_model_call/awrap_model_call 按 retry_on(排除 网络异常) + max_retries/on_failure 处理。不再复制父类的次数统计/退避计算/失败 处理,不再依赖 langchain.agents.middleware._retry 私有模块。 - is_network_error 改私有 _is_network_error,删除 __init__.py 导出; - 异常链边遍历边判断,不构建中间列表; - 删除 CancelledError 单独捕获(CancelledError 继承 BaseException); - 补网络异常→非网络异常→网络异常回归测试,预算起点跨父类重试保持。
|
感谢建议,已按此简化(最新 head 采纳:handler 包装 + retry_on 排除,不再复制父类逻辑
其余简化: 新增回归:网络异常 → 非网络异常 → 网络异常
关于真实断网测试真实断网/恢复 E2E 需要在运行时把模型 API host 断掉再恢复(如 worker 容器内改 |
现象
断网时,模型调用报
OpenAIConnectionError,ModelRetryMiddleware只重试 3 次就放弃,把错误文本写成 assistant 消息、Run 标记 completed。用户恢复网络后,任务已经「假完成」,还得手动重来。对标
Claude Code 断网恢复后能自动继续——网络错误不烧尽重试预算、按退避持续重试、重试期间任务挂起而非取消。
机理
现有的
ModelRetryMiddleware(max_retries=2)对所有错误一视同仁,都只重试固定次数。但网络错误是可自愈的(恢复后重试就成功),逻辑错误不可自愈(重试也没用),两者没有区分。改进方法
新增
NetworkRetryMiddleware,挂在ModelRetryMiddleware内层(先拦截异常):YUXI_NETWORK_RETRY_BUDGET_SECONDS(默认 600s)内不抛错;CancelledError不吞。效果
断网 100+ 秒任务保持 running,恢复后自动继续完成,零干预;正常逻辑错误仍按原语义快速失败。附 6 个单测覆盖错误分类、退避重试成功、非网络错误透传、预算耗尽、取消不吞。