一套 ArtCraft 工作流如果只在界面里点参数,关掉页面就等于丢了一次实验,团队里也没人能说清哪一组值才是有效的。更稳的顺序是先把参数分成“必须锁死”和“允许变化”两类,固定项写进一份带版本名的配置文件,然后用固定种子跑一次基线、按存档重跑一次做比对。判断复现是否成立的标准很直接:同一份配置、同一入口、同一输出目录规则下,两次出图的尺寸、构图、色调和细节都能对得上。
复现的起点是把参数落盘,而不是调提示词。建议先导出当前工作流的完整参数,按“影响画风与结构的固定项”和“只影响批次内变化的随机项”分开,固定项写进 workflows/<流程>/<版本名>/config.yaml,随机项集中到单独一块;然后用固定种子跑基线,把运行时间、版本名、输出文件名对应记录,再按同一份配置重跑一次,从尺寸、构图、色调、细节四个维度比对。任何固定项改动都要升版本名,不要原地覆盖;比对不一致时先回退到只含固定项的最小工作流再排查。
列出当前工作流里全部可调参数并分成固定项与随机项
先做一次清点,把界面上能改的、节点里写死的、从外部文件加载的参数都列出来。分类标准是:改变它会改变画面语义或结构的,归固定项;只影响同一套设定下的细微差异或产出数量的,归随机项。字段位置一列写的是该参数在工作流导出文件中的实际落点,下面的路径是占位写法,需要按你导出的 JSON 替换节点名;节点 id 通常不稳定,建议用节点标题定位而不是数字 id。
| 参数名 | 作用 | 固定或随机 | 对应字段位置 |
|---|---|---|---|
| 底模权重文件 | 决定画风与语义理解 | 固定 | <checkpoint_loader>.inputs.ckpt_name |
| VAE | 影响解码色彩与细节 | 固定 | <vae_loader>.inputs.vae_name |
| 采样器 sampler | 决定去噪轨迹 | 固定 | <sampler>.inputs.sampler_name |
| 调度器 scheduler | 决定噪声调度方式 | 固定 | <sampler>.inputs.scheduler |
| 步数 steps | 迭代次数 | 固定(同版本内) | <sampler>.inputs.steps |
| CFG | 提示词约束强度 | 固定 | <sampler>.inputs.cfg |
| 宽高 width / height | 构图与取景范围 | 固定 | <empty_latent>.inputs.width / height |
| 种子 seed | 起始噪声 | 基线时固定 | <sampler>.inputs.seed |
| LoRA 名称与权重 | 风格或角色增强 | 固定 | <lora_loader>.inputs.lora_name / strength |
| ControlNet 权重 | 结构约束强度 | 固定 | <controlnet_apply>.inputs.strength |
| 正负向提示词主体 | 语义指令 | 固定(模板部分) | <text_encode>.inputs.text |
| 批次数 batch_size | 单次产出数量 | 随机/可变 | <sampler>.inputs.batch_size |
| 种子递增策略 | 批内变化方式 | 随机 | <seed_control>.inputs.policy |
| 放大倍数 | 输出分辨率 | 固定 | <upscale>.inputs.scale |
清点完可以先只保留一张表,不要急着改工作流。表格的作用是让“这版到底改了什么”有据可查;如果某一项你自己也说不清固定与否,默认先归固定项,等确认不影响结果再放进随机区。
把固定项写进工作流配置并给这份配置起版本名
固定项单独成文件,随机项单独成块,这是后续能被找回和复用的前提。下面是一个通用骨架,字段名可以按你的实际工作流替换,占位符保留了尖括号:
# workflows/artcraft/<version>/config.yaml
meta:
version: artcraft-portrait-v1 # 版本名,唯一且不再改动
created_at: <YYYY-MM-DD>
owner: <负责人的名字>
note: <一句话说明这版相对上一版改了什么>
fixed:
checkpoint: <ckpt_name>
vae: <vae_name>
sampler: <sampler_name>
scheduler: <scheduler_name>
steps: <int>
cfg: <float>
width: <int>
height: <int>
seed: <int> # 基线使用的固定种子
lora:
- name: <lora_name>
strength: <float>
controlnet:
strength: <float>
prompt_template: |
<正向提示词主体>
random:
seed_policy: <fixed|increment|random>
batch_size: <int>
slots:
- hair_color
- background
文件命名建议固定成 <流程>-<用途>-v<序号>,目录按流程和版本两级分开:配置放 workflows/artcraft/artcraft-portrait-v1/config.yaml,运行记录放 runs/artcraft/artcraft-portrait-v1/<run_id>/。规则只有一条:任何固定项改动都要新建 v2、v3,不要在原目录上直接覆盖。覆盖一次,之前所有基于 v1 的输出就失去了对照物。
用固定种子跑一次并留下输出记录
基线运行的目的不是出一张好看的图,而是建立一个可回查的参照点。跑之前确认随机项里的种子策略是 fixed,并且界面上的种子输入没有被手动改写;某些工具会在种子框留“随机”钩子,这个钩子必须先去掉。跑完后立刻落一份 manifest,把运行时间、参数版本名、输出文件名三者绑在一起:
{
"run_id": "<YYYYMMDD-HHMM-序号>",
"version": "artcraft-portrait-v1",
"config_path": "workflows/artcraft/artcraft-portrait-v1/config.yaml",
"started_at": "<开始时间>",
"finished_at": "<结束时间>",
"seed": <实际使用的种子>,
"outputs": [
"outputs/00001-artcraft-portrait-v1-seed<N>.png"
]
}
输出文件名里带上版本名和种子,是为了能从一张图反查到配置,而不是靠记忆。如果工具支持把 manifest 直接写到输出目录同层,优先用工具产出,再手工补齐版本名和配置路径,避免两处记录对不上。
按存档配置重跑第二次,比对两次输出
第二次运行只有输入不同:清空工作流、重新加载 config.yaml,其他一概不动,包括输出目录规则。比对时按四个维度逐项看,不要只扫一眼整体感觉:
- 尺寸:像素宽高是否完全一致,文件元信息里的分辨率是否相同。
- 构图:主体位置、取景范围、元素数量与排布是否一致。
- 色调:整体亮度、对比、偏色倾向是否一致,可以把两张图并排或做缩略图对比。
- 细节:纹理、边缘、局部小结构是否落在同一位置。
发现不一致时,排查方向按代价从低到高排:先看 manifest 里记录的种子和实际传入的种子是否相同;再核对采样器、调度器名称有没有拼写或大小写差异,这类名称在不同版本里可能被重命名;接着确认底模、VAE、LoRA 文件是否被替换过,有条件就对比文件哈希;最后才怀疑节点或插件版本差异、缓存未清理导致复用旧中间结果。不确定的情况下,先退回到只含固定项的最小工作流跑一遍,再逐步把节点加回来,能较快定位是哪一段引入的差异。
把随机项集中到单独一处,说明允许变化的边界
随机项混进固定参数里,是复现失败最常见的原因之一。所有会变的东西只放在配置的 random 块里,固定块里不允许出现会被运行时覆盖的值。常见的随机项清单与边界可以这样定:
- 种子策略:批内递增或完全随机。允许的变化范围是同一套固定项下的不同噪声起点;一旦跨版本,种子不具备可比性。
- 批次数 batch_size:只影响一次产出多少张,不影响单张结果。
- 提示词词槽:发色、背景、配饰等可替换片段。允许在预设词表内替换,超出词表即视为新配置。
- 放大倍数:如果不作为固定项,需要限定在单一取值,不要在同版本内浮动。
越界的处理动作要写死:任何随机项的取值超出上述范围,就把它从 random 移到 fixed,升一个新版本名,重跑基线并重新记录 manifest,同时在 note 里写明移位原因。这样做的代价是版本号增长得快,好处是任何时候翻出一张图,都能顺着文件名找到那份没被改过的配置。