ComfyUI 入门教程
本教程旨在帮助新手快速上手 ComfyUI,一个强大的基于节点的 Stable Diffusion WebUI。
目录
什么是 ComfyUI?
ComfyUI 是一个基于节点的图形用户界面,用于生成 AI 图像。它通过可视化的工作流方式连接各种模块,让你能够:
- 灵活组合:自由连接不同的模型、采样器、VAE 等
- 精确控制:每个参数都可以独立调整
- 工作流复用:保存和分享你的生成流程
- 高效生成:相比 WebUI 更低的内存占用
安装 ComfyUI
方法一:独立安装(推荐)
bash
# 1. 克隆仓库
git clone https://github.com/comfyanonymous/ComfyUI.git
cd ComfyUI
# 2. 创建虚拟环境(可选但推荐)
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 3. 安装依赖
pip install -r requirements.txt
# 4. 启动
python main.py方法二:使用整合包
下载整合包(秋葉aaaki 等),解压即用,适合不想折腾的用户。
访问地址
启动后打开浏览器访问:http://127.0.0.1:8188
界面介绍
┌─────────────────────────────────────────────────────────────┐
│ 菜单栏 [Queue Prompt] [Clear] [Load] [Save] [Manager] │
├──────┬──────────────────────────────────────────────────────┤
│ │ │
│ 节点 │ 画布区域 │
│ 库 │ │
│ │ [KSampler]───[VAE Decode]───[Save Image] │
│ │ │ │
│ │ [CLIP Text Encode] │
│ │ │ │
│ │ [CLIP Vision Encode] │
├──────┴──────────────────────────────────────────────────────┤
│ [Queue Prompt] 状态栏 │
└─────────────────────────────────────────────────────────────┘核心区域
| 区域 | 说明 |
|---|---|
| 节点库 | 左侧面板,包含所有可用节点 |
| 画布 | 中间区域,拖拽连接节点构建工作流 |
| 队列 | 底部,显示生成任务进度 |
| 图片查看 | 点击输出端口查看生成的图片 |
快捷键
| 快捷键 | 功能 |
|---|---|
Ctrl + Enter | 执行队列 |
Ctrl + S | 保存工作流 |
Ctrl + L | 加载工作流 |
Space | 拖动画布 |
Ctrl + 滚轮 | 缩放画布 |
A | 全选 |
Delete | 删除选中 |
基础工作流
1. 基础文生图
┌─────────────────────────────────────────────┐
│ │
│ CLIP Text Encode (正面) │
│ │ │
│ ▼ │
│ KSampler ──► VAE Decode ──► Save Image │
│ │ │
│ ▼ │
│ CLIP Text Encode (负面) │
│ │ │
│ ▼ │
│ Load Checkpoint │
│ │
└─────────────────────────────────────────────┘步骤:
- 从节点库拖入
Load Checkpoint(加载基础模型) - 拖入
CLIP Text Encode (Prompt),输入正向提示词 - 再拖入一个
CLIP Text Encode,输入负向提示词 - 拖入
KSampler,连接各节点 - 拖入
VAE Decode和Save Image - 点击
Queue Prompt
2. 图生图
Load Checkpoint ──► KSampler
│
▼
Load Image ──► VAE Encode ──┘
│
▼
VAE Decode ──► Save Image3. ControlNet 控制
┌─────────────────────────────────────────────┐
│ │
│ Load Checkpoint ──► CLIP Text Encode │
│ │ │
│ ▼ │
│ Load ControlNet ──► Apply ControlNet │
│ │ │ │
│ ▼ ▼ │
│ Load Image ─────────► KSampler ──┘ │
│ │ │
│ ▼ E Decode │
│
│ VA│ │ │
│ ▼ │
│ Save Image │
│ │
└─────────────────────────────────────────────┘常用节点详解
加载类
| 节点 | 功能 | 常用参数 |
|---|---|---|
Load Checkpoint | 加载基础模型 | 选择 .safetensors/.ckpt |
Load LoRA | 加载 LoRA 模型 | 模型路径、强度 |
Load ControlNet | 加载 ControlNet | 模型选择 |
Load CLIP | 单独加载 CLIP | 配合 Text Encoder 使用 |
Load VAE | 加载自定义 VAE | 文件路径 |
采样类
| 节点 | 功能 | 常用参数 |
|---|---|---|
KSampler | 核心采样器 | seed、steps、cfg、sampler、scheduler |
KSamplerAdvanced | 高级采样 | 支持噪波控制、分步脚本 |
KSampler 参数详解:
python
seed: # 随机种子,相同种子+参数=相同结果
steps: # 采样步数,20-50 常用
cfg: # 提示词引导强度,5-12 常用,越高越贴近提示词
sampler: # 采样器算法
- euler # 快速,效果好
- euler_a # 细节丰富
- dpm2 # 质量高,速度慢
- ddim # 快速,适合低步数
scheduler: # 调度器
- normal # 标准
- karras # karras 噪声调度,质量提升编码类
| 节点 | 功能 |
|---|---|
CLIP Text Encode | 文本编码为向量 |
CLIP Vision Encode | 图像编码(用于 IP-Adapter) |
VAE Encode | 图像编码为潜在空间 |
VAE Decode | 潜在空间解码为图像 |
图像处理类
| 节点 | 功能 |
|---|---|
Load Image | 加载本地图像 |
Save Image | 保存图像 |
Image Scale | 缩放图像 |
Image Crop | 裁剪图像 |
Image Blend | 图像混合 |
Image Remove Background | 移除背景 |
辅助类
| 节点 | 功能 |
|---|---|
CLIP Set Last Layer | 设置 CLIP 层数 |
Random Noise | 自定义噪波 |
CLIP Skip | 跳过 CLIP 层 |
Preview Image | 预览图像 |
实用工作流示例
示例 1:基础文生图工作流
json
{
"last_version": 4,
"nodes": [
{
"id": 4,
"type": "KSampler",
"pos": [600, 300],
"size": [315, 370],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [
{"name": "model", "type": "MODEL", "link": 5},
{"name": "positive", "type": "CONDITIONING", "link": 6},
{"name": "negative", "type": "CONDITIONING", "link": 7},
{"name": "latent_image", "type": "LATENT", "link": 8}
],
"outputs": [
{"name": "LATENT", "type": "LATENT", "links": [9]}
],
"properties": {
"Seed": 123456789,
"steps": 20,
"cfg": 7,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1
}
},
{
"id": 5,
"type": "CLIP Text Encode (Prompt)",
"pos": [200, 300],
"size": [350, 150],
"flags": {},
"order": 1,
"inputs": [
{"name": "clip", "type": "CLIP", "link": 10}
],
"outputs": [
{"name": "CONDITIONING", "type": "CONDITIONING", "links": [6]}
],
"properties": {
"prompt": "1girl, beautiful, detailed eyes, sunset background, cinematic lighting"
}
},
{
"id": 6,
"type": "CLIP Text Encode (Prompt)",
"pos": [200, 500],
"size": [350, 150],
"flags": {},
"order": 2,
"inputs": [
{"name": "clip", "type": "CLIP", "link": 11}
],
"outputs": [
{"name": "CONDITIONING", "type": "CONDITIONING", "links": [7]}
],
"properties": {
"prompt": "bad quality, worst quality, blurry, deformed, ugly"
}
},
{
"id": 1,
"type": "Load Checkpoint",
"pos": [50, 300],
"size": [140, 250],
"flags": {},
"order": 3,
"outputs": [
{"name": "MODEL", "type": "MODEL", "links": [5]},
{"name": "CLIP", "type": "CLIP", "links": [10, 11]},
{"name": "VAE", "type": "VAE", "links": null}
],
"widgets": [
{"name": "ckpt_name", "type": "COMBO", "config": ["realisticVision_v51.safetensors"]}
]
},
{
"id": 2,
"type": "VAE Decode",
"pos": [950, 300],
"size": [210, 100],
"flags": {},
"order": 4,
"inputs": [
{"name": "samples", "type": "LATENT", "link": 9},
{"name": "vae", "type": "VAE", "link": 12}
],
"outputs": [
{"name": "IMAGE", "type": "IMAGE", "links": [13]}
]
},
{
"id": 3,
"type": "Save Image",
"pos": [1200, 300],
"size": [230, 100],
"flags": {},
"order": 5,
"inputs": [
{"name": "images", "type": "IMAGE", "link": 13}
]
},
{
"id": 7,
"type": "Empty Latent Image",
"pos": [200, 800],
"size": [240, 100],
"flags": {},
"order": 6,
"outputs": [
{"name": "LATENT", "type": "LATENT", "links": [8]}
],
"properties": {
"width": 512,
"height": 768
}
}
],
"links": [
[5, "MODEL", 4, "model"],
[6, "CONDITIONING", 4, "positive"],
[7, "CONDITIONING", 4, "negative"],
[8, "LATENT", 4, "latent_image"],
[9, "LATENT", 2, "samples"],
[10, "CLIP", 5, "clip"],
[11, "CLIP", 6, "clip"],
[12, "VAE", 2, "vae"],
[13, "IMAGE", 3, "images"]
]
}参数说明
| 参数 | 值 | 说明 |
|---|---|---|
| Checkpoint | realisticVision_v51 | 写实人像模型 |
| 分辨率 | 512×768 | 9:16 竖图 |
| Seed | 123456789 | 固定种子 |
| Steps | 20 | 采样步数 |
| CFG | 7 | 提示词引导强度 |
| Sampler | euler | 快速稳定 |
| 正面提示词 | 1girl, beautiful, detailed eyes... | 主体 + 细节 |
| 负面提示词 | bad quality, worst quality... | 基础负面 |
示例 2:LoRA + ControlNet 工作流
json
{
"last_version": 4,
"nodes": [
{
"id": 1,
"type": "Load Checkpoint",
"pos": [50, 200],
"size": [140, 250],
"outputs": [
{"name": "MODEL", "type": "MODEL", "links": [1]},
{"name": "CLIP", "type": "CLIP", "links": [2, 3]}
]
},
{
"id": 2,
"type": "Load LoRA",
"pos": [300, 200],
"size": [300, 200],
"inputs": [
{"name": "model", "type": "MODEL", "link": 1},
{"name": "clip", "type": "CLIP", "link": 2}
],
"outputs": [
{"name": "MODEL", "type": "MODEL", "links": [4]},
{"name": "CLIP", "type": "CLIP", "links": [5]}
],
"properties": {
"lora_name": "animeLinebase_20.safetensors",
"strength_model": 0.8,
"strength_clip": 0.8
}
},
{
"id": 3,
"type": "Load ControlNet",
"pos": [50, 500],
"size": [140, 200],
"outputs": [
{"name": "CONTROL_NET", "type": "CONTROL_NET", "links": [6]}
],
"widgets": [
{"name": "control_net_name", "type": "COMBO", "config": ["control_v11p_sd15_openpose.pth"]}
]
},
{
"id": 4,
"type": "Apply ControlNet",
"pos": [650, 200],
"size": [280, 200],
"inputs": [
{"name": "positive", "type": "CONDITIONING", "link": 7},
{"name": "control_net", "type": "CONTROL_NET", "link": 6},
{"name": "image", "type": "IMAGE", "link": 8}
],
"outputs": [
{"name": "CONDITIONING", "type": "CONDITIONING", "links": [9]}
],
"properties": {
"control_weight": 1.0,
"start_percent": 0,
"end_percent": 1
}
},
{
"id": 5,
"type": "Load Image",
"pos": [350, 500],
"size": [250, 150],
"outputs": [
{"name": "IMAGE", "type": "IMAGE", "links": [8, 10]}
]
},
{
"id": 6,
"type": "KSampler",
"pos": [1000, 200],
"size": [315, 400],
"inputs": [
{"name": "model", "type": "MODEL", "link": 4},
{"name": "positive", "type": "CONDITIONING", "link": 9},
{"name": "negative", "type": "CONDITIONING", "link": 11},
{"name": "latent_image", "type": "LATENT", "link": 12}
],
"outputs": [
{"name": "LATENT", "type": "LATENT", "links": [13]}
],
"properties": {
"Seed": 2024,
"steps": 30,
"cfg": 8,
"sampler_name": "euler_a",
"scheduler": "karras",
"denoise": 1
}
},
{
"id": 7,
"type": "CLIP Text Encode (Prompt)",
"pos": [700, 500],
"size": [350, 150],
"outputs": [
{"name": "CONDITIONING", "type": "CONDITIONING", "links": [7]}
],
"properties": {
"prompt": "anime style, 1girl, full body, dancing pose, detailed background"
}
},
{
"id": 8,
"type": "CLIP Text Encode (Prompt)",
"pos": [700, 700],
"size": [350, 150],
"outputs": [
{"name": "CONDITIONING", "type": "CONDITIONING", "links": [11]}
],
"properties": {
"prompt": "photo, realistic, 3d render, low quality"
}
},
{
"id": 9,
"type": "Empty Latent Image",
"pos": [1000, 700],
"size": [240, 100],
"outputs": [
{"name": "LATENT", "type": "LATENT", "links": [12]}
],
"properties": {
"width": 512,
"height": 768
}
},
{
"id": 10,
"type": "VAE Decode",
"pos": [1350, 200],
"size": [210, 100],
"inputs": [
{"name": "samples", "type": "LATENT", "link": 13},
{"name": "vae", "type": "VAE", "link": null}
]
},
{
"id": 11,
"type": "Save Image",
"pos": [1600, 200],
"size": [230, 100]
}
]
}效果说明
| 组件 | 作用 |
|---|---|
| LoRA (0.8) | 添加动漫风格 |
| ControlNet OpenPose | 保持人物姿势 |
| euler_a + karras | 细节更丰富 |
| CFG 8 | 增强风格表现 |
示例 3:批量生成脚本
python
# batch_generator.py - 批量生成不同种子的图片
import os
import json
def create_batch_workflow(seeds, output_dir="output"):
"""为每个种子生成工作流文件"""
base_workflow = {
"last_version": 4,
"nodes": [
{
"id": 1, "type": "Load Checkpoint",
"pos": [50, 200],
"outputs": [{"name": "MODEL"}, {"name": "CLIP"}]
},
{
"id": 4, "type": "KSampler",
"pos": [500, 200],
"properties": {
"steps": 25,
"cfg": 7,
"sampler_name": "euler",
"denoise": 1
}
},
{
"id": 2, "type": "CLIP Text Encode (Prompt)",
"pos": [200, 200],
"properties": {"prompt": "your positive prompt here"}
},
{
"id": 3, "type": "CLIP Text Encode (Prompt)",
"pos": [200, 400],
"properties": {"prompt": "negative prompt"}
}
]
}
os.makedirs(output_dir, exist_ok=True)
for i, seed in enumerate(seeds):
workflow = json.loads(json.dumps(base_workflow))
workflow["nodes"][1]["properties"]["Seed"] = seed
filename = f"{output_dir}/seed_{seed}.json"
with open(filename, 'w') as f:
json.dump(workflow, f, indent=2)
print(f"Created: {filename}")
# 使用
create_batch_workflow([123, 456, 789, 1000, 9999])使用方法
bash
# 1. 保存为 batch_generator.py
# 2. 修改 prompt 为你的提示词
# 3. 运行
python batch_generator.py
# 4. 在 ComfyUI 中依次加载并生成快速上手步骤
1. 启动 ComfyUI
python main.py
2. 新建空白工作流
3. 按顺序添加节点:
Load Checkpoint → CLIP Text Encode → KSampler → VAE Decode → Save Image
4. 连接节点:
Checkpoint.MODEL → KSampler.model
Checkpoint.CLIP → TextEncode.clip
TextEncode.CONDITIONING → KSampler.positive
TextEncode.NEGATIVE → KSampler.negative
KSampler.LATENT → VAE.samples
Checkpoint.VAE → VAE.vae
VAE.IMAGE → Save.images
5. 设置参数:
- 尺寸: 512×512
- 步数: 20-30
- CFG: 7-8
- Sampler: euler / euler_a
6. 点击 "Queue Prompt" 生成推荐资源
模型下载
- CivitAI - LoRA、模型社区
- Hugging Face - 官方模型
扩展节点
- ComfyUI-Manager - 节点管理
- ComfyUI-Impact-Pack - 实用工具包
工作流参考
- OpenArt - 工作流分享
- ComfyUIworkflows
进阶方向
- 自定义节点开发 - Python 编程
- ControlNet 高级应用 - 姿态、深度、线稿控制
- IP-Adapter - 图像风格迁移
- Inpainting/Outpainting - 局部编辑
- 高清修复 - Tile Diffusion、Ultimate SD Upscale
教程持续更新中,有问题欢迎反馈。