# OpenAI 图片 API 教程：Images API 还是 Responses

> 单次出图或改图用 Images API，对话中多轮改图用 Responses 的 image_generation 工具；两边都要显式写 GPT Image 2.5 模型。

- Source: https://www.aifreeapi.com/zh/posts/openai-image-api-tutorial
- Language: zh
- Published: 2026-03-22
- Updated: 2026-09-25
- Publisher: AI Free API (https://www.aifreeapi.com)

截至 2026 年 9 月 25 日，OpenAI 的图片生成有两个入口，选法可以压成一句话：**一个提示词生成或编辑图片，用 Images API；要在对话里生成、再一轮轮修改，用 Responses API 的 `image_generation` 工具**（图片生成工具）。这是 OpenAI [图片生成指南](https://developers.openai.com/api/docs/guides/image-generation#choosing-the-right-api)里给出的分工。

不管选哪条，都要把图片模型写明：新项目用 `gpt-image-2.5-flare`（快，适合日常出图）或 `gpt-image-2.5-sunburst`（更重视编辑精度）。原因很具体：Images API 不写 `model` 时默认是 `dall-e-2`，而它已在 2026 年 5 月 12 日移除；Responses 的图片工具不写 `model` 时默认是 `gpt-image-1`，它将在 2026 年 10 月 23 日停用。GPT 图片模型只返回 base64 数据，不返回图片链接。

下面的代码按 OpenAI 截至 2026 年 9 月 25 日的文档写成，不是实际调用后的记录；第一次运行时，以你拿到的响应内容为准。另外要先确认一件事：OpenAI API 的支持国家和地区列表里没有中国大陆和香港，详见后文「开始之前」。

## 先按场景选 Images API 还是 Responses API

| 你要做的事 | 用哪个 | 关键写法 |
| --- | --- | --- |
| 输入一段提示词，保存一张或几张图 | Images API：`/v1/images/generations` | `model="gpt-image-2.5-flare"`，`n` 可取 1–10 |
| 用提示词修改已有图片、加蒙版、多图参考 | Images API：`/v1/images/edits` | 细节见 [OpenAI 图片编辑 API](/zh/posts/openai-image-editing-api) |
| 聊天产品里用户说「背景再暗一点」，接着上一张改 | Responses API + `image_generation` 工具 | `previous_response_id` 或传入上一次的图片调用 ID |
| 让文本模型先理解需求、再决定要不要画，或和其他工具一起用 | Responses API + `image_generation` 工具 | 顶层写文本模型，图片模型写在工具里 |
| 离线批量出图、想用 Batch | Images API + `gpt-image-2` | GPT Image 2.5 不支持 Batch，`gpt-image-2` 支持 |

拿不准时，先用 Images API 跑通。它每次请求就是「提示词进、图片出」，失败时要排查的东西最少。只有当你的产品真的需要对话上下文——用户会基于上一张图继续提要求——Responses 多出来的那一层才有价值。

两条路的差别主要在下面几处：

| 对比项 | Images API | Responses API + `image_generation` |
| --- | --- | --- |
| 图片模型写在哪里 | 请求顶层的 `model` | `tools` 里工具对象的 `model`；顶层 `model` 是负责对话的文本模型 |
| 不写图片模型会怎样 | 默认 `dall-e-2`（已移除） | 默认 `gpt-image-1`（2026 年 10 月 23 日停用） |
| 图片在响应的哪里 | `data[0].b64_json` | `output` 中 `type` 为 `image_generation_call` 的那一项的 `result` |
| 一次出几张 | `n` 取 1–10 | 工具没有 `n` 参数 |
| 是否一定出图 | 请求成功就有图 | 文本模型可能只回文字，需要 `tool_choice` 强制调用 |
| 费用 | 图片生成的 token | 图片生成的 token + 文本模型的 token |

图片模型不能直接放在 Responses 的顶层 `model`：GPT Image 各模型页都注明不支持作为 `v1/responses` 的顶层模型。Responses 与 Chat Completions 这两套文本接口本身的差别，可以看 [Chat Completions 与 Responses API：差别不只是字段名](/zh/posts/chat-completions-vs-responses-api)。

## 旧代码先查模型：10 月和 12 月各停一批

手里有 2025 年前后的教程或旧项目时，先看模型名。OpenAI [弃用页面](https://developers.openai.com/api/docs/deprecations)的时间表如下：

| 模型 | 状态 | 时间 |
| --- | --- | --- |
| `dall-e-2`、`dall-e-3` | 已移除 | 2026 年 5 月 12 日 |
| `gpt-image-1` | 将停用 | 2026 年 10 月 23 日 |
| `gpt-image-1.5`、`gpt-image-1-mini`、`chatgpt-image-latest` | 将停用 | 2026 年 12 月 1 日 |
| `gpt-image-2` | 仍可用，文档把它归为较早模型 | 未公布停用时间 |
| `gpt-image-2.5-flare`、`gpt-image-2.5-sunburst` | 当前模型，快照为 `-2026-09-08` | — |

弃用页给停用模型写的替代是 `gpt-image-2`（那张表早于 2.5 发布），图片生成指南则建议新集成用 GPT Image 2.5。两种做法都成立：已经跑稳的 `gpt-image-2` 集成可以不急着换，需要 Batch 时也只能留在 `gpt-image-2`；新写的代码直接用 2.5。没有不带后缀的 `gpt-image-2.5` 这个模型 ID，要写全 `gpt-image-2.5-flare` 或 `gpt-image-2.5-sunburst`。两款怎么选，见 [GPT Image 2.5 介绍：Flare 与 Sunburst 怎么选](/zh/posts/gpt-image-2-5)。

在项目根目录搜一遍就能知道要不要改：

```bash
grep -rnE "dall-e|gpt-image-1|chatgpt-image-latest|image_generation" --include="*.py" --include="*.js" --include="*.ts" .
```

`gpt-image-1` 这个模式会同时命中 `gpt-image-1.5` 和 `gpt-image-1-mini`，三者都在停用名单里，全部要改。搜到 `image_generation` 的地方，逐个看工具对象里有没有写 `model`：没写就是在用默认的 `gpt-image-1`。OpenAI 工具指南里的 Java 和 Ruby 示例恰好没有写工具 `model`，照抄过来的代码也会落到这个默认值上。`gpt-image-1` 停用后，省略 `model` 的请求会报错还是被改指到别的模型，文档没有说明，所以不要等到那天再看结果。

![旧图片代码要改的四处：Images API 补上 model、Responses 工具补上 model、把 gpt-image-1.5 换成 gpt-image-2.5-flare、改读 b64_json](https://www.aifreeapi.com/posts/zh/openai-image-api-tutorial/img/old-code-migration.webp)

## 开始之前：Key、计费和所在地区

准备工作只有三步：

1. 安装官方 SDK：Python 用 `pip install openai`，Node 用 `npm install openai`。
2. 在 OpenAI 开发者平台创建 API Key，设成环境变量 `OPENAI_API_KEY`，SDK 会自动读取。
3. 确认 API 账户有余额。ChatGPT 的订阅和 API 是两套独立计费，Plus 或 Pro 会员不能抵扣 API 费用。

使用 GPT Image 模型前，组织可能需要先完成 API 组织验证。如果请求返回和验证有关的 403，先按 [GPT Image 2 提示组织必须验证](/zh/posts/openai-image-generation-api-verification) 处理；暂时无法验证时有哪些选择，见 [GPT Image 2 免组织验证怎么用](/zh/posts/gpt-image-2-without-organization-verification)。

所在地区要单独说清楚。截至 2026 年 9 月 25 日，OpenAI [支持的国家和地区](https://developers.openai.com/api/docs/supported-countries)列表中没有中国大陆和香港（台湾在列表内）。同一页面写明，在列表以外的地区访问或提供服务，可能导致账号被封禁或暂停。浏览器语言、账号资料填的地区都不等于你实际所在的位置。如果你在中国大陆，直接调用 OpenAI API 不在官方支持范围内。

## 路线一：Images API 生成第一张图

Python 版，保存为 `generate.py` 后运行 `python generate.py`：

```python
import base64
from openai import OpenAI

client = OpenAI()  # 从环境变量 OPENAI_API_KEY 读取 Key

result = client.images.generate(
    model="gpt-image-2.5-flare",  # 必须写；省略时默认 dall-e-2，已移除
    prompt="一只戴橙色围巾的水獭坐在书桌前看书，儿童绘本风格，暖色调",
    size="1024x1024",
    quality="medium",
)

image_b64 = result.data[0].b64_json
with open("otter.png", "wb") as f:
    f.write(base64.b64decode(image_b64))

print("已保存 otter.png")
```

Node 版，保存为 `generate.mjs`（`.mjs` 才能用顶层 `await`），运行 `node generate.mjs`：

```js
import fs from "node:fs";
import OpenAI from "openai";

const client = new OpenAI(); // 从环境变量 OPENAI_API_KEY 读取 Key

const result = await client.images.generate({
  model: "gpt-image-2.5-flare",
  prompt: "一只戴橙色围巾的水獭坐在书桌前看书，儿童绘本风格，暖色调",
  size: "1024x1024",
  quality: "medium",
});

fs.writeFileSync("otter.png", Buffer.from(result.data[0].b64_json, "base64"));
console.log("已保存 otter.png");
```

成功的标志是当前目录出现一张能打开的 `otter.png`。复杂提示词最长可能要约 2 分钟才返回，等待期间没有输出是正常的。

有三处旧写法要改掉：

- **不要读 `data[0].url`**。GPT 图片模型只返回 base64，`url` 字段不会出现；`response_format` 参数也不适用于 GPT 图片模型。「图片链接 60 分钟后失效」说的是 DALL·E 时代的链接，现在已经没有这回事。
- **不要只写 `prompt`**。省略 `model` 时，参考文档写的默认值是 `dall-e-2`（除非请求里用了 GPT 图片模型专属的参数），而 DALL·E 已经移除。
- **需要多张图时用 `n`**，范围 1–10，结果依次在 `data[0]`、`data[1]`……里。

编辑已有图片走另一个端点 `/v1/images/edits`。最简单的形式是一张输入图加一段修改说明：

```python
result = client.images.edit(
    model="gpt-image-2.5-sunburst",  # 编辑精度优先时选 Sunburst
    image=open("product.png", "rb"),
    prompt="把背景换成浅灰色摄影棚，产品本身保持不变",
)
```

返回结构与生成相同，照样从 `data[0].b64_json` 取图。蒙版、多图参考、从 variations 迁移，以及 `dall-e-2` 相关报错，见 [OpenAI 图片编辑 API](/zh/posts/openai-image-editing-api)。

## 路线二：Responses API 的 image_generation 工具

Responses 的请求分两层：顶层 `model` 是负责对话的文本模型，它读你的输入，决定要不要调用图片工具、怎么改写提示词；真正画图的 GPT Image 模型写在 `tools` 里。

```python
import base64
from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-6-astra",  # 文本模型；先在它的模型页确认支持 image_generation 工具
    input="画一只戴橙色围巾的水獭坐在书桌前看书，儿童绘本风格，暖色调",
    tools=[{
        "type": "image_generation",
        "model": "gpt-image-2.5-sunburst",  # 图片模型写在这里；省略会用默认的 gpt-image-1
        "size": "1024x1024",
        "quality": "medium",
    }],
    tool_choice={"type": "image_generation"},  # 这一轮必须出图时强制调用
)

calls = [item for item in response.output if item.type == "image_generation_call"]
if not calls:
    raise RuntimeError("本轮没有调用图片工具，模型回复：" + response.output_text)

call = calls[0]
if call.status != "completed" or not call.result:
    raise RuntimeError(f"图片没有生成完成：status={call.status}")

with open("otter.png", "wb") as f:
    f.write(base64.b64decode(call.result))

print("改写后的提示词：", call.revised_prompt)
print("response id：", response.id, "图片调用 id：", call.id)
```

Node 版（沿用上面 `generate.mjs` 里的导入和 `client`）：

```js
const response = await client.responses.create({
  model: "gpt-6-astra",
  input: "画一只戴橙色围巾的水獭坐在书桌前看书，儿童绘本风格，暖色调",
  tools: [{ type: "image_generation", model: "gpt-image-2.5-sunburst", size: "1024x1024", quality: "medium" }],
  tool_choice: { type: "image_generation" },
});

const call = response.output.find((item) => item.type === "image_generation_call");
if (!call || call.status !== "completed" || !call.result) {
  throw new Error("没有拿到图片：" + (call ? call.status : response.output_text));
}
fs.writeFileSync("otter.png", Buffer.from(call.result, "base64"));
```

这段代码里每一处检查都对应一个实际的坑：

- **工具的 `model` 必须写**。Responses 参考文档里，工具 `model` 的默认值是 `gpt-image-1`，而它 2026 年 10 月 23 日停用。
- **顶层模型要支持这个工具**。OpenAI 工具指南列出的支持名单（`gpt-5.5`、`gpt-5`、`o3`、`gpt-4.1`、`gpt-4o` 等）和它自己示例里用的 `gpt-6-astra` 对不上；图片生成指南的说法是 `gpt-5` 及更新的模型应当支持，以[模型详情页](https://developers.openai.com/api/docs/models)为准。换成别的文本模型前，先去它的模型页看托管工具里有没有图片生成。
- **不强制就不一定出图**。只把工具放进 `tools` 时，由文本模型决定要不要画、画几次，它可能只回一段文字，也可能调用不止一次。需要每轮都出图时加 `tool_choice={"type": "image_generation"}`，并且照样检查 `output` 里有没有 `image_generation_call`、`result` 是否为空。
- **状态和结果分开判断**。`image_generation_call` 的 `status` 可能是 `in_progress`、`generating`、`completed` 或 `failed`，`result` 允许为 `null`，只有 `completed` 且 `result` 非空才解码。
- **提示词会被改写**。文本模型会自动改写你的提示词，实际用于出图的版本在 `revised_prompt` 里。结果和预期差得远时，先看这个字段。

工具对象还能设置 `action`（`auto`、`generate`、`edit`，默认 `auto`）、`size`、`quality`、`output_format`、`output_compression`、`background`、`partial_images`、`moderation` 和 `input_image_mask`。它没有 `n` 参数；Responses 能否稳定地一次返回多张图，文档没有说明。需要固定张数时，用 Images API 的 `n`，或者发多次请求。

![一次 responses.create 请求里的顶层 model、工具 model 与 tool_choice，以及拿到图片和没拿到图片两种结果的处理](https://www.aifreeapi.com/posts/zh/openai-image-api-tutorial/img/responses-image-call.webp)

## 多轮改图：接上一轮的两种写法

Responses 的价值主要在这里。第一种写法最简单，把上一轮的 `response.id` 传给 `previous_response_id`：

```python
follow_up = client.responses.create(
    model="gpt-6-astra",
    previous_response_id=response.id,
    input="保持构图不变，改成写实摄影风格",
    tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst", "action": "edit"}],
    tool_choice={"type": "image_generation"},
)
```

第二种写法不依赖整条对话链，只把上一张图的调用 ID 和新要求一起作为输入：

```python
follow_up = client.responses.create(
    model="gpt-6-astra",
    input=[
        {"role": "user", "content": [{"type": "input_text", "text": "保持构图不变，改成写实摄影风格"}]},
        {"type": "image_generation_call", "id": call.id},
    ],
    tools=[{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}],
)
```

取图方式和第一轮完全一样。`action` 设成 `edit` 时，上下文里有图就强制在它的基础上修改；设成 `generate` 则总是画一张新图；保持 `auto` 由模型判断。

有两点容易误会：

- **当前文档里没有 `referenced_image_ids` 参数**。截至 2026 年 9 月 25 日，OpenAI 的图片生成指南、工具指南和 Responses 参考文档里都没有这个名字。接续编辑请用上面两种有文档记载的写法。
- **`previous_response_id` 不会让之前的内容免费**。链上之前所有轮次的输入 token 仍按输入 token 计费，对话越长，每轮的文本成本越高。

输入图片除了上一轮的结果，也可以是完整的图片 URL、base64 data URL 或已上传文件的 File ID。

## Images API 与 Responses 共用的参数：size、quality 等

| 参数 | 可选值与限制 | 何时需要注意 |
| --- | --- | --- |
| `size` | 推荐 `1024x1024`、`1536x1024`、`1024x1536`；也可自定义宽×高：边长是 16 的倍数，宽高比在 1:3 到 3:1 之间，单边不超过 3840，总像素 655,360–8,294,400，超过 `2560x1440` 属于实验性 | 报 invalid size 时见 [GPT Image 2 报 1024x576 invalid size](/zh/posts/gpt-image-2-invalid-size) |
| `quality` | `low`、`medium`、`high`、`auto`（默认）；2.5 另有 `xhigh`、`max` | 草稿用 `low`，定稿再比较更高档 |
| `output_format` | `png`（默认）、`jpeg`、`webp` | `jpeg` 比 `png` 快；`jpeg`、`webp` 可配 `output_compression`（0–100） |
| `background` | `transparent`、`opaque`、`auto` | 透明背景要配 `png` 或 `webp`，见 [GPT Image 2 透明背景 API](/zh/posts/gpt-image-2-transparent-background) |
| `partial_images` | 0–3 | 流式返回预览图；图生成得快时可能收不满这个数 |
| `moderation` | `auto`（默认）、`low` | `low` 过滤较宽松 |

`input_fidelity` 在参考文档和指南里的说明互相矛盾，GPT Image 2.5 如何处理它也没有写明，用 2.5 时不要传。

## 费用：Responses 多出来的是文本模型的 token

截至 2026 年 9 月 25 日，GPT Image 2.5 两款与 `gpt-image-2` 的 [token 单价](https://developers.openai.com/api/docs/pricing)相同：图像输出 $30 / 百万 token，图像输入 $8 / 百万 token，文本输入 $5 / 百万 token。单价相同不等于每张图同价，因为同一档质量下各模型消耗的 token 数不同。

OpenAI 计算器给出的 1024×1024、仅输出部分的估算：

| 质量 | GPT Image 2.5 | `gpt-image-2` |
| --- | --- | --- |
| `low` | $0.00588 | $0.00588 |
| `medium` | $0.01317 | $0.05268 |
| `high` | $0.05268 | $0.21072 |

这些数字不含提示词和输入图片的 token，也不含 Responses 的文本模型费用。走 Responses 时，账单是图片生成的 token 加上顶层文本模型的 token，多轮对话还会累计之前轮次的输入。OpenAI 价格页的内置工具表里没有图片生成的按次调用费，相关 token 按所选模型的单价计费。开启流式预览时，每张预览图额外计 100 个图像输出 token，按 $30 / 百万 token 算约 $0.003 一张。

实际花费以响应里的 `usage` 为准，拿自己的尺寸和质量跑几次再定预算。按张数和项目规模算账，见 [GPT Image 2 API 每张多少钱？](/zh/posts/openai-image-generation-api-pricing)

## 报错和空结果怎么分辨

| 现象 | 常见原因 | 处理 |
| --- | --- | --- |
| Images API 报模型相关错误，代码里没写 `model` | 默认落到已移除的 `dall-e-2` | 写上 `gpt-image-2.5-flare` 或 `gpt-image-2.5-sunburst` |
| `data[0].url` 是空的 | GPT 图片模型只返回 base64 | 改读 `data[0].b64_json` 并解码保存 |
| Responses 的 `output` 里没有 `image_generation_call` | 文本模型决定只回文字 | 加 `tool_choice`；打印 `output_text` 看它说了什么 |
| 有 `image_generation_call`，但 `result` 为空 | 调用未完成或失败 | 看 `status`，记录请求 ID 后再决定是否重试 |
| 403，提示组织需要验证 | 组织未完成 API 组织验证 | 见 [GPT Image 2 提示组织必须验证](/zh/posts/openai-image-generation-api-verification) |
| `error.type` 为 `image_generation_user_error`，或 `error.code` 为 `moderation_blocked` | 提示词或输入图需要修改 | 不要自动重试；`moderation_blocked` 可能附带 `moderation_details`，据此修改后再发 |
| 429 限流或 5xx 服务端错误 | 临时性问题 | 指数退避后重试；额度不足类错误不要自动重试 |
| 尺寸报错 | 不符合尺寸规则 | 对照上一节的 `size` 规则 |
| 等了一两分钟才返回 | 复杂提示词本身较慢 | 客户端超时至少留到 2 分钟以上 |

程序里判断错误类型时，以 `error.code` 为准，同时把请求 ID 记进日志，方便之后定位。

## 用 OpenAI 兼容服务时要改什么

有些团队用第三方的 OpenAI 兼容服务调 GPT Image 2.5，官方 SDK 只需把 `base_url` 和 Key 换成对方的。这类服务不是 OpenAI，前面关于 Responses 工具、默认值和错误码的说明都来自 OpenAI 文档，不一定适用于它们。以 laozhang.ai 为例，它的[文档](https://docs.laozhang.ai/api-capabilities/gpt-image-2-5)写的是：

- 地址 `https://api.laozhang.ai/v1`，模型 ID 为 `gpt-image-2.5-flare`、`gpt-image-2.5-sunburst`，有按 token 计费和按次计费的不同分组，价格以其文档当前页面为准；
- 编辑统一走 `/v1/images/edits`；
- 文档没有说明支持 Responses 的 `image_generation` 工具，所以路线二的代码不能直接搬过去；
- 文档也没有写明服务地区和可用性承诺。

换用任何兼容服务时，Key、`base_url` 和模型 ID 要来自同一个平台，并先确认它返回的是 base64 还是图片链接，别直接沿用只读 `b64_json` 的代码。

## 常见问题

### OpenAI 图片 API 返回的图片链接多久过期？

GPT 图片模型不返回链接，只返回 base64，你需要自己解码保存或上传到存储。「链接 60 分钟后失效」适用于 DALL·E 返回的图片链接，而 DALL·E 已于 2026 年 5 月 12 日移除。

### Responses 的图片为什么是空的？

先看 `output` 里有没有 `type` 为 `image_generation_call` 的项：没有，说明文本模型这轮没调用工具，加上 `tool_choice={"type": "image_generation"}`；有但 `result` 为空，看它的 `status` 是否为 `failed`。另外确认工具里写了 `model`，否则用的是 `gpt-image-1`。

### 能不能把 gpt-image-2.5-flare 直接写在 Responses 的顶层 model？

不能。GPT Image 模型不支持作为 Responses 的顶层模型。顶层写支持图片工具的文本模型，图片模型写在 `tools` 的 `model` 里。

### 已经在用 gpt-image-2，要马上换到 2.5 吗？

不必。`gpt-image-2` 目前没有停用时间，而且是唯一支持 Batch 的 GPT 图片模型。要尽快改的是 `gpt-image-1`（2026 年 10 月 23 日停用）以及 `gpt-image-1.5`、`gpt-image-1-mini`、`chatgpt-image-latest`（2026 年 12 月 1 日停用）。
