🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

模型故障转移 mufasa007/dsh-llm-failover

DeepSeek Harness
mufasa00726 天前有提交已提供中文文档扫描:未发现敏感能力

额度耗尽时自动切换到下一个可用模型厂商

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/5 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add mufasa007/dsh-llm-failover
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · model
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 26 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-llm
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 配额耗尽自动回退
  • 多路由重试
  • 流式请求瀑布切换

为 DeepSeek Harness 做配额感知的模型回退:某条模型路由配额耗尽时,自动在下一个路由上重试(llm/stream 瀑布流)。

README

由 DeepSeek 最新模型翻译生成
dsh-llm-failover 面向 DeepSeek Harness(dsh)的大模型厂商自动故障转移插件。 当某家厂商不可用时——额度耗尽、账户被封禁、密钥失效、服务宕机、网络异常——本插件会把请求透明地改发到优先级列表中的下一个可用厂商。不需要模型做任何决策,上层 agent 循环也完全感知不到这次失败。 优先级:Claude ──▶ Kimi ──▶ DeepSeek │ │ │ 额度/封禁/ 额度/封禁/ 按量付费宕机 宕机 保底 插件不限定厂商:任何注册在 ctx.llm 上的路由都可以参与。 为什么需要它 dsh 没有内建的模型故障转移。以下是逐条核对随应用分发的包之后确认走不通的路径: | 看起来可行的路径 | 为什么不行 | | @deepseek-ai/dsh-llm-retry | 只在同一个 provider/model 上重跑。默认可重试码是 EMPTY_RESPONSE、RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT —— 不含 QUOTA,而且它从不切换厂商。 | | retryPolicy: { mode: 'always' } | 无限重试同一个模型;账号已停用时只会一直空转。
展开完整文档(README 剩余 1 节)
dsh-llm-failover

面向 DeepSeek Harness(dsh)的大模型厂商自动故障转移插件。

当某家厂商不可用时——额度耗尽、账户被封禁、密钥失效、服务宕机、网络异常——本插件会把请求透明地改发到优先级列表中的下一个可用厂商。不需要模型做任何决策,上层 agent 循环也完全感知不到这次失败。

优先级:Claude ──▶ Kimi ──▶ DeepSeek │ │ │ 额度/封禁/ 额度/封禁/ 按量付费宕机 宕机 保底

插件不限定厂商:任何注册在 ctx.llm 上的路由都可以参与。

为什么需要它

dsh 没有内建的模型故障转移。以下是逐条核对随应用分发的包之后确认走不通的路径:

| 看起来可行的路径 | 为什么不行 |
| @deepseek-ai/dsh-llm-retry | 只在同一个 provider/model 上重跑。默认可重试码是 EMPTY_RESPONSE、RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT —— 不含 QUOTA,而且它从不切换厂商。 |
| retryPolicy: { mode: 'always' } | 无限重试同一个模型;账号已停用时只会一直空转。 |
| 修改 agent-default-model 或 --patch | 对已恢复的会话无效:selectionFor() 优先读会话自己请求头里记录的模型。 |
| 用 spawn_teammate 指定模型 | 工具 schema 没有 model 参数;teammate 继承 Lead 的路由 —— startContinuable 调用时根本没传 agentOptions。 |
| Anthropic 的 allowedFallbackModels | 是服务端对拒绝回复的兜底,与可用性无关。 |

唯一可用的钩子是 llm/stream 瀑布。

工作原理

LlmRuntime.stream(options)
└─ ctx.waterfall(this, "llm/stream", options, () => this.adapterStream(options))
↑ 适配器在这里才被选中,位于瀑布之后

四条关键事实(均已对照 @deepseek-ai/dsh-llm 源码核实):

1. dispatch() 不做监听器类型过滤 —— 任何 ctx.on("llm/stream", fn) 都参与瀑布。
2. 监听器签名是 (options, next),this 才是 LlmRuntime。cordis 会把 waterfall 的第一个参数从参数列表中 shift 出去、用于 bind 监听器 —— 所以必须用 function 而不是箭头函数,才能通过 this 拿到运行时。
3. 适配器选择发生在瀑布之后(adapterStream 内部的 this.registration(options.provider)),因此改写 options.provider / options.model 能够真正改变请求去向。
4. next() 是状态化推进器 —— 每调用一次就 shift 下一个监听器 —— 因此只能调用一次。所以故障转移重试是带着深度标记重新进入 llm.stream(),而不是再调一次 next()。

