概述
ComfyUI V3 架构引入了一种更有条理的节点定义方式,今后节点功能的扩展也只会添加到 V3 架构中。你可以参考本指南,将现有的 V1 节点迁移到新的 V3 架构。核心概念
V3 架构基于新的版本化 Comfy API,这意味着未来的架构更新都将向后兼容。comfy_api.latest 指向正在开发中的最新版本 API,而 latest 之前的版本可以认为是“稳定版”。目前版本 v0_0_2 是第一个 API 版本,之后可能还会有不兼容的更改。当它稳定后,会创建新的 v0_0_3 版本供 latest 指向。
V1 与 V3 架构
V3 架构的主要变化包括:- 输入和输出使用对象定义,而不是字典。
- 执行方法统一命名为 ‘execute’,并且是类方法。
- 使用
def comfy_entrypoint()函数返回 ComfyExtension 对象来定义节点,取代 NODE_CLASS_MAPPINGS/NODE_DISPLAY_NAME_MAPPINGS - 节点对象不保存状态 -
def __init__(self)不会影响节点函数的暴露内容,因为所有方法都是类方法。节点类在执行前也会被清理。
V1 (旧版)
V3 (现代版)
迁移步骤
从 V1 迁移到 V3 在大多数情况下都很简单,主要是语法的调整。步骤 1: 更改基类
所有 V3 节点都必须继承自ComfyNode。支持多层继承,只要继承链的顶层有 ComfyNode 父类即可。
V1:
步骤 2: 将 INPUT_TYPES 转换为 define_schema
原来分散在代码不同位置(如字典和类属性)的节点属性(节点 ID、显示名称、类别等)现在都通过Schema 类统一管理。
函数 define_schema(cls) 需要返回一个 Schema 对象,工作方式与 V1 中的 INPUT_TYPES(s) 类似。
支持的核心输入/输出类型存储在 comfy_api/{version} 的 _io.py 文件中,默认以 io 作为命名空间。由于输入/输出现在由类定义而不是字典或字符串,自定义类型可以通过编写自己的类或使用 io 中的 Custom 辅助函数来实现。
自定义类型在下面的章节中有详细说明。
类型类包含以下属性:
class Input用于定义输入(如Model.Input(...))class Output用于定义输出(如Model.Output(...))。注意,不是所有类型都支持作为输出。Type用于获取类型提示(如Model.Type)。有些类型提示可能只是any,未来会进一步完善。这些类型提示不会被强制执行,仅作为文档参考。
步骤 3: 更新执行方法
V3 中所有的执行函数都命名为execute 并且必须是类方法。
V1:
步骤 4: 转换节点属性
以下是一些属性名称的对照表,更多详细信息请查看comfy_api.latest._io 中的源代码。
步骤 5: 处理特殊方法
V3 支持与 V1 相同的特殊方法,但方法名改为小写或重新命名以更加清晰。使用方式保持不变。验证 (V1 → V3)
输入验证函数重命名为validate_inputs。
V1:
惰性求值 (V1 → V3)
函数check_lazy_status 改为类方法,其他部分保持不变。
V1:
缓存控制 (V1 → V3)
缓存控制的功能与 V1 相同,但原来的函数名容易误导。 V1 的IS_CHANGED 函数的逗辑是:如果返回值与上次执行时相同,则不重新执行节点。
因此函数 IS_CHANGED 被重命名为 fingerprint_inputs。开发者常见的错误是认为返回 True 就会让节点总是重新执行。但由于总是返回 True,反而会导致节点只执行一次然后重用缓存。
一个常见的使用场景是 LoadImage 节点。它返回所选文件的哈希值,这样文件变化时节点就会重新执行。
V1:
步骤 6: 创建扩展和入口点
不再使用字典来映射节点 ID 到节点类/显示名称,现在需要定义ComfyExtension 类和 comfy_entrypoint 函数。
将来可能会在 ComfyExtension 中添加更多函数,通过 get_node_list 注册节点以外的其他内容。
comfy_entrypoint 可以是同步或异步函数,但 get_node_list 必须声明为异步。
V1:
输入类型参考
虽然在步骤 2 中已经介绍过,但这里再提供一些 V1 与 V3 类型的对照表。完整的类型声明请查看comfy_api.latest._io。
基本类型
control_after_generate
Int 和 Combo 输入支持control_after_generate 参数,用于添加一个控制小部件,在每次生成后自动更改值。在 V1 中这是一个普通的 bool;在 V3 中你可以使用 io.ControlAfterGenerate 枚举进行显式控制。传递 True 等同于 io.ControlAfterGenerate.randomize。
ComfyUI 类型
组合类型(下拉框/选择列表)
V3 中的组合类型需要显式定义。 V1:Schema 参考
数据类Schema 定义了 V3 节点的所有属性。以下是所有可用字段的完整参考:
通用输入参数
所有输入类型共享这些基本参数:
小部件输入(Int、Float、String、Boolean、Combo)还支持:
高级功能
隐藏输入
隐藏输入提供对执行上下文的访问,例如提示词元数据、节点 ID 和其他内部值。它们不会显示在 UI 中。 在 V1 中,隐藏输入通过INPUT_TYPES 中的 "hidden" 键声明。在 V3 中,它们通过 Schema 的 hidden 参数声明,其值通过 cls.hidden 访问。
V1:
某些隐藏值会根据 Schema 标志自动添加。输出节点(
is_output_node=True)会自动接收 prompt 和 extra_pnginfo。API 节点(is_api_node=True)会自动接收身份验证令牌。UI 辅助工具
V3 在ui 模块中提供了内置的 UI 辅助工具,用于处理预览和保存文件等常见模式。通过 ui 参数将它们传递给 io.NodeOutput。
预览辅助工具
预览辅助工具保存临时文件并返回用于节点内显示的 UI 数据。保存辅助工具
保存辅助工具提供将文件保存到输出目录并嵌入相应元数据的方法。它们通常用于输出节点。返回原始 UI 字典
如果需要返回没有对应辅助工具的 UI 数据,可以直接传递字典:输出节点
用于产生副作用(如保存文件)的节点。与 V1 相同,将节点标记为输出节点后,节点的上下文菜单中会显示run 播放按钮,允许部分执行图。
自定义类型
可以通过类定义或Custom 辅助函数创建自定义输入/输出类型。
MultiType 输入
MultiType 允许一个输入接受多种类型。当节点需要通过同一个输入插槽处理不同数据类型时,这非常有用。
如果第一个参数(id)是 Input 类的实例而不是字符串,则该输入将使用其覆盖后的值来创建小部件。否则,该输入仅为插槽。
MatchType(泛型类型匹配)
MatchType 创建类型关联的输入和输出。当用户将特定类型连接到 MatchType 输入时,共享同一模板的所有其他输入和输出会自动约束为该类型。Switch 和 Create List 等节点能处理任意类型,靠的就是这个机制。
动态输入
V3 引入了根据用户交互改变可用输入的动态输入类型。这些功能在 V1 中没有对应物。Autogrow
Autogrow 创建数量可变的输入,随着用户连接更多输入而自动增长。有两种模板类型:
TemplatePrefix 生成带编号前缀的输入(例如 image0、image1、image2…):
DynamicCombo
DynamicCombo 创建一个下拉菜单,根据所选选项显示/隐藏不同的输入。这对于不同模式需要不同参数的节点非常有用。
异步 Execute
V3 支持异步的execute 方法。这对执行 I/O 操作、API 调用或其他异步工作的节点很有用。只需将 execute 声明为 async:
ComfyAPI
ComfyAPI 类提供对 ComfyUI 运行时服务的访问,例如进度报告和节点替换注册。导入它并创建实例:
进度报告
在节点的execute 方法内报告执行进度。进度条显示在 ComfyUI 界面中。这取代了 V1 中使用 comfy.utils.PROGRESS_BAR_HOOK 的模式。
set_progress 的 preview_image 参数可以接受 PIL 图像、ImageInput 张量或 None。在 execute 内部调用时,node_id 会从执行上下文中自动确定。节点替换
节点替换允许将旧节点/已弃用节点映射到新节点,使现有工作流自动升级。在扩展的on_load 方法中使用 ComfyAPI 注册替换。
old_widget_ids 参数很重要:工作流 JSON 按位置索引(而非名称)存储小部件值。此列表将这些位置索引映射到输入 ID,以便替换系统在迁移过程中能正确识别小部件值。
对于使用动态输入的节点(如 Autogrow),请在映射中使用点号路径:
扩展生命周期
ComfyExtension 类除 get_node_list 之外还支持生命周期钩子:
NodeOutput
NodeOutput 类是 execute 的标准化返回值。它支持多种模式: