为什么改了参数它不重跑:ComfyUI 局部重执行机制怎么读
新手在 ComfyUI 里最容易被绊一跤的地方,往往不是装环境,而是这个:明明动了某个节点的参数,Ctrl + Enter 排队,进度条一闪而过甚至根本没动,输出还是上一张。第一反应通常是「界面卡住了」或者「参数没生效」,于是开始重启、清缓存、删 custom_nodes。
绝大多数情况下什么都没坏。这是 ComfyUI 设计好的行为,而且官方 README 的 Notes 章节就把规则明写在那里。理解这两条规则,比记住十几个排查动作管用得多。
两条执行规则,一个字都不用改
截至 2026-08-09、对应 ComfyUI v0.31.0 的官方仓库 README,Notes 章节给出的执行规则是这样两条:
- 只有输出端所有输入都正确的那部分图会被执行。
- 只有相对上一次执行发生变化的部分会被执行。提交两次相同的图,只有第一次真正执行;如果只改了图的末端,则只有改动的部分与依赖它的部分会重新执行。
README 的 Features 章节把这件事命名为「局部图重执行」,和「异步排队」「智能 VRAM 与 RAM 管理」「模型 offload」并列,作为高效本地执行的一部分。也就是说,这不是某个版本的临时优化,而是被官方当成卖点写进特性列表里的机制。
这两条规则合起来解释了几乎所有「点了没反应」的场景,但它们各自对应的现象完全不同,混着排查只会绕远路。
规则一:不执行,是因为那一支根本不完整
第一条规则的关键词是「输出端」和「所有输入都正确」。规则的落点在输出端:一条支路能不能进入执行范围,取决于它的输入是不是都正确。README 并没有逐项列举「什么算不正确」,所以别指望官方给你一张判定清单;能确定的只有一句——不满足这个条件的那部分图,不会被执行。
这条规则最反直觉的表现是:你的画布上明明有三个输出节点,跑完之后只有两个出了东西,剩下那个安安静静什么也没说。按这条规则读,它更像是没进入执行范围,而不是执行到一半失败了。所以当你发现「某一块图像永远不动」时,先别怀疑缓存,去顺着那一支的输入逐个看一遍——连线、widget 里填的值,哪一处不对都归到同一条规则上。
规则二:不重跑,是因为它认为你没改
第二条规则才是标题里那个问题的答案。README 的措辞是「相对上一次执行发生变化」,它给出的两个具体推论值得逐字记住:
- 提交两次相同的图,只有第一次真正执行。
- 只改了图的末端,则只有改动的部分与依赖它的部分会重新执行。
第二个推论解释了为什么在 ComfyUI 里反复调后处理参数会越调越快:前面的 checkpoint 加载、文本编码、采样都没变,缓存命中,实际重算的只有你动的那几个末端节点。这是个好设计。
第一个推论解释了那个「不重跑」的现象:你以为你改了,但从图的角度看,这次提交和上次一模一样。为什么会这样?这里必须先划一条诚实的界线:README 只说了「相对上一次执行发生变化的部分会被执行」,至于哪些界面操作算「变化」、前端在哪个时机把 widget 里的输入交给节点,官方文档里没有描述。所以这一步不能靠别人的经验清单,只能靠判定动作去反推。
能作为线索的是快捷键表里那批纯视图操作:折叠节点(Alt + C)、Alt + + / Alt + - 缩放画布、. 视图适配、P 固定节点——README 给它们的描述都停留在视图层面,没有涉及节点输入。它们「应该」不构成图的变化,但请留意「应该」二字:官方没写这句因果,真要定性还得靠下面那套对照实验。
顺带说一个容易被拿来做错误类比的点:Ctrl + B 是 bypass 选中节点,README 对它的解释是「行为等同于该节点被移除、连线从中穿过重连」——按这个说法,bypass 是在改图的拓扑结构。而 Ctrl + M 是静音,README 只给了「静音/取消静音选中节点」这句功能描述,没有给出等价的语义解释。所以别把这两个键当成同义词互相替换着理解,官方对它们的说明详略本身就不一样。
怎么判定:是缓存生效,还是图确实没变
上面两条规则告诉你「为什么」,但面对一张自己都记不清改过什么的图,你需要的是可执行的判定动作。按下面的顺序走,一般三步之内能定性。
第一步,把队列与历史面板打开对一眼。 按 Q 切换队列面板,按 H 切换历史面板,这两个快捷键就在 README 的 Shortcuts 表里。要说清楚的是:README 对这两个键只给了「切换面板可见性」这一句描述,没有说明面板里呈现什么内容,所以这里不替官方解释某一行的含义。这一步的价值在于,它是官方明确给出的执行状态入口——你在按 Ctrl + Enter 前后各看一眼,用「有没有变化」这个最粗的信号先把范围收窄,比盯着画布干猜靠谱。顺带记一下另外两个容易按混的组合:Ctrl + Shift + Enter 是把当前图插到队首,Ctrl + Alt + Enter 是取消当前生成。
第二步,把日志打开看执行流。 ComfyUI 的日志参数在 comfy/cli_args.py(v0.31.0)里是 --verbose,它可以不带值、给一个 LEVEL、或者给 LEVEL FILE 两个值;合法等级常量是 ('DEBUG', 'DETAIL', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'),不带值时等价于 DEBUG,控制台默认等级是 INFO。
python main.py --verbose DEBUG
如果你习惯用管道接工具,注意 ComfyUI 的正常进程输出默认走 stderr,--log-stdout 才把它送到 stdout。这一条不留神会让你以为「日志是空的」。
第三步,用 --cache-none 做对照实验。 这是最干脆的判定手段。--cache-none 在 comfy/cli_args.py(v0.31.0)里的 help 写的是:降低 RAM/VRAM 占用,代价是每次运行都重新执行每个节点。
python main.py --cache-none
用它启一次,然后提交同一张图。逻辑很简单:
- 加了
--cache-none之后结果变了 → 结果复用确实在起作用。你的改动是真改动,只是上一次那部分节点的结果被复用了;接着该回头核对改动落在哪个节点上、这个节点在不在你关心的那条输出支路的上游。 - 加了
--cache-none之后结果还是一样 → 缓存不背这个锅。既然每个节点都重算了结果仍然一致,那要么这次提交的图在内容上确实没变,要么你改的那个参数根本不参与这条输出支路的计算。
注意这只是诊断姿势,不是日常配置。把每个节点每次都重算意味着 checkpoint、文本编码这些重活也得重来,--cache-none 换来的低占用是拿这个代价买的。定完性就把它去掉。
缓存这一组参数,只挑与本篇相关的看
comfy/cli_args.py(v0.31.0)里缓存是一个互斥组,五个选项。这篇只需要你分得清「默认是哪一档」和「哪一档会关掉复用」:
| 参数 | help 原意 |
|---|---|
--cache-ram [GB [GB]] | RAM 压力缓存,这是默认缓存模式。第一个值设 active-cache 阈值,可选的第二个值设 inactive-cache/pin 阈值 |
--cache-classic | 使用旧式(aggressive)缓存 |
--cache-lru N | LRU 缓存,最多缓存 N 个节点结果。可能占用更多 RAM/VRAM |
--cache-none | 降低 RAM/VRAM 占用,代价是每次运行都重新执行每个节点 |
--high-ram | 在高内存机器、或偏好用页面文件而非重新加载模型的系统上可略微提升性能 |
这张表怎么读:你什么参数都不加时,走的是 --cache-ram 那一行——它按 RAM 压力决定留多少。不给值时的默认是 active 为系统 RAM 的 10%(最小 2GB、最大 10GB),inactive 为系统 RAM 的 100%(最大 128GB)。所以「我明明什么参数都没加,为什么会有缓存」这个疑问,答案就在这一行:默认就是有缓存的模式。
源码里还有两条硬逻辑值得单独拎出来,因为它们不在各自的 help 文本里:
--cache-ram最多接受两个值,多给会直接报--cache-ram accepts at most two values: active GB and inactive GB。--high-ram会把cache_classic置真。也就是说你加--high-ram的时候,顺手就把缓存模式换成了旧式 aggressive 缓存。这是个连带效果,help 里没写,排查缓存行为异常时如果你的启动命令里有--high-ram,先把它摘掉再判断。
--cache-lru N 是用内存换命中率(help 自注「可能占用更多 RAM/VRAM」),和 --cache-none 正好是两个极端。想让复杂工作流多命中就往 LRU 走,想定位问题就往 none 走,日常保持默认。
以上参数按 v0.31.0 的 comfy/cli_args.py 为准,ComfyUI 版本节奏很快,参数与默认值都会变,用之前先 python main.py --help 对一眼。
把 png 拖回来,看看上一次到底跑的是什么
如果你已经忘了上次那张图长什么样,还有个官方给的办法。README 的 Notes 里写得很明确:把生成出来的 png 拖到网页上(或加载它),会得到完整的工作流,包括当时用的 seed。Features 章节的对应表述是:工作流可以存取为 JSON,也可以从受支持的生成媒体中恢复完整工作流与 seed。
这条在判定「我到底改了没有」时非常好用:把那张「不该一样却一样」的输出图拖回画布,得到的就是产出它的那一版工作流,再和你现在这版比对,差异一目了然。seed 也一并回来了,不用去猜当时的随机数。
有一个参数会影响这条路能不能走通,值得在这里点一下:comfy/cli_args.py(v0.31.0)里的 --disable-metadata,help 原意是「不把 prompt 元数据保存进文件」。官方并没有明写这两者的因果关系,我也不替它下结论,但你把两条 help 并排读一遍就知道该怎么取舍:从 png 恢复工作流依赖的是文件里带的那份数据,而这个开关管的正是写不写这份数据。如果你的习惯里包含「拖回旧图找参数」,就别顺手把这个参数加进启动脚本。
什么情况说明不是这个机制的锅
写到这里得划几条边界,免得读者拿这套解释去套所有异常。
结果变了但你不满意,不是「没重跑」。 这两件事的判据完全不同:「没重跑」的可验证判据是 --cache-none 下结果依然一致;「效果不满意」属于参数调优,和执行机制无关。
每次提交结果都不一样,也可能是图自己在变。 README 的 Notes 里有一条动态提示语法:{day|night} 这种写法,"{wild|card|test}" 会在每次排队提交时由前端随机替换成三者之一。原文用的措辞是 by the frontend every time you queue the prompt——替换发生在前端、发生在排队那一刻。这意味着含动态提示的图,你每次提交给后端的内容其实是不同的,「相对上次没变化」自然不成立。看到「同一张图每次结果都不同」,先去提示词里找有没有 {a|b},再去怀疑采样器。顺带一提,想在提示词里打出真正的 { } 字符要写成 \{ \},( ) 则写成 \( \)。
seed 一样、图一样,也不等于逐位可复现。 comfy/cli_args.py(v0.31.0)里有个 --deterministic,让 pytorch 尽量用较慢的确定性算法,但它的 help 明确写了「这可能并不能在所有情况下让图像可复现」。官方自己都没打这个包票,所以当你追一个极细微的差异时,先确认它是不是落在这个免责范围内,别把时间花在找一个不存在的配置项上。
前端相关的异常走另一条线。 README 的 Frontend Development 章节说明,2024-08-15 起前端已迁到独立仓库 Comfy-Org/ComfyUI_frontend,主仓库里的前端每两周更新一次,独立仓库有每日发布;README 明说前端相关的 bug 与需求应该提到前端仓库,便于官方分流。前面那个「widget 里的值到底有没有交到节点上」的疑问,正好落在交互层,属于前端范畴,报到主仓库会绕路。
回到最开始那个场景。下次再遇到「改了参数它不重跑」,顺序是:先按 H 打开历史面板、按 Q 打开队列面板,对着提交前后各看一眼 → 再用 --cache-none 跑一次做对照,这一步才是定性的那步 → 结果仍一致就回去核对改动是否真的落在参与计算的节点上 → 实在想不起上次跑的是什么,把那张 png 拖回画布,连 seed 一起找回来。这四步不需要重启,也不需要删任何东西。
延伸阅读
- 采样预览不显示,先看这个参数
- 让 ComfyUI 完全离线跑:
--disable-api-nodes之外还要关掉哪些出网路径 - ComfyUI 的五个注意力实现参数怎么选,以及 xformers 在里面扮演什么角色
本文依据 ComfyUI 官方仓库(github.com/Comfy-Org/ComfyUI)的 README、comfy/cli_args.py、
release notes 与官方安全公告整理,核对日 2026-08-09,对应版本 v0.31.0;
文中引用的 issue 状态为该日期的快照。本文内容为官方文档与源码口径,非本机实测。
参数、默认值与功能随版本变动,请以官方文档与 python main.py --help 的实际输出为准。