dsh-retry-policy:统一覆盖 DSH 全通道模型重试策略

前言

在 DeepSeek Harness(DSH)里跑智能体时,模型请求失败是否重试、退避多久,往往取决于各 adapter 插件在注册表里写死的 retryPolicy,而不是 profile 里一处全局配置。官方 deepseek adapter 默认甚至把 maxRetries 设为 0,失败即不重试。若你希望所有 provider 通道(官方 deepseek、workbuddy、our-free-model、pi-ai、qodercn 等)共用同一套重试规则,又不愿改 DSH 客户端源码,可以在 profile 里加载社区插件 dsh-retry-policy(维护者 User-Clb,分类:模型推理)。下面介绍它的做法、安装与配置。

这是什么

dsh-retry-policy 是 DSH 模型请求重试策略的统一覆盖插件。它在插件 apply 阶段包装 ctx.llm.prepareCall,把每一次模型调用携带的 retryPolicy 换成本插件配置的那一套,从而所有 provider 通道共用同一份重试规则,且不修改 DSH 客户端任何文件。

为什么需要旁路覆盖

DSH 的重试策略链路大致如下:

adapter.providerRetryPolicy(provider)   // 插件内部写死
  -> registration.retryPolicy           // dsh-llm 注册时求值
  -> preparedCall.retryPolicy           // llm.prepareCall 时取出
  -> dsh-llm-retry                      // 监听 agent/request-error 决定重试与退避

profile 的 cordis.patch.yml 只能改插件的 config,改不动 adapter 内部写死的返回值。本插件在 llm 服务的 prepareCall 外再套一层:拿到返回对象后替换 retryPolicy。原对象是 Object.freeze 的,因此浅拷贝出新对象返回;用 llm.__retryPolicyPatched 保证同一进程只包装一次。补丁作用在 llm 服务实例上,与 adapter 插件加载先后无关。

默认行为

未改配置时,净效果为:单次请求失败后固定每 10 秒再试一次,最多再试 20 次(约 200 秒),且仅对下列错误码重试:EMPTY_RESPONSE、RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT。

安装与启用

在 profile 的 package.json 里声明依赖,并把 bundle 名加入 bundles,否则不会加载:

// ~/.dsh/profiles/<profile>/package.json
{
  "dependencies": {
    "dsh-retry-policy": "github:User-Clb/dsh-retry-policy"
  },
  "dsh": {
    "profile": {
      "bundles": [
        // ...
        "dsh-retry-policy"   // ← 加进 bundles 才会被加载
      ]
    }
  }
}

在 profile 目录执行 pnpm install(或在 DSH 插件面板里安装),重启 DSH 生效。

配置

改本包在 profile 中生效的 cordis.patch.yml 里的 config 块即可,无需改插件源码。字段含义如下(越界值会被自动夹取):

- insert:
    - id: dsh-retry-policy
      name: dsh-retry-policy
      inject: [llm]
      config:
        maxRetries: 20          # 单次请求失败后最多再试几次
        initialDelayMs: 10000   # 退避基数
        maxDelayMs: 10000       # 退避上限;与基数相等 => 指数退避被夹平,等效固定间隔
        jitterRatio: 0          # 抖动比例 0..1
        retryableCodes:         # 只有这些错误码才重试
          - EMPTY_RESPONSE
          - RATE_LIMIT
          - SERVER
          - TIMEOUT
          - TRANSPORT
参数 默认 取值范围 说明
maxRetries 20 0..100 达到上限后把错误交给上层(配合 dsh-model-rotation 时,可理解为「扛不过就轮换」)
initialDelayMs 10000 1..600000 退避基数,delay = min(initial × 2^n, max) × jitter
maxDelayMs 10000 1..600000 退避上限
jitterRatio 0 0..1 0 为每次整间隔;越大越分散,避免多通道同步重试
retryableCodes 上述 5 项 非空字符串数组 全非法值时回落到默认列表

验证补丁是否生效

启动 DSH 后在日志中搜索如下一行,应能看到实际参数:

[dsh-retry-policy] 已覆盖模型重试策略: maxRetries=20 initialDelayMs=10000 maxDelayMs=10000 jitterRatio=0 retryableCodes=[EMPTY_RESPONSE,RATE_LIMIT,SERVER,TIMEOUT,TRANSPORT]

仓库 README 还建议对入口文件做语法检查:node --check index.js。

适用场景与注意

适合谁: 需要在多 provider 通道上统一重试次数与退避策略、又不想 fork 或 patch 各个 adapter 的 DSH 用户。

Retry-After 取舍: dsh-llm-retry 中,若服务端返回的 Retry-After 大于 maxDelayMs,normal 模式会直接放弃重试。在默认 maxDelayMs = 10000 下,遇到「429 请等 60 秒」一类响应,插件不会等满 60 秒,而是把错误抛给上层。若希望尊重服务端等待时长,可将 maxDelayMs 调大,例如 60000 或 120000。

运行与信任边界: 插件随当前 DSH profile 加载,以 DSH 进程权限运行。安装前请自行查看 GitHub 仓库 源码与 MIT 许可证;社区目录 SkillHub 插件页 为独立站点,与 DeepSeek / 幻方无官方从属关系。

对外 API(供二次开发或测试):

import { apply, resolveConfig, name, inject } from 'dsh-retry-policy';

resolveConfig(raw) // 纯函数:夹取与规整配置,返回 frozen 对象
apply(ctx, config) // 安装补丁;llm.prepareCall 不可用时只打 warn、不抛错

apply(ctx) 不带 config 时使用 DEFAULT_CONFIG,与 cordis.patch.yml 默认值一致。实现集中在约 97 行的 index.js,依赖 Node.js >=20,peer 为 @deepseek-ai/cordis。

结尾

dsh-retry-policy 用一层 prepareCall 包装,在不改客户端的前提下,把全通道模型重试策略拉到同一套参数上;默认 20 次、10 秒固定退避、零抖动,可按 profile 配置调整。更多信息见 SkillHub 目录页 与 GitHub:User-Clb/dsh-retry-policy。

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

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

小夜