imrcpan/dsh-retry:給模型請求換一套固定間隔的重試策略

前言

這篇文章介紹一個 DeepSeek Harness 插件,叫 dsh-retry,維護者是 imrcpan。它解決的是智能體開發中一個很具體的問題:模型請求算不上貴,但不穩定,尤其是走中轉站(relay)或共享上游池的時候,一次 401 或限流就把整個 turn 帶崩了。

DeepSeek Harness 本身在 agent step 邊界上有重試能力,自帶的 executor 叫 @deepseek-ai/dsh-llm-retry,它只暴露指數退避:initialDelayMs、maxDelayMs、jitterRatio。這套曲線對中轉場景並不友好——等一次 401,可能要退避到幾十秒,而下一次請求換一個上游賬號很可能就成功了。dsh-retry 就是替換掉這條曲線,改用一張固定的時間表。

這是什麼

一句話定位:dsh-retry 是一個 DSH 插件,它替換系統內置的重試 executor,把模型請求的重試間隔從指數退避改成固定調度,並針對中轉端點、共享賬號池和不穩定網絡做了適配。

維護者:imrcpan。分類:模型推理。許可證:MIT。版本:0.1.0。倉庫:https://github.com/imrcpan/dsh-retry ,目錄頁:https://www.skillhub.cn/plugins/imrcpan/dsh-retry 。

下面是它的重試等待時間表:

第幾次重試 1 2 3 4 5 6 及以後
等待時間 2s 5s 5s 5s 10s 20s,不限次數

前 5 次由 schedule 數組控制,之後統一走 tailDelayMs,每次 20s,不設上限。相比指數退避,這條曲線對短暫抖動反應更快,對永久失敗的上游也只是每 20s 重試一次。

核心功能

固定間隔的重試調度

原 executor 使用指數退避,等待時間會不斷翻倍直到上限。dsh-retry 改成顯式調度:2s、5s、5s、5s、10s,之後每 20s 重試一次且不設上限。理由是中轉站的失敗是按賬號發生的,不是按請求發生的:某個後端返回 401 或配額耗盡,下一個 attempt 換到另一個賬號很可能成功,所以等待應該短而固定,而不是越爬越高。

針對中轉端點和不穩定上游的失敗分類

README 明確說明這個 executor 針對 relay endpoint 和不穩定網絡調優,失敗碼覆蓋三類:

  1. 賬號級失敗會被重試。AUTH、QUOTA、ACCOUNT_QUOTA、ACCOUNT_TOKEN_INVALID、INVALID_CREDENTIAL 都在默認重試列表裏。
  2. 網關噪聲會被重試。Cloudflare 和非代理返回的 5xx 歸爲 SERVER,包括根本不是合法 JSON 的 HTML 錯誤頁。
  3. 流損壞會被重試。斷裂的 SSE 幀歸爲 MALFORMED_RESPONSE。

另外 HTTP_* 是前綴規則,覆蓋所有未分類的 4xx,所以 HTTP_404 這類錯誤會被重試而不是直接結束 turn。

重試不產生重複輸出

被重試的 step 在同一個開放 turn 內、針對同一份 durable history 重新執行。模型看不到重試,它只收到被重試 step 重建後的請求,所以不會有半截答案被重複寫一遍。

事件與界面

每次計劃中的重試會追加一條 durable 的 llm/retry 事件,等待結束後追加 llm/retry-started。Chat 界面會渲染形如 Retrying model request (2/5) . 4s 的一行,可展開查看失敗原因和延遲;Trajectory 面板會列出 attempt、錯誤碼和延遲。第 6 次及以後的重試會以 unlimited 形式展示。沒有 toast 彈窗,失敗嘗試的中間輸出不會被保留。

安裝與啓用

插件是一個 DSH bundle:package.json 裏聲明瞭 dsh.bundle.patch,等於 ./cordis.patch.yml。標準安裝會自動掛載新的 executor,並把內置的 llm-retry 下線,不需要手寫 patch。

安裝命令(來自 README):

dsh plugin --profile web add github:imrcpan/dsh-retry

裝完要重啓 profile,因爲組合關係是在啓動時讀取的。重啓後這一行會出現在 Plugins 下,其中的 config 可以編輯。

安裝後插件做了什麼

掛載的 layer 插入 dsh-retry executor 並禁用 llm-retry:

- insert:
    - id: dsh-retry
      name: "dsh-retry"
      config:
        schedule: [2000, 5000, 5000, 5000, 10000]
        tailDelayMs: 20000
        retryableCodes: [ ... ]   # 完整列表見 cordis.patch.yml
- id: llm-retry
  disabled: true

