Skip to content

下载原始 Skill 文件

bash
curl https://ai.ospreyai.cn/docs/raw/skills/comfyui-flux2-edit.md -o comfyui-flux2-edit.md

对话式接入

本 Skill 文件可被 AI 助手(Claude Code、Cursor、ChatGPT 等)学习,通过自然语言对话完成图片编辑。

在 AI 对话中发送以下指令即可:

学习:https://ai.ospreyai.cn/docs/raw/skills/comfyui-flux2-edit.md,保存为本地的技能 skills

更多接入方式和使用示例详见 API 文档 — AI 助手对话式接入


ComfyUI FLUX.2-klein 图生图编辑

Overview

通过公网网关 https://ai.ospreyai.cn 使用 ComfyUI FLUX.2-klein-9b-kv-fp8 模型进行图片编辑,基于 Reference Conditioning 技术实现服装/形象迁移和背景替换。

核心特性:

  • 4 步极速生成:使用 FluxKVCache + Flux2Scheduler 加速,< 1 秒完成
  • 双图参考编辑:图1 提供主体人物/姿势,图2 提供服装/风格参考
  • 单图自我编辑:图1=图2 时可实现局部微调(去外套、改细节)
  • Qwen3-8B CLIP:文本编码更自然,提示词理解更精准

所有 API 均需 Bearer Token 鉴权(Authorization: Bearer sk-xxx)。

Quick Start

bash
export GW="https://ai.ospreyai.cn"
export API_KEY="sk-your-api-key"

# 1. 上传参考图片
curl -s -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/upload" \
  -F "image=@person.png" -F "type=input"

curl -s -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/upload" \
  -F "image=@outfit.png" -F "type=input"

# 2. 提交编辑工作流(完整 JSON 见下方 Route A)
curl -s -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/ai/image/generate" \
  -H "Content-Type: application/json" \
  -d '{"prompt":{...}}'

# 3. 查询任务状态
curl -s -H "Authorization: Bearer $API_KEY" "$GW/api/v1/ai/tasks/{prompt_id}"

# 4. 下载生成的图片
curl -s -H "Authorization: Bearer $API_KEY" \
  "$GW/api/v1/ai/image/view/?filename=Result_00001_.png&type=output&subfolder=" \
  -o result.png

Task Routing

场景动作
首次图片编辑→ Route A: Upload & Generate
需要查看任务是否完成→ Route B: Check Status
需要获取或下载 PNG→ Route C: Download
需要调优提示词或编辑效果→ Route D: Tune Parameters
需要排查服务、节点、模型或文件问题→ Route E: Troubleshoot

Route A: Upload & Generate

服务信息

  • 网关地址: https://ai.ospreyai.cn
  • 上传接口: POST /api/v1/upload
  • 提交接口: POST /api/v1/ai/image/generate
  • 鉴权方式: Authorization: Bearer sk-xxx

基本流程

  1. 上传参考图片到 ComfyUI 的 input 目录
  2. 提交 FLUX.2-klein 图生图编辑工作流
  3. 工作流包含 15 个节点:
    • LoadImage × 2 — 加载图1(主体)和图2(服装参考)
    • ImageScaleToTotalPixels — 缩放到 1MP 以内
    • GetImageSize — 获取图片尺寸
    • CLIPTextEncode — 提示词编码
    • ConditioningZeroOut — 负向条件置零
    • EmptyFlux2LatentImage — 生成空 latent
    • Flux2Scheduler — 控制步数(4 步)
    • RandomNoise — 随机噪声
    • UNETLoader — 加载 FLUX.2-klein 主模型
    • VAELoader — 加载 VAE 解码器
    • SamplerCustomAdvanced — 高级采样器
    • VAEDecode — VAE 解码 latent → 像素图
    • SaveImage — 保存图片为 PNG
    • ReferenceLatent × 4 + VAEEncode × 2 — Reference Conditioning 子图

Step 1: 上传图片

bash
# 上传主体图片(图1)
curl -s -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/upload" \
  -F "image=@/path/to/person.png" \
  -F "type=input"

# 上传服装参考图片(图2)
curl -s -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/upload" \
  -F "image=@/path/to/outfit.png" \
  -F "type=input"

响应:

json
{"name": "person.png", "subfolder": "", "type": "input"}

记住返回的 name 值,工作流中 LoadImage 节点需要使用。type=input 确保上传到 ComfyUI input 目录。

最大文件大小: 50MB。推荐使用 PNG/JPG 格式。

Step 2: 提交编辑工作流

