在这里插入图片描述
最近在项目上遇到了一个非常头疼的问题——成本

最开始,我尝试使用智谱清言、豆包等大模型的图像生成 API。不可否认,它们的效果很不错,接入也非常快速。但是,如果你的应用场景需要大量生成图片(比如基于脚本逐句生成视频背景图或分镜),按照每张图5分到1毛的单价计算,跑一个完整项目的账单绝对会让你“肉痛”。

为了在保证出图质量的前提下把成本压到0元,我决定转向本地化部署方案——ComfyUI

今天这篇文章,我就把今天踩坑、调试 ComfyUI 并将其封装为一个“免费 API 服务”的完整过程记录下来。内容从环境搭建到代码调试,由浅入深,只用ComfyUI最基础的默认工作流,小白也能轻松上手!


1. 为什么选择 ComfyUI?

在开源 AI 绘画领域,WebUI(如 Stable Diffusion WebUI)和 ComfyUI 是两座大山。
相比于 WebUI 的“重度产品化”,ComfyUI 以其节点式(Node-based)的架构设计脱颖而出。你不仅可以像搭乐高一样自由组合生图逻辑,更重要的是,它天生就适合作为 API 供第三方系统调用

我今天的需求十分简单:只需要最纯粹的“文生图(Text-to-Image)”功能,以此替代昂贵的在线 API。


2. 环境说明:Windows 与 WSL 的“双城记”

很多开发者在部署时会纠结操作系统。我的最终方案是:ComfyUI 跑在 Windows 上,而调用它的 Python 代码跑在 WSL (Windows Subsystem for Linux) 中。

2.1 硬件与环境配置

  • 显卡:NVIDIA RTX 3070(8GB 物理显存 + 8GB 共享显存,对于常规的 1080P/4K 初期生图基本够用)
  • 宿主机:Windows 11(运行 ComfyUI)
  • 开发机:Ubuntu (基于 WSL2,运行 Python 脚本)
    在这里插入图片描述

2.2 为什么采用这种混合架构?

采用这种“跨次元”架构并不是因为喜欢折腾,而是基于以下考量:

  1. 显卡驱动与性能(Why Windows):NVIDIA 的显卡驱动和 CUDA 工具包在 Windows 原生环境下兼容性最好,ComfyUI 在 Windows 上可以通过便携包(Standalone)一键运行,省去了大量配置环境的麻烦。
  2. 开发体验与流水线(Why WSL):我的短视频生成核心代码逻辑(涉及视频处理、Git 管理等)都在 WSL 里面。Linux 拥有更好的开发手感和包管理体验。

为了让你更直观地理解,我们可以看下面这张架构交互图:

RTX 3070 GPU ComfyUI 服务 (Windows 宿主机) WSL 网络网关 Python 脚本 (WSL 内部) RTX 3070 GPU ComfyUI 服务 (Windows 宿主机) WSL 网络网关 Python 脚本 (WSL 内部) 1. 解析宿主机 IP (如 192.168.111.x) 2. POST /prompt 提交 JSON 任务 3. 分配显存,加载模型并开始渲染 4. 轮询 GET /history/$prompt_id 获取状态 5. 渲染完成,保存物理图像文件 6. 返回 outputs (包含生成的文件名) 7. GET /view?filename=xxx 下载图片 8. 返回图片二进制流保存到本地

3. ComfyUI 安装与避坑指南

