DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-llm-failover

g

dsh-llm-failover

Discovered

DeepSeek Harness model auto-failover plugin: retry threshold -> mark unavailable -> seamless switch to next healthy model -> cooldown auto-recover. 18-model pool, 19/19 tests, boot-safe.

dsh-llm-failover

When your model goes down, your task doesn't.

DeepSeek Harness 的社区模型自动故障切换插件。当 Provider 出现 429 / 5xx / 超时 / 网络错误 / SSE 中断时,自动切换到健康模型继续执行,而不是让整个任务失败。

⚠️ Community plugin for DeepSeek Harness. Not affiliated with or endorsed by DeepSeek.

version license MIT node tests boot-safe

What & Why

你在用 DeepSeek Harness 跑任务,突然当前模型挂了——429 限流、5xx 服务端错误、超时、网络断连、SSE 流中断。没有 failover 插件时,整个任务直接失败,你得手动重试。

本插件在 Provider 级别实现自动故障转移:

Provider A (DeepSeek V4)
  │
  ├── 5xx / Timeout / Transport / 短促 429 ──► 阈值(默认 5 次,抖动交给 retry 层吸收)
  │                                              │
  │                                              ▼
  │                                        A 停车(60s 起,连续停车翻倍)
  │
  └── 配额用尽 / 用量窗口 / 上游公布长时间重置 ──► 墙:第一次就切
                                                 │
                                                 ▼
                                           A 停车到上游说的重置时间
                                                 │
        ┌────────────────────────────────────────┘
        ▼
Switch to Provider B (next healthy model in priority pool) — 半开的不抢健康 provider
  │
  ▼
Task continues seamlessly — same session, same context
  │
  ▼
Cooldown expires → A 以「探针」身份入场,一次请求定生死
  │
  ├── 出活(assistant message 证明)→ 记录清空、惩罚归零
  └── 又失败 → 立刻回停车(不用重攒阈值),冷却翻倍(封顶 maxCooldownSeconds)

「墙」不靠猜:上游公布的重置时间(providerRetryAfterMs、正文里的 resets at <ISO>、"retry again in N 单位")原样采用;账号级措辞("usage limit for your plan"、"insufficient credits"…)按无公布时间的墙处理;模糊说法(单独一句 "quota exceeded")不算墙。判定表与取舍见 docs/architecture.md。

Features

  • 自动 Retry + Failover — 基于 agent loop 的两个公开 waterfall 扩展点,零修改核心循环
  • 墙与抖动分开 — 配额/用量窗口这类"确定要等到重置"的失败第一次就切,并按上游公布的时间停车(上界 30 天);5xx、超时、传输、流中断、短促 429 仍走阈值
  • half-open 探针 — 冷却到期不直接放行,而是放一次探针请求:成功才恢复,失败立刻回停车且冷却翻倍(封顶);上游公布的时间永远原样使用(信息不打折,只惩罚递增)
  • Provider 健康管理 — 按 provider 粒度跟踪连续失败次数、停车原因与累计停车次数
  • 优先级池切换 — models 数组顺序即优先级;半开状态的 provider 不抢占健康 provider
  • 双通道恢复 — 冷却到期惰性入场探针 + assistant message 主动证明恢复(改道后的歧义证据会被拒收,避免冷却被自己发起的切换绕过)
  • 最大切换保护 — 单回合切换上限防止死循环
  • 错误分类 — 7 种可恢复错误 + 多种永久错误,精确决定是否切换;每类一个开关
  • 终止时说得清 — 所有 provider 都停车时,日志给出最早恢复的是谁、还有多久,并附全 provider 状态快照
  • 两套本地测试 — node --test test/failover.test.mjs(22 项,node:test 风格)+ node test/smoke.test.mjs(46 项,纯离线、不需要 harness)
  • 敏感信息日志脱敏 — URL 凭据 / Bearer token / key 参数自动掩码
  • Session 安全设计 — 不写自定义事件类型,避免会话重载兼容问题
  • 与 llm-retry 共存 — 阈值以下决策权归 llm-retry,达到阈值才由本插件接管;下游任何决定都原样尊重

Installation

三步手工操作,不联网、不 npm install:

# 1. 复制插件到 Harness(排除 node_modules)
$dst = "<DSH安装目录>\\resources\\app.asar.unpacked\\node_modules\\@deepseek-ai\\dsh-llm-failover"
New-Item -ItemType Directory -Force -Path $dst | Out-Null
Copy-Item "<本仓库目录>\\*" $dst -Recurse -Force -Exclude node_modules

# 2. 把 patches/cordis.patch.snippet.yml 的内容追加到 DSH home 下的 profiles\\desktop\\cordis.patch.yml 末尾
#    DSH home 默认:Windows %USERPROFILE%\\.dsh / Linux·macOS ~/.dsh

# 3. 重启 DeepSeek Harness Desktop

启动日志出现 llm-failover active 即加载成功。详见 INSTALL.md。

完全可逆:删目录 + 删配置块 + 重启。

更省事的部署方式(推荐):不要拷进 harness 本体(升级会覆盖),而是放在 harness 之外的覆盖目录里,用 profile 的 link: 依赖指过去;改了代码用 node tools/sync-to-dsh.mjs --dest <覆盖目录> 同步(先备份再覆盖)。见 INSTALL.md。

Quick Configuration

models 数组的顺序就是故障切换优先级——排在第一位的是主模型,后面的依次作为备份。

- insert:
    - id: llm-failover
      name: '@deepseek-ai/dsh-llm-failover'
      config:
        enabled: true                  # 总开关
        models:                        # 故障切换池(顺序 = 优先级)
          - provider: deepseek-official
            model: deepseek-v4-flash
          - provider: my-siliconflow   # llm-pi-ai settings 里的 profile 名
            model: deepseek-ai/DeepSeek-V3
        maxConsecutiveFailures: 5      # 「抖动」类失败:同一 provider 连续失败多少次后切换
        cooldownSeconds: 60            # 抖动类的停车时长(必须 > 0)
        quotaCooldownSeconds: 14400    # 「墙」类(配额/用量窗口,且上游没给重置时间)的停车时长
        maxCooldownSeconds: 86400      # 连续停车翻倍的上限
        autoRecover: true              # 冷却到期是否自动入场探针
        maxSwitchesPerTurn: 8          # 单回合最大切换次数

未配置键取默认值;未知键不会导致报错,只记录警告后忽略。models 为空时插件保持惰性。

Per-class failover switches

SwitchDefaultControls
failoverOnRateLimit✅ trueHTTP 429
failoverOnTimeout✅ true请求/连接/空闲超时
failoverOnServerError✅ trueHTTP 5xx
failoverOnTransportError✅ true网络/代理链路异常
failoverOnStreamInterrupted✅ trueSSE 流中断
failoverOnEmptyResponse❌ false退化空补全
failoverOnQuota✅ true配额/余额/用量窗口(第一次就切,停到上游说的重置时间)

Error Classification

ErrorDefault BehaviorWhy
RATE_LIMIT (429)Failover(抖动走阈值;点明重置时间/账号级措辞的按墙立即切)限流可能是瞬时,也可能是计量窗口,用措辞区分
SERVER (5xx)Failover服务端瞬时故障
TIMEOUTFailover请求/连接超时
TRANSPORTFailoverDNS、连接重置/拒绝、代理异常
STREAM_CLOSEDFailoverSSE 流中途中断
EMPTY_RESPONSERetry only可安全重复,不一定需要切模型
QUOTAFailover(墙:第一次就切,停到重置)配额是事实不是抖动;同 provider 重试必然再失败
AUTH / INVALID_CREDENTIALNever failover凭证问题,切换无用
INVALID_REQUEST / UNKNOWN_MODELNever failover请求本身有误
CONTEXT_WINDOW_EXCEEDEDNever failover交给 compaction 处理
ABORTEDNever failover用户主动取消

Architecture

agent/request-error (请求失败恢复点) —— 本插件是最外层
  │
  ├── 永久错误 → 永不切换,让错误冒泡
  │
  ├── 「墙」(配额/用量窗口/长时间重置)→ 第一次就切:停车到重置时间
  │
  └── 「抖动」→ 计数
      ├── 未达阈值 → 交给下游栈(通常是 llm-retry),任何下游决定都原样尊重
      └── 达到阈值 → 停车(冷却翻倍,封顶)→ 切换到下一个健康目标

agent/request (每次构建请求时)
  │
  └── 目标 provider 处于停车期 → 自动改写到最优健康条目
      (健康 > 半开:半开的不抢占健康的)
      └── 改写时丢弃继承的 reasoningEffort(属于失败路由的每模型设置)

