首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ComfyUI AI系统深度实践:从工作流编排到自定义节点开发

ComfyUI AI系统深度实践:从工作流编排到自定义节点开发

原创
作者头像
用户12687280
发布2026-08-29 18:17:35
发布2026-08-29 18:17:35
440
举报

ComfyUI 凭借其基于节点的低显存占用和高度确定性,正从桌面 GUI 进化为 AI 图像生成的后端核心引擎。其本质是一套有向无环图(DAG)执行系统——每个节点封装了模型加载、采样或后处理逻辑,连线定义了张量数据的流动路径。本文将带您跳出鼠标拖拽,用代码直接操控这套系统,实现自动化、定制化和服务化。

一、工作流即代码:通过 REST API 编排生成任务

ComfyUI 原生提供 /prompt 接口,接受 JSON 格式的工作流描述。我们首先需将 GUI 中设计好的工作流导出为 workflow_api.json,然后通过 Python 脚本动态修改其中的提示词、种子和尺寸参数。

代码语言:javascript
复制
import json
import requests
import websocket
import uuid
import time

class ComfyUIRuntime:
    def __init__(self, server_address="127.0.0.1:8188"):
        self.base_url = f"http://{server_address}"
        self.ws_url = f"ws://{server_address}/ws"
    
    def load_workflow(self, json_path):
        with open(json_path, 'r') as f:
            self.workflow = json.load(f)
        return self
    
    def set_prompt(self, text, node_id="6"):  # 默认 CLIP Text Encode 节点为 6
        self.workflow[node_id]["inputs"]["text"] = text
        return self
    
    def set_seed(self, seed, node_id="3"):   # 默认 KSampler 节点为 3
        self.workflow[node_id]["inputs"]["seed"] = seed
        return self
    
    def queue_prompt(self):
        """提交任务并返回 prompt_id"""
        payload = {"prompt": self.workflow}
        resp = requests.post(f"{self.base_url}/prompt", json=payload)
        return resp.json()["prompt_id"]
    
    def wait_for_image(self, prompt_id, timeout=120):
        """通过 WebSocket 监听执行进度,并获取输出图像路径"""
        ws = websocket.WebSocket()
        ws.connect(self.ws_url)
        images = []
        start = time.time()
        while time.time() - start < timeout:
            out = ws.recv()
            if isinstance(out, str):
                data = json.loads(out)
                if data["type"] == "executing" and data["data"]["prompt_id"] == prompt_id:
                    if data["data"]["node"] is None:  # 执行完毕
                        break
            else:
                # 二进制数据(图像预览)
                pass
            time.sleep(0.1)
        ws.close()
        # 实际生产环境从 output 文件夹读取图片或直接解析 Base64
        return f"http://{self.server_address}/view?filename=output.png"

通过上述封装,我们能够用纯代码驱动 ComfyUI,轻松实现批量生成、参数网格搜索或 A/B 测试,彻底摆脱手工操作。

二、自定义节点开发:打造系统级扩展能力

原生节点无法满足特定业务需求,比如在生成前调用 LLM 优化提示词,或在生成后调用 OpenCV 进行人脸修复。ComfyUI 允许用 Python 开发自定义节点,只需将脚本放入 custom_nodes/ 目录,系统启动时自动注册。

我们实现一个 “LLM 提示词增强器” 节点,它接收用户简短的描述,调用本地 Qwen 模型扩展为包含光影、构图和风格修饰语的详细正向提示词:

代码语言:javascript
复制
# custom_nodes/prompt_enhancer.py
import comfy
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

class PromptEnhancer:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "raw_prompt": ("STRING", {"multiline": True, "default": "一只猫"}),
                "creativity": ("FLOAT", {"default": 0.8, "min": 0.1, "max": 1.0, "step": 0.05})
            }
        }
    
    RETURN_TYPES = ("STRING",)
    FUNCTION = "enhance"
    CATEGORY = "custom/llm"

    def __init__(self):
        self.model = None
        self.tokenizer = None
    
    def load_model(self):
        if self.model is None:
            self.tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct")
            self.model = AutoModelForCausalLM.from_pretrained(
                "Qwen/Qwen2.5-1.5B-Instruct",
                torch_dtype=torch.float16,
                device_map="cuda"
            )
        return self.model, self.tokenizer
    
    def enhance(self, raw_prompt, creativity):
        model, tokenizer = self.load_model()
        sys_msg = f"将以下简短描述扩展为Stable Diffusion正向提示词,添细节、光效、风格,扩展系数{creativity}:"
        messages = [{"role": "system", "content": sys_msg}, {"role": "user", "content": raw_prompt}]
        text = tokenizer.apply_chat_template(messages, tokenize=False)
        inputs = tokenizer(text, return_tensors="pt").to("cuda")
        outputs = model.generate(**inputs, max_new_tokens=150, temperature=creativity)
        enhanced = tokenizer.decode(outputs[0], skip_special_tokens=True)
        # 清洗掉系统指令部分,仅保留扩展后的提示词
        return (enhanced.split("assistant")[-1].strip(),)

