ComfyUI 原生提供 /prompt 接口,接受 JSON 格式的工作流描述。我们首先需将 GUI 中设计好的工作流导出为 workflow_api.json,然后通过 Python 脚本动态修改其中的提示词、种子和尺寸参数。
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 模型扩展为包含光影、构图和风格修饰语的详细正向提示词:
# 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 回调。
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 在服务器环境稳定运行,必须进行深度调优:
--lowvram 模式虽能省显存,但会拖慢速度,生产环境建议 --highvram 配合单模型专属 Worker。wait_for_image 中捕获 WebSocket 的二进制预览帧,直接转为 JPEG Base64 返回,减少磁盘 I/O 和网络传输开销。# 优化后的图像获取(直接捕获 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 删除。