@apinggithub/mydsh-auto-model-router

中文文档
0.3.4发布于 2026/10/22MITES Module零依赖近 30 天下载 2201

Hybrid model router for DeepSeek Harness: declarative rules, user-configurable cost control (cost-first / quality-first / balanced), optional LLM task classifier, and failure fallback chains.

原始使用文档
文档目录33 节
  1. 致谢
  2. 工作原理
  3. 四个层级
  4. 模型选择框中的 Auto 模式
  5. 设置界面页签(浏览器端)
  6. 安装
  7. 宿主兼容性
  8. 配置
  9. costControl 三种模式
  10. 预算降级可见
  11. 免费额度优先(freeQuota)
  12. 加载时询问(无需客户端界面)
  13. 规则语法
  14. 挂载点
  15. 测试
  16. 已知问题
  17. 配套插件:按档位拆账
  18. License
  19. 上下文窗口守卫(contextGuard)
  20. 部署到其它电脑
  21. 改配置前必读:先校验,再重启
  22. 每台机器必须自带档位块
  23. 额度看门狗(quotaWatch)
  24. 它解决什么问题
  25. 它能看见什么
  26. 配置
  27. 阿里云 RAM 子账号怎么开(重要)
  28. 凭据放哪里
  29. 状态接口
  30. 发布到 npm
  31. 目录新鲜度守卫(modelsGuard)
  32. 发布到 npm
  33. 免费额度的静默计费陷阱(真实事故 · 守则)

mydsh-auto-model-router

一个适配 DeepSeek Harness(DSH)的混合式自动模型路由插件。通过 L0–L3 四个能力层级为每个 agent 请求选择模型——日常问答、代码测试、编写审查、复合多步任务——支持用户可配置的成本策略、可选的 LLM 任务分类器、以及失败降级链。

设计思路参考 open-world-project/model-router(Hermes Agent)与 opencode-model-router(fast/medium/heavy 分层):层级化路由 + 成本模式决定模糊时的偏移方向。

致谢

本插件的思路来自以下开源项目:

工作原理

用户消息
  │
  ▼
① agent/pre-step         任务文本 + token 记账
  │
  ▼
② system-prompt/assemble 让 {{model}} 与路由结果保持一致
  │
  ▼
③ agent/request   ★ 决策点:
  │
  ├─ Tier 1 规则:        子串 / 正则匹配 → 层级(L0…L3)——永远优先
  ├─ Tier 2 成本:        预算耗尽 → 钉到最便宜层级;
  │                      未命中规则 → 模式决定默认层级
  ├─ Tier 3 分类器:      可选便宜 LLM → 层级;层级缺模型 → 按模式漂移
  └─ Tier 4 降级:        请求失败 → 沿链切换模型并重试
  │
  ▼
LLM 分发

四个层级

层级典型任务模型建议
L0日常问答、快速回答最便宜/最快
L1小改动、简单测试普通
L2写代码、审查、重构较强
L3复杂 BUG 修复、多步任务、汇报最强

每个层级是一个用户自行指定的 provider/model 路由,可选附带 reasoningEffort:不写(或写 null)= 不发送该字段——GLM/Qwen flash 这类没有 思考模式的模型必须这样,否则宿主会拒绝请求;off = 显式关闭思考;high/max = 思考强度。层级可以留空不配置;路由会落到最近的已配置层级(方向由成本模式决定)。

模型选择框中的 Auto 模式

插件注册了一个虚拟的 auto provider,模型选择框会出现 Auto Router 分组, 内含一个 Auto 模型:

Auto Router
  └─ Auto
deepseek-official
  ├─ deepseek-v4-flash
  └─ deepseek-v4-flash
  • 选 Auto → 插件接管,按 L0–L3 层级自动路由。
  • 选具体模型 → 插件原样放行,你手选的模型优先,路由不干预。

设置界面页签(浏览器端)

浏览器端会在 DSH 设置面板(齿轮图标 → 侧栏)注册一个 Auto Router 页签,展示当前路由策略——即 host 在会话开始时注入的 <mydsh-auto-model-router-status> 状态报告——并附提示文案:如需修改配置, 直接在对话中告诉 AI(例如"把 L2 改成 deepseek-v4-flash 且 max 思考"或 "成本模式切换为 cost-first"),AI 会帮你编辑 cordis.patch.yml, 重启 DSH 后生效。

