Loogen 上层调度结合 ComfyUI 本地绘图工作流实战|SD 底层图生图批量画面输出方案

简介: 该方案提出Loogen+ComfyUI分层架构,解决漫剧批量生产中的角色漂移、显存溢出、跨层参数不兼容等痛点。Loogen负责剧本解析与任务调度,ComfyUI本地GPU渲染,中转脚本实现协议转换与异常处理,支持IPAdapter/ControlNet精准控图,适配8G显卡稳定量产。(239字)

方案背景与架构设计

业务痛点

  1. 纯 ComfyUI 方案:节点堆叠严重,剧本文本导入、分镜循环、任务重试、素材分类归档没有原生能力,批量生产时管理成本极高;
  2. 纯上层云端方案:无法复用本地显卡,IPAdapter 角色参考图、ControlNet 固定姿态、图生图重绘容易出现角色漂移,云端 API 调用成本随产量线性上涨;
  3. 跨层对接痛点:上层输出的提示词、种子、参考图路径、重绘强度参数,和 ComfyUI 工作流节点输入格式不兼容,缺少标准化转换层;
  4. 显存瓶颈:8G 消费级显卡,连续批量渲染极易触发 OOM,缺少模型自动卸载、分片解码、任务限流的配套方案;
  5. 素材链路断裂:渲染完成后的图片没有自动回传给上层管理系统,分镜和剧本对不上,后续视频生成环节需要人工二次整理。

分层架构分工

  • Loogen(上层管理层):业务控制层。读取漫剧剧本,按照镜头拆分成分镜任务;读取角色人设库,自动生成正向、反向提示词;维护任务队列、任务优先级、失败重试机制;记录每一条分镜对应的 task_id、角色编号、镜头描述;接收底层返回的图片,绑定元数据,存入素材库,后续可以下发视频生成任务;不执行 GPU 绘图运算。
  • 适配中转层(Python 脚本):协议转换层。接收 Loogen 下发的 JSON 任务,映射参数到 ComfyUI 工作流节点;提交渲染任务、轮询任务状态、捕获显存溢出、超时异常;渲染完成后抓取图片,做简单压缩、格式统一,回调结果给 Loogen。
  • ComfyUI(SD 底层渲染层,本地部署):算力执行层。加载 SD 基础大模型、VAE、ControlNet 权重、IPAdapter 权重;加载图生图工作流模板,接收传入的参考图、原图、提示词、种子、denoise 强度;执行采样、解码输出图片;支持 ModelUnloader 节点自动释放显存,适配 8G 显存。
  • 数据流链路Loogen剧本解析 → 生成分镜任务入队 → 中转脚本消费队列 → HTTP调用ComfyUI API → SD图生图/文生图渲染 → 图片输出 → 脚本回调结果至Loogen → Loogen归档素材,触发后续视频生成

横向对比补充:SD WebUI 也具备 API 能力,但自定义节点拓展、图生图 + IPAdapter 联动的灵活性弱于 ComfyUI;LocModel 是一体化方案,自带调度和绘图,适合不想分层搭建的用户;而 Loogen+ComfyUI 分层方案适合需要精细化管控剧本、大批量漫剧稳定生产的场景。

具体资源模型请看这一篇文章https://developer.aliyun.com/article/1772270?spm=a2c6h.13148508.setting.32.50d94f0eR9PlDH

ComfyUI 底层环境准备(供 Loogen 远程调用的渲染基座)

硬件与软件基线

硬件:NVIDIA 显卡,最低 8G 显存;推荐开启系统虚拟内存 16G 以上,作为显存溢出兜底; 驱动:CUDA 11.8 / 12.1,对应 torch 版本匹配; 软件:ComfyUI 源码版(推荐,整合包版本环境容易出现版本冲突); 必备节点插件:IPAdapter Plus、ControlNet Aux、ModelUnloader、Tiled VAE、Image Saver; 模型准备:SD 基础模型、对应风格 VAE、IPAdapter 角色模型、ControlNet OpenPose/LineArt 权重。

ComfyUI 启动配置(开放 API、显存优化)

进入 ComfyUI 根目录,使用下面命令启动,开启跨域、局域网访问、低显存模式:

python main.py --listen 0.0.0.0 --enable-cors-header --lowvram --gpu-memory 7.0 --comfyui-log-level info

参数说明:

  • --listen 0.0.0.0:允许局域网内 Loogen 服务、中转脚本访问 8188 端口;如果 Loogen 和 ComfyUI 在两台电脑,需要放行防火墙 8188 端口;
  • --lowvram:显存分片调度,适合 8G 显卡;
  • --gpu-memory 7.0:限制显卡占用上限 7GB,预留空间给系统、驱动;
  • --enable-cors-header:解决跨域请求报错。

