
在Comfy UI里所有人都在讨论模型、LoRA、采样器但很少有人会仔细聊聊输入节点。实际上输入节点是整个工作流的起点所有数据——不管是图片、文本、模型还是你手动调的一个数字——都必须通过输入节点进入管线。没有输入节点工作流连跑都跑不起来。我自己刚开始用Comfy UI时经常遇到“input type mismatch”之类的报错后来研究了一段时间输入节点的设计才恍然大悟。今天就把我理解的输入节点设计思路和实操经验完完整整写出来希望能帮到正在自定义节点或想深入理解工作流的人。1. 输入节点的基础认知与设计逻辑1.1 输入节点工作流的起点你可以把Comfy UI的工作流想象成一条水管系统。你从水龙头接水水管里流过的是各种类型的数据最后出水口得到的是生成图像。输入节点就是最上游的水龙头它负责把外部世界的资源比如磁盘上的一张照片、用户输入的提示词、下载好的模型文件接进这条管线并转化成Comfy UI内部能识别的数据类型。Comfy UI基于节点图执行每个节点有输入和输出。输入节点比较特殊它没有前置节点只有输出。简单说它就是一个数据源。Load Image从磁盘读取图片并输出IMAGE张量CLIP Text Encode把字符串变成CONDITIONINGCheckpointLoader读取模型文件输出MODEL、CLIP、VAE三个引用。这三种是最典型的输入节点。你仔细观察就会发现所有工作流的第一层几乎都是这类节点它们是数据的源头。1.2 为什么必须用输入节点类型系统的魔力Comfy UI内部使用Python张量torch.Tensor表示图像、latent等数据同时为了约束流程定义了一套严格的类型系统IMAGE、LATENT、MODEL、CLIP、VAE、CONDITIONING、MASK等等。你直接把一个图片路径扔进流程是不行的必须由Load Image转化为IMAGE张量这样后续节点才能用torch操作去处理它。类型系统相当于管道口径只有接口匹配才能插上。你不可能把一根水管接到电线上这就是兼容性问题。设计输入节点时你首先要思考清楚这个节点应该输出什么类型的数据是整个IMAGE张量还是一个MASK掩码或者是几个LATENT一旦类型定错后面所有节点都会报错。1.3 输入节点与输出节点如何协同输入节点一般放在工作流的左侧输出节点比如Save Image、Preview Image放在右侧中间是处理节点。数据流单向输入节点 - 处理节点 - 输出节点。举个例子一个典型的文生图流程CheckpointLoader输入 - CLIPTextEncode输入处理 - KSampler处理 - VAEDecode处理 - SaveImage输出。理解这个流向后你会发现输入节点的设计会影响整个工作流的接口。如果设计得好用户可以只通过修改几个输入节点的值来控制整个生成结果不需要去动内部的节点连线。好的输入节点设计本质上是在定义工作流的控制面板。2. 常见输入节点分类与核心文件解析2.1 文件加载类图片、视频、模型文件加载类输入节点是从磁盘读取数据最常用的是Load Image、Load Video和Load Checkpoint。Load Image输出IMAGE和MASK两个端口如果你要处理透明背景可以在节点的alpha参数里设置。Load Checkpoint则负责加载Stable Diffusion模型它会从models/checkpoints目录读取.safetensors文件输出MODEL、CLIP、VAE三个引用。注意下载新模型比如Qwen Image 2.1后要把模型文件放到Comfy UI安装目录的models/checkpoints下然后在Load Checkpoint节点右侧的下拉列表里选择它。如果下拉列表里看不到点击旁边的刷新按钮。另外有些模型需要特定的VAE这时可以用独立的Load VAE节点从models/vae目录加载。视频类节点相对少见但在视频编辑工作流中很重要它会逐帧读取视频并输出一个五维张量帧数, 高度, 宽度, 通道数, 帧数维度实际上Comfy UI的video节点输出的是frames x C x H x W或frames x H x W x C取决于实现。在设计文件加载类输入节点时一个常见的需求是让用户通过文件选择器而不是手动输入路径这可以通过在INPUT_TYPES的STRING类型参数里设置file: True来实现前端会自动生成一个文件浏览器按钮。2.2 文本与参数输入你的控制面板CLIP Text Encode是工作流中控制文本的输入节点。它接收CLIP来自CheckpointLoader输出和文本字符串输出CONDITIONING。这个CONDITIONING会被KSampler用于引导生成方向。实际使用时你可以写“1girl, detailed face”之类的正面提示词也可以写“negative quality”之类的负面提示词。你可能会好奇为什么文本要经过CLIP变成CONDITIONING而不是直接以字符串传给采样器因为CLIP是一种多模态编码器它能把自然语言映射到与图像特征对齐的高维空间这样采样器才能理解你的描述。所以CLIP Text Encode这个输入节点的工作是接收原始文本提取语义特征输出条件向量。另一类参数输入节点最常见的是PrimitiveNode也就是基础数据节点。它不像Load Image那样从文件读而是由用户在节点面板上直接输入数值、字符串或布尔值。比如你想让KSampler的采样步数可以从界面直接改就可以用PrimitiveNode输出一个INT连到KSampler的steps输入。这种节点的设计思路就是暴露可调节参数提供可控性。之所以需要独立的基础数据节点是因为Comfy UI的连线只允许相同类型而INT、FLOAT、STRING这些基础类型也需要有对应的“源头”PrimitiveNode就是源头。你可以把多个PrimitiveNode的输出同时连接到同一个节点的不同输入很方便。2.3 自定义输入节点造一个你自己的入口自定义节点需要写Python脚本。最常见的方式是在Comfy UI的“custom_nodes”目录下建一个文件夹里面写一个py文件。每个节点类需要定义一个名为INPUT_TYPES的类方法用来声明这个节点需要哪些输入参数。同时还要定义RETURN_TYPES来声明输出类型以及FUNCTION字段指定实际执行的函数。以创建一个“读取JSON配置”的输入节点为例它可以接收一个JSON字符串并解析成多个数值。你定义INPUT_TYPES{required: {json: (STRING, {multiline: True})}}然后定义RETURN_TYPES希望输出多个INT或FLOAT在FUNCTION里解析字符串并返回一个元组。返回的每个值会对应一个输出端口。这里要注意返回的元组长度必须与RETURN_TYPES列表的长度一致否则Comfy UI会报错。3. 输入节点设计核心原理参数、类型与数据流3.1 INPUT_TYPES如何驱动界面每个自定义节点的类里都要写INPUT_TYPES方法它返回一个字典包含“required”和“optional”两个键。每个输入项都是一个元组(类型, {参数列表})。参数列表可以设置default、min、max、step、display_name、multiline等。Comfy UI的前端会读取这些定义自动生成对应的控件。比如定义一项(steps, (INT, {default: 20, min: 1, max: 100}))界面上就会出现一个数值输入框你改动后这个值会被传入FUNCTION处理。但要注意在多线程工作流中输入节点的值可能会被并发读取所以不要在节点内部保存可变状态。原因很简单Comfy UI可能会并行执行多个工作流如果节点内部有一个可变列表两个工作流同时读写会导致数据错乱。最好的做法是把所有状态都放在输入参数和返回值里节点本身保持无状态。3.2 返回类型与输出端口映射节点定义里还要设置RETURN_TYPES比如(IMAGE, MASK)它决定了输出端口的类型和数量。如果你返回的Python元组长度与RETURN_TYPES不一致Comfy UI会在验证时报错。每个返回值的实际类型必须对应比如返回的是torch.Tensor而RETURN_TYPES写IMAGE才能通过类型校验。具体来说Comfy UI内部有一套类型检查机制当你想把一个节点的IMAGE输出连到另一个节点时它检查目标节点的输入端是否接受IMAGE类型。如果你的RETURN_TYPES写的是IMAGE但实际返回的是float那么后续节点在运行时就会崩溃。另外RETURN_NAMES是给输出端口起名字方便识别不是必须的但强烈建议写上因为在复杂工作流中端口名字能帮助你快速理解输出数据的含义。3.3 版本差异秋叶v3.7 vs v3.27以及Qwen模型加载很多朋友在秋叶整合包的v3.7和v3.27之间纠结。据我使用经验这两个版本在核心的节点引擎上没有本质区别区别主要在UI细节和内置节点库的版本。比如v3.27可能内置了更新的节点版本修复了某些输入节点的参数面板刷新问题或者调整了默认端口名。如果你是从v3.7升级到v3.27有时会发现旧工作流里某个输入节点的“channel”项变了需要重新选择。另外v3.27的预置工作流模板更丰富里面用到了更多新的输入节点比如处理视频帧的LoadVideoInput或者直接解析URL的加载节点。这些模板可以直接参考能省下很多设计工作。至于Qwen Image 2.1模型它的加载和使用同样是通过输入节点实现的。你需要用Load Checkpoint或专门的QwenImageLoader加载它。有些自定义模型会要求专门的输入节点比如要传入ImageHint或者MaskHint等额外信息那么设计输入节点时就必须在INPUT_TYPES里留好这些参数否则模型无法正常工作。这里有一个小技巧如果你使用Qwen这类基于多模态语言模型的图像生成模型它可能需要额外的文本输入与图像输入结合这时你需要设计一个既能接收图像又能接收文本的输入节点并在FUNCTION里实现两种模态的编码融合。这种节点的返回类型往往更复杂可能是CONDITIONING也可能是IMAGE具体取决于模型架构。4. 实操过程从零到一设计一个输入节点并接入工作流4.1 明确需求与设计思路假设我们要设计一个输入节点它能读取一个视频文件的路径输出视频的帧数INT和视频张量IMAGE。目的让后续节点可以按帧处理视频。设计思路节点不直接保存视频数据而是从路径参数中读取文件用OpenCV解析帧率与总帧数然后转换成torch.Tensor输出。这里有个关键决策什么时候读文件可以在FUNCTION调用时读取这样每次执行时都会重新读取确保数据最新。但这样性能较差如果视频很大执行会很慢。另一种方式是在节点初始化时读取但这样可能会导致状态污染。我更推荐在FUNCTION内部读取因为Comfy UI的缓存机制会保证同一份输入在参数不变时不会重复调用也就是说如果你没有改变路径参数节点不会重复执行读取操作性能不会成为瓶颈。4.2 完整代码实现与注释下面我给出一个实际可运行的示例代码文件路径基于Windows风格如果你在Linux记得改成/。import os import cv2 import torch import numpy as np class LoadVideoFrames: classmethod def INPUT_TYPES(cls): return { required: { video_path: (STRING, {default: C:/videos/input.mp4, multiline: False}), max_frames: (INT, {default: 5, min: 1, max: 1000, step: 1}), } } RETURN_TYPES (IMAGE, INT) RETURN_NAMES (frames_image, total_frames) FUNCTION load_video CATEGORY MyNodes/Input def load_video(self, video_path, max_frames): if not os.path.exists(video_path): raise ValueError(f视频文件不存在: {video_path}) cap cv2.VideoCapture(video_path) if not cap.isOpened(): raise ValueError(f无法打开视频文件: {video_path}) total_frames int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) cap.set(cv2.CAP_PROP_POS_FRAMES, 0) frames [] for i in range(min(max_frames, total_frames)): ret, frame cap.read() if not ret: break rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) tensor torch.from_numpy(rgb).float() / 255.0 # 转换为 (1, H, W, C) 便于拼接 frames.append(tensor.unsqueeze(0)) cap.release() if len(frames) 0: raise ValueError(没有读取到任何视频帧) image_tensor torch.cat(frames, dim0) # (N, H, W, C) return (image_tensor, total_frames)这段代码有几个设计要点。返回值第一个是IMAGE形状为(N, H, W, C)N是实际读取的帧数每帧的RGB值都归一化到0-1之间这是Comfy UI的标准做法。返回的第二个是INT总帧数方便下游节点知道完整视频长度。如果你只想读视频的第一帧作为图像可以单独写一个LoadVideoFrame节点只需在循环里取一次break即可。4.3 接入工作流并测试把这个py文件保存到Comfy UI/custom_nodes/LoadVideoFrames.py然后重启Comfy UI。在节点列表里搜索“LoadVideoFrames”你会发现它出现在“MyNodes/Input”分类下。拖出这个节点填入视频路径和最大帧数点击执行它会输出“frames_image”和“total_frames”两个端口。把“frames_image”接到Save Image的输入上就能看到视频前几帧的预览。你可以进一步把“total_frames”接到一个文本显示节点验证数值是否正确。调试的时候我推荐在节点代码里加print语句。Comfy UI会把print输出打印到后端控制台这是排查问题最简单的方法。比如在load_video函数开头打印video_path和max_frames确认输入值是否和你界面上设置的一致。另一个常见问题是如果视频路径中包含中文字符某些操作系统环境下OpenCV可能无法读取此时你需要检查编码或者干脆改成英文路径。我踩过这个坑后来设计输入节点时都会在检测到路径不存在时抛出明确的异常信息而不是让OpenCV静默报错。5. 常见问题排查与避坑心得5.1 输入节点常见错误速查表下面这张表是我在社区里看到频率最高的出错情况按使用频率排了一下错误类型可能原因解决方法input type mismatch输出端口类型与目标节点输入类型不一致检查RETURN_TYPES确保与目标节点INPUT_TYPES的期望类型匹配如IMAGE、LATENT、CONDITIONINGFileNotFoundError输入节点引用的文件路径不存在或路径写错了检查路径是否正确注意Windows与Linux路径差异以及相对路径与绝对路径的区别节点输出为空FUNCTION内忘记返回值或返回了None确保FUNCTION返回一个元组且长度等于RETURN_TYPES的长度UI不显示控件自定义节点的INPUT_TYPES字典结构不对比如遗漏了“required”键检查INPUT_TYPES是否包含“required”和“optional”两个键每个输入项是否为元组模型加载失败模型文件未放在models/checkpoints目录或模型版本不兼容将模型拷贝到对应目录点击刷新按钮更新列表阅读模型文档确认是否需要其他输入节点视频帧乱序读取视频时没有重置帧位置使用cap.set(cv2.CAP_PROP_POS_FRAMES)设置起始帧或检查是否在循环中改变了读取顺序图像颜色错乱RGB与BGR通道顺序搞混在cv2读取后使用cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)转换再转torch.Tensor节点执行非常慢输入节点在FUNCTION里处理了大文件而且没有利用缓存机制检查是否在FUNCTION里反复读取同一个文件考虑使用Comfy UI的节点缓存功能避免改变输入参数时重复执行或增加一个“force_load”布尔开关5.2 独家避坑指南输入节点设计中的三个典型坑第一个坑在自定义节点里写死了文件路径。我刚开始写的时候把“./test.jpg”写死结果别人拿过去全都报错。你应该设计成从文件选择器或路径参数读取。对于文件类参数可以在INPUT_TYPES的STRING类型里加上file: True这样前端会生成一个文件选择按钮用户不需要手动打字。第二个坑返回类型与张量形状不匹配。比如你返回了一个形状是(B, H, W)的灰度张量但RETURN_TYPES写IMAGEIMAGE要求在末维有3个通道RGB。你必须在返回前把灰度图转成RGB格式比如用torch.stack([gray, gray, gray], dim-1)或者gray.expand(-1, -1, 3)。否则下游节点处理时会在某个reshape操作上崩溃这种错误通常很难一眼看出来。所以设计输入节点时一定要弄清楚Comfy UI对每种类型的形状定义。第三个坑没有处理默认值。很多输入节点在用户还没操作时会用默认值执行。如果你的FUNCTION假定字符串非空就会报错。你可以在FUNCTION开头加一个判断比如如果没有输入则返回一个1x1的黑色图像或者抛出一个明确错误提示。我建议设计节点时给所有输入项都设置一个合理的默认值这样就算用户不手动修改工作流也能跑通。毕竟在大型工作流里用户可能希望先连线再慢慢调参数。另外还有一个心得输入节点的名称要起得足够直观。Comfy UI社区有很多节点包每个包都有自己的命名风格。如果你的节点叫“Input1”那别人根本不知道它是干嘛的。按我的习惯分类名会写成“MyNodes/Input/Video”节点名用“LoadVideoFrames”。这样在搜索框里输入“LoadVideo”就能快速找到。在RETURN_NAMES里用“frames_image”而不是“image”这也是为了减少歧义。尽量做到一看名字就知道输出是什么数据能大大降低工作流搭建成本。最后再说一个关于版本差异的提醒。如果你在秋叶v3.7下写好的自定义节点升级到v3.27后突然出现“无法加载节点”的情况先检查一下节点文件是否有编码问题以及依赖是否缺失。因为新版整合包可能会升级Python或第三方库旧的自定义节点可能依赖了过时的库版本。通常最简单的办法是在v3.27的Python环境里重新安装一遍依赖或者查看报错信息里缺失的是哪个库然后pip install。输入节点本质上是Python代码所以它受限于环境。理解这一点你就能更快地排查问题。这篇解析写到这里基本把输入节点的设计、原理和落地流程都过了一遍。我自己在设计输入节点时最大的体会是输入节点不只是技术接口更是用户体验的一部分。一个好的输入节点应该让用户可以不用打开代码就能控制工作流。最后分享一个小技巧调试时可以在FUNCTION里打印一个字典包含所有输入值这样你能非常清楚地看到Comfy UI传进来的数据长什么样。用print即可输出会显示在Comfy UI的日志中。希望这篇解析能帮你少走一些弯路。