在模型选择框选 Auto 立即生效,不再有确认弹窗。

无需额外构建步骤:client.js 是本仓库维护的自包含 ModuleLoader bundle (pnpm run build:client 可从 client/ 源码重新生成)。

安装

dsh plugin --profile web add ./mydsh-auto-model-router

或通过已发布的 npm 包安装:

npm install @apinggithub/mydsh-auto-model-router
dsh plugin --profile web add @apinggithub/mydsh-auto-model-router

宿主兼容性

DSH 把 profile 的插件树当成一次组合:补丁失败的 bundle 可能让整个 Harness 起不来, 而抛错的插件条目会被标记为「did not activate」——路由器从会话里直接消失。 所以本插件的行为约定是能挂载、能降级、能打日志,而不是在接口变动时直接失败。

宿主版本线状态
0.1.x – 0.3.x已实测(0.2.1-rc.2 为基准宿主)
0.4.x – 1.x允许挂载,但在日志与 GET /api/mydsh-auto-model-router/status 中标记为「未实测」

挂载时 compat.mjs 会探测插件用到的每个接口(llm.registerAdapter、 llm.listModels、llm.stream、scoped ctx.inject、webServer.register、 可选的 tokenMeter),结果记录在状态接口的 host.compat 字段里。在未知宿主上:

  • tokenMeter 不再是硬依赖——软查找,缺失时改用插件自带的估算器。
  • 没有 registerAdapter 也能挂载——只记一条警告,模型选择框里不出现 Auto,路由逻辑本身不受影响。
  • HTTP 路由方法适配——webServer.register()、route()、addRoute() 都可接受;全都没有时设置页显示「暂无报告」,而不是报错。
  • 事件负载容错——既接受当前的 { agent } / (session, event) 形状,也接受 裸 agent / { session, event } 形状;处理函数抛错时原样返回宿主自己的提案, 路由器的 bug 不会再让用户请求失败。
  • 不再使用进程级全局变量——适配器按每次挂载创建并闭包引用该次挂载的 router,同进程多 profile 不会互相覆盖。
  • 版本报告——当宿主愿意暴露版本(环境变量、app 服务或可解析的 manifest)时, 超出 >=0.1.0-0 <0.4.0 会打一条同时含宿主版本与实测范围的警告。能力探测始终 执行,因此即使宿主隐藏版本,也能从状态接口看到它实际提供了哪些接口。

peer 范围(>=0.1.0-0 <1.0.0)和 engines.dsh 故意比实测范围宽,避免宿主升级后 直接拒装;真正的提示是运行时那条警告——看到它就请提 issue。

配置

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

