☰
从手动点到全自动:用WorkBuddy搭建ComfyUI批量出图流水线
2026/10/21 12:51:21 网站建设 项目流程

如果你跟我一样,跑 ComfyUI 不只是玩票,而是真的每天要出几十上百张图,那你迟早会撞上同一堵墙:显卡算得过来,我点鼠标的手却跟不上。我最开始的做法是手动调好参数、跑一遍工作流,出图之后人工改 seed 继续跑,一个晚上折腾下来,任务没做完多少,人先被重复劳动磨得没脾气。后来我用 WorkBuddy 把本地 ComfyUI 管成了一条出图流水线,出图这件事从“人肉点击”变成了“提交任务—自动调用—定时收图—自动归档”。这篇文章完整记录我是怎么搭的、关键配置怎么写的、踩了哪些坑,给同样被手工出图折磨的人一份可以照着抄的作业。

这套方案不需要改 ComfyUI 源码,也不需要对图像生成原理有多深入的理解,只要你会看配置文件、能跑一下命令行,就能把它复现出来。适合的人群很明确:批量出图需求多的人、做风格试验需要跑大量参数组合的人、想把手动操作交给程序去盯的人。如果你一天只出三五张图,那手动点完全没问题;如果你像我一样经常一次要跑 50 张、100 张,这篇文章就是为你准备的。

1. 从“手动出图”到“流水线”,我实际经历的三类损耗

1.1 手动模式不只是慢,而是注意力被切碎

很多人觉得手动出图无非是“多点几下”,真正批量跑过的人才知道,最耗人的不是点 Queue 那一下,而是任务与任务之间的参数切换。我要跑一组“同一个构图、不同光源描述”的对比图时,每个图都要改提示词,改完检查一下,点提交,等十几秒,再看着图片生成,再改下一张。一次跑 20 张,注意力就被切成了 20 段。

这种模式下我经常出现两个问题:一是改着改着把参数改错了,等跑完 5 张才发现整组构图都不对;二是中间被别的事打断,回来后完全忘了刚才跑到哪一张。手动模式不是不能跑,而是只要任务量大于 10,人的大脑就开始变成劣质的任务管理器。

1.2 输出文件的命名与归档,比出图本身更让人头大

ComfyUI 默认生成的图片文件名,通常是一串时间戳加上一个序号。单张看没问题,几十张图混在一起,事后想找到“某一组提示词对应的图”,基本只能靠肉眼一张张辨认。我最早的做法是把图按天存到一个文件夹里,结果三天之后就彻底乱了。

更头疼的是,图片本身不携带参数信息。我跑完一组图后想复盘“这张图的 CFG 是多少、seed 是多少”,只能回去翻工作流配置。如果中间重新加载过多次工作流,那就完全对不上号了。这也是我后来下决心要解决的核心问题:图不只是图,它背后必须能回溯到生成它的完整参数。

1.3 手动模式与流水线模式的对比

我把两种模式的差别整理成一张表,看完就明白为什么值得折腾:

对比项手动模式WorkBuddy 流水线模式
任务来源人肉逐条操作参数矩阵自动展开,一次生成几十个任务
参数切换每次改完再提交模板占位符替换,自动套用
运行监控盯着界面看轮询任务状态,异常自动告警/重试
失败处理出错后手动重新提交自动重试并记录错误快照
文件归档全靠手工整理按日期/项目/类别自动归档
参数回溯基本靠记忆每次运行自动写 manifest 记录

当然,流水线不是万能药。我在做风格探索、还没确定方向的时候,依然会手动跑图,因为那种场景下灵感驱动的随机尝试更重要。自动化真正发挥价值的地方,是方向已经确定、只需要批量产出的阶段。先用少量图把“质感”定下来,再切到流水线去“放量”,这是我目前认为最合理的配合方式。

2. WorkBuddy 的定位:它不是替代 ComfyUI,而是包在 ComfyUI 外面的任务大脑

2.1 为什么 ComfyUI 自带的 Queue 不够用

