delltig/dsh-multi-model-collab:把一个任务同时交给多个大模型

前言

在 DSH(DeepSeek Harness)上写 Agent 时,常见的做法是让一个模型串行地把活干完。遇到答案可能不稳定、需要第二个意见,或者需要交叉验证的场景,就得自己在外层写编排逻辑:发多次请求、合并结果、处理部分失败。delltig/dsh-multi-model-collab 把这个动作收进了一个插件:它向当前 Profile 注册一个 multi_model_run 工具,主 Agent 调用时,插件内部通过 ctx.llm 服务并行(或按主/副角色)发起多次模型调用,再按配置的策略聚合,返回「每个模型的独立结果 + 聚合摘要」。下面介绍它做了什么、怎么装、怎么配。

插件定位

这是一个 DeepSeek Harness(dsh)插件,仓库为 delltig/dsh-multi-model-collab,package.json 里 author 字段为 applestore,版本 0.1.0,MIT 许可证。README 的自我定位很明确:不修改 dsh 源码,是纯 Cordis 插件挂载,靠 ctx.tools.register + ctx.llm 两个接口工作。

它解决的是「一个任务让 N 个模型各答一遍」这件事,而不是带工具、带会话、多步的子 Agent 委派。插件明确写了它不硬编码任何 API Key、端点或模型清单,模型一律用 ctx.llm.listProviders() 报告的 <provider>/<model> 路由;单个模型失败不会让整个工具调用失败,只有全部模型失败时 execute 才抛异常;调用方取消时,仍在进行的模型调用一并取消。

核心功能

主要能力是注册 multi_model_run 工具。主 Agent 调用它时,插件内部按配置发起多次模型调用,再按策略聚合,把每个模型的独立结果和聚合摘要返回给主 Agent。

执行模式有两种:

  • parallel——每个模型独立回答同一个任务,全部并行。适合要第二意见、要跨供应商一致性、答案可能有分歧的场合。
  • primary_secondary——主模型先答;其余模型拿到「原始任务 + 主模型草稿 + secondaryInstruction」,做审阅、纠错与补全。适合需要一个”审稿人”、单点判断风险高的场合。主模型失败时自动降级为各副模型独立作答,而不是整体失败。

聚合策略有三种:

  • all——原样返回全部结果,不做选择(answer 为空串)。这是默认值,理由是分歧本身往往是主 Agent 需要的信息。
  • vote——先把文本归一化(大小写、标点、空白、Markdown 符号)再分组;严格多数则取该组代表,无严格多数则回退到最长答案,并在 summary 里说明实际票数与回退原因。
  • longest——取最长的成功答案作为 answer。

