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
羽毛球分组比赛记分
小程序二维码

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

Xiaoye