Appearance
下载原始 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.pngTask 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
基本流程
- 上传参考图片到 ComfyUI 的 input 目录
- 提交 FLUX.2-klein 图生图编辑工作流
- 工作流包含 15 个节点:
LoadImage× 2 — 加载图1(主体)和图2(服装参考)ImageScaleToTotalPixels— 缩放到 1MP 以内GetImageSize— 获取图片尺寸CLIPTextEncode— 提示词编码ConditioningZeroOut— 负向条件置零EmptyFlux2LatentImage— 生成空 latentFlux2Scheduler— 控制步数(4 步)RandomNoise— 随机噪声UNETLoader— 加载 FLUX.2-klein 主模型VAELoader— 加载 VAE 解码器SamplerCustomAdvanced— 高级采样器VAEDecode— VAE 解码 latent → 像素图SaveImage— 保存图片为 PNGReferenceLatent× 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为空对象{}表示工作流校验通过。如有错误会在此列出。
使用前需修改:
| 节点 | 字段 | 修改为 |
|---|---|---|
| 76 | image | 图1文件名(主体人物,已上传) |
| 81 | image | 图2文件名(服装参考,已上传) |
| 135 | text | 你的英文提示词 |
| 94 | filename_prefix | 输出文件名前缀 |
| 125 | noise_seed | 任意整数(不同值生成不同结果) |
节点说明
| 节点 ID | class_type | 功能 |
|---|---|---|
| 76 | LoadImage | 加载图1(主体人物/目标图片) |
| 81 | LoadImage | 加载图2(服装/风格参考图片) |
| 126 | UNETLoader | 加载 FLUX.2-klein-9b-kv-fp8 主模型 |
| 133 | CLIPLoader | 加载 Qwen3-8B CLIP 文本编码器 |
| 127 | VAELoader | 加载 Flux2 VAE 解码器 |
| 130 | ImageScaleToTotalPixels | 图1缩放到 1MP(加速推理) |
| 131 | ImageScaleToTotalPixels | 图2缩放到 1MP(加速推理) |
| 128 | GetImageSize | 获取缩放后的图片尺寸 |
| 135 | CLIPTextEncode | 编辑提示词编码 |
| 685 | ConditioningZeroOut | 负向条件置零 |
| 139 | FluxKVCache | KV Cache 加速(核心加速节点) |
| 137 | Flux2Scheduler | 调度器,控制采样步数(4) |
| 129 | EmptyFlux2LatentImage | 生成空 latent |
| 125 | RandomNoise | 随机噪声种子 |
| 122 | KSamplerSelect | 选择采样器(euler) |
| 138 | CFGGuider | CFG 引导,连接正负向条件 |
| 123 | SamplerCustomAdvanced | 高级采样器(核心生成节点) |
| 124 | VAEDecode | VAE 解码 latent → 像素图 |
| 94 | SaveImage | 保存图片为 PNG |
| 134_116~134_118 | ReferenceLatent + VAEEncode | 图1 Reference Conditioning 子图 |
| 132_119~132_121 | ReferenceLatent + 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)关键参数
| 节点 | 字段 | 说明 | 示例值 |
|---|---|---|---|
| 76 | image | 图1文件名(主体人物) | "person.png" |
| 81 | image | 图2文件名(服装参考) | "outfit.png" |
| 135 | text | 编辑提示词(英文) | "Have the man wear the clothes from Figure 2" |
| 137 | steps | 采样步数 | 4(固定,Flux2Scheduler 内置) |
| 130/131 | megapixels | 缩放上限(MP) | 1.0 |
| 125 | noise_seed | 随机种子 | 720512742793301 |
| 94 | filename_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为空字符串 - 图片输出的
type为output - 下载的是 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 1Route 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 重试 |
模型文件清单
| 类型 | 文件 | 用途 |
|---|---|---|
| UNet | flux-2-klein-9b-kv-fp8.safetensors | 主去噪模型 |
| CLIP | qwen_3_8b_fp8mixed.safetensors | Qwen3-8B 文本编码器 |
| VAE | flux2-vae.safetensors | VAE 解码器 |
技术细节
- FluxKVCache:KV Cache 缓存加速,避免重复计算
- Flux2Scheduler:内置 4 步调度,无需手动设置 steps
- Reference Conditioning:通过 4 个 ReferenceLatent 节点 + 2 个 VAEEncode 子图实现双图参考
- SamplerCustomAdvanced:相比 KSampler 提供更精细的采样控制
- CFG 1.0:Flux 系列模型的推荐 CFG 值
内网直连 vs 公网网关
| 内网直连 | 公网网关 | |
|---|---|---|
| 地址 | 192.168.1.236:8188 | ai.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为空字符串) - [ ] 图片可正常查看且编辑效果符合预期