render() 把这些渲染成一段 Markdown(每个模型一节 + ## aggregate 摘要 + 可选 ## selected answer),主 Agent 读到的就是这段文本。

安装与启用

方式 A:安装到 Profile(长期生效)。在插件包目录内(即本仓库根目录)执行:

dsh plugin --profile desktop add .

该命令把本包装进 ~/.dsh/profiles/<profile>/node_modules,package.json 的 dsh.bundle.patch 指向的 cordis.patch.yml 会作为 bundle patch 层生效。也可以用 dsh 的插件管理器,在 dsh 会话内调用:

plugin_manager(action="install_bundle", target="<本目录绝对路径>")

方式 B:--patch 覆盖层,不安装直接试。cordis.patch.yml 里插入行的 name 是相对路径(./lib/index.js),Loader 会把它锚定在该 patch 文件旁边,所以无需安装即可挂载:

dsh web --patch ./cordis.patch.yml
# 若用 pnpm 管理 dsh:
pnpm dsh web --patch ./cordis.patch.yml
# 不抢端口、不自动开浏览器:
dsh web --patch ./cordis.patch.yml --no-open --port 0

也可以一次性 headless 验证:

dsh --profile <headless-profile> --patch ./cordis.patch.yml "用 multi_model_run 跑一个任务"

这里有一个坑:headless 模板默认把 credentials 行设为 disabled: true;如果 Profile 没有其它层重新启用它,API Key 会查找失败(MISSING_CREDENTIAL)。Web / Desktop Profile 本来就启用了该行,无需处理。

改源码后重新构建:

npm install
npm run build   # tsc -> lib/,并 node --check 校验产物
npm test        # 离线行为测试(假 ctx.llm,不发网络请求)

配置

所有配置都在 Loader 行(cordis.yml / cordis.patch.yml)的 config: 下,改值不需要改代码。字段与默认值如下,与 src/index.ts 的 Config 一致。

字段 类型 默认值 说明
models string[] ["deepseek-official/deepseek-flash", "deepseek-official/deepseek-v4-pro"] 默认模型组合,格式 <provider>/<model>。primary_secondary 模式下第一个是主模型。
mode parallel / primary_secondary parallel 执行模式。
aggregate all / vote / longest all 聚合策略。
defaultProvider string "" 模型标识不带 provider 前缀时使用哪个 provider;空则按各 provider 的目录自动匹配。
system string "" 发给每个模型的 system prompt;空则不发。
temperature number -1 采样温度;负数表示不发该字段(用适配器默认)。
maxTokens number 0 单次调用的输出 token 上限;0 表示不限制(用适配器默认)。
perModelTimeoutMs number 180000 单个模型调用的取消预算。
toolTimeoutMs number 900000 整个工具调用的协作预算;0 表示交给注册表默认。
maxConcurrency number 4 同时在飞的模型调用数上限。
clipChars number 12000 每个模型返回文本的截断长度;0 表示不截断。未截断长度仍记录在 chars。
includeUsage boolean true 是否上报每个模型的 token 用量(适配器提供时)。
secondaryInstruction string 审阅指令(中英双语) primary_secondary 模式下要求副模型做什么。

models 的默认值是示例组合,实际跑什么模型取决于当前 Profile 里 listProviders() 报告了哪些路由,所以默认值未必都能解析。

工具用法

工具名 multi_model_run。入参如下。

参数 必填 说明
task 是 要执行的任务/问题。每个模型只看到这段文本,看不到当前会话,必须自带上下文。
models 否 本次使用的模型列表,覆盖配置的 models。
mode 否 本次执行模式,覆盖配置。
aggregate 否 本次聚合策略,覆盖配置。
system 否 本次 system prompt,覆盖配置。

task 是唯一必填项,这意味着调用前要在 task 里把上下文写全。返回结构如下(节选):

{
  "task": "…",
  "mode": "parallel",
  "aggregate": "all",
  "models": ["deepseek-official/deepseek-flash", "deepseek-official/deepseek-v4-pro"],
  "succeeded": 2,
  "failed": 0,
  "results": [
    {
      "provider": "deepseek-official",
      "model": "deepseek-flash",
      "id": "deepseek-official/deepseek-flash",
      "role": "peer",
      "status": "ok",
      "text": "…",
      "clipped": false,
      "chars": 12,
      "durationMs": 1840,
      "error": null,
      "usage": { "inputTokens": 10, "outputTokens": 5, "totalTokens": 15 }
    }
  ],
  "answer": "",
  "summary": "mode=parallel aggregate=all models=2 ok=2 failed=0 elapsed=2140ms\n- OK   …"
}

失败与取消的边界:

  • 单个模型失败(适配器报错、抛异常、无终止 chunk、超时)→ 该条 status: "failed" + error.code,其余模型继续;工具整体仍然成功。
  • 全部模型失败 → execute 抛错,错误信息里带每个模型的 code: message,并带 code: "ALL_MODELS_FAILED"。
  • exec.signal 触发 → 已发出的模型调用被取消;若一个都没成功则抛 ABORTED。
  • 模型引用无法解析(例如只写了 deepseek-flash 但目录里匹配不到、又没配 defaultProvider)→ 抛错并列出当前所有可用的 provider/model 路由。

验证

离线行为测试不发网络请求,共 21 个用例:

npm test

覆盖插件契约、defineTool 参数/输出 schema 编译、并行执行、失败隔离、全失败抛错、vote/longest 聚合、primary_secondary 的审阅 prompt 与主模型失败降级、模型引用解析(含目录查找与报错文案)、文本截断、取消、缺终止 chunk。

端到端测试(真实模型,需要已配置的供应商):

npm run e2e        # 4 个真实场景,约 2 分钟,会消耗真实 token

它会自建/复用临时 headless profile(默认 mmcollab),挂 ./cordis.patch.yml 让真实 Agent 调用 multi_model_run,并断言四件事:并行双模型都返回、单模型失败被隔离、primary_secondary 的副模型真的审阅了草稿、全部失败时工具调用本身报错。

手工单跑的等价命令(需要先造临时 headless profile):

node "<dsh>/lib/bin.js" --profile mmcollab --from-default-profile headless --dump-config

node "<dsh>/lib/bin.js" --profile mmcollab \
  --patch ./verify/patch-forms/enable-credentials.yml \
  --patch ./cordis.patch.yml --json \
  "Call the multi_model_run tool exactly once with task='Reply with exactly the single word PONG and nothing else.' and omit every other argument. Then print the tool result verbatim."

这里有个容易漏的点:只看退出码不够。Loader 对没能激活的插件行只打印一条 stderr 警告,进程照样 exit 0。验收必须断言 --json 输出里出现 tool_call / tool_result。

适用场景与注意

适合的场景:需要第二意见、需要跨供应商对同一个问题的答案做对比,或者想让一个模型产出草稿、另一个模型审校的场合。它不承担带工具、多步的委派任务——那应该用子 Agent 机制。README 在设计说明里明确写了,这个插件走 ctx.llm.stream() 而不是复用子 Agent,因为前者的每条调用只有一个模型请求,没有会话、工具集和上下文;后者的每个子 Agent 有自己的 loop 和上下文,适合需要模型自己查资料再回答的任务。

使用前要注意几点:

  1. 插件以当前 dsh 进程的权限运行,安装前应检查源码与许可证(MIT)。
  2. 这些调用不是完整 Agent 回合,不会写入 session,也不会被按会话计量的插件(如 cost-meter)统计,因为 GenerateOptions.sessionId 没有设置。每个模型的实际用量看返回里的 usage 字段(includeUsage: true 时)。
  3. 没有工具循环,模型只能拿到 task 文本,不能自己检索或执行命令。
  4. vote 是文本归一化后的严格多数,不是语义投票。开放式答案很少逐字一致,通常会回退到最长答案,并在 summary 里写明。
  5. 默认每个模型最多 12000 字符乘以模型数,模型多或答案长时调小 clipChars。
  6. README 写明实测于 dsh 0.2.1(CLI rc.2 / 桌面打包运行时 rc.3),package.json 声明兼容性为 >=0.2.0-rc.1 <0.3.0-0。
  7. GitHub 上存在一个同名但无关的项目 zanapeng/dsh-multi-model-collab(2026-08 创建),它把固定的四段流水线写死;本插件不是流水线,而是一个通用工具,选型时别装错。

结尾

这个插件的价值在于把”一个任务问多个模型”从一个需要自己搭的编排动作,收敛成 Profile 里一个配置项加一次工具调用,同时把部分失败、取消、聚合策略这些边界情况处理掉了。如果你已经在 DSH 上做模型对比或交叉验证,可以先按方式 B 挂 --patch 试一次,再决定要不要装到 Profile。

目录页:https://www.skillhub.cn/plugins/delltig/dsh-multi-model-collab
GitHub:https://github.com/delltig/dsh-multi-model-collab

羽毛球分组比赛记分
小程序二维码

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

小夜