dsh-undici-timeout-fix:去掉 undici 300 秒 body 超時,避免本地模型 prefill 被掐斷

前言

在 DSH 裏接 LM Studio 等本地推理服務時,長上下文 prefill 往往要安靜算很久。若請求在恰好五分鐘後失敗,客戶端報 terminated,模型端日誌卻是 Client disconnected,很容易先懷疑 DSH 或 provider 的 streamIdleTimeoutMs。實際上,Node 內置 fetch 走 undici,連接級 bodyTimeout 默認 300,000ms,且是「空閒計時」:prefill 階段沒有 body 字節時計時器不會重置,五分鐘後 undici 會直接銷燬 socket。下面介紹社區插件 dsh-undici-timeout-fix(維護者 lilinhua0413,分類:模型推理)如何在不改 DSH 本體的前提下處理這一層限制。

這是什麼

dsh-undici-timeout-fix 是一個 DSH Cordis 插件(npm 包名 dsh-undici-timeout-fix,當前資料中的版本爲 1.1.0,MIT 許可)。它通過替換 undici 的全局 dispatcher,將 headersTimeout 與 bodyTimeout 設爲 0(表示禁用計時器,而非設成某個時長),從而避免本地模型長時間 prefill 時被 undici 的 300 秒 body 超時切斷。

DSH 經 @deepseek-ai/dsh-llm-pi-ai(pi-ai)調用 OpenAI 兼容 SDK,該 SDK 使用全局 fetch(Shims.getDefaultFetch())。插件在加載時安裝 dispatcher,因此覆蓋模型相關 HTTP 請求,無需 patch DSH 核心。

問題與 streamIdleTimeoutMs 的區別

本地模型 prefill 超過約五分鐘後,典型現象是請求以 terminated 結束,服務端出現 Client disconnected。原因不在 DSH 某一項「總超時」開關,而在 undici 默認 bodyTimeout: 300_000ms。

streamIdleTimeoutMs 配置的是 DSH / pi-ai 自己的流空閒看門狗,是另一套計時器。在未裝本插件前,它也在 300,000ms 處可能觸發;僅把 streamIdleTimeoutMs 調大,往往只是讓 undici 先觸發,報錯會從 stream idle timeout after 300000ms 變成單純的 terminated。本插件針對的是 undici 傳輸層;裝插件之後仍建議爲本地 provider 單獨配置足夠大的 streamIdleTimeoutMs,作爲有限兜底(見下文)。

核心功能

  1. 插件加載時執行 setGlobalDispatcher(new Agent({ headersTimeout: 0, bodyTimeout: 0 })),禁用 undici 連接級 header/body 空閒超時。
  2. 通過 Cordis patch 註冊插件 id undici-timeout-fix,與 DSH 插件體系集成。
  3. 依賴 undici(package.json 中爲 ^8.10.2),要求 Node >=22.19。
  4. README 說明:未聲明 peerDependencies,一般不會被 DSH 插件版本兼容性檢查攔截。

安裝與啓用

安裝前請自行查看 GitHub 倉庫 源碼與 MIT 許可證。插件在 DSH 進程權限下運行,與任何第三方插件一樣,安裝即信任其代碼行爲。

從 Release 包安裝(不依賴插件 registry)

從倉庫 Releases 下載 dsh-undici-timeout-fix-1.1.0.tgz,再執行:

dsh plugin --profile <your-profile> add /path/to/dsh-undici-timeout-fix-1.1.0.tgz

依賴 undici 仍會從你能訪問的 npm registry(或內網鏡像)解析。

從 npm 安裝

dsh plugin --profile <your-profile> add dsh-undici-timeout-fix

也可在 DSH 插件管理界面添加包名 dsh-undici-timeout-fix,並將安裝源指向提供該包的 registry。若 pnpm 的 minimumReleaseAge(默認 24 小時)導致裝到舊版本,可指定:

dsh plugin add dsh-undici-timeout-fix@1.1.0

手動寫入 patch

在 profile 的 cordis.patch.yml 中增加:

- insert:
    - id: undici-timeout-fix
      name: 'dsh-undici-timeout-fix'

必須完全重啓 DSH

dispatcher 在插件加載時設置;已運行進程不會熱更新。完全退出 DSH 後再啓動(macOS 需 Cmd+Q,僅關窗口不夠)。README 指出,漏重啓是「裝了仍失敗」最常見原因。

典型配置:本地 provider 的 streamIdleTimeoutMs

本插件去掉傳輸層 300 秒上限後,DSH 側若沒有有限看門狗,真正卡死的連接可能長期掛起。應對每一個指向本地模型的 provider 設置足夠大但有限的 streamIdleTimeoutMs;未配置的 provider 仍退回默認 300,000ms。

示例(來自 README,字段名與結構請按你實際 profile 調整):

- id: llm-pi-ai
  name: "@deepseek-ai/dsh-llm-pi-ai"
  config:
    providers:
      lmstudio1:
        displayName: lmstudio
        apiKeyEnv: LMSTUDIO1_API_KEY
        api: openai-completions
        baseURL: http://127.0.0.1:1234/v1/
        streamIdleTimeoutMs: 1800000   # 30 分鐘
        models:
          - id: qwen3.5-122b-a10b
            name: qwen3.5-122b-a10b

若不想完全禁用 undici 計時,可在自研或 fork 中採用有限值(README 示例爲 3,600,000ms);本插件默認策略是 0 表示禁用。

驗證與排錯

  1. 發送一次 prefill 明顯超過五分鐘的請求;若正常完成,說明修復已生效。
  2. 根據報錯區分計時來源:
報錯 含義
terminated undici 傳輸層——本插件負責
pi-ai stream idle timeout after xxxms DSH 看門狗——增大對應 provider 的 streamIdleTimeoutMs

適用場景與注意

適合誰: 在 DSH 中通過 OpenAI 兼容接口調用本地大模型(如 LM Studio),且 prefill 或長時間無 body 輸出會超過五分鐘的開發者。

代理環境變量: 不要設置 HTTP_PROXY、HTTPS_PROXY、ALL_PROXY。dsh-http-proxy 會在 boot 階段安裝自帶五分鐘限制的 Agent,並覆蓋本插件;DSH 先裝 proxy、後加載插件,因此無代理時本插件纔可靠生效。

平臺: README 記錄 macOS(Darwin 24,Node 24.21.0,內建 undici 7.29.1)已測試可用;Windows 尚未驗證,代碼無平臺專用邏輯,歡迎通過 issue 反饋。

生態說明: DSH 採用「一切皆插件」的 Cordis 擴展方式;SkillHub 目錄頁 爲社區收錄,與 DeepSeek / 幻方無官方從屬關係。

結尾

dsh-undici-timeout-fix 把問題定位在 undici 全局 fetch 的默認 body 空閒超時,用最小侵入的方式換全局 dispatcher,並提醒同時配置 streamIdleTimeoutMs 與避免代理插件搶 dispatcher。若你正在排查「本地模型五分鐘必斷」,可先對照報錯表區分 undici 與 pi-ai 看門狗,再按 README 安裝並完整重啓 DSH。

  • 目錄頁:https://www.skillhub.cn/plugins/lilinhua0413/dsh-undici-timeout-fix
  • GitHub:https://github.com/lilinhua0413/dsh-undici-timeout-fix
羽毛球分组比赛记分
小程序二维码

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

小夜