bash
curl -s -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/ai/image/generate" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": {
      "122": {"class_type": "KSamplerSelect", "inputs": {"sampler_name": "euler"}},
      "126": {"class_type": "UNETLoader", "inputs": {"unet_name": "flux-2-klein-9b-kv-fp8.safetensors", "weight_dtype": "default"}},
      "133": {"class_type": "CLIPLoader", "inputs": {"clip_name": "qwen_3_8b_fp8mixed.safetensors", "type": "flux2", "device": "default"}},
      "138": {"class_type": "CFGGuider", "inputs": {"model": ["139", 0], "positive": ["132_121", 0], "negative": ["132_119", 0], "cfg": 1.0}},
      "127": {"class_type": "VAELoader", "inputs": {"vae_name": "flux2-vae.safetensors"}},
      "135": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["133", 0], "text": "Have the man in Figure 1 put on the clothes from Figure 2, keep same posture"}},
      "139": {"class_type": "FluxKVCache", "inputs": {"model": ["126", 0]}},
      "123": {"class_type": "SamplerCustomAdvanced", "inputs": {"noise": ["125", 0], "guider": ["138", 0], "sampler": ["122", 0], "sigmas": ["137", 0], "latent_image": ["129", 0]}},
      "125": {"class_type": "RandomNoise", "inputs": {"noise_seed": 720512742793301}},
      "124": {"class_type": "VAEDecode", "inputs": {"samples": ["123", 0], "vae": ["127", 0]}},
      "94":  {"class_type": "SaveImage", "inputs": {"images": ["124", 0], "filename_prefix": "Result"}},
      "685": {"class_type": "ConditioningZeroOut", "inputs": {"conditioning": ["135", 0]}},
      "137": {"class_type": "Flux2Scheduler", "inputs": {"width": ["128", 0], "height": ["128", 1], "steps": 4}},
      "129": {"class_type": "EmptyFlux2LatentImage", "inputs": {"width": ["128", 0], "height": ["128", 1], "batch_size": 1}},
      "128": {"class_type": "GetImageSize", "inputs": {"image": ["130", 0]}},
      "130": {"class_type": "ImageScaleToTotalPixels", "inputs": {"image": ["76", 0], "upscale_method": "lanczos", "megapixels": 1.0, "resolution_steps": 1}},
      "131": {"class_type": "ImageScaleToTotalPixels", "inputs": {"image": ["81", 0], "upscale_method": "lanczos", "megapixels": 1.0, "resolution_steps": 1}},
      "76": {"class_type": "LoadImage", "inputs": {"image": "person.png"}},
      "81": {"class_type": "LoadImage", "inputs": {"image": "outfit.png"}},
      "134_116": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["685", 0], "latent": ["134_117", 0]}},
      "134_117": {"class_type": "VAEEncode", "inputs": {"pixels": ["130", 0], "vae": ["127", 0]}},
      "134_118": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["135", 0], "latent": ["134_117", 0]}},
      "132_119": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["134_116", 0], "latent": ["132_120", 0]}},
      "132_120": {"class_type": "VAEEncode", "inputs": {"pixels": ["131", 0], "vae": ["127", 0]}},
      "132_121": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["134_118", 0], "latent": ["132_120", 0]}}
    }
  }'

响应:

json
{"prompt_id": "f5a1b2c3-...", "number": 150, "node_errors": {}}

node_errors 为空对象 {} 表示工作流校验通过。如有错误会在此列出。

使用前需修改:

节点字段修改为
76image图1文件名(主体人物,已上传)
81image图2文件名(服装参考,已上传)
135text你的英文提示词
94filename_prefix输出文件名前缀
125noise_seed任意整数(不同值生成不同结果)

节点说明

节点 IDclass_type功能
76LoadImage加载图1(主体人物/目标图片)
81LoadImage加载图2(服装/风格参考图片)
126UNETLoader加载 FLUX.2-klein-9b-kv-fp8 主模型
133CLIPLoader加载 Qwen3-8B CLIP 文本编码器
127VAELoader加载 Flux2 VAE 解码器
130ImageScaleToTotalPixels图1缩放到 1MP(加速推理)
131ImageScaleToTotalPixels图2缩放到 1MP(加速推理)
128GetImageSize获取缩放后的图片尺寸
135CLIPTextEncode编辑提示词编码
685ConditioningZeroOut负向条件置零
139FluxKVCacheKV Cache 加速(核心加速节点)
137Flux2Scheduler调度器,控制采样步数(4)
129EmptyFlux2LatentImage生成空 latent
125RandomNoise随机噪声种子
122KSamplerSelect选择采样器(euler)
138CFGGuiderCFG 引导,连接正负向条件
123SamplerCustomAdvanced高级采样器(核心生成节点)
124VAEDecodeVAE 解码 latent → 像素图
94SaveImage保存图片为 PNG
134_116~134_118ReferenceLatent + VAEEncode图1 Reference Conditioning 子图
132_119~132_121ReferenceLatent + VAEEncode图2 Reference Conditioning 子图

