安装
在 DeepSeek Harness 里通过 dsh-market 安装
dsh plugin --profile web add dshmarket
或使用命令行
dsh plugin --profile web add github:BOWLUNA/dsh-zcode-farm
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络。请先审阅源码,并尽量锁定 commit(github:owner/repo#sha)。
README
English | 中文
让 DeepSeek Harness 的 Agent 看见整个 ComfyUI 农场,并把每个任务派给最空闲的那一台。
dsh plugin --profile web add dsh-zcode-farm
dsh-comfyui(77★) |
本插件 | |
|---|---|---|
| 能寻址的端点 | 一个 | 多个,并发探测 |
| 队列深度 | 会读 /queue,但只有一个实例时可比较的只有它自己 |
跨实例加权进排序 |
| 任务落在哪 | 就那一台 | 空闲显存最多且队列为空的那台 |
| 会不会写 ComfyUI | 会 | 会(comfyui_farm_run),但只读也够用 |
零运行时依赖 · 适配 Node ≥ 22 · MIT
为什么需要它
ComfyUI 官方文档写得很清楚:一个 ComfyUI 进程一次只跑一个工作流,真正的并发只能靠
「每张卡一个进程,再把任务路由到最空闲的实例」。生态里也已经有 comfyui-orchestrator
这类 Node.js 池化库。
但把它们接到 AI Agent 上时,有一个缺口一直没人填:Agent 看不见农场。
实测(2026-09-21 某一刻的真实读数,来自本插件自己的探针):
| 实例 | GPU | 空闲显存 | 队列 | 判定 |
|---|---|---|---|---|
18100 ← dsh-comfyui 唯一能看见的那台 |
RTX 5090 | 0.8 / 33.7 GB | 1 跑 / 0 等 | 装不下 |
18300 |
RTX 5090 | 0.8 / 33.7 GB | 1 跑 / 0 等 | 装不下 |
18301 |
RTX 5090 | 0.9 / 33.7 GB | 1 跑 / 0 等 | 装不下 |
18302 |
RTX 5090 | 0.5 / 33.7 GB | 1 跑 / 0 等 | 装不下 |
18303 |
RTX PRO 6000 Blackwell | 99.4 / 102.0 GB | 0 / 0 | ✅ 全空 |
dsh-comfyui(77★,市场里做这件事最成熟的插件)只能连一个端点,
于是 Agent 的每次出图请求都会撞上最忙的那台——而 102 GB 的算力从头到尾闲置。
本插件补的就是这一层:先让 Agent 看见,再让它派发。
它做什么
三个工具:
| 工具 | 作用 |
|---|---|
comfyui_farm_status |
农场全景:每台的 GPU、空闲显存、队列深度、在跑什么,以及当前该派给谁 |
comfyui_farm_pick |
只选择、不执行:按显存门槛 / 队列上限 / GPU 型号关键字 / 排除名单挑一台,并给出理由 |
comfyui_farm_run |
负载感知派发:自动选实例(或指定某台),支持原始 API 工作流,也支持「提示词 + 模型」一键文生图 |
安装
dsh plugin --profile web add dsh-zcode-farm
装完重启应用,Agent 立刻获得上述三个工具。
配置
- id: comfyui-farm
config:
# 主端点,总是纳入探测(不在 instances 里也会被探测)
primaryUrl: 'http://127.0.0.1:8188'
# 农场成员。留空则退化为单实例模式。
instances:
- { id: gpu-18301, baseUrl: 'http://127.0.0.1:18301', label: '5090 分片' }
- { id: gpu-18303, baseUrl: 'http://127.0.0.1:18303', label: 'Blackwell 102G' }
# 派发策略
needVramGb: 8 # 低于此空闲显存视为「装不下」
maxQueueDepth: 3 # 队列深到此值就不再派发
queueWeight: 1000 # 排序惩罚,见下
# 探测
probeTimeoutMs: 5000
probeRetries: 1
选实例的规则(两段式)
- 过滤——不可达 / 空闲显存
< needVramGb/ 队列深> maxQueueDepth的,一律出局。 - 排序——
score = 空闲显存(GB) − 队列深 × queueWeight
默认 queueWeight = 1000 是刻意的:让队列主导排序,显存只在队列相同时做平局决胜。
直觉上是对的——一台空着的小卡,比一台正排队的大卡更快出结果。
只想用「显存最多者优先」?把
queueWeight设成0即可。
与 dsh-comfyui 的关系:互补,可共存
dsh-comfyui(77★) |
dsh-zcode-farm |
dsh-comfyui 那一列怎么核 |
|
|---|---|---|---|
| 管的范围 | 一个端点 | 一整个农场 | grep -n baseUrl package/lib/config.js → 一个 z.string() |
| 强项 | 工作流库、技能包、画布、资产面板 | 状态感知、选实例、派发 | ls package/lib |
| 任务怎么落地 | 单端点在哪就发哪 | 按「空闲显存 − 队列深 × 权重」排序 | grep -n "constructor(baseUrl" package/lib/comfyui.js |
| 装配行 id | comfyui |
comfyui-farm |
两个都出现在本仓库的 cordis.patch.yml 里 |
两行 id 不同,可以同时装配:用 dsh-comfyui 管深度体验,用本插件决定"这活派给谁"。
也可以只用其中一个。本插件不依赖 dsh-comfyui,反之亦然。
dsh-comfyui 的单端点设计是从它已发布的源码核出来的,不是断言 —— 三条命令见下面「怎么自己复核这张表」。
与 ZCode 的关系
本仓库是自研的 —— 与 ZCode 没有代码血缘。 ZCode(zai-org/ZCode、zai-org/GLM-skills)
在这里的角色是工程约定的灵感来源,不是依赖:安装路径、运行时、验收检查里没有任何一处
需要它,本仓库也不涉及任何第三方厂商的 key。
因此下表多数格子是故意留白的,而不是填上编出来的东西。
| ZCode 有什么 | 本插件取了什么 | 本插件多了什么(优于在哪) | 证据(自己跑一遍) |
|---|---|---|---|
| 多实例 ComfyUI 调度:无 | —— | 整个「探测 → 排序 → 派发」闭环 | grep -rli comfyui <zcode 检出目录> | wc -l → 0 |
带两个跳过条件的记忆抽取子代理(apps/zcode-cli/packages/core/src/memory/extraction.ts:23) |
——(不同领域) | —— | 不适用 —— 没取任何东西,所以没有主张要复核 |
| 双语配对文档 | 作为本工作区的约定沿用 | 扩展到了图文件(*.svg)—— 示意图与译文不会再各自漂移 |
node tools/verify-translation-pairing.mjs |
| 守卫纪律 —— 提交前跑得动的检查 | 作为本工作区的约定沿用 | 扩展到六道,第六道是真启动检查 | node test/run.mjs 与 node tools/boot-check.mjs --port 32041 |
写着 —— 的行是如实留白,不是漏填。
怎么自己复核这张表
上面每一条都不需要你相信 —— 下面就是它背后的命令:
git clone https://github.com/BOWLUNA/dsh-zcode-farm && cd dsh-zcode-farm
node test/run.mjs # 2 个套件、23 项检查
node tools/ordering-replay.mjs # 图背后的排序对照表
node tools/boot-check.mjs --port 32041 # 真装一次、真启动一次(需要一个 harness)
关于 dsh-comfyui 的几条,是拿它已发布的包核的,不是拿本仓库:
npm view dsh-comfyui version # 0.5.1
npm pack dsh-comfyui@0.5.1 && tar xzf dsh-comfyui-0.5.1.tgz
grep -n baseUrl package/lib/config.js # 一个字符串,不是列表
grep -n "constructor(baseUrl" package/lib/comfyui.js
9: baseUrl: z.string().default('http://127.0.0.1:8188'),
71: constructor(baseUrl, apiKey, connectTimeoutMs, maxMediaBytes) {
以上命令在 2026-09-22 对 dsh-comfyui@0.5.1 实跑过。
设计取舍
- 零运行时依赖。 只用 Node 内置的
fetch/AbortController。 - 不做工作流编辑。 那是
dsh-comfyui的地盘;这里只回答"派给谁"。 - 不假设本地。 所有成员都是 URL——SSH 隧道、局域网、远端机器一视同仁。
本机的 5 条隧道就是
ssh -L转发出来的。 - 探测失败会重试。 跨隧道抖动很常见:实测同一台机器一次探测
>3s超时、 紧接着106ms就返回。单次失败不当结论,重试后再判,并把attempts报出去, 让 Agent 能区分「真宕机」和「抖了一下」。 - 失败原因不被覆盖。 例如按 GPU 型号筛选时,不可达的实例会保留"不可达"这个原因, 不会被改写成"型号不匹配"而把真正的问题藏起来。
开发
npm test # 单元测试(纯函数,不碰网络)
node probes/probe-farm.mjs # 独立探针:只看农场状态
node probes/probe-tools.mjs # 加载插件入口并真实执行工具(只读)
node probes/probe-tools.mjs --run # 真的派发一次任务(默认最小负载:512² / 12 步)
开发期需要把宿主提供的 peer 依赖(@deepseek-ai/schemastery 及其依赖)放到本地
node_modules/,否则入口无法加载。装配到真实 profile 时不需要——宿主会提供。
已知限制
comfyui_farm_run的内置模板只覆盖最简文生图(KSampler + CheckpointLoaderSimple + EmptyLatentImage + 两个 CLIPTextEncode + VAEDecode + SaveImage)。复杂需求请直接传workflow。- 不检测"两个 URL 指向同一台机器"。如果你同时配了一个可切换的转发口(如把
127.0.0.1:8188指向"当前聚焦实例")和它的真实目标,你会看到两行读数完全相同的成员。 这是如实反映,不是 bug——探测本身无法区分。 /prompt返回的number是服务端累计接单序号,不是队列位置 (实测:队列为空时它照样返回 22)。真实队列深度以comfyui_farm_status的输出为准。
License
MIT
状态
- 2 个套件、23 项检查 —— 跑
node test/run.mjs - 声明兼容范围:
>=0.1.5-rc.2 <0.2.0-0 || >=0.1.6-alpha.1 <0.2.0-0 || >=0.1.7-alpha.1 <0.2.0-0(见engines.dsh与 peer 范围) - 钉住版本可绕过 pnpm 的发布冷却期:
dsh plugin --profile web add dsh-zcode-farm@1.0.1 - 已在 5 个 SSH 隧道实例 + 1 个可切换转发口上验证
评论
评论存放在 GitHub Discussions。用 GitHub 账号登录后可发表评论或点表情。