- insert:
    - id: mydsh-auto-model-router
      name: '@deepseek-ai/cordis-plugin-group'
      group: true
      isolate:
        modelRouter: true
      config:
        - id: mydsh-auto-model-router-runtime
          name: '@apinggithub/mydsh-auto-model-router'
          config:
            # ── 四个层级(出厂默认)────────────────────────────────────
            # reasoningEffort:off = 无思考,medium/high/max = 思考强度
            levels:
              L0:                              # 日常问答
                provider: deepseek-official
                model: deepseek-v4-flash
                reasoningEffort: off
              L1:                              # 代码与测试
                provider: deepseek-official
                model: deepseek-v4-flash
                reasoningEffort: medium
              L2:                              # 编写与审查
                provider: deepseek-official
                model: deepseek-v4-flash
                reasoningEffort: high
              L3:                              # 复合多步任务
                provider: deepseek-official
                model: deepseek-v4-flash
                reasoningEffort: max

            # 关键词规则仅在全自动模式生效,默认为空
            rules: []

            # ── 模式A:字符统计锁(零延迟)────────────────────────────
            heuristic:
              windowSize: 3        # 统计最近 N 次用户输入
              counting: cjk2       # 中文计2字符/其他计1;可选 tokens
              thresholds:          # 宽度 → 层级(用户可改)
                - maxChars: 10
                  level: L0
                - maxChars: 100
                  level: L1        # 锁顶;超过 100 弹窗询问用户

            # ── 模式C:关键词积分(全自动)────────────────────────────
            scoring:
              weights:             # 每次命中积分(按层级)
                L1: 1
                L2: 2
                L3: 3
              bands:               # 积分 → 层级(用户可改)
                - maxScore: 0
                  level: L0
                - maxScore: 5
                  level: L1
                - maxScore: 15
                  level: L2
                - maxScore: null
                  level: L3

            # ── Tier 2:成本控制(用户可配置)─────────────────────────
            costControl:
              enabled: true
              mode: balanced        # cost-first | quality-first | balanced
              defaultLevel: L1      # 未命中规则时使用的层级
              tokenBudgetPerSession: 0   # 0 = 不设预算(默认);
                                        # 设置正值即按会话封顶
              # 会话预算耗尽时的行为:
              #   silent  — 静默切到最便宜层级(不告知用户)
              #   notify  — 注入用户可见消息说明降级原因
              #   ask     — 弹窗询问;用户可选"继续用当前模型"
              #             (本会话豁免预算)
              downgradeBehavior: notify

            # ── LLM 分类器(全自动模式兜底;默认开启)───────────────────
            llmClassifier:
              enabled: true
              model:
                provider: deepseek-official
                model: deepseek-v4-flash
              requestTimeoutMs: 10000

            # ── Tier 3:免费额度优先(可选)──────────────────────────
            # 声明哪些路由是「免费额度」:优先走它们,额度用尽/报错自动换线。
            freeQuota:
              enabled: true          # 没有任何免费声明时自动失效
              routes:                # 不在 levels 里的额外免费路由
                - provider: glm
                  model: glm-4.7-flash
                  maxLevel: L1       # 这一档及以下的活可以交给它(含),默认 L1
                  reasoningEffort: off
              demoteOnError: true    # 该路由一报错即在本会话内降级到付费路由
              notify: true           # 降级时插入一次可见提示

            # 固定层级模式每 N 次用户输入重新弹窗询问
            askEveryInputs: 3

            # ── Tier 4:失败降级链(模型级)───────────────────────────
            fallbackChain:
              - provider: deepseek-official
                model: deepseek-v4-flash

            maxRetries: 1

costControl 三种模式

模式默认层级(未命中规则)模糊时偏移方向
cost-first最低已配置层级向下(更便宜)
quality-first最高已配置层级向上(更强)
balancedcostControl.defaultLevel不动

规则命中永远优先于成本模式:用户显式匹配到的层级不会被成本层降级。

预算降级可见

tokenBudgetPerSession 默认为 0(不设预算)——成本层不会因预算耗尽而强制 降级,downgradeBehavior 此时不生效。设置一个正值即可开启按会话封顶:

  • 例如 tokenBudgetPerSession: 300000:会话用满 30 万 token 后降级。
  • 降级行为由 downgradeBehavior 控制(默认 notify):
    • notify:注入一条用户可见消息,说明预算耗尽、剩余请求使用哪个模型、 如何调高上限。
    • ask:弹窗询问"切到便宜模型还是继续用当前模型";选"继续"则本会话 豁免预算。
    • silent:静默切换(不推荐——用户会疑惑回答质量为何变化)。

免费额度优先(freeQuota)

很多 provider 会送免费额度(例如智谱的 glm-4.7-flash 长期免费),但免费通道 同时意味着限流、额度耗尽、参数上限更严。这一层让「免费」变成可声明的路由属性, 并在它不可用时自动换线,而不是把整轮对话做废。

声明方式有两种,可以混用:

levels:
  L0: { provider: glm, model: glm-4.7-flash, reasoningEffort: off, freeQuota: true }
  L1: { provider: glm, model: glm-4.7-flash, reasoningEffort: low,  freeQuota: true }
  L2: { provider: deepseek-account, model: deepseek-flash, reasoningEffort: high }
  L3: { provider: deepseek-account, model: deepseek-flash, reasoningEffort: max }

# 或者:层级仍指向付费模型,另外声明免费路由来「抢」这些档位的活
freeQuota:
  routes:
    - { provider: glm, model: glm-4.7-flash, maxLevel: L1, reasoningEffort: off }