ComfyUI 本身确实有队列功能,可以把多个任务排在一起,依次执行。但用过的朋友都知道,这个队列里的每个任务,本质上还是“你手动改好参数后塞进去的那一张图”。它不会自动把一组提示词拆成十个变体,不会自动循环 random seed,也不会在你跑完一组以后自动把下一个项目的任务接上。

另一个比较恼火的点是,ComfyUI 的队列是跟当前加载的工作流绑定的。我想在跑量产任务的中途插入一个快速测试,就得动界面上的工作流,队列逻辑会变得很难控制。WorkBuddy 的思路是把任务调度和计算解耦:ComfyUI 只负责“把这张图算出来”,WorkBuddy 负责“下一步该算哪张、算完之后文件放哪、要不要重跑”。

2.2 WorkBuddy 与 ComfyUI 的分工边界

我一开始也想过直接写 Python 脚本调 ComfyUI 的 API,毕竟它本身就提供了/prompt和/history接口。但自己写脚本最大的问题是:任务一旦跑起来,我依然要自己处理队列持久化、失败重试、并发控制、文件归档这些和“出图”无关但非常占精力的事。

WorkBuddy 在这个场景下的角色,更像一个本地任务编排工具。它通过 HTTP 与 ComfyUI 通信,把用户定义的任务清单翻译成 ComfyUI 能理解的工作流 JSON,提交之后轮询执行状态,再把最终产物移动到归档目录。它不介入图像生成,也不碰模型文件,所以 ComfyUI 升级或者换模型,对流水线本身没什么影响。

我用家里的旧工作机做部署,Windows 系统,单卡 12GB 显存,ComfyUI 装在本地磁盘。选择本地方案而不是云服务,主要考虑三点:一是底模和 LoRA 都在本地,省去上传下载的等待;二是数据不出本机,不用纠结隐私问题;三是离线也能跑,不依赖网络稳定。WorkBuddy 本身也只监听本地端口,默认不开放到外网。

2.3 最小安装与连接验证

先说明一下基础环境:我用的 ComfyUI 启动方式是常规的本地运行,启动参数很简单:

python main.py --listen 127.0.0.1 --port 8188

--listen我限制为 127.0.0.1,只有本机可以访问,因为 WorkBuddy 也跑在同一台机器上,没必要把 API 暴露到局域网。

ComfyUI 起来之后,先用浏览器确认界面能打开,然后验证 API 是否正常响应:

curl http://127.0.0.1:8188/system_stats

如果能返回{"system": {...}}这样的 JSON,说明 API 服务已经就绪。接下来在 WorkBuddy 的配置目录里创建一个配置文件config.yaml,我贴出最简版的骨架:

comfyui: base_url: http://127.0.0.1:8188 queue_poll_interval: 3 tasks: default_template: workflows/base_workflow_api.json output_root: D:/ArtPipeline/outputs schedule: concurrency: 2 max_retries: 3 task_timeout_multiplier: 2.5

queue_poll_interval控制 WorkBuddy 每隔几秒去查一次任务状态;concurrency是同时跑的任务数,这个不是越大越好,后面我会专门讲怎么调;max_retries是单个任务失败后的重试次数。配置写好之后,可以先跑一个测试任务,确保 WorkBuddy 能正常向 ComfyUI 提交工作流并接收到完成状态。这一步跑通了,后面批量扩量才安心。

3. 把一张工作流改造成可批量复用的“工序卡”

3.1 必须使用 API 格式的工作流 JSON

ComfyUI 界面里保存工作流时,有两种格式容易混淆:一种是.json的 UI 工作流,里面包含节点坐标、连线信息,这种文件是给界面加载用的;另一种是 API 格式,结构更精简,只保留每个节点的class_type和inputs,可以直接提交给/prompt接口。

我踩过的第一个坑就是:直接把 UI 保存的 JSON 丢给 API 提交,结果返回 400。所以正确做法是在 ComfyUI 界面里,通过菜单导出 API 格式的 JSON。如果界面上找不到入口,也可以用另一个思路:先自己加载好工作流,然后在浏览器开发者工具里看提交给/prompt的请求体,把它存下来,那就是最真实的 API 格式。

