简介:这份资源面向使用 ComfyUI 进行 AI 绘画的进阶用户,聚焦 SDXL 基础模型与 Refiner 精炼模型的两阶段文生图工作流,帮助解决单模型出图细节不足、画面质感欠佳的问题。资源包内共 1 个文件,为 json 格式的工作流配置文件,压缩包体积约 4KB,可直接导入 ComfyUI 加载使用,省去手动搭建节点的繁琐过程。该工作流将基础采样与精炼采样串联,通过 Refiner 对潜空间结果二次处理,从而提升图像清晰度与细节表现,适合已有 ComfyUI 环境、希望快速体验 SDXL 精炼流程的创作者参考。目前已有 138 人学习下载,可作为搭建高质量文生图管线的起点,便于在此基础上调整采样步数、切换比例与提示词策略,逐步形成自己的出图方案。
1. 为什么 SDXL 出图总差一口气,Refiner 到底补了什么
用 ComfyUI 跑 SDXL 文生图的人,十有八九经历过这个场景:底模一口气采样完,画面构图、光影、色彩都对,可放大一看,皮肤纹理发糊、发丝边缘发虚、材质细节像蒙了层雾。这不是你的提示词写得不好,而是 SDXL 的 base 模型和 refiner 模型分工不同导致的。base 负责在低噪声阶段把整体结构和语义搭出来,refiner 负责在高噪声阶段接手,专门打磨高频细节。跳过 refiner,等于让 base 一个人干两份活,细节自然撑不住。
这篇要讲的就是在 ComfyUI 里把 SDXL base + Refiner 这条链路跑通、跑稳、跑出可复现效果。适合已经装好 ComfyUI、能跑通基础文生图、但出图质量卡在“能用但不够好”这个阶段的从业者。核心问题有三个:refiner 在哪个时间点切入、切入时噪声水平怎么对齐、显存不够时怎么取舍。把这三个问题解决,SDXL 的出图质量会有肉眼可见的提升。
2. SDXL 双模型架构拆解:base 和 refiner 各自管什么
2.1 从噪声调度看两个模型的分工边界
SDXL 的采样过程是一条从纯噪声到清晰图像的轨迹。base 模型在整条轨迹上都能跑,但它的训练重点在低噪声区间——也就是从纯噪声到中等噪声这一段,它擅长把“这是什么”定下来。refiner 的训练重点在高噪声区间,也就是从中等噪声到接近清晰这一段,它擅长把“这长什么样”磨出来。
具体到参数上,base 和 refiner 的切换点通常设在总步数的 0.2 左右。假设总步数 30 步,base 跑前 24 步,refiner 接手后 6 步。这个比例不是拍脑袋定的,Stable Diffusion 官方在 SDXL 论文里给出的推荐值是 0.2,社区大量实测也验证了这个区间最稳。低于 0.1,refiner 介入太晚,细节提升有限;高于 0.3,refiner 介入太早,它还没足够的信息去判断该磨哪里,容易把结构磨坏。
这里有个容易翻车的点:base 和 refiner 的噪声调度必须对齐。ComfyUI 的 KSampler 节点里有个add_noise和start_at_step参数,如果 base 跑完直接接 refiner 而不做噪声水平匹配,refiner 会以为自己在处理一个完全不同的噪声状态,结果就是画面崩坏或者细节全丢。正确做法是用KSampler (Advanced)节点,把 base 的end_at_step和 refiner 的start_at_step设成同一个值,让两个采样器在同一个噪声水平上交接。
2.2 ComfyUI 里搭出 base + refiner 的最小节点图
先给一个能直接抄的最小工作流结构。你需要这些节点:
CheckpointLoaderSimple加载 SDXL base 模型CheckpointLoaderSimple加载 SDXL refiner 模型CLIPTextEncode正面提示词CLIPTextEncode负面提示词EmptyLatentImage设置出图尺寸KSampler (Advanced)跑 base 采样KSampler (Advanced)跑 refiner 采样VAEDecode解码最终 latentSaveImage保存
关键连接逻辑:base 的 KSampler 输出 latent 直接连到 refiner 的 KSampler 输入,refiner 的 KSampler 输出连到 VAEDecode。两个 KSampler 共用同一组提示词编码,但 refiner 那一路的提示词可以稍微调整——比如加一些细节描述词,因为 refiner 对细节类提示更敏感。
下面是一个可复现的参数配置,直接对应到节点里的数值:
# base KSampler (Advanced) 参数 base_sampler = { "seed": 42, "steps": 30, "cfg": 7.0, "sampler_name": "dpmpp_2m", "scheduler": "karras", "denoise": 1.0, "start_at_step": 0, "end_at_step": 24, # 总步数的 80% "add_noise": "enable", "return_with_leftover_noise": "enable" # 关键:保留噪声给 refiner } # refiner KSampler (Advanced) 参数 refiner_sampler = { "seed": 42, # 必须和 base 一致 "steps": 30, # 必须和 base 一致 "cfg": 7.0, "sampler_name": "dpmpp_2m", "scheduler": "karras", "denoise": 1.0, "start_at_step": 24, # 接上 base 的 end_at_step "end_at_step": 10000, # 跑完剩余步数 "add_noise": "disable", # 关键:不再加新噪声 "return_with_leftover_noise": "disable" }逻辑说明:base 的return_with_leftover_noise必须设为enable,这样它跑完 24 步后不会把 latent 完全去噪,而是保留当前噪声水平交给 refiner。refiner 的add_noise必须设为disable,因为它接手的是一个已经带噪声的 latent,再加噪声就乱了。两个采样器的seed和steps必须一致,否则噪声调度对不上。
参数说明:steps设 30 是 SDXL 的常用值,显存够可以拉到 40,但超过 40 收益递减明显。cfg7.0 是 SDXL 的甜点值,低于 5 画面偏灰,高于 9 容易过饱和。sampler_name用dpmpp_2m配karras调度器是社区验证过最稳的组合,换euler也能跑但细节稍弱。
2.3 显存不够时怎么砍:refiner 的取舍策略
SDXL base 模型 fp16 大概占 6.5GB 显存,refiner 再占 6.5GB,加上 latent 和中间激活,12GB 显存跑双模型会非常紧张。如果你的卡是 8GB 或 12GB,有几个降级方案:
方案一:base 用 fp16,refiner 用 fp8。ComfyUI 支持在CheckpointLoaderSimple里指定精度,refiner 用 fp8 后显存占用降到 3.5GB 左右,画质损失在可接受范围内。方案二:refiner 只跑最后 4 步而不是 6 步,减少 refiner 的激活显存。方案三:如果显存实在不够,可以只跑 base,然后用Ultimate SD Upscale做后期放大,但这不是真正的 refiner 精炼,细节提升方式不同。
我一般会先看显存余量再决定 refiner 的精度。用nvidia-smi监控,如果 base 跑完还剩 4GB 以上,refiner 用 fp16 没问题;剩 2-3GB,refiner 切 fp8;剩不到 2GB,要么降分辨率要么放弃 refiner。
3. 把 Refiner 接进工作流:从节点连线到参数对齐
3.1 用 KSampler (Advanced) 做噪声交接的完整步骤
很多人第一次接 refiner 会直接用两个普通KSampler节点串起来,结果发现画面要么没变化要么直接崩。问题出在普通 KSampler 没有start_at_step和return_with_leftover_noise这两个关键控制项。必须用KSampler (Advanced),它在 ComfyUI 的节点菜单里叫KSampler (Advanced),不是KSampler。
完整操作步骤:
第一步,在 ComfyUI 画布上添加两个KSampler (Advanced)节点。右键菜单 →sampling→KSampler (Advanced)。
第二步,把 base 模型的MODEL输出连到第一个 KSampler 的model输入,refiner 模型的MODEL输出连到第二个 KSampler 的model输入。
第三步,正面和负面提示词的CONDITIONING输出同时连到两个 KSampler 的positive和negative输入。如果想让 refiner 用不同的提示词,可以再加一组CLIPTextEncode单独连给 refiner。
第四步,EmptyLatentImage的LATENT输出连到第一个 KSampler 的latent_image输入。第一个 KSampler 的LATENT输出连到第二个 KSampler 的latent_image输入。
第五步,按 2.2 里的参数表设置两个 KSampler 的数值。重点检查:base 的end_at_step等于 refiner 的start_at_step,base 的return_with_leftover_noise是enable,refiner 的add_noise是disable。
第六步,第二个 KSampler 的LATENT输出连到VAEDecode,再连SaveImage。
跑之前建议先用 512x512 小图测试,确认噪声交接没问题再上 1024x1024。小图跑一次大概 15 秒,大图要 1-2 分钟,先小后大能省不少调试时间。
3.2 切换步数比例怎么定:0.2 不是唯一答案
官方推荐 0.2 的切换比例,但实际用下来,这个值跟你的提示词复杂度、采样器类型、甚至出图尺寸都有关系。我整理了一个实测对照表,基于 30 步总步数、dpmpp_2m + karras:
| 切换步数 | 切换比例 | 适用场景 | 细节表现 | 结构风险 |
|---|---|---|---|---|
| 21 | 0.3 | 简单主体、大色块 | 细节提升明显 | 偶发结构变形 |
| 24 | 0.2 | 通用场景 | 细节与结构平衡 | 低 |
| 27 | 0.1 | 复杂构图、多主体 | 细节提升有限 | 极低 |
| 18 | 0.4 | 纯纹理、材质特写 | 纹理极强 | 结构容易崩 |
我的习惯是:人像和产品图用 0.2,风景和建筑用 0.15,纯材质特写可以试 0.25 但要做好结构崩了重跑的心里准备。如果发现 refiner 接手后画面变糊,大概率是切换太早,refiner 还没足够信息;如果画面局部出现不合理的纹理堆积,是切换太晚,base 已经把细节定死了 refiner 改不动。
3.3 提示词要不要分两套:base 和 refiner 的编码差异
base 和 refiner 共用一套 CLIP 编码器,但它们的注意力重点不同。base 对主体、动作、场景类提示更敏感,refiner 对材质、光照、纹理类提示更敏感。所以一个实用技巧是:base 的提示词写清楚“画什么”,refiner 的提示词补上“什么质感”。
比如画一个陶瓷杯子:
# base 提示词 a ceramic coffee cup on a wooden table, soft daylight, minimalist composition # refiner 提示词(在 base 基础上追加) a ceramic coffee cup on a wooden table, soft daylight, minimalist composition, glossy ceramic surface, subtle reflections, fine grain texture on woodrefiner 那一路多加的glossy ceramic surface、subtle reflections、fine grain texture就是专门喂给 refiner 的高频细节描述。实测下来,这样分开写比两路用同一套提示词,细节丰富度能提升一档。但注意不要给 refiner 加太多主体描述词,否则它会试图重新理解画面内容,反而干扰 base 已经定好的结构。
4. 避坑与排查:Refiner 工作流里最容易翻车的五个地方
4.1 画面全黑或全灰:噪声交接没对齐
现象:base 跑完接 refiner,出图要么全黑要么一片灰雾,完全看不出内容。
原因:base 的return_with_leftover_noise没开,或者 refiner 的add_noise没关。base 如果完全去噪了,交给 refiner 的是一个干净 latent,refiner 按自己的噪声调度去处理,等于在干净图上加噪声再采样,结果就是崩。反过来 refiner 如果开了add_noise,它会在 base 的噪声 latent 上再加一层噪声,噪声水平翻倍,采样直接失控。
解决:检查两个开关。base 的return_with_leftover_noise必须是enable,refiner 的add_noise必须是disable。这两个是硬性条件,没有例外。
4.2 细节没提升反而更糊:切换步数设错了
现象:接了 refiner 之后,画面比只用 base 还糊,细节像被抹平了。
原因:切换步数太早,比如总步数 30 步,base 只跑了 15 步就交给 refiner。refiner 接手时噪声水平还很高,它没有足够的信息去判断该磨哪里,只能按自己的先验去猜,结果就是把 base 好不容易搭出来的结构又糊回去了。
解决:把切换步数往后调,从 0.2 比例开始试。如果 0.2 还糊,降到 0.15。同时检查 base 的end_at_step和 refiner 的start_at_step是否一致,不一致的话噪声水平对不上,也会糊。
4.3 显存爆了:refiner 加载时机不对
现象:跑 base 的时候显存正常,一接 refiner 就 OOM。
原因:ComfyUI 默认会把两个模型都加载到显存里。base 跑的时候 refiner 已经在显存里占着位置,两个模型加起来超过显存上限。
解决:在 ComfyUI 设置里开启--lowvram或--medvram启动参数,让 ComfyUI 按需加载模型。或者用CheckpointLoaderSimple的model输出接一个ModelSamplingDiscrete节点做精度转换,把 refiner 转成 fp8。如果还不行,考虑用--reserve-vram参数预留一部分显存给系统,避免爆显存导致进程被杀。
4.4 出图尺寸变了:latent 被 refiner 重采样
现象:base 出图是 1024x1024,接了 refiner 之后变成 512x512 或者比例不对。
原因:refiner 的 KSampler 如果denoise设成了小于 1.0 的值,它会按自己的方式重采样 latent,可能导致尺寸变化。或者EmptyLatentImage的尺寸没同步给 refiner 那一路。
解决:refiner 的denoise保持 1.0,不要动。EmptyLatentImage只连给 base 的 KSampler,refiner 的 latent 输入来自 base 的输出,不需要再连EmptyLatentImage。如果尺寸还是不对,检查VAEDecode是不是接在了 base 的输出上而不是 refiner 的输出上。
4.5 换了采样器就崩:调度器不匹配
现象:base 用 dpmpp_2m + karras 正常,换成 euler + normal 之后接 refiner 就崩。
原因:不同采样器和调度器的噪声调度曲线不同。base 和 refiner 必须用同一套采样器和调度器,否则两个模型的噪声水平定义不一致,交接时对不上。
解决:base 和 refiner 的sampler_name和scheduler必须完全一致。如果非要换,两个一起换,不要只换一个。实测 dpmpp_2m + karras 是最稳的组合,euler + normal 也能跑但细节稍弱,dpmpp_sde + karras 细节更强但显存占用更高。
5. 进阶:用 Refiner 做局部精炼和批量出图的技巧
5.1 只精炼人脸区域:用遮罩控制 refiner 的作用范围
refiner 全图跑一遍显存和时间成本都不低,如果只是人脸细节不够,可以只让 refiner 处理人脸区域。做法是在 base 跑完之后,用MaskFromSegmentation或者手动画一个遮罩,把 latent 的人脸区域抠出来,只对这块区域跑 refiner 的 KSampler,然后再合并回去。
具体节点组合:base 输出 latent →LatentCompositeMasked配合遮罩 → refiner KSampler 只处理遮罩区域 → 再LatentCompositeMasked合并回原 latent。这样 refiner 的步数可以设得更少,比如只跑 4 步,因为作用范围小,收敛更快。
我一般会在人像工作流里加这个分支,显存占用比全图 refiner 低 40% 左右,出图速度提升明显。遮罩不用画得很精确,比人脸大一圈就行,refiner 会自动在边缘做过渡。
5.2 批量出图时怎么固定 refiner 的效果
批量跑图最怕的是每张图 refiner 的效果不一致。要固定效果,关键是固定三个东西:seed、切换步数、refiner 的提示词。seed 固定后 base 的初始噪声就固定了,切换步数固定后交接点固定,refiner 提示词固定后细节方向固定。
如果要做 seed 遍历,比如同一个提示词跑 10 个不同 seed,建议把 refiner 的切换步数稍微调低到 0.15,因为不同 seed 下 base 的收敛速度略有差异,切换晚一点能让 refiner 更稳定地接手。另外批量跑的时候把SaveImage的filename_prefix设成带 seed 的格式,方便回溯哪张图对应哪个 seed。
5.3 验证 refiner 是否真的生效:一个简单的对比方法
跑完一张图,怎么确认 refiner 真的起作用了而不是白跑?最直接的方法是对比 latent 的数值变化。在 refiner KSampler 后面接一个LatentToRGB或者直接看VAEDecode前后的像素差异。更简单的方法:把 refiner 的end_at_step设成和start_at_step一样,等于 refiner 不跑,出一张图;再把 refiner 正常跑,出另一张图。两张图放一起对比,如果细节有肉眼可见的提升,说明 refiner 生效了;如果完全一样,检查 refiner 的模型是不是加载错了,或者add_noise和return_with_leftover_noise的设置是不是反了。
我自己的习惯是每次调完 refiner 参数,先跑一张 512x512 的对比图,确认细节有变化再上大图。这个习惯帮我省了很多次白跑大图的时间。希望帮到你。
本文还有配套的精品资源,点击获取