3.1 极简安装步骤

    1. 前往 ComfyUI 的 GitHub Release 页面,下载最新的 Windows 版本安装包。
    1. 成功安装后运行服务:
    • 我的安装路径选在D盘了, 执行程序安装在:
      D:\Users\<换成你的用户名>\AppData\Local\Programs\ComfyUI\resources\ComfyUI
      
    • ComfyUI自动把环境配置在C盘, 路径在:
      C:\Users\<换成你的用户名>\Documents\ComfyUI\
      
    • 在命令行窗口执行
      cd /d D:\Users\<换成你的用户名>\AppData\Local\Programs\ComfyUI\resources\ComfyUI
      C:\Users\<换成你的用户名>\Documents\ComfyUI\.venv\Scripts\python.exe main.py --gpu-only --listen 0.0.0.0
      
    • 其中因为我的宿主机配置了GPU, 所以使用gpu-only;
    • 0.0.0.0代表ComfyUI服务监听所有网络接口的请求。这是因为我的WSL并没有配置Netwoking Mirror, 所以我需要WSL上的代码可以通过宿主机的IP,而不是默认的127.0.0.1来访问ComfyUI服务. 命令行运行ComfyUI服务
    1. 如果运行成功后,使用浏览器访问 http://127.0.0.1:8188,这就是你的控制台。
    1. SD等必要的渲染模型, 需要放在 "C:\Users<换成你的用户名>\Documents\ComfyUI\models\checkpoints"路径下。 模型文件可以在 huggingface上下载,我刚下载的版本sd_xl_base_1.0.safetensors大概6G多。
      配置SDX模型

3.2 踩坑记录一:如何提供后台 API 服务?

很多初学者以为需要复杂的配置才能把 ComfyUI 变成服务。事实上,当你运行 main.py 后,ComfyUI 本身已经是一个标准的、提供 HTTP 完整接口的 API 服务了。
它默认监听在 8188 端口。 当然如果你并不需要通过API来调用,也可以在浏览器上直接操作了。

对于宿主机和WSL之间的通信,我遇到跨端访问的问题。我在 WSL 中无法直接通过 127.0.0.1 访问 Windows 宿主机的8188端口。而我又不想配置WSL的Networking mirror(我的windows和Ubuntu上都有80端口的web服务, mirror的话会导致端口冲突)。
💡 解决办法: 我在windows上通过ipconfig列出了所有的本地IP,然后通过ping命令,找到了WSL上Ubuntu可以访问的IP地址。这样我的Ubuntu就可以使用这个IP来访问Windows上的ComfyUI服务了。

3.3 踩坑记录二:如何建立默认工作流并导出 JSON?

我们要把界面里的连线,变成 Python 能看懂的代码。

    1. 加载默认工作流:点击右侧菜单的 模版,在搜索框中输入 default,你会看到一个包含 “Load Checkpoint - CLIP Text Encode - KSampler - VAE Decode - Save Image”的经典流程。如果你不需要API调用, 你就可以试试修改图形界面的CLIP节点中的提示词, 然后点击“运行”按钮, 看看图片的输出效果了。
      创建简单文生图的工作流
      图形界面文生图的操作
    1. 开启开发者选项:默认情况下,你是找不到“导出为 API”的按钮的。点击右侧面板的图标 ⚙️ (Settings),勾选 Enable Dev mode Options
      配置开发者模式
    1. 导出 JSON:回到主界面,点击右侧的 导出 (API),可以下载一个 workflow_api.json 文件。这个文件就是把工作流框中的节点信息转换成json格式,方便Python调用。
      保存json文件, python代码调用API使用

[!WARNING]
巨坑预警:务必使用 Save Image 节点!
在这里插入图片描述
在调试中我发现,如果你在界面里图方便,使用的是 Preview Image(预览节点)而不是 Save Image(保存节点),导出的 JSON 虽然能提交执行,但它是没有任何物理文件输出的,Python 后续的获取结果会得到一个空的列表 []!务必确保你的最后一棒连接的是标准的保存节点。


4. Python 代码实战:自动化调用的核心逻辑

在搞定了宿主机服务和 API JSON 后,我们要在 WSL 中写一段 Python 代码来自动化这个流程:

  1. 替换 Prompt:读取 JSON 并修改提示词。
  2. 提交任务:发送给 8188 端口。
  3. 轮询状态并下载:等待生图结束,下载并存储到 WSL 目录。

以下是我优化后能够完美处理单图及多图并发任务的 Python 测试脚本:

4.1 调用ComfyUI服务的代码

# -*- coding: utf-8 -*-
import json
import requests
import time
import subprocess
import os

# 1. 获取宿主机 IP (WSL -> Windows 穿透)
def get_host_ip():
    return "127.0.0.1" # 此处务必要替换成你可以访问的宿主机IP !!!!!! 💀💀💀 

COMFY_URL = f"http://{get_host_ip()}:8188"