图生图工作流导入与改造

  1. 导入图生图工作流 JSON 模板;
  2. 手动调试:分别测试文生图分支、图生图分支,测试 IPAdapter 角色参考、ControlNet 姿态锁定;
  3. 固定节点 ID:把正向提示词、反向提示词、种子、分辨率、图生图原图、denoise 强度、IPAdapter 参考图、输出节点记录下来,后续脚本需要绑定节点 ID;
  4. 嵌入 ModelUnloader 节点:每张图渲染完成自动卸载模型,释放显存,避免连续批量任务显存持续上涨;
  5. 嵌入 Tiled VAE 节点:分块解码图片,大幅降低 VAE 解码瞬间显存峰值,是 8G 显存稳定跑竖屏 576×1024 画面的关键;
  6. 调试参数基线(漫剧 9:16 竖屏)
  • denoise 重绘强度:角色保持优先 0.4~0.5;想要改动画面内容 0.5~0.65,不建议超过 0.7;
  • IPAdapter 权重:0.65~0.78,权重太高容易覆盖画面构图;
  • ControlNet 权重:0.6~0.75,姿态线稿锁定;
  • 采样器 DPM++ 2M Karras,采样步数 18~22;
  • 分辨率:576×1024,8G 显卡不建议直接跑 768×1344,极易 OOM。

调试完成后,导出最终的 workflow.json 模板,放到中转脚本目录,作为渲染模板。

中转适配层完整 Python 代码

该脚本实现:任务队列消费、参数映射、提交 ComfyUI 任务、轮询状态、异常捕获、图片本地归档、回调 Loogen、显存异常重试。

import requests
import json
import os
import time
import threading
from queue import Queue
from PIL import Image
# ====================== 配置区,根据自己环境修改 ======================
COMFYUI_URL = "http://127.0.0.1:8188"
WORKFLOW_PATH = "./sd_img2img_workflow.json"
# 渲染图片输出目录
OUTPUT_DIR = "./comfy_render_output"
# Loogen回调地址
LOOGEN_CALLBACK_BASE = "http://127.0.0.1:9000/task/callback"
# 8G显卡限制并发为1,不要修改
MAX_WORKER = 1
# 任务超时时间
TASK_TIMEOUT = 300
# 模板内节点ID,和你工作流一一对应
NODE_POSITIVE = "3"
NODE_NEGATIVE = "4"
NODE_SEED = "7"
NODE_SIZE = "10"
NODE_IMG2IMG_SRC = "12"
NODE_DENOISE = "13"
NODE_IP_REF = "15"
NODE_OUTPUT = "20"
# =====================================================================
os.makedirs(OUTPUT_DIR, exist_ok=True)
task_queue = Queue(maxsize=20)
def load_workflow_template():
    with open(WORKFLOW_PATH, "r", encoding="utf-8") as f:
        return json.load(f)
def comfy_submit_prompt(prompt_data):
    res = requests.post(f"{COMFYUI_URL}/prompt", json={"prompt": prompt_data}, timeout=60)
    res.raise_for_status()
    return res.json()
def comfy_query_history(prompt_id):
    r = requests.get(f"{COMFYUI_URL}/history/{prompt_id}", timeout=30)
    return r.json()
def wait_task_finish(prompt_id):
    start_time = time.time()
    while time.time() - start_time < TASK_TIMEOUT:
        hist = comfy_query_history(prompt_id)
        if prompt_id in hist:
            return hist[prompt_id]
        time.sleep(2)
    raise TimeoutError("ComfyUI渲染任务超时")
def save_and_compress_img(img_url, save_path):
    resp = requests.get(img_url, timeout=30)
    with open(save_path, "wb") as f:
        f.write(resp.content)
    # 简单压缩,降低体积,方便Loogen读取
    im = Image.open(save_path)
    im.save(save_path, quality=85, optimize=True)
    return save_path
