dsh-llm-network-retry:断网时不让一轮对话死掉

前言

跑智能体任务时最常见的一种失败是:一轮对话跑到一半网络断了——合盖、切 VPN、弱网握手超时。DSH 自带的 @deepseek-ai/dsh-llm-retry 确实会重试,但预算来自 provider 的 retryPolicy,默认 normal 只有最多 5 次,约 10 秒就放弃。结果是轮次结束,必须手动点「继续」。

elfgzp/dsh-llm-network-retry 专门为这个场景做插件:连接类失败无限重试,直到网络恢复;其它错误仍然有界,让真正的 400、鉴权、上下文超长立刻失败。

下面介绍它的定位、安装、配置与边界。事实来自插件 GitHub README 与 package.json。

这是什么

一句话定位:挂到 agent loop 的重试瀑布上,给「网断了」这一类失败加一条无上限重试链。

  • 插件名:dsh-llm-network-retry
  • 维护者:elfgzp
  • 分类:模型推理
  • 版本:1.2.0
  • 许可证:MIT
  • 星标:0

它实现的是 Codex CLI 里的 unbounded_connection_retries 规则:只有 ConnectionFailed 这类「网断了」的错误无上限重试,从 5 s 起翻倍到 60 s;其余照旧有界。装好即生效,不需要配置。

核心功能

重试预算分开,不把 token 烧在死路上

它和自带 llm-retry 的区别不在「能不能重试」,而在预算从哪来:

自带 llm-retry 本插件
默认预算 provider retryPolicy,默认最多 5 次 连接类失败无上限;其它 5 次
默认退避 500 ms → 10 s 连接类 5 s → 60 s;其它 500 ms → 10 s
约多久放弃 ~10 秒 连接类永不放弃;其它 ~10 秒
断网 10 秒 轮次结束,需手动「继续」 自动接上

换句话说,插件的改变是「值不值得等」的判断:死链不值得等,活链应该一直等到恢复。

不重复建链

插件 prepend 在自带执行器之前,连接类失败由它一家接管成一条无限链,而不是「自带 5 次 + 本插件再来一条」。已经声明 mode: always 的 provider 则完全让给它,不叠加。这样避免两个执行器各建重试链、互相抢预算。

每条重试都是真实计费请求

无上限模式会一直重试到成功或你取消为止。这是它的设计目的,但需要知悉:等待期间每次重试都是一次真实请求。

崩溃中断的那一轮,另走一条链路

进程被杀、崩溃或关闭超时后,agent-loop 会在下次启动时发现日志末尾有一轮没闭合,补一条合成 turn/end{interrupted} 关掉。这种失败和断网无关,请求级重试插不进去。

插件补了三件事:

  1. 输入框下方给提示条,写明「上次运行被中断(第 3 轮)」,列出结果未知的工具调用(bash、write),让你先核对真实状态再继续。
  2. 启动时扫描全部会话,把上次以崩溃收尾的会话在侧边栏点一个小黄点,悬停显示「第 N 轮被中断,这些工具调用结果未知:…」。
  3. 打开这种会话时自动继续末尾那一轮,不需要点按钮。

触发条件是「日志末尾那一轮是 interrupted」,不看启动来源。这样能同时做到三件事:崩溃会话会续跑,三个月前的正常会话不动,崩溃可复现时不循环(下次重启不再自动续,改为留给人工判断)。

两条实现细节值得留意:扫描是只读的(open(id, 'read'),不取写权),有限并发默认 4,单会话读失败只跳过、不影响其它,且可取消;继续消息用 agent.followup() 而不是 sessionController.prompt(),因为后者会把消息源写成 user-rpc,日志里看不出这条来自插件。

判定表

哪类错误重试、哪类不重试,按下表:

失败 code 行为
TRANSPORT / TIMEOUT / NETWORK 无上限,5 s → 60 s
SERVER / RATE_LIMIT / EMPTY_RESPONSE 有界,默认 5 次,500 ms → 10 s
AUTH / QUOTA / CONTEXT_WINDOW_EXCEEDED / INVALID_REQUEST 不重试,立即交给下游
本轮已取消 不重试,且不惊动下游
未列出的 code 交给下游(preset: always 时改为重试)

服务端返回的 Retry-After 会被尊重——只要不超过本策略上限;超过上限就用本地退避,策略不会就此终止。

安装与启用

需要 DeepSeek Harness 0.2.x。

Web 界面:侧边栏 → 插件 → 添加插件 → 安装第三方插件,粘贴仓库地址:

https://github.com/elfgzp/dsh-llm-network-retry

确认后在「已安装插件」里打开网络重试。

让 agent 装:在开启了插件管理工具的会话里说

从 https://github.com/elfgzp/dsh-llm-network-retry 安装这个插件并启用

命令行:

dsh plugin --profile <profile> add "github:elfgzp/dsh-llm-network-retry#main"

装完直接对话即可,断网时聊天里会出现重试行自己倒数。改了 config 或更新了插件代码,把插件 toggle 一次(关掉再打开)就会重载;唯独新增浏览器半边需要重启一次 Harness。

配置

默认值就是 Codex 的形状,config 留空即可:

- insert:
    - id: llm-network-retry
      name: dsh-llm-network-retry
      config:
        preset: codex
        maxRetries: 5
        unboundedConnectionRetries: true
        maxUnboundedWaitMs: 0
        providers: []
        models: []
        honorRetryAfter: true
        respectProviderPolicy: true
        requestBackoff:
          initialDelayMs: 500
          maxDelayMs: 10000
          jitterRatio: 0.1
          multiplier: 2
        connectionBackoff:
          initialDelayMs: 5000
          maxDelayMs: 60000
          jitterRatio: 0.1
          multiplier: 2

三种 preset:

  • codex(默认):连接类无上限,其它有界。日常用这个。
  • always:只要不是致命错误就无上限重试。适合「宁可等一小时也别断」的长任务。
  • normal:任何情况都不无上限,等价于自带 llm-retry 的默认行为,只是预算由本插件管。

写错字段名会在激活时直接报错,不会悄悄不生效。

典型用法

安装后无需额外配置,直接对话即生效。断网时聊天里会渲染原生的重试行,样式大致是:

↻ 正在重试… 3/∞ · 12 秒后   连接被重置

崩溃中断的会话打开后会看到提示条,选择「继续上次任务」即可让模型按顺序做:先核实真实状态(文件、Git、远端、服务)→ 只直接重试只读或幂等操作 → 有副作用的先确认是否已生效 → 状态不清楚先问你。这正是插件刻意的设计:进程死亡时可能有 git push、npm publish、部署在飞,不能盲目重放。

适用场景与注意

适合经常跑长任务、且会受网络切换影响的 DSH 用户,尤其是希望断网窗口(合盖、VPN、弱网)不打断一轮对话的场景。

需要注意几点:

  • 插件以当前 dsh 进程权限运行。安装第三方插件前,应先检查源码与许可证(MIT)。
  • 只覆盖模型请求失败的这一层。工具调用、shell 命令失败各有自己的超时与重试语义,插件不碰。
  • 直接调用 ctx.llm.stream() 的代码不走 agent loop,因此不享受这里的重试(自带执行器也是同样边界)。
  • 崩溃恢复只处理日志末尾那一轮,更早的中断轮次已被后续轮次覆盖,页面不会追问。
  • 社区目录是独立站点,与 DeepSeek / 幻方无官方从属关系,这不是官方应用商店。

结尾

这个插件的价值很收敛:把「网络断了」这类本可以自愈的失败,从需要手动继续,变成自动接上;同时不改变真正该快速失败的错误的行为。默认配置即 Codex 的形状,需要时再调 preset 和退避。

目录页:https://www.skillhub.cn/plugins/elfgzp/dsh-llm-network-retry

GitHub:https://github.com/elfgzp/dsh-llm-network-retry

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