这个 API 格式的文件,就是我要说的“工序卡”。它描述的是“一张图应该经过哪些节点、每个节点用什么参数”。同一张工序卡,配合不同的参数替换,就能批量生产一堆构图一致但细节不同的图。

3.2 找出需要动态替换的节点

看 API 格式的 JSON,你会发现它是用节点 ID 做 key 的字典结构。比如:

{ "3": { "class_type": "KSampler", "inputs": { "seed": 1000, "steps": 30, "cfg": 7.0, "sampler_name": "euler", "scheduler": "normal", "denoise": 1.0 } }, "6": { "class_type": "CLIPTextEncode", "inputs": { "text": "a cat sitting on a windowsill, morning light", "clip": ["11", 0] } } }

我一般会先找出这几个最常改的节点:

  • CLIPTextEncode节点:替换text字段,实现不同提示词的任务;
  • KSampler节点:替换seed字段,实现同一提示词下不同随机种子;
  • EmptyLatentImage节点:替换width、height,控制分辨率;
  • LoraLoader节点:替换strength_model、strength_clip,控制 LoRA 权重。

把这些字段找齐之后,在 WorkBuddy 里把它们映射成模板占位符。比如把提示词替换为${prompt},把 seed 替换为${seed}。这一步是整个流水线最核心的建模工作:先想清楚“我批量出图时,哪些参数是会变化的”,然后把它们变量化。

3.3 参数矩阵展开:一组配置生成几十个任务

有了模板还不够,还得让 WorkBuddy 知道“具体生成哪些任务”。我常用的做法是定义一个任务清单文件,里面的每一项都是一组参数。比如我想跑“同一张构图,3 种提示词风格,前 10 个 seed 各出一张”,那就是 30 张图。

在 WorkBuddy 的配置里,我推荐使用tasks.yaml来声明任务矩阵:

task_groups: - name: lighting_test workflow: workflows/base_workflow_api.json inputs: width: 768 height: 768 steps: 28 prompt_variants: - "golden hour lighting, warm tones, soft shadows" - "neon lighting, cyberpunk style, high contrast" - "overcast sky, diffused light, muted colors" seeds: from: 10001 count: 10 output_dir: lighting_test

WorkBuddy 读取这个配置后,会做一个简单的笛卡尔积:每个 prompt 配 10 个 seed,一共 30 个任务。output_dir字段存在模板 JSON 的一个附加节点里,最后输出图片时会按照这个字段来分目录。这样做的好处是:我不用手写 30 条任务,只需改prompt_variants和seeds.count,就能扩展或收缩规模。

3.4 任务 ID 与出图文件挂钩,保证可回溯

批量生成最大的隐患,是图出来了却不知道它对应哪组参数。我的解决办法是让 WorkBuddy 在提交任务时生成一个task_id,并把它写入工作流里SaveImage节点的filename_prefix字段。比如filename_prefix设为lighting_test/task_0042,那么 ComfyUI 输出的图片路径就带上了任务信息。

同时,WorkBuddy 每完成一个任务,就把task_id、对应参数、输出文件路径、耗时写入一个运行记录表。后面我哪怕隔了一个月再翻看这张图,也能立刻查到它当时用的什么提示词、什么 seed。这比任何“凭感觉复盘”都靠谱。

4. 调度策略:串行、并发与失败重试的取舍

4.1 先想清楚你显卡的显存上限

流水线跑起来以后,最需要控制的就是并发数。很多人一看“并发”两个字就想开大,结果一跑就显存溢出。以我常用的 12GB 显卡为例,出 1024x1024 的图,单任务大概占 8GB 左右显存。如果同时提交 3 个任务,峰值显存很可能超过 12GB,直接 OOM。