def worker_loop():
    """消费任务队列的工作线程"""
    while True:
        task = task_queue.get()
        try:
            workflow = load_workflow_template()
            # 填充提示词
            workflow[NODE_POSITIVE]["inputs"]["text"] = task["positive"]
            workflow[NODE_NEGATIVE]["inputs"]["text"] = task["negative"]
            workflow[NODE_SEED]["inputs"]["seed"] = task["seed"]
            workflow[NODE_SIZE]["inputs"]["width"] = task["width"]
            workflow[NODE_SIZE]["inputs"]["height"] = task["height"]
            # 图生图参数
            if task.get("img2img_enable", False):
                workflow[NODE_IMG2IMG_SRC]["inputs"]["image"] = task["img2img_source"]
                workflow[NODE_DENOISE]["inputs"]["denoise"] = task["denoise_strength"]
            # IPAdapter角色参考图
            workflow[NODE_IP_REF]["inputs"]["image"] = task["ref_char_img"]
            # 提交任务
            submit_ret = comfy_submit_prompt(workflow)
            prompt_id = submit_ret["prompt_id"]
            print(f"【{task['task_id']}】已提交ComfyUI,prompt_id:{prompt_id}")
            # 等待渲染完成
            result = wait_task_finish(prompt_id)
            img_info = result["outputs"][NODE_OUTPUT]["images"][0]
            img_view_url = f"{COMFYUI_URL}/view/{img_info['filename']}"
            local_save = os.path.join(OUTPUT_DIR, f"{task['task_id']}_{img_info['filename']}")
            save_and_compress_img(img_view_url, local_save)
            # 回调Loogen上层
            callback_data = {
                "task_id": task["task_id"],
                "status": "success",
                "comfy_prompt_id": prompt_id,
                "local_file": local_save,
                "img_url": img_view_url,
                "seed": task["seed"]
            }
            requests.post(LOOGEN_CALLBACK_BASE, json=callback_data, timeout=20)
            print(f"【{task['task_id']}】渲染完成,回调Loogen成功")
        except Exception as e:
            err_msg = str(e)
            print(f"【{task['task_id']}】任务失败:{err_msg}")
            # 失败回调,通知Loogen重试
            callback_data = {
                "task_id": task["task_id"],
                "status": "failed",
                "error": err_msg
            }
            try:
                requests.post(LOOGEN_CALLBACK_BASE, json=callback_data, timeout=20)
            except:
                pass
        finally:
            task_queue.task_done()
def add_task(task_data):
    """对外接口,Loogen调用这个方法加入任务"""
    task_queue.put(task_data)
if __name__ == "__main__":
    # 启动工作线程
    for _ in range(MAX_WORKER):
        t = threading.Thread(target=worker_loop, daemon=True)
        t.start()
    print("中转服务启动成功,监听任务队列,最大并发:", MAX_WORKER)
    # 模拟Loogen批量下发多条漫剧分镜任务
    demo_task_list = [
        {
            "task_id": "loogen_scene_001",
            "positive": "年轻女生,长发,居家卧室,暖光,漫剧手绘,9:16竖屏,柔和阴影",
            "negative": "畸形,多手指,扭曲人脸,水印,文字,模糊",
            "seed": 10001,
            "img2img_enable": True,
            "img2img_source": "./source_img/scene001_base.png",
            "denoise_strength": 0.45,
            "ref_char_img": "./ref/char_girl01.png",
            "width": 576,
            "height": 1024
        },
        {
            "task_id": "loogen_scene_002",
            "positive": "年轻女生站在窗边,看向窗外,傍晚,漫剧手绘,9:16竖屏",
            "negative": "畸形,多手指,扭曲人脸,水印,文字,模糊",
            "seed": 10002,
            "img2img_enable": True,
            "img2img_source": "./source_img/scene002_base.png",
            "denoise_strength": 0.42,
            "ref_char_img": "./ref/char_girl01.png",
            "width": 576,
            "height": 1024
        }
    ]
    for tsk in demo_task_list:
        add_task(tsk)
    task_queue.join()
    print("所有模拟任务执行完毕")

配套辅助脚本:图片预处理 + FFmpeg 批量转码指令

Loogen 下发的参考图、原图尺寸不一,提前统一尺寸、去除透明通道,减少 ComfyUI 渲染异常。

# preprocess_img.py 图片预处理脚本
from PIL import Image
import os
def preprocess_image(input_path, out_path, target_w=576, target_h=1024):
    im = Image.open(input_path).convert("RGB")
    im = im.resize((target_w, target_h), Image.Resampling.LANCZOS)
    im.save(out_path, quality=90)
    print(f"预处理完成:{out_path}")
if __name__ == "__main__":
    src_dir = "./source_raw"
    out_dir = "./source_img"
    os.makedirs(out_dir, exist_ok=True)
    for fname in os.listdir(src_dir):
        if fname.lower().endswith((".jpg", ".png", ".webp")):
            preprocess_image(os.path.join(src_dir, fname), os.path.join(out_dir, fname))

当 Loogen 收集完所有分镜图片后,调用 FFmpeg 合成漫剧片段,给图片加上停留时长:

# 生成文件列表,每帧图片停留2秒
ffmpeg -f concat -safe 0 -i filelist.txt -c:v libx264 -r 25 -pix_fmt yuv420p manju_scene.mp4

filelist.txt 示例:

file 'comfy_render_output/loogen_scene_001_xxx.png'
duration 2
file 'comfy_render_output/loogen_scene_002_xxx.png'
duration 2

显存优化与任务调度策略

分层架构下,8G 显卡的瓶颈不在上层 Loogen,而在 ComfyUI 渲染环节,必须强制执行下面规则:

  1. 并发硬限制:8G 显卡只允许 MAX_WORKER=1,串行渲染;12G 显卡可放宽至 2;
  2. 自动模型卸载:工作流末尾加入 ModelUnloader,每次渲染完成清空显存;
  3. Tiled VAE 强制开启,避免大图解码瞬间显存爆掉;
  4. Loogen 上层做任务持久化队列,脚本返回 failed 状态时,Loogen 自动重试 2 次,重试间隔拉长,避免短时间反复下压任务;
  5. 定期清理 ComfyUI 输出缓存目录,缓存图片堆积也会占用磁盘、间接影响调度;
  6. 不开启实时预览,预览会额外占用显存。

踩坑排错要点

  1. 连接 ComfyUI 超时:检查--listen 0.0.0.0,确认防火墙放行 8188;跨机器部署时,不能传递本地磁盘路径,需要 Loogen 上传图片到静态服务,传入 http 图片地址;
  2. IPAdapter 角色漂移:denoise 强度不要过高;Loogen 生成提示词时,固定角色描述词;参考图优先使用正面清晰半身照;
  3. 节点参数不生效:脚本内绑定的 NODE_ID 和你本地工作流节点 ID 不一致,打开 ComfyUI,开启节点 ID 显示,核对修改;
  4. 回调失败:Loogen 的回调接口需要可以被中转脚本网络访问,不要绑定 127.0.0.1;
  5. 随机 OOM:优先检查是否忘记加 ModelUnloader;其次降低分辨率、调低 denoise 强度;最后增大虚拟内存兜底。

FAQ

Q:Loogen 和 ComfyUI 分开部署在两台电脑,图片怎么互通?

A:搭建简易静态图片服务,Loogen 上传原图、角色参考图,生成 http 链接,把链接传给中转脚本,ComfyUI 可以远程加载网络图片,避免磁盘路径不互通。

Q:这套架构能不能同时支持文生图和图生图?

A:可以,工作流保留双分支,Loogen 下发参数里携带 img2img_enable 开关,脚本自动判断是否传入原图与 denoise 参数。

Q:8G 显存显卡,一天稳定可以跑多少张漫剧分镜?

A:单张 576×1024,采样 20 步,单张渲染大约 25~40 秒,串行渲染,除去异常重试,一天稳定产出 1500~2200 张左右,取决于模型大小。

Q:可以把这套流程扩展到图生视频吗?

A:可以。ComfyUI 增加 VideoHelperSuite、AnimateDiff 节点,Loogen 在图片渲染完成后,下发视频生成任务,同样走这套 API 对接逻辑,只是工作流模板替换为视频工作流。

Q:对比 LocModel 一体化方案,Loogen+ComfyUI 分层优势在哪?

A:LocModel 开箱即用,一体化调度绘图;Loogen+ComfyUI 分层方案自由度更高,剧本逻辑、分镜规则、重试策略、素材库可以完全自定义,适合需要长期量产、定制化漫剧业务的团队,缺点是部署和调试成本更高。

总结

Loogen 作为上层管理层,和 ComfyUI 本地 SD 绘图引擎组合,是私有化漫剧量产里非常成熟的解耦架构。Loogen 聚焦剧本业务、分镜编排、任务管理,ComfyUI 专注 GPU 渲染,依靠 IPAdapter、ControlNet 保证角色一致性,Tiled VAE、ModelUnloader 适配 8G 显存本地部署。

相关文章
|
14天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
5936 44
|
14天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
5021 60
|
9天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
2370 6
|
6天前
|
人工智能 安全 API
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(dsh)是DeepSeek AI于2026年开源的轻量级Agent运行框架,基于Cordis内核,践行“一切皆插件”理念。支持Web/桌面双端,开箱即用;内置多模型接入、丰富插件生态(超3.5万),适配编程、办公、创作等场景。(239字)
1475 0
|
9天前
|
云安全 人工智能 安全
|
2天前
|
云安全 人工智能 安全
|
8天前
|
人工智能 并行计算 调度
本地 AI 一键部署工具 LocModel:Windows 端集成画图、视频生成、Agent 的开源模型运行方案
LocModel 是专为 Windows 设计的一站式本地 AI 工具,支持零配置启动、自动硬件检测、GGUF 模型一键加载、文生图/视频生成及 Agent 自动化任务。适配 8G 显存,内置显存分片调度,轻松实现 AI 漫剧批量创作与离线大模型调用。(239 字)