故障分类

| 类别 | 错误码 | 行为 |
| 确定性故障 | QUOTA、AUTH、INVALID_CREDENTIAL,以及措辞匹配 | 立即熔断并继续向后走。AUTH / INVALID_CREDENTIAL 属于账户级,会熔断整个厂商;QUOTA 只熔断该路由——不同模型的额度池相互独立。 |
| 瞬时故障 | RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT、EMPTY_RESPONSE,以及无法识别者 | 计数;连续达到 failureThreshold 才熔断,因此一次抖动不会把你从某家厂商上赶走。 |
| 调用方问题 | INVALID_REQUEST、CONTEXT_WINDOW_EXCEEDED、ABORTED、UNKNOWN_MODEL、NO_ADAPTER | 既不切换也不熔断——换厂商修不好一个畸形的请求。原样透传。 |

熔断与恢复

每个路由(provider/model)与每个厂商各持有健康状态。已熔断的路由会被跳过,改用下一个候选;重复失败时冷却时间翻倍,上限由 maxCooldownMs 决定。

恢复采用半开策略且不产生任何额外请求:冷却时间一过,该路由重新变为可用,于是下一次真实请求就会重试它。成功即彻底清除状态并重置退避;失败则以更长的冷却重新熔断。若你在低流量场景下也想刷新厂商模型列表,可开启 probe.enabled。

内容安全

切换只发生在产出任何可见内容之前。若某家厂商在回答中途失败,已产出的部分与错误会原样透传——把两个模型的半截回复拼起来会得到自相矛盾的答案。

环境要求

- DeepSeek Harness,且插件能访问到 @deepseek-ai/dsh-llm(任何暴露 llm/stream 瀑布与 QUOTA_EXCEEDED_CODE 的较新版本)。
- 已在桌面端随附的 dsh-llm 0.1.5-rc.3 与 cordis 上验证。

安装

插件必须位于 profile 的 node_modules 内,否则无法解析同级的 @deepseek-ai/dsh-llm。

cp -R ./dsh-llm-failover "$DSH_HOME/profiles/node_modules/dsh-llm-failover"

cd "$DSH_HOME/profiles"
node -e "import('dsh-llm-failover').then(m => console.log(m.name, m.inject))"
→ llm-failover [ 'llm' ]

然后追加到 profile 的用户补丁层($DSH_HOME/profiles/<profile>/cordis.patch.yml):

⚠️ 新增插件必须用 insert: 形式。 写成 - id: <新id> 会被当作对已有条目的覆盖,报错 entry "<id>" not found。

- insert:
- id: llm-failover
name: dsh-llm-failover
config:
priority:
- provider: anthropic
model: claude-sonnet-5
- provider: kimi-coding
model: k3
- provider: deepseek-account
model: deepseek-flash

重启应用 —— cordis.patch.yml 在 profile 加载时读取。

设置页面

加载后,插件会在 设置 → 侧栏「插件」→ 本插件 下注册自己的配置页,编辑三个最常调的旋钮:

| 控件 | 对应设置 |
| 厂商优先级 | 逗号分隔,越靠前优先级越高:anthropic/claude-sonnet-5, kimi-coding/k3, deepseek-account/deepseek-flash。只写厂商名时使用该厂商公告的首个模型。 |
| 瞬时故障切换阈值 | failureThreshold。 |
| 冷却时长(分钟) | cooldownMs,界面上以分钟呈现。 |

保存的值进入设置文档,作为组合配置之上的用户层,插件实时读取 —— 无需重启。其余字段(chains、错误码列表、措辞、maxCooldownMs、probe)仍属于组合层。

接线方式(便于二次开发):

- .volatile() 是插件页出现的前提。 dsh-settings 逐条目调用 volatileForm(条目 schema),只保留带 volatile 标记的字段;一个都没有的条目会被整体丢弃(if (form === void 0) return [])。标记 volatile 同时把字段变成实时访问器,所以插件用 config.priority.get() 读取。
- 设置命名空间自动等于 loader 条目 id(ns: entry.options.id),无需任何注册调用;installSection 只存在于较旧的 dsh 构建里。
- 浏览器半侧(./client)通过 ctx.configForms.whileServed(["llm-failover"], …) 注册进插件页的 plugins.item slot;没装本插件的部署看不到这个页面。
- 包在 package.json 中声明 dsh.client —— 这是客户端模块系统把 ./client 送到浏览器的前提。
- 保存经由 profile 补丁编辑器写回:它会跳过 insert: 行,改为追加一条顶层 config 行。若配置来自 --patch 命令行叠加层,则页面无法编辑,宿主会以 "overridden by a home patch or command-line overlay" 拒绝。