行为:

  1. 优先——决策落在 maxLevel 及以下的档位时,走声明的免费路由(免费路由 总是带着显式 reasoningEffort,默认 off,不会掉进适配器的默认思考档)。
  2. 失败即降级——免费路由上任何一次请求失败(额度耗尽、429 限流、鉴权被拒、 参数被拒……)都会把该路由在本会话内标记为已耗尽,请求立刻重试到下一跳 可用路由(通常就是该档位原本的付费路由)。
  3. 不再重试坏路由——降级后,fallbackChain 的游走会跳过所有已耗尽的免费路由, 同一个会话不会反复撞同一堵墙。
  4. 可见——notify: true 时插入一条说明「哪个免费路由、为什么、现在改用什么」 的消息,每个会话最多一条。
  5. 会话级——降级只在当前会话内生效,下个会话重新尝试免费路由;freeQuota 完全未声明时整层失效,老配置行为不变。

注意:免费的视觉模型通常有更小的输出上限(例如 glm-4v-flash 只允许 max_tokens ≤ 1024)。这类限制要在 provider 的 models 条目上写 maxTokens 修正,路由器无法替你猜——遇到 INVALID_REQUEST: max_tokens参数非法 时按提示 给该模型加 maxTokens 即可。

加载时询问(无需客户端界面)

安装或热插拔插件后的第一个会话,DSH 会:

  1. 注入一条状态汇报消息(当前层级→模型映射、成本模式、预算、降级链)。 语言跟随 settings.yaml 的 locale.preference(zh/en,默认 en)。
  2. 弹窗询问三个问题(每轮插件加载只问一次):
问题选项
Q1 匹配规则 (T1)保持现有规则 / 查看现有规则(注入规则清单)
Q2 成本模式 (T2)保持当前 / cost-first / balanced / quality-first(选择立即生效)
Q3 其他配置跳过 / 检查某项配置(输入 budget、fallbackChain、classifier 等,注入当前值)

Q1/Q3 注入的清单与当前值让用户决定是否调整;持久修改仍落在 cordis.patch.yml(消息中会说明)。headless 或无可询问通道时自动降级为 只汇报、不询问,不会阻塞。

规则语法

  • 纯文本:match: 'refactor' —— 大小写不敏感的子串匹配。
  • 正则字面量:match: '/\\bdebug\\b/' —— 首尾斜杠界定正则,末尾可加标志(如 /.../i)。
  • 规则按顺序求值,第一个命中生效。
  • match 可匹配用户消息文本、工具调用结果文本,或会话 cwd(以 cwd:<path> 匹配)。

挂载点

DSH 事件作用
agent/session-start重置每会话路由状态
agent/pre-steptoken 记账(预算跟踪)
system-prompt/assemble保持 {{model}} 提示词变量一致
agent/request路由决策点 —— 替换 provider/model
agent/request-error降级链 → { kind: 'retry' }
session/event从 assistant 消息统计 token 消耗

测试

npm test        # node --test *.test.mjs

无需外部服务——所有层级均以 fixture 做单元测试。

已知问题

  • 全自动模式延迟:开启 LLM 分类器后,每个新用户输入的第一步会增加一次分类器调用(LLM 请求)。虽然同一输入内的后续步骤已缓存、无额外开销,但多步任务的整体响应时间仍比直接选择模型慢。欢迎贡献优化方案——例如跨会话缓存分类结果,或用轻量启发式作为 LLM 分类的前置过滤。

配套插件:按档位拆账

tier-cost/ 里是本仓库附带的第二个插件 @apinggithub/dsh-tier-cost: 它把会话日志按路由档位折叠成 L0–L3 的 token 与花费(金额向计费插件 @kenz1117/dsh-ui-usage-billing 借 per-turn 数据,本身不维护价目表), 在设置页多出一栏「档位花费」——因为四个档位常常共用同一个模型,计费面板 按模型分账时看不出是哪一档花的钱。

dsh plugin --profile desktop add ./tier-cost

细节见 tier-cost/README.zh.md。

License

MIT

上下文窗口守卫(contextGuard)