WorkBuddy 的并发指的是“同时处于运行状态的任务数”,不是一次性提交到队列里的任务总数。提交太多任务进去,ComfyUI 也是排队处理,并不能提升速度,反而会让队列难以控制。所以我建议先保守起步,单卡 12GB 用concurrency: 2,24GB 卡可以试concurrency: 3或4,但也要结合具体分辨率和模型来看。核心判断标准是:任务并发执行时,显存占用峰值不要超过显卡可用显存的 85%。

4.2 不要无脑塞队列,让 WorkBuddy 动态补充任务

ComfyUI 的接口里有一个/queue,可以查询当前排队和正在执行的任务数。我让 WorkBuddy 不是把 30 个任务一次性全提交,而是维护一个“待执行任务池”,只有当队列剩余数量低于某个阈值时,才补充下一批。

对应的逻辑可以理解成:

while 还有未完成任务: 查询当前队列剩余数 如果剩余数 < 3: 从待执行列表里取 2 个任务提交 等待几秒后再查询

这种设计有几个实际好处:第一,显存压力可控,不会因为一次性提交太多而互相挤占;第二,如果中途想插队跑一个紧急测试,队列不长,很快就能轮到;第三,如果某个任务反复失败,我可以人工介入,而不会被后续几十个任务淹没。

4.3 超时判定与自动重试的细节

生成任务不是每次都能顺利跑完。我遇到的情况有几类:模型加载后第一次跑偶尔报错、显存峰值瞬间超限、某些采样器参数组合导致执行时间异常长。WorkBuddy 的判断逻辑是,先记录单个任务正常执行的耗时基线,如果某次任务执行时间超过基线的 2.5 倍,就标记为可疑任务,进入超时处理流程。

超时之后不直接重试,而是先把任务放到“延迟队列”,等当前正在跑的图全部结束后再重跑。原因很简单:显存溢出的任务,立刻重跑大概率还是一样的结果,等别的任务释放显存后再试成功率会高很多。

重试次数我控制在 3 次以内,每次重试之间间隔 1 到 2 分钟。如果 3 次都失败,就不再动了,把错误快照和任务参数保留下来,提醒我人工排查。这里有个很重要的原则:宁可重跑,也不要让失败任务把整条流水线堵死。我早期是失败后一直挂起等待人工处理,结果后面几十个任务全都在排队围观那一个失败任务,白白浪费了一个晚上。

5. 出图产物的自动化整理:从乱糟糟一片到目录清晰

5.1 按“日期/项目/任务组”三级归档

图片生成只是流水线的一半,另一半是把散落在ComfyUI/output里的文件收拾整齐。WorkBuddy 在任务完成之后,会把图片从 ComfyUI 的输出目录移动到指定的归档目录。我用的目录结构是:

D:/ArtPipeline/outputs/2025-06-01/lighting_test/task_0042.png

日期在最外层,方便按时间回溯;项目名在第二层,和我在tasks.yaml里定义的output_dir对应;最里层是具体任务产生的文件,文件名直接包含task_id。这样连续跑一周,目录依然整齐,不用每周花时间“收拾房间”。

5.2 每次运行都写一份 manifest,图片和参数不再断联

前面提到过任务记录表,具体实现上我让 WorkBuddy 每次运行追加写一个run_manifest.jsonl文件,每行是一个 JSON 对象,字段包括:

{ "task_id": "task_0042", "group": "lighting_test", "prompt": "golden hour lighting, warm tones, soft shadows", "seed": 10001, "width": 768, "height": 768, "steps": 28, "output_file": "D:/ArtPipeline/outputs/2025-06-01/lighting_test/task_0042.png", "elapsed_seconds": 42 }

这张表看起来简单,实际用起来价值非常大。比如我在某个项目里发现“某一张图的风格特别合适”,只要查一下表格,就能知道它的全部生成参数,然后直接把这一行参数改造成一个新的任务组,继续延展。没有这张表的时候,复盘基本靠回忆,有了它之后,复盘变成了一次精准的“数据查询”。

5.3 把常用工作流沉淀成模板库