工作流连接图

LoadImage(76) ──→ ImageScale(130) ──→ GetImageSize(128) ──→ EmptyFlux2Latent(129)
                    │                    │
                    └→ VAEEncode(134_117) ──→ RefLatent(134_116/134_118)

CLIPLoader(133) ──→ CLIPTextEncode(135) ──→ ConditioningZeroOut(685) ──→ RefLatent(134_116)
                    │                                                          ↓
                    └→ RefLatent(134_118) ──→ RefLatent(132_121) ──────────→ CFGGuider(138)
                                                  ↑                               ↓
LoadImage(81) ──→ ImageScale(131) ──→ VAEEncode(132_120) ──→ RefLatent(132_119)  │

UNETLoader(126) ──→ FluxKVCache(139) ──→ CFGGuider(138) ──→ SamplerCustomAdv(123)

Flux2Scheduler(137) ──→ SamplerCustomAdv(123)                     │
RandomNoise(125) ──→ SamplerCustomAdv(123)                        │

                                                            VAEDecode(124) ──→ SaveImage(94)
                                                            VAELoader(127) ──→ VAEDecode(124)

关键参数

节点字段说明示例值
76image图1文件名(主体人物)"person.png"
81image图2文件名(服装参考)"outfit.png"
135text编辑提示词(英文)"Have the man wear the clothes from Figure 2"
137steps采样步数4(固定,Flux2Scheduler 内置)
130/131megapixels缩放上限(MP)1.0
125noise_seed随机种子720512742793301
94filename_prefix输出文件名前缀"Result"

输出图片参数

  • 分辨率: 与输入图片一致(缩放至 ≤1MP)
  • 格式: PNG
  • 输出路径: subfolder=""(空字符串), type=output

Route B: Check Status

查询队列

bash
curl -s -H "Authorization: Bearer $API_KEY" "$GW/api/v1/ai/queue"

响应:

json
{
  "queue_running": [[150, "f5a1b2c3-...", {...}]],
  "queue_pending": []
}
  • queue_running 不为空 → 任务正在执行
  • queue_pending 不为空 → 任务排队等待

查询任务状态

bash
curl -s -H "Authorization: Bearer $API_KEY" "$GW/api/v1/ai/tasks/{prompt_id}"

进行中:

json
{
  "f5a1b2c3-...": {
    "status": {"status_str": "success", "completed": false},
    "outputs": {}
  }
}

已完成:

json
{
  "f5a1b2c3-...": {
    "status": {"status_str": "success", "completed": true},
    "outputs": {
      "94": {
        "images": [
          {"filename": "Result_00001_.png", "subfolder": "", "type": "output"}
        ]
      }
    }
  }
}

FLUX.2-klein 4 步生成极快(< 1 秒),通常提交后立即完成。

Route C: Download

下载前先从任务状态中获取输出文件信息(filename, subfolder, type),然后通过查看接口下载。

bash
# 下载 PNG 图片(注意 subfolder 为空字符串)
curl -s -H "Authorization: Bearer $API_KEY" \
  "$GW/api/v1/ai/image/view/?filename=Result_00001_.png&type=output&subfolder=" \
  -o result.png

关键点:

  • 图片输出的 subfolder 为空字符串
  • 图片输出的 typeoutput
  • 下载的是 PNG 格式,可直接查看

Python 调用示例

python
import requests
import time
import os

GW = os.getenv("GW", "https://ai.ospreyai.cn")
API_KEY = os.getenv("API_KEY", "")
headers = {"Authorization": f"Bearer {API_KEY}"}

# 1. 上传图片
def upload(path):
    with open(path, "rb") as f:
        resp = requests.post(f"{GW}/api/v1/upload", headers=headers,
                             files={"image": f}, data={"type": "input"})
        return resp.json()["name"]

img1 = upload("person.png")
img2 = upload("outfit.png")
print(f"Uploaded: {img1}, {img2}")

# 2. 提交编辑工作流(prompt 同上方 curl 示例,替换 76/81 的 image 和 135 的 text)
prompt = {
    "prompt": {
        # ... 完整工作流 JSON
    }
}
resp = requests.post(f"{GW}/api/v1/ai/image/generate", headers=headers, json=prompt)
prompt_id = resp.json()["prompt_id"]
print(f"Task submitted: {prompt_id}")

