我平时最烦的一件事,就是本地 ComfyUI 出图的时候,参数、工作流、模型、结果散落一地。每张图都是随机文件名,种子靠手记,模型靠脑子回忆,调了几版之后连自己都分不清哪张图用的哪套配置。后来我把 WorkBuddy 引进来,把本地 ComfyUI 从“手动出图”改造成了“标准流水线”,从任务下发、参数批量注入、排队执行到结果归档,全部走流程。这篇文章就是我搭这条流水线的完整记录,写清楚我为什么这么设计、每一步怎么配置、中间踩了哪些坑,适合那些本地批量出图、一个人管多台机器或者想把 ComfyUI 用成稳定产能的朋友。
1. 先说说 ComfyUI 单机出图到底乱在哪
1.1 节点式工作流是优势,也是“重灾区”
ComfyUI 最大的优点是节点灵活,想怎么接就怎么接。但灵活的另一面,是没人管得住工作流的版本。我在本地玩的时候,今天为了一张图拉两三个节点,明天为了换个 LoRA 权重又拆掉重连,最后工作流文件存了七八个版本,命名全是final_v2、final_v3_真最终、测试改1这种。
这不是 ComfyUI 本身的问题,而是“人肉管理”撑不住复杂度。当你的需求从“出一张图”变成“按固定规格出 50 张图”的时候,手拖节点就彻底没戏了。你得先搞清楚:这批图用什么基础模型,统一用哪个 LoRA,步数和 CFG 是多少,种子是随机还是固定。这些参数如果不固化下来,哪怕只改一个数字,整个批次的结果都不可比。
我自己做过一次“三十张同一提示词的变体测试”,当时靠手在界面上点随机种子,点一次记一次,生怕漏了哪张图的参数。到头来三十张图里真正有用的不到五张,而且其中有几张我根本没法复现当时的配置。那一刻我就知道,必须得有个外部工具来统一管这件事。
1.2 出图过程中的三个失控点,流水线要解决的就是这三个点
我复盘下来,手动模式主要失控在三个地方:
- 种子和工作流配置失控:种子是随机的,工作流 JSON 是反复改的,结果和参数之间没有强绑定。
- 结果文件失控:ComfyUI 默认输出文件名大多是时间戳加随机字符串,靠文件名根本看不出这张图用了什么模型、什么参数。
- 批次任务失控:想跑一百张参数渐变图,手动改参数能改到手抽筋,中间一点错就得重来。
这三个失控点,本质上是同一件事:“状态”没有收拢。种子、模型路径、LoRA 权重、采样参数、输出路径,这些都属于任务状态,散落在界面、记忆和磁盘里,出问题只是时间问题。
我看过很多人在社区里求“批量出图插件”,其实插件只能解决某一个点,比如批量改种子。真正要把出图做成一件事,需要的是把流程串起来,而不是在 ComfyUI 里继续手工补丁。
2. WorkBuddy 在流水线里到底扮演什么角色
2.1 调度层,不是替代 ComfyUI
我一开始以为 WorkBuddy 是个类似 WebUI 的控制台,后来才搞明白,它更像是一个“调度层”。ComfyUI 还是那个执行引擎,负责跑工作流;WorkBuddy 在外面做任务编排、参数注入、执行监控和结果归档。
打个比方,ComfyUI 是车间里的加工机器,WorkBuddy 是车间的生产计划台。生产计划台不加工零件,但它要知道每台机器能做什么、每个订单用什么工艺参数、什么时候开工、产出往哪放。
WorkBuddy 对 ComfyUI 的管理方式也是这个思路:它跟本地 ComfyUI 建立连接,但从不干预你内部的节点逻辑。你原来怎么搭工作流,现在还怎么搭,只是要在工作流里留出几个“变量口”,让 WorkBuddy 能把参数塞进去。
2.2 参数库与任务模板的价值
ComfyUI 的工作流本身就是一张 JSON,里面每个节点的参数是写死的。要想实现批量参数注入,就得把这些写死的值改成“占位符”,然后由 WorkBuddy 在每次提交任务时替换成实际值。
我实际用下来,最值得做的参数化字段有这么几类:
- seed:这个是必须的,批量化生产全靠种子控制随机性。
- 模型和 LoRA 路径:把模型切换变成任务参数,不同批次可以指定用哪个底模。
- 采样参数:steps、cfg、sampler_name、scheduler,这些在测试阶段常常要成组变化。
- 图片尺寸:width、height 在跑分辨率测试时很有用。
- 文件名前缀:让结果文件从一开始就按项目编号命名。
WorkBuddy 里可以给这些参数做组合,比如 a 模型配合 b LoRA 配一组参数,跑 20 张;a 模型配 c LoRA 另外一组,再跑 20 张。这些组合全部可以预设在任务清单里,一个任务清单相当于一张“生产工单”。
2.3 为什么不用“ComfyUI 官方 API + 自己写脚本”的方案
可能你会问,ComfyUI 本来就有 API 模式,自己去写 Python 脚本也能提交任务、轮询结果、下载图片。我最初也是这么干的,写了几百行脚本,确实能跑,但用了一段时间发现问题更多。
脚本的问题在于它只有“逻辑”,没有“状态管理”。我那次脚本跑到一半,想改一下种子范围,得去改代码;跑到一半断了,没有任务台账,不知道到底完成了多少张;出图失败了,日志里只有一串异常,也不知道是哪条任务、哪组参数导致的。
WorkBuddy 把上面这些散装逻辑做成了可视化的界面和状态记录。任务跑没跑完、成功几张失败几张、每一张对应什么参数,都有据可查。对个人用户来说,这可能只是方便一点点;但如果你要跑 200 张图过夜,第二天早上起来看任务清单,一眼就知道产出情况,这就是刚需。
3. 把 ComfyUI 接入 WorkBuddy 的实操配置
3.1 前置准备:ComfyUI 启动起来
WorkBuddy 要跟 ComfyUI 通信,前提是 ComfyUI 得跑在 API 模式下,并且端口能被 WorkBuddy 访问到。我自己是在本机跑,直接默认端口就行。
启动命令一般是这个样子:
python main.py --listen 127.0.0.1 --port 8188这里有个容易被忽略的点:--listen参数决定了 ComfyUI 监听哪个地址。如果只在本机用,写127.0.0.1就够了;如果是局域网里别的机器也要调,那得监听0.0.0.0,但这时候就涉及到安全问题了,你自己得掂量清楚。
启动之后,先在浏览器打开 ComfyUI 面板,确保能正常加载模型、能出图,再接到 WorkBuddy 上。这是最笨但最稳的验证顺序,先确认机器本身没问题,再谈上层调度。
3.2 工作流 JSON 的“占位符改造”
这是整个接入过程里最关键的一步,也是我最想提醒你用心做的一步。
你先在 ComfyUI 界面里把工作流搭好,比如“文生图 + 高清放大 + 保存图片”,然后导出 JSON。这个 JSON 就是蓝图。WorkBuddy 拿到它之后,需要在里面找到想参数化的节点字段,把这些字段的固定值改成占位符。
我当时是这样改的:找到KSampler节点里的seed字段,把里面的数值替换成${seed};找到CheckpointLoaderSimple里的ckpt_name,替换成${ckpt_name};输出文件名前缀改成${prefix}。
改完之后,工作流 JSON 里大概会长这样:
{ "3": { "class_type": "KSampler", "inputs": { "seed": "${seed}", "steps": 20, "cfg": 7, "sampler_name": "euler", "scheduler": "normal", "denoise": 1.0 } }, "4": { "class_type": "CheckpointLoaderSimple", "inputs": { "ckpt_name": "${ckpt_name}" } }, "9": { "class_type": "SaveImage", "inputs": { "filename_prefix": "${prefix}" } } }这一步的感悟是:别一口气把太多东西都参数化。刚开始只需要把 seed、模型、前缀这三个核心变量做成占位符,跑通了再慢慢加。参数化得越多,模板越灵活,但出错的可能性也越大,尤其是动态尺寸这类,手一抖就控制不住了。
3.3 WorkBuddy 里的任务定义与批次跑通
接下来在 WorkBuddy 里建任务。我在 WorkBuddy 里的操作逻辑是:先建立一个“项目”,然后在项目下维护“任务清单”,再给任务清单绑定一套“参数组合”。
举个例子,我要做一组“五十张不同种子的城市夜景图”,任务清单里就定义成:
- 工作流模板:城市夜景 + 高清放大
- 模型组:
realisticVision+夜景增强 LoRA - 步数:25
- CFG:7
- 分辨率:512 x 768
- 种子:从 10001 到 10050
- 文件名前缀:
city_night_
提交之后,WorkBuddy 会自动把五十个 seed 依次注入工作流模板,每个 seed 生成一个任务,任务按顺序排队,提交给 ComfyUI 执行。
第一次跑的时候,我没有一次性提交五十个,而是先提交一个任务试跑。确认输出目录里有图,文件名前缀和参数都对上了,再放开到五十个。这个习惯我一直保持到现在:先跑单,再跑批,永远不要拿整批任务去试错。
3.4 输出验证与状态回读
跑完任务之后,WorkBuddy 会在任务列表里显示每个任务的状态:排队中、执行中、成功、失败。我拿到成功状态之后,还会做一步验证:去输出目录里找对应前缀的文件,确认文件存在且不是零字节。
这里有个经验:ComfyUI 执行成功不等于图片真的可用。有时候生成出来的是全黑图或者纯噪点图,它也是“成功”状态,但实际是废图。所以我在 WorkBuddy 之外,还会定期抽查输出文件夹,用文件大小做一个粗筛,小于某个阈值的文件基本可以判定为异常。
4. 批量出图时的资源控制与排队策略
4.1 一次塞一百个任务,显存为什么炸
第一次把任务提到 100 个的时候,我天真地以为 WorkBuddy 会帮我排队管理,结果它默认把所有任务一次性投给了 ComfyUI。ComfyUI 自己的队列是顺序执行的,本来问题不大,但问题出在并发设置上。
我在 ComfyUI 启动参数里开了多进程并行,以为能加快速度。结果就是 100 个任务同时往下灌,显存瞬间爆了,卡死,任务全部失败。
后来我明白了一个道理:ComfyUI 的批次能力,本质上是单任务内的多批次,而不是多任务并发。真正要管的是“同一时刻在 ComfyUI 里跑几个任务”,而不是“总共提交了几个任务”。
我在 WorkBuddy 里把最大并发调成了 1,也就是同一时间只让 ComfyUI 跑一个任务,剩下的排队等待。虽然速度没有翻倍,但稳定性提升了一大截,至少不会出现那种“前面跑得好好的,突然所有任务全部失败”的惨剧。
4.2 按模型分组排队,减少模型换载
ComfyUI 每次切换底模都要重新加载模型到显存,这个加载时间有时候比出图时间还长。我后来在 WorkBuddy 里做任务规划时,会把同一个底模的任务排在一起,让相同配置的批次连续跑,然后再切换到另一个底模。
比如我这个月的一个任务是:用 A 模型出 200 张,用 B 模型出 200 张,用 C 模型出 100 张。如果按“A 一张,B 一张,C 一张”这么切,三个模型来回换,显存里反复载入卸载,效率低得离谱。按模型分组之后,A 跑完 200 张再换 B,B 跑完再换 C,实测时间能省 30% 以上。
这个经验可以推广到任何批量出图场景:把配置相近的任务尽量放在一起,让 ComfyUI 复用已加载的资源,而不是频繁横跳。
4.3 失败自动重试:不能无脑开
WorkBuddy 里有失败重试的设置。我一开始把重试次数设成 3,结果有个任务因为显存问题连续失败了三次,又重试了三次,白白浪费了大量时间。
后来我把重试策略改成了“只在前一个任务成功的情况下才允许重试”,也就是同一时刻最多跑一个任务,失败了先停下来检查问题,而不是盲目重试。
对于批量出图这种场景,我的建议是:重试打开,但次数别超过 2 次,而且一定要看失败日志。如果是因为显存不足、模型加载失败这种系统性原因,重试再多也没用,得先把根因解决了。
4.4 显存监控与爆显存的自动处理
我在跑流水线的时候,习惯每隔几十秒看一眼显存占用,特别是刚切换模型的前几秒。最危险的时候不是出图过程中,而是 ComfyUI 加载新模型那一刻,加载瞬间显存需求会突然冲高,容易爆。
后来我在 WorkBuddy 里加了一个“显存预留”的设定,就是给 ComfyUI 留出一些余量,不至于把显存全部吃满。这个数值没有标准答案,取决于你的显卡型号和模型大小。我自己的显卡是 12G 显存,普通 SD1.5 模型加放大节点,预留 1.5G 左右就够;如果跑 XL 系列模型,那预留空间还要更大。
没有预留的后果就是,任务跑到第 30 张的时候突然爆显存,排队队列里剩下的 170 张全部跟着遭殃,一旦发生就得从头来。宁可慢一点,也要把余量留够。
5. 出图结果的质检与归档:流水线的最后两公里
5.1 文件命名规范:没人愿意翻两小时图库
档案管理这件事,看着不起眼,其实决定流水线能不能长期用。我早期就是吃了命名的亏,输出目录里几千张图,文件名全是00001_time这种,想找一张图比大海捞针还难。
在 WorkBuddy 里,我把文件名前缀当成一个完整的信息载体。一个标准的输出文件名大概长这样:
20250412_城市夜景_v3_seed10001这个命名规范里包含了日期、项目代号、工作流版本和种子号,看到名字就能定位到当时用的模板、参数和批次。这四个字段是我反复调整后确定下来的最小信息集,再加其他内容文件名就太长了,反而不好用。
同时目录结构也要配合好。我用的结构是:
输出目录/ 2025-04/ 城市夜景/ 20250412_city_night_seed10001.png按月份做一级目录,按项目做二级目录,文件按规范命名。这样就算累计上万张图,要找某一次跑批的产出,也只需要三步:进月份、进项目、按 seed 搜文件。
5.2 人工挑图的流程:流水线不能替你审美
流水线能帮你把图生成、命名、归档,但它不会替你做审美判断。所以我保留了一个“人工挑图”环节,只是把挑图这件事也变成了流程的一部分。
我的做法是:每批任务跑完后,先通过 WorkBuddy 查看任务清单和参数记录,把明显异常的任务挑出来(全黑图、畸形图、爆显存残留的半成品),删掉;然后把正常的图导入到看图软件里,用键盘翻图,在文件名里标记_good或_keep后缀,同时把对应的 seed 记下来,方便后续复现。
这里有个心得:挑图的速度通常会远超你的预期。五百张图,正常看下来也就一两个小时。真正费时间的不是挑图,而是挑完之后去回看参数:这一张好看的,到底用了什么模型、什么 CFG、什么 LoRA 权重?所以参数归档才是关键。
5.3 记录废图的原因,比记录废图本身更有价值
我后来在 WorkBuddy 里养成了一个习惯:每个批次跑完,我都写一点批注,记录这批次里废图的主要原因。比如“CFG 开到 9 之后对比度过高,植被糊了”“这个 LoRA 权重超过 0.8 之后肢体开始变形”“夜景提示词加了月光,但出图全是死黑”。
这个习惯看上去是在做记录,其实是在积累一套自家的参数经验库。下次再做类似需求,直接翻批注,能少走很多弯路。我之前出图全靠感觉,现在出图靠记录,两者最大的区别就是:靠感觉的结果不可复现,靠记录的结果每一版都有据可查。
6. 踩坑复盘:本地 ComfyUI 流水线最容易翻车的几个点
6.1 端口冲突和 ComfyUI 更新后的 API 变化
有一次我同时开了两个 ComfyUI,一个用来调试,一个被 WorkBuddy 调度,结果端口占用了,WorkBuddy 连不上。排查了半天才发现是我自己忘了改端口。
还有一个更容易踩的坑:ComfyUI 更新之后,API 结构有可能变化,工作流里某些节点的class_type或者输入字段名变了,你旧的工作流模板跑起来会直接报错。我的处理方式是把工作流模板锁定,不在流水线上直接改,新的测试先在 ComfyUI 界面里跑通,确认无误再更新到 WorkBuddy 的任务模板里。
6.2 模型路径的坑:不要用绝对路径硬编码
工作流 JSON 里的ckpt_name,ComfyUI 是按相对路径读的。但我见过有人直接把模型路径写成了某个绝对路径,换了一台机器之后,整个工作流直接崩掉。
我的建议是:模型路径统一使用相对路径,并且把模型目录里的文件命名规范好,中英文和特殊符号都尽量避免。WorkBuddy 里参数化模型名的时候,直接传“模型文件名”就行,尽量不要带目录层级。
6.3 种子相同的“假随机”问题
提防一个反直觉的情况:当你把种子固定成同一个值,但改了模型的权重或者加了提示词,出来的图其实还是会在某些局部保持相似,让人觉得“是不是没随机成功”。
实际上,ComfyUI 的随机性不只取决于种子,还取决于输入条件图的形态。相同种子下,只要 prompt 不同、模型不同,出来的结果就会有差异,只是这种差异不像你想象的“完全不同”,而是在构图上有某种延续性。这不是 bug,是扩散模型的固有特性。
在流水线里,如果你想做“相同提示词下测试种子对构图的影响”,种子就要保持连续递增,而且每次只改 seed 一个变量,其他参数全部固定,对比才有意义。
6.4 临时文件与磁盘空间的隐形增长
ComfyUI 跑长时间任务的时候,预览图片、中间缓存、工作流备份都会慢慢占磁盘。我有一次连续跑了一整夜,第二天早上发现磁盘满了,ComfyUI 直接卡死,任务全部中断。
从那以后,我在 WorkBuddy 里加了一层磁盘监控,并且在系统层面定期清理 ComfyUI 的 temp 目录和旧版本输出。另外建议给输出目录单独挂一个容量足够的分区,跟系统盘分开,避免因为磁盘满导致整个机器动弹不得。
6.5 不要忽略 ComfyUI 界面里“手动跑一次”的价值
最后这条可能听着有些反流水线,但恰恰是我最大的经验:接入 WorkBuddy 之后,别把所有出图都交给自动化。遇到新模型、新工作流或者新需求,先在 ComfyUI 界面里手动跑一两张,确认工作流逻辑正确、参数合理,再更新到 WorkBuddy 模板里。
我之前图省事,新做的 LoRA 测试直接丢进流水线跑了一整批,结果 LoRA 本身就有问题,一百张全废,白浪费两个多小时。手动画一两张的时间成本几乎可以忽略,但能帮你省下整批重跑的时间。
结语:流水线工作流的最终收益,是让“下一次”变简单
我搭这条 WorkBuddy + ComfyUI 流水线,最核心的目的不是让单张图变得更好看,而是让批量生产这件事变得可控、可跟踪、可复现。以前每次调整参数都是一次新的冒险,现在每一次跑批都是基于模板的增量迭代,哪怕翻车,也能从记录里找到原因。
最后分享一个我现在还在用的小技巧:每跑完一个项目,我会把 WorkBuddy 里的任务模板和这个项目的成品图一起打包备份,模板用于后续复用,成品图用于随时回看。过两个月再翻出来,依然能快速定位到某张图用的参数配方。对长期做图库、做素材积累的人来说,这大概就是流水线最实在的价值。如果你也准备自己搭这么一套,我建议从小批量开始,先把模板跑稳,再慢慢放量,千万不要一上来就整五百张。