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。

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

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

小夜