# 3. 轮询任务状态
while True:
    resp = requests.get(f"{GW}/api/v1/ai/tasks/{prompt_id}", headers=headers)
    data = resp.json()
    task = data.get(prompt_id, {})
    if task.get("status", {}).get("completed"):
        print("Task completed!")
        break
    time.sleep(2)

# 4. 下载图片
outputs = task.get("outputs", {}).get("94", {})
image_info = outputs.get("images", [{}])[0]
resp = requests.get(f"{GW}/api/v1/ai/image/view/", headers=headers,
                    params={"filename": image_info["filename"],
                            "subfolder": image_info.get("subfolder", ""),
                            "type": image_info.get("type", "output")})
with open("result.png", "wb") as f:
    f.write(resp.content)
print(f"Downloaded: result.png ({len(resp.content)} bytes)")

Route D: Tune Parameters

参数节点建议
提示词135 text英文效果更稳定;用 Figure 1/Figure 2 指代两张图片
缩放分辨率130/131 megapixels默认 1.0MP;增大可提高画质但显存占用更高
随机种子125 noise_seed不同值生成不同结果;相同种子可复现
采样步数137 steps默认 4 步,由 Flux2Scheduler 内置;不建议修改
CFG 强度138 cfg默认 1.0,Flux 系列推荐保持为 1.0
输出前缀94 filename_prefix自定义输出文件名前缀

提示词技巧

Reference Conditioning 用 Figure 1/Figure 2 指代两张图:

换装:

text
Have the man in Figure 1 put on the clothes from Figure 2, keep same posture

改背景:

text
Change the background of Figure 1 to African savannah at sunset, keep person unchanged

局部修改(单图自我参考,图1=图2):

text
Remove the outer jacket from the person in Figure 1, keep inner clothing and background unchanged

添加元素:

text
Add a red scarf to the person in Figure 1, keep everything else identical

风格迁移:

text
Apply the artistic style from Figure 2 to the image in Figure 1

Route E: Troubleshoot

问题排查方法
上传图片失败检查文件大小(≤50MB)、格式(推荐 PNG/JPG)、Bearer Token 是否有效
工作流提交报 value_not_in_list模型文件名不正确,检查 UNet/CLIP/VAE 名称是否与服务器一致
工作流提交报 return_type_mismatch节点间连接类型不匹配,检查节点输出→输入的链接是否正确
node_errors 非空图片文件未上传成功,检查 LoadImage 的 image 值是否与 upload 返回值一致
生成结果与原图完全一样提示词没被应用,检查 135 text 是否有效英文描述
生成结果异常/乱码检查 type=input 是否在 upload 时正确设置
401 鉴权失败检查 Bearer Token 是否有效:curl -H "Authorization: Bearer sk-xxx" $GW/api/v1/ai/queue
429 请求被限流AI 接口 10次/分/IP,稍后重试
503 后端服务不可用检查内网 ComfyUI 服务是否运行
图片质量不理想使用英文提示词;确保参考图清晰度足够;更换 noise_seed 重试

模型文件清单

类型文件用途
UNetflux-2-klein-9b-kv-fp8.safetensors主去噪模型
CLIPqwen_3_8b_fp8mixed.safetensorsQwen3-8B 文本编码器
VAEflux2-vae.safetensorsVAE 解码器

技术细节

  • FluxKVCache:KV Cache 缓存加速,避免重复计算
  • Flux2Scheduler:内置 4 步调度,无需手动设置 steps
  • Reference Conditioning:通过 4 个 ReferenceLatent 节点 + 2 个 VAEEncode 子图实现双图参考
  • SamplerCustomAdvanced:相比 KSampler 提供更精细的采样控制
  • CFG 1.0:Flux 系列模型的推荐 CFG 值

内网直连 vs 公网网关

内网直连公网网关
地址192.168.1.236:8188ai.ospreyai.cn
鉴权Authorization: Bearer sk-xxx
上传路径/upload/image/api/v1/upload
提交路径/prompt/api/v1/ai/image/generate
任务查询/history/{id}/api/v1/ai/tasks/{id}
队列查询/queue/api/v1/ai/queue
下载路径/view?filename=.../api/v1/ai/image/view/?filename=...&type=output&subfolder=
限流10次/分/IP

Verification Checklist

  • [ ] 参考图片上传成功,返回 name
  • [ ] 工作流提交成功,node_errors 为空
  • [ ] 任务在 /api/v1/ai/queue 中执行完成(通常 < 1 秒)
  • [ ] 任务状态 completed: true,outputs 包含 PNG 文件信息
  • [ ] 成功下载 PNG 文件(注意 subfolder 为空字符串)
  • [ ] 图片可正常查看且编辑效果符合预期

AI API Gateway Documentation