# 2. 下载图片的协助函数
def download_image(filename):
    print(f"📥 正在下载: {filename} ...")
    url = f"{COMFY_URL}/view?filename={filename}"
    try:
        r = requests.get(url)
        r.raise_for_status()
        local_name = f"output_{int(time.time())}_{filename}"
        with open(local_name, "wb") as f:
            f.write(r.content)
        print(f"✨ 保存成功: {local_name}")
    except Exception as e:
        print(f"❌ 下载失败 {filename}: {e}")

# 3. 主调度函数
def run_task(prompt_text):
    print(f"🚀 初始化并加载 workflow_api.json ...")
    with open("workflow_api.json", "r", encoding="utf-8") as f:
        workflow = json.load(f)

    # 这里的 "6" 对应导出 json 中 正向提示词(CLIPTextEncode) 节点的 ID
    # 如果你的节点 ID 不同,请根据实际 JSON 结构修改
    if "6" in workflow:
        workflow["6"]["inputs"]["text"] = prompt_text

    print(f"📡 发送生图任务到 ComfyUI ({COMFY_URL})...")
    p = requests.post(f"{COMFY_URL}/prompt", json={"prompt": workflow}).json()
    prompt_id = p['prompt_id']
    print(f"✅ 任务已排队,ID: {prompt_id}")

    # 轮询状态处理多图延迟
    while True:
        h = requests.get(f"{COMFY_URL}/history/{prompt_id}").json()
        
        # history 只有在任务彻底完成后才会出现对应的 prompt_id 键
        if prompt_id in h:
            outputs = h[prompt_id].get("outputs", {})
            if not outputs:
                print("⚠️ 任务结束,但没有找到输出!请检查刚才的警告,是否使用了 SaveImage 节点。")
                break
                
            print(f"🎨 渲染完成!发现 {len(outputs)} 个输出节点。")
            for node_id, node_data in outputs.items():
                if "images" in node_data:
                    for img in node_data["images"]:
                        download_image(img['filename'])
            break
        
        print("⏳ 渲染中,由于可能包含多张图片,请耐心等待...")
        time.sleep(2)

if __name__ == "__main__":
    # 测试生成指令
    run_task("a high-tech laboratory, futuristic, blue lighting, photorealistic, 8k")

4.2 核心调试复盘

在这段代码的编写中,我遇到了一个关于**“多张图片并发响应为空”的问题:
一开始跑脚本时,控制台直接抛出了找不到键值的错误。排查发现,生图是一个重资源操作。如果要生成 Batch Size > 1 或者是多图任务,渲染时间会从 5 秒激增到 15 秒以上。
之前因为没有做
轮询(Polling)**等待,请求发出去后直接去拿结果,任务处于 QueuedExecuting 状态,自然拿不到被保存的 outputs
因此,加入一个 while True + time.sleep(2) 的设计是极其必要的。只有当 /history 接口的返回值里包含了当前任务的 ID,才说明执行生命周期彻底结束。
在这里插入图片描述


5. 效果与总结

在跑通这个自动化流水线之后,我一连生成了上百张不同领域的转场和背景图。
生成图片的效果图
通过本次调试我们可以得出:

  1. 大规模应用的必备品:如果你要做自动化的视频流水线、小说推文或者批量插图,一定要放弃按量计费的生图 API,把本地 GPU 利用起来。 ComfyUI 这种 Server-Client 结构堪称完美。
  2. API 的门槛其实很低:无需复杂的编程框架,只需要把可视化连线导出为 JSON,再通过 requests.post 发送字典即可,哪怕是编程新手也能在一天内完成改造。
  3. WSL环境的兼容性佳:事实证明,宿主机(Windows)扛算力、子系统(WSL)跑逻辑这种分层架构不仅不复杂,还能最大化两者的天然优势。

希望这篇博文能帮到由于业务需求被 文生图模型API 费用困扰的朋友们。如果大家感兴趣,下一期我还会讲讲如何在 ComfyUI 内部通过自动化脚本加载不同的 LoRA 模型以及高清放大(Upscale)算法。

欢迎在评论区探讨交流!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