档位可声明其模型的 contextWindow。会话实际上下文(最近一次请求的输入侧 token,含缓存读写)超过 window × headroom(默认 0.85)时,该档位被跳过, 路由向上漂到最近的装得下的档位;没有任何声明窗口装得下时保持原档(fail-open), 让 provider 用真实错误说话、交给降级链处理。跳过每 (档位, 会话) 记录一次, /status 的 contextGuard 字段可见。未声明任何窗口时整层不生效。

levels:
  L0: { provider: bailian, model: qwen-max, contextWindow: 32768 }   # 小窗口模型的保护
contextGuard: { enabled: true, headroom: 0.85 }

部署到其它电脑

一台机器 = 三条命令(本仓库含两个插件):

# 1. 从 npm 装(推荐;peer 范围已放宽为宿主自适应,不需要 allow-version 豁免)
dsh plugin --profile desktop add '@apinggithub/[email protected]'

# 2. 可选:按档位拆账
dsh plugin --profile desktop add '@apinggithub/[email protected]'

# 3. 改完 cordis.patch.yml 后先校验(见下),再重启
node scripts/check-patch.mjs --profile desktop

# 4. 重启 DSH(bundle 只在启动时组合;配置改动用热加载即可)

改配置前必读:先校验,再重启

cordis.patch.yml 里一个少的换行就能让宿主启动失败:

DesktopHostFatalError: failed to parse overlay … YAMLException: bad indentation (454:44)

更麻烦的是崩溃对话框里有 "Disable third-party plugins" 按钮——点它会把所有第三方 bundle 从 profile 里摘掉,插件(含 Auto 入口)随之消失,需要手工恢复。

所以每次改完都跑一次(会用宿主自己的解析器校验,并清理临时 profile):

node scripts/check-patch.mjs --profile desktop
# PASS  profile "desktop" composes (194 top-level entries)
# FAIL  … 会打印宿主的原始错误

参数:--home <DSH_HOME>、--profile <name>、--file <patch>(只做静态检查)、--keep(保留临时 profile 便于排查)。

也可以从源码装:git clone … 后 dsh plugin --profile desktop add ./mydsh-auto-model-router。

每台机器必须自带档位块

插件的出厂默认档位是历史值(deepseek-official/deepseek-flash),这台机器上不一定可用。 装完在该机器 profiles/<profile>/cordis.patch.yml 末尾写自己的档位块, provider/model 必须是那条机器真实可用的路由,别照抄 id:

- id: mydsh-auto-model-router-runtime
  name: '@apinggithub/mydsh-auto-model-router'
  config:
    levels:
      # reasoningEffort: null = 该模型没有思考能力(Qwen/GLM flash 都是),必须写 null,
      # 否则宿主会以 UNSUPPORTED_REASONING_EFFORT 拒绝请求。
      L0: { provider: zhipu, model: glm-4.7-flash, reasoningEffort: null, freeQuota: true }
      L1: { provider: zhipu, model: glm-4.5-flash, reasoningEffort: null, freeQuota: true }
      L2: { provider: zhipu, model: glm-4-flash,   reasoningEffort: null }
      L3: { provider: deepseek-official, model: deepseek-flash, reasoningEffort: max }
    freeQuota:   { enabled: true, demoteOnError: true, notify: true }
    contextGuard: { enabled: true, headroom: 0.85 }
    quotaWatch:  { enabled: true, provider: bailian-dell-vostro, balanceFloorCny: 10 }

provider 本身要在 cordis.patch.yml 里先定义好(llm-pi-ai 的 providers: 段), 密钥通过 DSH 凭据库或 apiKeyEnv 提供。

多机同账号的注意点:额度与余额都在服务端,所以本机累计的 token 数不参与判断—— quotaWatch 读的是云端账单/余额。但每台机器都要各自配置一次(凭据库不跨机同步)。

额度看门狗(quotaWatch)

它解决什么问题

免费额度耗尽后,服务商未必报错——可能静默转按量计费。那时 demoteOnError 无错可捕, 路由会一直烧钱(见文末「静默计费陷阱」)。看门狗改读账单,一旦某个"免费"模型出现花费, 30 分钟内把它摘掉。

它能看见什么

数据源能拿到限制
QueryAccountBalance账户可用余额(¥)准实时
DescribeInstanceBill按模型拆分的当期花费T+1 延迟
QueryResourcePackageInstances资源包余量无资源包时为空
DeepSeek GET /user/balance开放平台余额准实时