session/event (assistant/message)
  └── 出活 = 证明恢复:清空该 provider 的记录与惩罚
      (冷却期内、且刚被改道过的"成功"判为歧义并拒收 —— 否则冷却会被自己发起的切换绕过)

恢复是双通道的:冷却到期后以探针身份惰性入场(一次请求定生死);任何 assistant 消息证明某 provider 成功出活时立即恢复。冷却中的 provider 不会被当作切换目标,除非所有 provider 都在停车;那时日志会给出最早恢复的那个是谁、还有多久。

详见 docs/architecture.md(状态机、判定表、与 retry 层的分工)。

Project Status

Release Candidate — 版本 0.2.0-rc.1

  • ✅ 核心 failover 功能已实现并通过两套本地回归测试(node --test test/failover.test.mjs 22 项 + node test/smoke.test.mjs 46 项,合计 68 项,都不需要 harness 在场)
  • ✅ 启动安全设计经真实加载器验证(见 INSTALL.md 的安装前冒烟彩排)
  • ✅ 已安装进真实 DSH Desktop 环境(2026-08-27)
  • ✅ 冷却保护(2026-09-21):切换后返回的"成功"证据若与插件自己发起的改道冲突,会被判为歧义并拒收,避免冷却被提前取消
  • ✅ 墙/抖动分开 + half-open 探针(2026-09-25):配额与用量窗口第一次就切并按上游公布的重置时间停车;冷却到期改为放一次探针,探针失败立刻回停车且冷却翻倍封顶;终止日志给出最早恢复时间与全 provider 状态。判定表与取舍见 docs/architecture.md,借鉴来源见下
  • ✅ QA 彩排脚本 6 个(smoke / badconfig / disabled / doc-crosscheck / s0-session-compat / final-round)
  • 🔄 当前生产配置:4 个目标,每厂商一条 —— deepseek-official/deepseek-flash、bailian/qwen3.8-flash、ark-plan/glm-5.3-flash、commandcode/deepseek/deepseek-v4.1-flash

Intentionally descoped

  • 会话内可见切换提示 — DSH 当前未暴露注册自定义会话事件类型的扩展点,插件侧不存在受支持的实现通道。详见 docs/session-compatibility.md。
  • 自动推导备份模型 — 切换目标必须显式列在 models 里,不会从适配器目录自动推导。
  • 旁路调用保护 — 直接消费 ctx.llm.stream() 的调用(标题生成、compaction 摘要)不在保护范围内。
  • 终止错误的文案改写 — RequestErrorAction 只有 { kind: 'retry' } | undefined,改不了客户端看到的错误;有用的信息(最早恢复时间、各 provider 状态)写进宿主日志。
  • 探针并发上限 — 本插件观察失败而不是代理调用,做不到 opossum 那种"半开只放一个并发探针";靠"探针失败立刻回停车 + 冷却递增"限制影响面。
  • 健康状态持久化 — 重启后从头开始(乐观),第一次失败重新学习。

未来可能的扩展

  • 若 DSH 提供事件词汇注册面或 ignorable 公开写入口,可重新评估恢复会话事件记录
  • 若 RequestErrorAction 扩展出携带文案/原因的形状,把"最早何时恢复"放进用户可见的错误里

Prior art(借鉴来源)

这个插件的关键设计是照着现成实现改的,不重复造轮子;下面逐条记清借了什么、为什么不能直接当依赖。