配置

| 字段 | 默认值 | 含义 |
| priority | [] | 有序的厂商路由。失败时,按顺序尝试该厂商之后的路由;若失败厂商不在列表中,则使用整条列表。 |
| chains | [] | 按厂商(或按确切模型)覆盖。精确的 provider+model 条目优先,否则用第一个仅按 provider 匹配的条目。优先于 priority。 |
| fatalCodes | [] | 额外立即熔断的错误码。QUOTA、AUTH、INVALID_CREDENTIAL 始终包含。 |
| transientCodes | [] | 额外计入阈值的错误码。 |
| patterns | [] | 额外的正则字符串,匹配失败信息;命中即立即熔断。 |
| failureThreshold | 2 | 瞬时故障连续多少次后熔断。 |
| cooldownMs | 300000 | 首次熔断的冷却时间(5 分钟)。重复失败时翻倍。 |
| maxCooldownMs | 3600000 | 冷却上限(1 小时)。 |
| probe.enabled | false | 定时刷新厂商模型列表。 |
| probe.intervalMs | 600000 | 刷新间隔。 |

priority 条目可以省略 model,此时插件使用该厂商自己公告的首个模型(经 ctx.llm.listModels 解析)。它绝不会把当前请求的模型名套到别的厂商上;暂时解析不到的条目会被跳过,而不是瞎猜。

内置措辞

有些真实世界的说法永远到不了正确的错误码:pi-ai 的 classifyPiAiError() 会先判 isQuotaExceededError、后判 429 | rate limit,而 isQuotaExceededError 要求 usage limit 紧跟 exceeded|exhausted|reached:

| 厂商返回的措辞 | dsh 能否识别 | 归一后的码 |
| usage limit exceeded | 能 | QUOTA |
| insufficient quota | 能 | QUOTA |
| You have reached your usage limit for Claude. | 不能 | RATE_LIMIT |
| Your limit will reset at … | 不能 | 其它 |
| Your account has been suspended. | 不能 | 其它 |

因此插件自带补充措辞并自行匹配:

/usage[\s_-]limit/i
/reached your [^.]{0,40}limit/i
/limit will reset/i
/weekly limit|monthly limit/i
/account[^.]{0,30}(?:banned|suspended|disabled|deactivated)/i
/(?:banned|suspended)[^.]{0,20}(?:account|user|key)/i
/(?:insufficient|no)\s_-/i

可用 patterns 追加自己的。

测试

测试套件通过真实的 cordis 瀑布驱动插件、使用真实的 dsh-llm 辅助函数,只伪造 llm 服务,并用可拨动的时钟验证冷却与恢复:

cd "$DSH_HOME/profiles" && node path/to/test.mjs

必须在 profile 目录下运行,@deepseek-ai/cordis 与插件本身才能被解析到。

十个用例:确定性故障转移、熔断后跳过、冷却后半开恢复、瞬时故障按阈值熔断、调用方问题不介入、已产出内容后不切换、候选全部耗尽、账户级故障覆盖同厂商所有模型、封禁措辞识别、请求方不在优先级列表内。

局限

- 只在产出可见内容之前切换(刻意如此,见上文)。
- 熔断状态存于内存:应用重启即清空。仍在故障中的厂商会被重试一次并再次熔断。
- 健康状态按路由与厂商判定,但没有跨进程协调。
- 拦截每一次 llm/stream,包括 workflow 子代理与 teammate。这通常是想要的效果——它们都不该因为某家厂商宕机就整体失败——但会增加日志量。
- 非 DeepSeek 官方项目。它依赖 dsh 的内部包,升级后可能失效。
- 代码注释为中文;同时提供英文与中文 README。

许可证

MIT —— 见 LICENSE。
预览分享卡片长什么样 ↓mufasa007/dsh-llm-failover
分享 · DeepSeek Harness Hub
mufasa007/dsh-llm-failover

额度耗尽时自动切换到下一个可用模型厂商

回到顶部