没有"查询免费额度剩余"的公开接口——那个进度条只在服务商控制台里。 所以看门狗的语义是发现即降级,不是提前拦截;真正的超前拦截仍要靠服务商侧的「用完即停」。

配置

quotaWatch:
  enabled: true
  provider: bailian-dell-vostro      # 账单描述的是哪个已配置 provider(要摘的路由)
  productCode: sfm                   # 百炼在阿里云账单里的商品码
  pollMs: 1800000                    # 轮询间隔,最小 60000
  balanceFloorCny: 10                # 阿里云余额低于此值 → 暂停所有付费档;0 = 关闭
  demoteOnSpend: true                # 某模型出现花费 → 摘掉它的路由
  deepseekBalanceFloor: 10           # DeepSeek 平台余额低于此值 → 只暂停 deepseek-official;0 = 关闭
  deepseekApiKeyRef: DEEPSEEK_API_KEY
  accessKeyIdRef: ALIBABA_CLOUD_ACCESS_KEY_ID
  accessKeySecretRef: ALIBABA_CLOUD_ACCESS_KEY_SECRET
  timeoutMs: 20000

阿里云 RAM 子账号怎么开(重要)

不要用主账号 AccessKey。 正确的做法:

  1. 阿里云控制台 → RAM 访问控制 → 用户 → 创建用户,勾选只允许编程访问;
  2. 给它只读账单权限:直接附加系统策略 AliyunBSSReadOnlyAccess; 想更小可用自定义策略,只允许这几个 Action: bss:QueryAccountBalance、bss:DescribeInstanceBill、bss:QueryResourcePackageInstances;
  3. 创建 AccessKey,把 ID/Secret 存进 DSH 凭据库(见下),不要再给它任何写权限;
  4. 验证(只读,不花钱):
$ak = (Resolve the ID);  $sk = (Resolve the secret)
# 期望返回 {"Success":true,"Data":{"AvailableAmount":"..."}}

AccessKey Secret 不要写进 cordis.patch.yml,也不要提交进仓库——配置文件里只有 accessKeyIdRef / accessKeySecretRef 这样的引用名。

凭据放哪里

看门狗通过 ctx.credentials.resolve(ref) 读取,所以密钥存在 DSH 凭据库 ($DSH_HOME/.credentials.yaml,与 provider 的 API key 同一个文件),形如:

refs:
  ALIBABA_CLOUD_ACCESS_KEY_ID: LTAI...
  ALIBABA_CLOUD_ACCESS_KEY_SECRET: ...
  DEEPSEEK_API_KEY: sk-...

两种写入方式,任选:

  • GUI:插件 → 内置插件设置 → Models / 凭据,按 API key 的方式存(键名用上面的 ref 名);
  • 命令行(secret 不进 shell 历史,也不进对话):
$sec = Read-Host -AsSecureString 'Paste AccessKey Secret'
$plain = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
  [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec))
# 写入 $DSH_HOME/.credentials.yaml 的 refs 段后,立即删除任何临时明文文件

⚠️ 多机部署:每台机器都要各自配置一次凭据(凭据库不跨机同步)。 额度/余额在服务端,所以多机读到的数字一致,不存在方案 A 那种"各机各算、互不知情"的偏差。

状态接口

GET /api/mydsh-auto-model-router/status 的 quotaWatch 字段:

{
  "enabled": true,
  "lastCheckAt": "2026-10-22T09:57:18Z",
  "lastError": null,
  "balanceCny": 28.21,
  "cycle": "2026-10",
  "spendByModel": { "glm-5.3": 62.5611, "qwen3.8-flash": 8.0478 },
  "totalCny": 70.67,
  "exhausted": [],
  "balanceLow": false,
  "deepseekBalanceCny": 158.25,
  "deepseekBlocked": false,
  "deepseekError": null
}

任何一环失败都只写进 lastError / deepseekError,不会影响路由本身。

发布到 npm

目录新鲜度守卫(modelsGuard)