跑了一个月后,会沉淀出一批“常用套路”:文生图、图生图、局部重绘、ControlNet 构图约束等等。我会把每个套路都保存成一张 API 格式的工序卡,放到 WorkBuddy 的模板目录里。下次要做类似任务时,不用重新拖节点,直接选模板、填参数矩阵,流水线就可以开工。

这个过程很像把做菜的手艺标准化成菜谱:同一道菜,今天放多少盐、明天放多少糖,不需要每次重新凭感觉试,直接按菜谱批量操作,做出来基本稳定。对内容创作来说,模板化不会消灭创意,它只是把“可复制的部分”固化下来,让人把精力花在真正需要判断的地方。

6. 运行一周后踩过的几个坑,每条都是真实教训

6.1 用错了 JSON 格式,接口返回 400

我第一次提交任务时,WorkBuddy 一直报错,日志里显示 HTTP 400。一开始我以为是网络配置问题,排查了很久才发现,自己导入的是 ComfyUI 界面的 UI workflow,不是 API 格式。后来我专门在界面里导出 API 格式,问题立刻消失。

这个坑很隐蔽,因为两种 JSON 从肉眼上看都包含节点信息,不仔细看根本发现不了差别。建议第一次搭建时,先用一条任务调通整个链路,再去扩展任务矩阵。

6.2 图片已经生成,任务状态却一直显示 running

有一类任务让我困惑了很久:输出文件夹里图片已经出现了,但 WorkBuddy 始终认为任务还没完成。查了 ComfyUI 的/history接口后才发现,有一些节点组合(比如某些 VAE 解码后处理)会在主图保存后继续做一些额外操作,状态切换会晚一步。

我的处理方式是把“任务完成”的判断条件从“只看状态字段”改成“状态完成 + 输出文件已出现”二者兼备。这样虽然偶尔要多个几秒才能确认,但不会出现“图在文件夹里、系统还在空转”的尴尬场景。

6.3 并发稍微调高一点,立刻 OOM

有一次我把并发数从 2 调到 3,觉得 12GB 卡应该能扛住,结果不到两分钟,任务日志里就开始出现显存溢出的报错。后来我换了个思路:不是追求同时跑几个任务,而是保证同一时刻只有一个任务处在显存占用峰值。

实现方法也很简单:WorkBuddy 支持给同一个concurrency并发池里的任务设置“启动延迟”,比如每个任务延迟 15 秒再提交,错开峰值。实测下来,整体吞吐量反而比硬开 3 个并发更稳。如果你用的也是单卡小显存机器,我强烈建议试试这个“错峰提交”的方式。

6.4 输出文件重名,把上一次的成果覆盖了

ComfyUI 输出文件的命名,如果不显式指定filename_prefix,可能会因为计数器重置导致重名。我在早期跑批量任务时遇到过一件事:中间手动重置过 ComfyUI,重新加载工作流之后,新一轮任务的输出文件把上一轮的同名文件覆盖了,真金白银的跑图时间打了水漂。

从那以后,WorkBuddy 提交的每个任务都会强制把task_id写进filename_prefix,并且在归档时检查目标路径是否已存在同名文件。如果存在,自动生成带时间后缀的文件名,绝不允许覆盖。这个机制听起来基础,但对流水线来说,它是防止“无声损失”的重要防线。

最后再分享一个小技巧

把整套流水线跑顺之后,我最大的体会是:自动化的价值不是让你“什么都不用管”,而是把精力集中到真正需要人判断的地方。

我现在的工作流程是,每天早上一到工位,就把当天的任务矩阵丢给 WorkBuddy,中午休息前扫一眼日志,下午回来整理归档,顺便挑几张效果好的图进项目素材库。遇到失败任务,看看错误快照,是参数问题就改参数,是显存问题就错峰重跑,基本不会被琐碎操作缠住。

如果你准备动手搭建,我的建议是先不要急着追求“大而全”。第一次尝试,先跑一个 5 张小图的测试任务,走通“提交—监控—归档—回溯”全链路,再逐步增加任务组和并发上限。这样出了问题容易定位,也不会一上来就被一堆任务淹没。祝你的本地出图流水线早日跑起来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询