来源借了什么为什么不能直接用
LiteLLM Router429 类失败立刻进冷却而非等阈值;retry-after 作为最短等待;每类错误各自的失败阈值(allowed_fails_policy);所有部署都在冷却时把"最早恢复时间"说清楚;fallback 路径上的失败也要触发冷却(他们 issue #31876);以及"重试会相乘"的教训(他们把 provider SDK 自己的重试钉成 0)语言与形态不同(Python 服务 vs 宿主内插件);安装路径是文件拷贝、不能 npm install,所以只借设计
opossumhalf-open 语义:冷却到期先放探针,成功才恢复、失败立刻回打开;冷却递增 + 上限插件不能引三方依赖(宿主 node_modules 由 harness 拥有);且它代理调用、我们只观察失败,探针并发上限做不到
@mars-sea/dsh-commandcode-provider"点名了用量窗口才算窗口用尽"(issue #54)、"两个窗口都读、解禁取最晚"(issue #51 后续)、账号级措辞的标记列表、resets at <ISO> 记法它管同一 provider 的多个账号(换密钥),本插件管多 provider 之间的切换(换路由),层次不同
dsh-llm-retry(宿主自带)分工与字段:它消费 failure.providerRetryAfterMs 做同 provider 退避,本插件把它作为唯一的结构化重置信号;阈值以下决策权交给它它不切 provider,本插件不抢它的活
dsh-llm 的 isQuotaExceededError(宿主自带分类器)措辞 → QUOTA 的映射:本插件主路径直接吃这个 code,措辞列表只做兜底宿主内部实现,插件只读 failure.code

Security

本插件在设计上避免敏感信息泄露:

  • URL 内嵌凭据掩码 — 日志中 URL 里的 key=、token= 参数自动替换为 ***
  • Bearer token 掩码 — Authorization header 中的 token 不会明文出现在日志
  • 错误文本截断 — 错误信息截断至 200 字符,减少意外泄露窗口
  • 不写会话事件 — 决策轨迹只存在于宿主日志,不追加任何会话事件

Troubleshooting

ProblemCheck
插件没有加载启动日志搜索 llm-failover,确认目录复制位置正确
models 没有配置models 为空时插件仅日志提示,不执行切换
provider 名称配置错误切换目标会跳过不存在的 provider,不影响原请求
模型切换没有发生检查 maxConsecutiveFailures 是否达到;检查 per-class 开关
为什么 AUTH 不切换凭证问题切换无用,设计行为
为什么某些错误只 retry参考 Error Classification 表
为什么这次 429 立刻切了那是「墙」:上游公布了 ≥60s 的重置时间,或正文带账号级措辞(如 usage limit for your plan)。日志里会写明来源(quota-code / message-marker / provider-retry-after / reset-stamp / retry-after-prose)
刚切过去又被切回来 / provider 一直反复失败half-open 探针在工作:每次失败会翻倍延长停车(封顶 maxCooldownSeconds)。日志里找 parked ... after a failed probe
所有 provider 都停了,怎么办日志的 no healthy target left 会给出 Earliest recovery: "X" in …;等它,或往 models 里加一个 provider,或解决那个配额用尽的账号
为什么 session 中看不到 failover 消息插件不写会话事件,见 docs/session-compatibility.md
如何查看日志Host 日志面板过滤 llm-failover
如何关闭插件config.enabled: false 或 patch 行块加 disabled: true

详见 docs/troubleshooting.md。

Demo

License

MIT

Comments

Loading…

Similar plugins

dsh-failover-continue

by elanski

Unified auto-continue + model failover plugin for DeepSeek Harness (RU/EN settings card)

Terminal & ClientsManifest valid

★ 0

MIT

TypeScript

Sep 22, 2026

dsh plugin --profile web add dsh-failover-continue

by qinyu765

Provider discovery, matching, health checks, and pre-output failover for DeepSeek Harness

Manifest valid

★ 0

MIT

TypeScript

Aug 14, 2026

dsh plugin --profile web add dsh-llm-auto-route

Rule-based multi-provider model routing for DeepSeek Harness with pre-first-token failover, cooldown circuit-breaking, usage accounting, and a status API.

Models & ProvidersManifest valid

★ 0

dsh plugin --profile web add @botton/dsh-model-router

by SipengXie2024

LLM-gated auto approval for DeepSeek Harness: a model judges every approval ask first, low-risk operations pass without prompting (fail-closed)

Manifest valid

★ 0

MIT

TypeScript

Aug 16, 2026

dsh plugin --profile web add dsh-auto-approval

by GooDAnDReaDY

Per-provider API key rotation for DeepSeek Harness: key pools, automatic 429 rate-limit failover, cooldown probing & Settings UI

Models & ProvidersTools & CapabilitiesTerminal & ClientsManifest valid

★ 8

↓ 3.3k/wk

MIT

JavaScript

Oct 1, 2026

dsh plugin --profile web add @goodandready/dsh-key-rotation

by huchunlinnk

Recursive Self-Improvement engine for DeepSeek Harness — DSH maintains DSH: bounded perceive→integrate→verify→parity→repair→propose loop enforcing 1:1 upstream feature parity

Manifest valid

★ 4

MIT

JavaScript

Aug 18, 2026

dsh plugin --profile web add dsh-desk-rsi