前言¶
跑智能体任务时最常见的一种失败是:一轮对话跑到一半网络断了——合盖、切 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} 关掉。这种失败和断网无关,请求级重试插不进去。
插件补了三件事:
- 输入框下方给提示条,写明「上次运行被中断(第 3 轮)」,列出结果未知的工具调用(bash、write),让你先核对真实状态再继续。
- 启动时扫描全部会话,把上次以崩溃收尾的会话在侧边栏点一个小黄点,悬停显示「第 N 轮被中断,这些工具调用结果未知:…」。
- 打开这种会话时自动继续末尾那一轮,不需要点按钮。
触发条件是「日志末尾那一轮是 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