# 节点注册
NODE_CLASS_MAPPINGS = {"PromptEnhancer": PromptEnhancer}
NODE_DISPLAY_NAME_MAPPINGS = {"PromptEnhancer": "LLM 提示词增强器"}

将此节点接入工作流后,用户输入“赛博朋克街道”即可自动扩展为“霓虹灯闪烁的雨中街道,赛博朋克风格,高对比度,电影级布光,8k”,显著提升出图质量,且无需人工斟酌词汇。

三、企业级微服务架构:任务队列与异步回调

面向生产环境,我们需要将 ComfyUI 封装为高可用微服务。引入 Redis 任务队列 解耦生成请求,并支持异步 Webhook 回调。

代码语言:javascript
复制
from fastapi import FastAPI, BackgroundTasks
from rq import Queue
from redis import Redis
from pydantic import BaseModel
import uuid

app = FastAPI()
redis_conn = Redis(host='localhost', port=6379)
task_queue = Queue('comfy_tasks', connection=redis_conn)

class GenRequest(BaseModel):
    prompt: str
    width: int = 512
    height: int = 512
    callback_url: str = None

def run_comfy_task(prompt, width, height, callback_url):
    """后台工作函数,由 RQ Worker 执行"""
    runtime = ComfyUIRuntime()
    runtime.load_workflow("base_workflow.json") \
           .set_prompt(prompt) \
           .set_seed(int(time.time()))
    pid = runtime.queue_prompt()
    image_url = runtime.wait_for_image(pid)
    
    if callback_url:
        requests.post(callback_url, json={"status": "done", "image_url": image_url, "prompt": prompt})
    return image_url

@app.post("/generate")
async def generate(request: GenRequest, background_tasks: BackgroundTasks):
    task_id = str(uuid.uuid4())
    # 将任务推入 Redis 队列,由独立 Worker 进程消费
    job = task_queue.enqueue(run_comfy_task, request.prompt, request.width, request.height, request.callback_url)
    return {"task_id": job.id, "status": "queued", "eta": "约15秒"}

通过此架构,前端请求瞬时返回 task_id,后端多个 ComfyUI 实例(Worker)并行消费队列,生成完毕主动回调业务服务器,完美适配高并发场景。

四、性能调优与系统级优化

要让 ComfyUI 在服务器环境稳定运行,必须进行深度调优:

  1. 显存预加载与卸载:编写启动脚本,预先将 Checkpoint 加载至 GPU 显存,避免每次任务重复加载(耗时增加 300%)。使用 ComfyUI 的 --lowvram 模式虽能省显存,但会拖慢速度,生产环境建议 --highvram 配合单模型专属 Worker。
  2. 工作流缓存编译:对于固定结构的工作流,首次执行后 ComfyUI 内部会编译计算图。我们可通过 Python 脚本预热(Warm-up),发送 5 个假请求促使缓存生效。
  3. 输出图像即时压缩:在 wait_for_image 中捕获 WebSocket 的二进制预览帧,直接转为 JPEG Base64 返回,减少磁盘 I/O 和网络传输开销。

代码语言:javascript
复制
# 优化后的图像获取(直接捕获 WebSocket 二进制)
def wait_and_capture(ws, prompt_id):
    while True:
        msg = ws.recv()
        if isinstance(msg, bytes):
            # 解析 ComfyUI 二进制头,提取图片数据
            import struct
            header = msg[:8]
            # 实际逻辑略,直接保存为 BytesIO
            from PIL import Image
            import io
            img = Image.open(io.BytesIO(msg[8:]))
            return img

五、总结与演进方向

本文从底层 API 调用、自定义节点开发到上层微服务架构,完整展示了 ComfyUI 从交互工具蜕变为 AI 系统核心的全过程。这套方案的价值在于 “确定性 + 可编程性”——JSON 工作流保证了生成结果的可复现性,Python 接口赋予了它与业务逻辑(如 RAG 检索、用户画像)深度融合的能力。

未来,ComfyUI 系统可进一步结合 LoRA 动态加载器(每个任务热加载不同微调权重)和 多 GPU 调度器(自动分配空闲显存卡)。掌握了这套技术栈,开发者便能在 AIGC 应用层构建高度定制化的解决方案,无论是批量电商出图还是个性化艺术创作,都能以工业化标准高效输出。ComfyUI 不再是复杂的玩具,而是智能图像工厂的操作系统内核。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • ComfyUI 凭借其基于节点的低显存占用和高度确定性,正从桌面 GUI 进化为 AI 图像生成的后端核心引擎。其本质是一套有向无环图(DAG)执行系统——每个节点封装了模型加载、采样或后处理逻辑,连线定义了张量数据的流动路径。本文将带您跳出鼠标拖拽,用代码直接操控这套系统,实现自动化、定制化和服务化。
    • 一、工作流即代码:通过 REST API 编排生成任务
    • 二、自定义节点开发:打造系统级扩展能力
    • 三、企业级微服务架构:任务队列与异步回调
    • 四、性能调优与系统级优化
    • 五、总结与演进方向
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档