禁用 llm-retry 這一步很關鍵:兩個掛載的 executor 會爭搶同一個失敗,並且各自寫重試鏈狀態。如果 profile 覆蓋了這個設置,要保持它處於 disabled。

從源碼目錄安裝

如果用的是 checkout,需要作爲 bundle 安裝,這樣 manifest 纔會生效:

dsh plugin --profile web add /absolute/path/to/dsh-retry

也接受普通的 file: 依賴,但那樣不會應用 bundle layer,需要手工把上面那段 patch 複製到 profile 的 cordis.patch.yml:

{
  "dependencies": {
    "dsh-retry": "file:./plugins/dsh-retry"
  }
}

配置

config 下有三個鍵:

key 默認值 含義
schedule [2000, 5000, 5000, 5000, 10000] 第 1..n 次重試前的等待毫秒數;數組長度就是有上限的頭部
tailDelayMs 20000 schedule 用完之後每次重試的等待
retryableCodes 見下 值得重試的失敗碼

retryableCodes 裏以 * 結尾的條目是前綴規則。HTTP_* 會命中 HTTP_404、HTTP_409、HTTP_422 以及其他未分類狀態碼。裸 * 會被拒絕,因爲它會命中所有失敗。

默認會重試的失敗碼

code 典型成因
EMPTY_RESPONSE 響應完成但沒有內容塊
RATE_LIMIT HTTP 429 或 provider 的限流錯誤
SERVER HTTP 5xx,包括網關和 Cloudflare 的 5xx
TIMEOUT 請求或流超時
TRANSPORT 連接重置、socket 錯誤、流被截斷
PI_AI_ERROR pi-ai adapter 無法分類的上游錯誤
AUTH HTTP 401 或 403;走共享賬號池時換一個賬號可能成功
QUOTA、ACCOUNT_QUOTA 餘額或賬號配額耗盡
ACCOUNT_TOKEN_INVALID 已存賬號 token 被 401 拒絕
INVALID_CREDENTIAL 池子裏格式錯誤的憑據條目
MALFORMED_RESPONSE SSE 幀損壞或事件類型不匹配
HTTP_* 未分類的 4xx,例如 HTTP_404、HTTP_409、HTTP_422

默認不重試的失敗碼

code 原因
CONTEXT_WINDOW_EXCEEDED compaction 負責恢復,重試會形成循環
INVALID_REQUEST 請求本身錯了,換賬號也救不了
NO_ADAPTER、UNSUPPORTED_REASONING_EFFORT 配置錯誤
MISSING_CREDENTIAL 該路由沒有配置憑據
ACCOUNT_SIGN_IN_REQUIRED 需要人工登錄
ABORTED 取消必須保持終態
UNKNOWN 外部錯誤的兜底 code,無上限重試不安全

如果部署環境的判斷和默認值不一樣,可以把這些 code 加進 retryableCodes。

適用場景與注意

適合誰:使用中轉站、共享賬號池,或上游明顯不穩定的 DSH 部署。這類失敗是按賬號分散的隨機噪聲,固定短間隔重試收益最大。如果走的是穩定直連,內置 executor 已夠用,沒必要換。

幾個必須知道的行爲:

  1. 插件以當前 dsh 進程的權限運行,能讀到什麼憑據就會按該進程的授權範圍使用。安裝前建議先檢查 cordis.patch.yml、index.js 和 LICENSE,確認來源再啓用。
  2. 重試鏈計數器放在內存裏,按 session 一個。host 重啓會結束 turn,不會丟失什麼。只有 agent loop 的請求會被重試,直接調用 ctx.llm.stream() 的地方仍然是單次嘗試。
  3. tail 是真的不限次數。當上遊始終不恢復,turn 會一直停在 retrying 狀態,直到被手工停止。
  4. 重試池子裏的憑據和配額失敗,前提是池子會在下一次 attempt 輪轉。如果池子本身永久耗盡,就會每 20s 循環一次。
  5. executor 自己不會輪換賬號,它只重新發起請求,所以中轉站必須爲下一次 attempt 選中另一個上游。
  6. 每一次 attempt 都是一次單獨計費的 provider 請求。

結尾

dsh-retry 的價值不在於發明新的重試機制,而在於用一張固定時間表替換指數退避,並把 relay 場景下最常見的三類失敗(賬號級、網關級、流損壞)納進重試範圍,同時保證不產生重複輸出。想直接看源碼和配置,可以打開 https://github.com/imrcpan/dsh-retry ,或在 https://www.skillhub.cn/plugins/imrcpan/dsh-retry 查看目錄條目。

生態背景補充一句:DSH 的理念是「一切皆插件」,社區目錄是獨立站點,與 DeepSeek 或幻方沒有官方從屬關係,使用時以插件自身來源爲準。

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

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

小夜