# 图像编辑

来源: https://platform.lyrouter.com/ai_gateway/docs/images-edits
更新日期: 2026-10-19

按提示词修改输入的图片，或以一张、多张图片为参考生成新图。兼容 OpenAI Images API 的 `images.edit`，请求体有两种写法：`multipart/form-data` 上传图片文件（OpenAI 官方 SDK 的写法），或 JSON 把图片以 Base64 放在请求体里（LYRouter 的扩展）。支持编辑的是 GPT-Image 和 Gemini Image 两个系列，两种写法都可用；Seedream 不支持本接口，它的图生图请用[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations)的 `image` 参数。

`POST /v1/images/edits`

## 鉴权

在请求头中携带 API Key：

```text
Authorization: Bearer <API Key>
```

`Bearer` 区分大小写。也可以改用 `x-api-key: <API Key>`，两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建，只用于 LYRouter 鉴权，不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。

## 请求头

| 请求头 | 必填 | 说明 |
| --- | --- | --- |
| `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-2`<br>`openai/gpt-image-2.5-flare`<br>`openai/gpt-image-2.5-sunburst` | 透传 | 无，全部原样转发 |
| Gemini Image | `google/gemini-3-pro-image`<br>`google/gemini-3.1-flash-image` | 契约转换 | 除 `model`、`prompt`、`image`、`size` 外的全部参数；`size` 无法匹配时也会丢弃 |

被丢弃的参数列在响应头 `X-Gateway-Unsupported-Parameters` 中，请求照常执行；带 `X-Gateway-Strict-Parameters: true` 时改为返回 400。模型的能力对比和使用场景见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。

### 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`）。详见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst) |
| `size` | string | 只接受 `宽x高`，不接受档位名；须满足四条硬约束：宽高都能被 16 整除、最长边不超过 3840、总像素在约 100 万到约 830 万之间，见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)。不传时输出尺寸由上游决定：实测 `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` | — | 与[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)相同 |
| `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` 的量级差异见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)。

### 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 两个模型不同，见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gemini-image-3-pro-3-1-flash) |
| `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 的说明见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gemini-image-3-pro-3-1-flash)。

## 请求示例

### 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'`。

**请求示例（multipart）**

cURL:
```bash
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="把背景换成雪山"
```

Python:
```python
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)
```

Node.js:
```js
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 放进请求体：

**请求示例（JSON）**

cURL:
```bash
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
```

Python:
```python
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"]))
```

Node.js:
```js
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"));
```

## 响应

响应格式与[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations)相同：成功时图片在顶层 `data` 数组中，以 `b64_json` 返回；出错时返回 `error` 对象。下面的 200 是 GPT-Image 的编辑结果（上文 multipart 示例，未传 `size`），400 是开启严格模式时给 Gemini 传了它不支持的 `quality`，403 是模型未开通，或使用了虚拟模型、Auto。

**响应示例**

200:
```json
{
  "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
  }
}
```

400:
```json
{
  "error": {
    "message": "unsupported parameters for this model: quality",
    "type": "invalid_request_error",
    "code": "unsupported_parameters"
  }
}
```

403:
```json
{
  "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`。各字段见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations) |

单价以控制台模型广场为准，每次调用的实际扣费在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看。

### 响应头

| 响应头 | 说明 |
| --- | --- |
| `X-Gateway-Unsupported-Parameters` | 网关丢弃了参数时出现（只会发生在 Gemini 上），值为逗号分隔的参数名，例如 `n,quality`。请求照常执行，列出的参数没有生效 |

配置了配额时，响应还会带 `x-aigw-quota-*` 系列响应头，见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。

## 网关行为

与直接调用上游相比，经 LYRouter 调用有以下差别：

- **两种请求体**：GPT-Image 的 multipart 请求只改写 `model` 字段，文件原样转发；JSON 请求原样转发。Gemini 的两种写法都先归一成同一组字段，再翻译成 Gemini 的格式，因此行为完全相同。
- **只用指定的模型**：图像接口不会改用其他模型。同一模型有多个通道时，失败后依次尝试其他通道；虚拟模型、Auto 智能路由和工作空间默认模型的回退都不用于图像接口，见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。
- **丢弃参数与严格模式**：只有 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 秒；客户端超时后不要立即重复提交，先在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中确认上一次请求的结果。

## 常见错误

网关返回的错误为 `{"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 的图生图请用[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations) |
| 400 | `This model does not support the images API` | `unsupported_model_api` | 模型声明的接口类型（[列出模型](https://platform.lyrouter.com/ai_gateway/docs/models)中的 `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` 不满足四条硬约束之一，按[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)中的约束表调整 |
| 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：鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)，429 见[429：限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。
- 500 / 504 是连接上游失败或等待上游超时，响应体是 HTML 页面而不是 JSON，见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。
- 完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。