模型版本升级后,provider 不再公布的 id 会变成「过期路由」。守卫在激活时与每 refreshMs(默认 10 分钟)用 ctx.llm.listModels(provider) 读取各 provider 实际公布的模型:过期档位的请求自动漂移到最近的鲜活档位(绝不静默打死), 状态报告列出过期档位与同族候选 id,改档位仍是一行编辑的事。目录读不到或 为空时一律 fail-open(不判过期)。未注册 listModels 的环境整层惰性。

modelsGuard: { enabled: true, refreshMs: 600000 }

静态列表本身仍是配置(cordis.patch.yml)——这是刻意的:插件不会替你决定 换成哪个模型(窗口/单价/能力都变了),它只保证坏档位不再被选中并告诉你该换什么。

发布到 npm

两个插件同一仓库、各自独立发布(root 与本目录的 package.json 都可直接 publish):

npm publish                 # @apinggithub/mydsh-auto-model-router(root)
cd tier-cost && npm publish # @apinggithub/dsh-tier-cost

0.2.0 起 peerDependencies 已放宽为宿主自适应范围,新机器安装不再需要 allow-version 豁免(豁免仅 0.1.1 及更早需要)。发布前各自 npm login --scope=apinggithub。

免费额度的静默计费陷阱(真实事故 · 守则)

本仓库作者机器上的实录事故:L1 指向百炼免费模型 glm-5.3(freeQuota: true),额度耗尽后 服务商没有按「用完即停」返回 403(批量开关未覆盖到该模型/生效延迟),调用照常成功—— 于是 demoteOnError 无错可捕,glm-5.3 静默转按量计费跑了一整天,直到账单通知才被发现。

三条守则,缺一不可:

  1. 先在服务商侧逐模型确认「用完即停」真的生效(发一条超额调用看是否返回 403,别信批量开关)。 路由器只能在看得见错误时换线;额度耗尽若被服务商静默转按量,插件无从得知。
  2. costControl.defaultLevel 指向稳定付费档(本文各处示例的 defaultLevel: L1 若 L1 是免费档, 正是本次事故形态)。免费档只放最低层(L0),或至少每个免费档都有明确的付费替代。
  3. 用计费面板按档核账:任何"免费"档的费用行持续大于 0 且不归零,立刻怀疑额度已尽、 在按量扣费——把该档从免费路由摘下来。

另一个易错点:免费额度池按 provider+model 独立计数。同一个模型 id 出现在多个 provider (如 qwen3.8-flash 同时在 bailian 与 qianwen)是不同的池子,额度与计费互不相干。

版本与发布记录

@apinggithub/mydsh-auto-model-router 共发布 13 个版本,首次发布于 2026/10/11;过去 12 个月发布了 13 个版本。

版本发布日期距今
0.3.4latest2026/10/2216 天前
0.3.32026/10/2216 天前
0.3.22026/10/2216 天前
0.3.12026/10/2216 天前
0.3.02026/10/2216 天前
0.2.62026/10/2216 天前

关于 @apinggithub/mydsh-auto-model-router 的常见问题

@apinggithub/mydsh-auto-model-router 是什么?

Hybrid model router for DeepSeek Harness: declarative rules, user-configurable cost control (cost-first / quality-first / balanced), optional LLM task classifier, and failure fallback chains.

如何安装 @apinggithub/mydsh-auto-model-router?

在项目目录运行 npm install @apinggithub/mydsh-auto-model-router,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@deepseek-ai/dsh-llm(>=0.1.0-0 <1.0.0)、@deepseek-ai/dsh-tools(>=0.1.0-0 <1.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@apinggithub/mydsh-auto-model-router 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/apinggithub__mydsh-auto-model-router 是否存在。

@apinggithub/mydsh-auto-model-router 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@apinggithub/mydsh-auto-model-router 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js ^22.19.0 || >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@apinggithub/mydsh-auto-model-router 可以商用吗?

@apinggithub/mydsh-auto-model-router 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@apinggithub/mydsh-auto-model-router 的下载量有多少?

根据 npm 官方下载统计,@apinggithub/mydsh-auto-model-router 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,201 次,日均约 73 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@apinggithub/mydsh-auto-model-router 还在维护吗?

最新版本 0.3.4 发布于 2026/10/22(16 天前);至今共发布 13 个版本,其中过去 12 个月发布了 13 个;首次发布于 2026/10/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。