在 ComfyUI 界面里点一次"生成",整套流程你是看得见的:改提示词、点队列、等进度条、右键另存。可一旦要跑二十组参数,或者想让脚本、编程智能体替你按批次出图,这套动作就变成了负担——重复点击、手动改值、手抄文件名,忙的不是生成,是人。Comfy CLI 解决的正是这个落差:把"装环境、起服务"放到终端里,再用 ComfyUI 自带的 HTTP 接口把工作流真正跑起来、把文件取回本地。

准备:让 comfy-cli 把环境和服务管起来
comfy-cli 是 ComfyUI 官方维护的命令行管理工具,能安装、启动、更新 ComfyUI,也能管理自定义节点和模型。装它只需要一条命令:
pip install comfy-cli
# 或使用隔离环境,避免污染系统 Python
pipx install comfy-cli
装好后先确认命令可用,再让它把 ComfyUI 本体装好并启动:
comfy --help
comfy install
comfy launch
comfy install 负责下载 ComfyUI 代码与依赖,comfy launch 把服务跑起来,本机默认监听 127.0.0.1:8188。注意 ComfyUI 本身不带模型,checkpoint、LoRA、VAE 需要你按目录放好,否则工作流能提交、却会在执行阶段报"找不到模型"。
这一步的边界要说清楚:comfy-cli 的强项是环境生命周期管理。真正要"提交工作流、拿回结果",最稳妥、跨本机与云端都通用的方式,是走 ComfyUI 的 HTTP 接口。
把界面里的工作流导出成 API 格式
这是新手最容易踩的坑。你在界面里"保存"得到的是 UI 格式 JSON,里面有 nodes、links 这些给前端渲染用的结构;接口要的是 API 格式 JSON,结构是"节点 ID → 输入参数"的字典。在 ComfyUI 里用"导出(API)"保存,文件名建议就叫 workflow_api.json。
两者提交给接口的结果完全不同:UI 格式基本会被拒绝,或者返回一个读不懂的错误。

想改参数,不用回到界面:直接在 JSON 里按节点 ID 定位。比如第 3 号节点是 KSampler,改 inputs.seed;第 6 号节点是正向 CLIPTextEncode,改 inputs.text。批量出图时,这比在界面里来回点要快得多。
提交任务、等待完成、取回文件
整个交互只有三步:提交拿到 ID、轮询历史记录、按返回的文件信息下载。下面这段脚本可以直接复制修改——把 HOST 换成你的地址,云端则换成对应端点并带上密钥。
import json, time, os, urllib.request, urllib.parse
HOST = "http://127.0.0.1:8188"
OUT = "./outputs"
os.makedirs(OUT, exist_ok=True)
with open("workflow_api.json", encoding="utf-8") as f:
wf = json.load(f)
# 1. 提交
req = urllib.request.Request(
f"{HOST}/prompt",
data=json.dumps({"prompt": wf}).encode(),
headers={"Content-Type": "application/json"},
)
prompt_id = json.loads(urllib.request.urlopen(req).read())["prompt_id"]
print("prompt_id:", prompt_id)
# 2. 等待完成:轮询 /history,直到该 ID 出现
while True:
with urllib.request.urlopen(f"{HOST}/history/{prompt_id}") as r:
hist = json.loads(r.read())
if prompt_id in hist:
break
time.sleep(2)
# 3. 取回:遍历 outputs,按 images 里的 filename/subfolder/type 下载
for node_id, out in hist[prompt_id]["outputs"].items():
for img in out.get("images", []):
q = urllib.parse.urlencode({
"filename": img["filename"],
"subfolder": img.get("subfolder", ""),
"type": img.get("type", "output"),
})
data = urllib.request.urlopen(f"{HOST}/view?{q}").read()
with open(os.path.join(OUT, img["filename"]), "wb") as f:
f.write(data)
print("saved:", img["filename"])
关键点有三个:/prompt 返回的 prompt_id 是后续查询的唯一凭据;/history/{prompt_id} 里出现该键,就代表这次任务已经有结果;下载时 type 不要自己猜,接口返回什么就原样传什么,否则会拿到空文件或 404。
云端还是本机:先划清边界
两条路走的是同一套接口形状,差别在资源和依赖。
| 维度 | 本机运行 | 云端运行 |
|---|---|---|
| 环境准备 | comfy-cli 装 ComfyUI 与依赖 | 无需本地显卡,需 API 密钥 |
| 模型与节点 | 目录和自定义节点自己维护,自由度高 | 受平台预置支持范围限制 |
| 成本构成 | 硬件投入与电费 | 按积分或额度计费 |
| 适合场景 | 大批量、私有模型、需要固定环境 | 机器不够、偶发出图、快速验证 |
云端需要 API 密钥,且积分规则与模型、节点支持情况会变动,动手前请以 Comfy 官方文档的当期说明为准。一个实用策略是:先在云端把工作流跑通、确认参数,再迁到本机做批量生产。

跑不通时,先查这几处
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
| 提交返回 400 | 工作流是 UI 格式 | 重新用"导出(API)"保存 |
| 401 / 403 | 缺少或密钥错误 | 云端请求头补上正确密钥 |
| 执行报找不到模型或节点 | 模型未放入对应目录、自定义节点未安装 | 补齐文件后重启服务 |
| 一直排队不结束 | 服务已退出或显存不足 | 查看启动日志,降低分辨率或批量 |
| 下载到空文件或 404 | type 参数填错 | 按返回的 type 原样请求 |
怎么算跑通了
一次成功的判断标准很直接:终端打印出 prompt_id,随后在 ./outputs 里出现带时间戳或随机后缀的图片文件,且能在本地正常打开。到这一步,你就有了把生成任务接进脚本和自动化流程的最小闭环。
下一步可以做的调整:把提示词和种子抽成外部配置文件批量替换,用 WebSocket 订阅进度而不是轮询,或者把下载目录改成按任务 ID 分文件夹——这些都不需要改动工作流本身。

评论列表 (1条):
加载更多评论 Loading...