图像编辑
按提示词修改输入的图片,或以一张、多张图片为参考生成新图。兼容 OpenAI Images API 的 images.edit,请求体有两种写法:multipart/form-data 上传图片文件(OpenAI 官方 SDK 的写法),或 JSON 把图片以 Base64 放在请求体里(LYRouter 的扩展)。支持编辑的是 GPT-Image 和 Gemini Image 两个系列,两种写法都可用;Seedream 不支持本接口,它的图生图请用图像生成的 image 参数。
/v1/images/edits鉴权
在请求头中携带 API Key:
Authorization: Bearer <API Key>
Bearer 区分大小写。也可以改用 x-api-key: <API Key>,两者同时存在时只读 Authorization。API Key 在工作空间的 API 密钥 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见接入地址与鉴权。
请求头
| 请求头 | 必填 | 说明 |
|---|---|---|
Content-Type |
是 | multipart/form-data; boundary=... 或 application/json。multipart 的 boundary 由 curl -F 或 SDK 自动生成,自己拼请求时不要只写 multipart/form-data |
X-Gateway-Strict-Parameters |
否 | 设为 true(只认小写)时,请求中有会被网关丢弃的参数就直接返回 400 unsupported_parameters,不调用上游、不计费。编辑接口上只有 Gemini 会丢弃参数,GPT-Image 的参数全部原样转发,不受这个请求头影响 |
请求体
两种写法的字段名相同,GPT-Image 和 Gemini 都支持,按调用方便选择即可。
multipart/form-data
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
model |
string | 是 | 模型 ID,例如 openai/gpt-image-2。只能写具体的模型 ID:虚拟模型 @vmodel/<名称> 和 lyrouter/auto 返回 403 |
image |
file | 是 | 待编辑的图片文件。Gemini 上重复多个 image 字段即传入多张图,按出现顺序使用 |
prompt |
string | 是 | 编辑指令 |
mask |
file | 否 | 遮罩图,GPT-Image 使用;Gemini 会丢弃 |
quality |
string | 见说明 | GPT-Image 使用,gpt-image-2 必填;Gemini 会丢弃 |
n |
integer | 否 | 生成张数,GPT-Image 使用(最大 10);Gemini 会丢弃 |
size |
string | 否 | 输出尺寸,写法见各模型小节 |
- GPT-Image:网关只改写
model字段,文件和其他字段一个字节都不动,原样发给上游。 - Gemini:网关解析表单,把文件转成 Base64(格式取自文件段的
Content-Type,没有时按文件头识别),再按 JSON 写法转换。所有文件合计不能超过 30 MB,超过返回 400。
JSON
OpenAI 官方的 /images/edits 只收 multipart,JSON 写法是 LYRouter 的扩展,图片以 Base64 放在 image 中。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model |
string | 是 | 模型 ID,同上 |
prompt |
string | 是 | 编辑指令,不能为空 |
image |
string | array | 是 | 一张或多张输入图,写成 data:image/png;base64,<数据>,多张时传数组。Gemini 也接受不带前缀的 Base64,见下文 |
quality、n、size 等 |
— | 否 | 与 multipart 写法相同,见各模型小节 |
各模型的处理方式
| 模型系列 | 模型 ID | 处理方式 | 网关丢弃的参数 |
|---|---|---|---|
| GPT-Image | openai/gpt-image-2openai/gpt-image-2.5-flareopenai/gpt-image-2.5-sunburst |
透传 | 无,全部原样转发 |
| Gemini Image | google/gemini-3-pro-imagegoogle/gemini-3.1-flash-image |
契约转换 | 除 model、prompt、image、size 外的全部参数;size 无法匹配时也会丢弃 |
被丢弃的参数列在响应头 X-Gateway-Unsupported-Parameters 中,请求照常执行;带 X-Gateway-Strict-Parameters: true 时改为返回 400。模型的能力对比和使用场景见多模态能力。
GPT-Image(2 / 2.5-flare / 2.5-sunburst)
透传:请求体原样发给上游,只改写模型名,参数与 OpenAI 图像 API 一致,固定返回 b64_json。
| 参数 | 类型 | 说明 |
|---|---|---|
quality |
string | 取值逐模型不同:gpt-image-2 为 low、medium、high、auto(auto 实测等同 low),必填,不传会间歇性返回 400(INVALID_REQUEST_BODY);2.5 系列为 low、medium、high、xhigh、max、auto,默认 low,xhigh、max 可能被上游拒绝(收到 Invalid value: 'xhigh' 时改用 high)。详见图像生成 |
size |
string | 只接受 宽x高,不接受档位名;须满足四条硬约束:宽高都能被 16 整除、最长边不超过 3840、总像素在约 100 万到约 830 万之间,见图像生成。不传时输出尺寸由上游决定:实测 gpt-image-2 输入 1024×1024 的图时输出 1254x1254(不能被 16 整除,在生成接口主动请求这个尺寸会被拒),gpt-image-2.5-flare 输入 1536×1024 的图时输出 1024x1024。需要固定尺寸时请显式传 size |
mask |
file | 遮罩图,multipart 写法上传 |
n、background、output_format、moderation、user |
— | 与图像生成相同 |
response_format、stream |
— | 不要传。编辑接口上网关不丢弃它们:response_format 原样转发给上游,这个系列固定返回 b64_json;stream 为 true 时网关目前会自行补上 stream_options,上游返回 400 Unknown parameter: 'stream_options'. |
- 耗时:两种写法在网关侧的开销相同(约 0.1 秒),耗时几乎全在上游,单次从 20 秒到 4 分钟以上不等,同样的请求两次耗时也可能差好几倍。客户端超时请设为不低于 300 秒。
- 图片校验:上游会校验图片本身,过小或损坏的图片会被拒绝(例如返回
Invalid image file or mode),请换一张正常的图片重试。
计费:与图像生成相同,按 Token 计,输入文本、输入图片、输出分别计价。编辑比生成多一项输入图片的费用:图片按 32×32 像素一块折算成 Token,记在 usage.input_tokens_details.image_tokens:长边不足 1024 时先放大到长边的 2 倍(最多 1024),像素超过约 152 万时先等比缩小,再按 ceil(宽/32) × ceil(高/32) 计。实测 1024×1024 的图为 1024 Token,8×8 的图为 1 Token。mask 也按同样的规则计入 image_tokens:实测 1024×1024 的原图加同尺寸的 mask,image_tokens 为 2048。同样的 quality 和 size 下,编辑与生成的输出 Token 相同;输出 Token 随 quality 的量级差异见图像生成。
Gemini Image(3 Pro / 3.1 Flash)
契约转换:网关把请求翻译成 Gemini 原生的 generateContent 格式,只使用下表中生效的参数,其余参数丢弃并在响应头中列出。固定返回 b64_json。
| 参数 | 是否生效 | 说明 |
|---|---|---|
prompt |
生效 | 必填,不写或为空返回 400 prompt is required for this model |
image |
生效 | 一张或多张。JSON 写法中,带 data:<格式>;base64, 前缀时使用其中声明的格式;不带前缀时按 PNG、JPEG、WEBP、GIF 的文件头识别;都无法识别时返回 400 并指明第几张图。不接受图片 URL |
size |
生效 | 与图像生成相同:档位名(1K、2K、4K)控制分辨率,512 档在生产环境被服务商拒绝,不要使用;宽x高 匹配宽高比并按长边取档,比例偏差超过 2% 时整个 size 被丢弃、请求仍返回 200 并计费。各档输出 Token 两个模型不同,见图像生成 |
n、quality、mask、response_format、user 等 |
丢弃 | — |
- multipart 写法中,所有文件合计不超过 30 MB。OpenAI 官方 SDK 的
images.edit()总是以 multipart 发送,可以直接用来调用 Gemini。
计费:按 Token 计,输入、输出、思考三项分别计价,输入图片并入「输入」(usage.input_tokens),每张输入图按固定 Token 数计,与图片尺寸无关:生产实测 gemini-3-pro-image 每张 560,gemini-3.1-flash-image 每张 1120,两者相差一倍。思考 Token 的说明见图像生成。
请求示例
multipart/form-data
以 openai/gpt-image-2 为例,上传 cat.png 并把结果保存为文件。Python 示例需要较新版本的 openai SDK:实测 1.58.1 的 images.edit() 不接受 quality,会报 TypeError: edit() got an unexpected keyword argument 'quality'。
curl https://api.lyrouter.com/v1/images/edits \
--max-time 300 \
-H "Authorization: Bearer $LYROUTER_API_KEY" \
-F model=openai/gpt-image-2 \
-F quality=medium \
-F image=@cat.png \
-F prompt="把背景换成雪山"
import base64
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["LYROUTER_API_KEY"],
base_url="https://api.lyrouter.com/v1",
timeout=300,
)
with open("cat.png", "rb") as image:
result = client.images.edit(
model="openai/gpt-image-2",
image=image,
prompt="把背景换成雪山",
quality="medium",
)
with open("cat-snow.png", "wb") as f:
f.write(base64.b64decode(result.data[0].b64_json))
print(result.usage)
import { createReadStream, writeFileSync } from "node:fs";
import OpenAI, { toFile } from "openai";
const client = new OpenAI({
apiKey: process.env.LYROUTER_API_KEY,
baseURL: "https://api.lyrouter.com/v1",
timeout: 300_000,
});
const result = await client.images.edit({
model: "openai/gpt-image-2",
// 用 toFile 指明图片类型:直接传 createReadStream 时文件段的类型是 application/octet-stream,上游返回 400
image: await toFile(createReadStream("cat.png"), "cat.png", { type: "image/png" }),
prompt: "把背景换成雪山",
quality: "medium",
});
writeFileSync("cat-snow.png", Buffer.from(result.data[0].b64_json, "base64"));
console.log(result.usage);
JSON
以 google/gemini-3-pro-image 为例,把图片转成 Base64 放进请求体:
printf '{"model":"google/gemini-3-pro-image","prompt":"把背景换成雪山","image":"data:image/png;base64,%s"}' \
"$(base64 < cat.png | tr -d '\n')" > body.json
curl https://api.lyrouter.com/v1/images/edits \
--max-time 300 \
-H "Authorization: Bearer $LYROUTER_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @body.json
import base64
import os
import httpx
with open("cat.png", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
resp = httpx.post(
"https://api.lyrouter.com/v1/images/edits",
headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"},
json={
"model": "google/gemini-3-pro-image",
"prompt": "把背景换成雪山",
"image": f"data:image/png;base64,{b64}", # 多张图时传数组
},
timeout=300,
)
resp.raise_for_status()
with open("cat-snow.png", "wb") as f:
f.write(base64.b64decode(resp.json()["data"][0]["b64_json"]))
import { readFileSync, writeFileSync } from "node:fs";
const b64 = readFileSync("cat.png").toString("base64");
const resp = await fetch("https://api.lyrouter.com/v1/images/edits", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "google/gemini-3-pro-image",
prompt: "把背景换成雪山",
image: `data:image/png;base64,${b64}`, // 多张图时传数组
}),
signal: AbortSignal.timeout(300_000),
});
const result = await resp.json();
if (!resp.ok) throw new Error(JSON.stringify(result.error));
writeFileSync("cat-snow.png", Buffer.from(result.data[0].b64_json, "base64"));
响应
响应格式与图像生成相同:成功时图片在顶层 data 数组中,以 b64_json 返回;出错时返回 error 对象。下面的 200 是 GPT-Image 的编辑结果(上文 multipart 示例,未传 size),400 是开启严格模式时给 Gemini 传了它不支持的 quality,403 是模型未开通,或使用了虚拟模型、Auto。
{
"created": 1791950400,
"data": [
{ "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…" }
],
"size": "1254x1254",
"quality": "medium",
"output_format": "png",
"background": "opaque",
"usage": {
"input_tokens": 1036,
"input_tokens_details": { "text_tokens": 12, "image_tokens": 1024 },
"output_tokens": 2058,
"total_tokens": 3094
}
}
{
"error": {
"message": "unsupported parameters for this model: quality",
"type": "invalid_request_error",
"code": "unsupported_parameters"
}
}
{
"error": {
"message": "Model is not available in the model plaza",
"type": "access_denied",
"code": "model_not_available"
}
}
| 字段 | 说明 |
|---|---|
created |
Unix 时间戳(秒)。Gemini 不返回这个字段 |
data |
产物数组,只生成一张时也是数组 |
data[].b64_json |
Base64 编码的图片 |
size、quality、output_format、background |
本次实际使用的生成参数(GPT-Image 返回) |
usage |
计量信息。GPT-Image 在 input_tokens_details 中分开报文字与图片 Token;Gemini 的输入图片计入 input_tokens,有思考 Token 时另有 output_tokens_details.reasoning_tokens。各字段见图像生成 |
单价以控制台模型广场为准,每次调用的实际扣费在请求日志中查看。
响应头
| 响应头 | 说明 |
|---|---|
X-Gateway-Unsupported-Parameters |
网关丢弃了参数时出现(只会发生在 Gemini 上),值为逗号分隔的参数名,例如 n,quality。请求照常执行,列出的参数没有生效 |
配置了配额时,响应还会带 x-aigw-quota-* 系列响应头,见网关扩展请求头与响应头。
网关行为
与直接调用上游相比,经 LYRouter 调用有以下差别:
- 两种请求体:GPT-Image 的 multipart 请求只改写
model字段,文件原样转发;JSON 请求原样转发。Gemini 的两种写法都先归一成同一组字段,再翻译成 Gemini 的格式,因此行为完全相同。 - 只用指定的模型:图像接口不会改用其他模型。同一模型有多个通道时,失败后依次尝试其他通道;虚拟模型、Auto 智能路由和工作空间默认模型的回退都不用于图像接口,见失败重试与备用模型。
- 丢弃参数与严格模式:只有 Gemini 会丢弃参数,并在响应头
X-Gateway-Unsupported-Parameters中列出;带X-Gateway-Strict-Parameters: true时改为直接返回 400、不调用上游、不计费。GPT-Image 的参数全部原样转发,是否被接受由上游判断。 - 上游在成功响应里声明错误:Gemini 的上游拒绝请求时可能返回 HTTP 200 而没有图片。网关把它改写成错误响应:上游拒绝时
error.code为upstream_rejected,error.message是上游原文;没有产出图片时为upstream_no_artifact,并带upstream_finish_reason(如NO_IMAGE、SAFETY)。upstream_status保留上游原本的 200。这类错误不换通道重试,请按提示修改提示词或图片。 - 上游错误原样返回:GPT-Image 的参数和图片错误由上游返回,格式和错误码以上游为准。上游返回错误状态却没有响应体时,网关补一个错误体,带
upstream_status和generated_by: "ai-gateway";上游提供了请求 ID 时还带upstream_request_id,向服务商报障时提供它。 - 日志中不保存图片:请求和响应中的 Base64 图片在日志里替换成
[base64 <字节数>B #<CRC32>]摘要,日志详情里看不到图片不代表请求失败,图片在响应体里。 - 超时:编辑同样是同步返回,GPT-Image 系列常需数分钟。客户端超时请设为不低于 300 秒;客户端超时后不要立即重复提交,先在请求日志中确认上一次请求的结果。
常见错误
网关返回的错误为 {"error":{"message":"...","type":"...","code":"..."}};GPT-Image 的参数错误由上游返回,格式以上游为准。
| 状态码 | error.message |
error.code |
原因与处理 |
|---|---|---|---|
| 400 | unsupported parameters for this model: <参数名> |
unsupported_parameters |
带了 X-Gateway-Strict-Parameters: true,且给 Gemini 传了它不支持的参数。删掉列出的参数 |
| 400 | prompt is required for this model |
invalid_parameter |
调用 Gemini 时没有写 prompt 或为空 |
| 400 | image[<序号>]: cannot determine the image MIME type; send a data URI such as `data:image/png;base64,<payload>` |
invalid_parameter |
Gemini 认不出第几张图的格式,例如传了图片 URL。改写成 data URI |
| 400 | inline file parts exceed the limit of 31457280 bytes |
invalid_parameter |
调用 Gemini 时 multipart 中的文件合计超过 30 MB。压缩图片后重试 |
| 400 | you must provide a model parameter |
missing_model |
没有写 model(multipart 写法缺少 model 字段同样如此),工作空间也没有默认模型。图像接口请总是写明模型 ID |
| 400 | This model does not support the images_edits operation |
unsupported_model_operation |
所选模型不支持图像编辑。换用 GPT-Image 或 Gemini;Seedream 的图生图请用图像生成 |
| 400 | This model does not support the images API |
unsupported_model_api |
模型声明的接口类型(列出模型中的 api_types)不含图像接口,例如用对话模型调用本接口。没有声明 api_types 的对话模型不会触发这条,请求会转发给上游,可能返回 404 upstream_not_found 等上游错误。图像接口请只用图像模型 |
| 400 | 上游原文,例如 Request contains an invalid argument. |
upstream_rejected |
Gemini 的上游拒绝了请求,按原文修改参数或图片 |
| 400 | upstream produced no image (finishReason: <原因>) |
upstream_no_artifact |
Gemini 没有产出图片,按 upstream_finish_reason 修改提示词或图片后重试 |
| 400 | 上游原文,例如 Invalid size '<宽>x<高>'. Width and height must both be divisible by 16.、Invalid size '<宽>x<高>'. Requested resolution is below the current minimum pixel budget. |
— | GPT-Image 的 size 不满足四条硬约束之一,按图像生成中的约束表调整 |
| 400 | 上游原文 | INVALID_REQUEST_BODY |
GPT-Image 请求体不合法,先检查是否传了 quality:gpt-image-2 不传会间歇性返回 400 |
| 403 | Model is not available in the model plaza |
model_not_available |
工作空间没有开通这个模型,或者写了 @vmodel/<名称>、lyrouter/auto。请管理员在模型广场开通,或改写已开通的具体模型 ID |
- 401 / 403 鉴权问题见401 / 403:鉴权与权限,429 见429:限流与配额。
- 500 / 504 是连接上游失败或等待上游超时,响应体是 HTML 页面而不是 JSON,见超时与流式中断。
- 完整列表见错误码与请求标识。