AI 绘图工作流:从 Stable Diffusion 到 ComfyUI
一、为什么“工作流”成为 2025 必谈关键词
2025 年,Stable Diffusion(SD)生态已经从“能出图”进化到“能工业化”。
WebUI 的“一键生成”在 2023 年降低了门槛,却在 2025 年暴露出三大痛点:
- 无法原子化控制:一次只能改一个参数,无法把“采样器→LoRA→ControlNet→Refiner→Upscale”做成一条流水线。
- 无法版本化:别人复现你的图,需要手动抄 20 个参数+种子。
- 无法自动化:批量电商海报、游戏立绘,需要人工逐张点按钮。
ComfyUI 用“节点式工作流”把 SD 拆解成可复用、可版本化、可自动化的 DAG(有向无环图),恰好解决上述痛点。
本文将带你从 0 到 1 搭建一条“文生图→LoRA 注入→ControlNet 姿态控制→SDXL Refiner→4×Upscale”的完整工作流,并给出可直接加载的 JSON 与 Python 脚本,方便嵌入 CI/CD 或云端批量管道。
二、Stable Diffusion 原子能力拆解
在 ComfyUI 里,每一个橙色矩形就是一个“原子节点”。先回顾 SD pipeline 的 7 大原子步骤,后续节点直接映射。
步骤 | 对应模块 | 输出数据类型 | 关键超参 |
1. Prompt 编码 | CLIP Text Encode | Conditioning | truncate, padding |
2. 潜空间噪声 | Empty Latent / Rand | LatentTensor | width, height, batch_size |
3. 扩散去噪 | KSampler | LatentTensor | steps, cfg, sampler_name, scheduler |
4. LoRA 注入 | LoraLoader | Model&CLIP | lora_strength |
5. ControlNet 控制 | ControlNetApply | Conditioning | strength, start/end % |
6. VAE 解码 | VAEDecode | Image | —— |
7. 后处理 | Upscale Model / FaceRestore | Image | upscale_ratio, codeformer_weight |
ComfyUI 把每一步都做成一个“积木”,你可以任意插拔、并行、条件分支。
三、ComfyUI 安装与最小可运行环境
3.1 系统&驱动
- NVIDIA Driver ≥ 535
- CUDA 12.2+(无需完整 toolkit,只要驱动支持)
- Python 3.10(官方推荐,3.11 会有部分 pywheel 缺失)
3.2 一键安装脚本(Windows / Linux 通用)
git clone https://github.com/comfyanonymous/ComfyUI.git
cd ComfyUI
python -m venv venv
source venv/bin/activate # win: venv\Scripts\activate
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -r requirements.txt
# 启动
python main.py --listen 0.0.0.0 --port 8188
浏览器打开 http://localhost:8188
即可看到空白画布。
3.3 模型目录结构(重要)
ComfyUI
├─models
│ ├─checkpoints # 放 SD1.5 / SDXL 基模
│ ├─loras # 自己炼的 LoRA
│ ├─controlnet # pth / safetensors
│ ├─vae # 独立 VAE
│ └─ upscale_models # 4x-UltraSharp / RealESRGAN
四、20 分钟搭建第一条“文生图 + LoRA + ControlNet”工作流
下面用“游戏立绘”场景举例:
输入一句 prompt,先让 LoRA 赋予“二次元厚涂”风格,再用 ControlNet OpenPose 控制人物姿态,最后走 SDXL Refiner 提升细节。
4.1 节点拓扑图
Text Prompt → CLIP Text Encode ┐
├-> KSampler -> VAE Decode -> Image
OpenPose Img → ControlNet Apply ┘
↑
LoRA Loader -> Base Model -> KSampler
4.2 逐步拖节点(图文对照)
- 右键空白处 → Add Node → loader → Load Checkpoint,选
sd_xl_base_1.0.safetensors
- 同上,Add Node → loader → Lora Loader,选
thickpaint_v2.safetensors
,strength=0.8 - Add Node → conditioning → CLIP Text Encode,输入正向/反向 prompt
- Add Node → latent → Empty Latent Image,width=832, height=1216, batch=1
- Add Node → sampling → KSampler
- seed=42, steps=30, cfg=7, sampler=dpmpp_2m, scheduler=karras
- Add Node → controlnet → ControlNetLoader,选
controlnet-openpose-sdxl.safetensors
- Add Node → image → LoadImage,上传一张 512×768 的 Pose 骨架图
- Add Node → controlnet → ControlNetApply,strength=1.0, start=0, end=0.8
- 连接:Base Model → LoRA Loader → KSampler model 输入
CLIP Text Encode → ControlNetApply conditioning 输入
ControlNetApply → KSampler positive 输入 - Add Node → latent → VAEDecode → Save Image
4.3 运行与调参
点击右侧“Queue Prompt”,首次编译约 15s(RTX 4070),后续 4.8s/张。
如果想一次跑 20 张不同种子,把 KSampler 的 seed 改成 “incremental_batch” 并设置 batch_size=20,ComfyUI 会自动并行。
五、代码级自动化:把工作流变成 Python 脚本
ComfyUI 的幕后协议非常简单:POST 一个 JSON 到 /prompt
。
下面给出最小可执行范例,适合嵌入 Flask / Airflow / Jenkins。
5.1 导出工作流 JSON
在 Web 界面按 Ctrl+S
,保存为 workflow_api.json
。
注意:默认保存的是“可视化版”,需要再点右上角 “Save (API Format)” 才能得到无冗余的 API JSON。
5.2 Python 批跑脚本
import requests, json, uuid, time, os
COMFY_URL = "http://localhost:8188"
WORKFLOW_PATH = "workflow_api.json"
OUTPUT_DIR = "./output"
def queue_prompt(flow):
p = {"prompt": flow, "client_id": str(uuid.uuid4())}
r = requests.post(f"{COMFY_URL}/prompt", json=p)
return r.json()
def wait_png(prompt_id):
while True:
r = requests.get(f"{COMFY_URL}/history/{prompt_id}")
if r.status_code == 200:
hist = r.json()
if prompt_id in hist and hist[prompt_id]["outputs"]:
for node_id in hist[prompt_id]["outputs"]:
if "images" in hist[prompt_id]["outputs"][node_id]:
return hist[prompt_id]["outputs"][node_id]["images"]
time.sleep(1)
def run_batch(prompts):
with open(WORKFLOW_PATH) as f:
template = json.load(f)
# 找到 CLIPTextEncode 节点(正向提示词)
text_node_id = "6" # 视你保存的 JSON 而定,可用 jq 快速定位
for i, prompt in enumerate(prompts):
flow = json.loads(json.dumps(template)) # 深拷贝
flow[text_node_id]["inputs"]["text"] = prompt
# 改种子
flow["3"]["inputs"]["seed"] = 42 + i
resp = queue_prompt(flow)
prompt_id = resp["prompt_id"]
imgs = wait_png(prompt_id)
for img in imgs:
os.makedirs(OUTPUT_DIR, exist_ok=True)
with open(f"{OUTPUT_DIR}/{img['filename']}", "wb") as f:
f.write(requests.get(f"{COMFY_URL}/view?filename={img['filename']}").content)
print("saved", img["filename"])
if __name__ == "__main__":
prompts = [
"1girl, thick paint style, white hair, cyberpunk city",
"1boy, thick paint style, holding sword, sunset"
]
run_batch(prompts)
运行后 ./output
会多出两张 4K 图,且自带 PNG Info,可在 ComfyUI 直接反序列化继续编辑。
六、高级技巧:让工作流“可版本、可复现、可灰度”
6.1 Git-LFS 管理大模型
git lfs track "*.safetensors"
git add .gitattributes models/checkpoints/sd_xl_base_1.0.safetensors
git commit -m "chore: add base model v1.0"
6.2 用 ComfyUI-Manager 做“节点即代码”
安装插件:
git clone https://github.com/ltdrdata/ComfyUI-Manager custom_nodes/ComfyUI-Manager
重启后,在 UI 内就能像 pip install
一样搜索节点,并自动生成 requirements.txt
快照。
6.3 灰度发布 A/B 工作流
把 KSampler 的 scheduler 作为变量抽出来,建两条分支:
- workflow_a.json → scheduler=normal
- workflow_b.json → scheduler=karras
用脚本分别跑 1000 张,统计 CLIP 美学分数 + 人工打分,再决定全量切流。
七、性能调优:在 8G 显存笔记本跑 SDXL + ControlNet 不爆显存
- 启动参数
python main.py --lowvram --dont-upcast-attention --use-pytorch-cross-attention
- 节点级优化
- 把 Empty Latent 设成 768×1152,batch=1,先跑低分辨率,再走 Upscale Model 节点,显存占用从 7.8G→5.2G。
- ControlNet 使用
controlnet-sdxl-lllite
轻量版,权重 < 800 MB,速度提升 35%。
- 按需卸载
ComfyUI 默认“执行完即卸载”,比 WebUI 的“常驻”节约 1.2G。
八、常见问题排雷
现象 | 根因 | 解决 |
加载工作流空白 | 用了可视化版 JSON | 重新 Save(API Format) |
ControlNet 无效 | 骨架图分辨率≠512 | 预处理器节点里选 |
LoRA 权重 >1 后崩图 | 与 SDXL 基模冲突 | 把 strength 降到 0.6 以下,或换 SD1.5 基模 |
跑批时 502 | 并发排队堵死 | 改 |
九、总结与展望
- WebUI 像“傻瓜相机”,ComfyUI 像“可换镜头的微单”。
- 节点式工作流 = 可版本化的 DAG,天然适合 MLOps / AIOps。
- 2025 年,ComfyUI 已经支持 SD3、Flux、Stable-Cascade、Mochi-Video,一条画布就能完成“文生图→视频→音频”多模态流水线。