GPT Image 2.5 API:用 Python 生成和编辑图片
一个 POST 建任务,一个 GET 取结果。下面是能直接抄的请求代码、我们 2026 年 10 月 29 日跑出来的尺寸,和一组改图前后对比。
本页内容
发一个 POST 到 https://api.omniakey.com/v1/media/tasks,model 填 gpt-image-2.5-flare,拿到任务 id 就轮询,状态变成成功再下载 assets[0].url。2026 年 10 月 29 日,我们用这个 id 生成 1K、2K、1536x1024 三张图,又改了一张咖啡馆照片。每个文件都打开量过,真实像素是 1024×1024、2048×2048、1536×1024 和 1024×682。1K 那张用了 29.5 秒,2K 那张 45.2 秒。
用哪个 2.5 模型 id
用 gpt-image-2.5-flare,下面每一次运行用的都是它。GPT-Image 2.5 Flare 的模型页(2026 年 10 月 29 日核对)写明供应商是 OpenAI,支持文生图和改图。页面上还有第二个 2.5 的 id gpt-image-2.5-sunburst,并标着 "Guide updated 2026-10-27"。
Flare 两种活都干:生成只发提示词,改图再附一张源图。质量有 low、medium、high 三档,同一页写着档位不影响价格,我们每次都用的 medium。sunburst、low 和 high、4K 和 3840x2160、蒙版、多张参考图我们都没跑。先按 Flare 加 medium、一张源图来规划,其余的等你自己试过再上。
请求代码
下面的脚本就是我们跑的那份,一行没改:两个函数,一次生成调用,一次改图调用。只用 Python 标准库,key 从 OMNIAKEY_API_KEY 读,图片写进运行脚本所在的文件夹。
import base64
import json
import os
import time
import urllib.request
import uuid
API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "gpt-image-2.5-flare"
def request(method, url, body=None, extra_headers=None):
headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
data = None
if body is not None:
headers["Content-Type"] = "application/json"
data = json.dumps(body).encode()
headers.update(extra_headers or {})
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.load(resp)
def run_task(body, out_path):
task = request("POST", API, body, {"Idempotency-Key": str(uuid.uuid4())})["id"]
for _ in range(150):
time.sleep(4)
state = request("GET", f"{API}/{task}")
if state["status"] not in ("queued", "processing"):
break
if state["status"] != "succeeded":
raise RuntimeError(state.get("error") or state["status"])
asset_url = state["assets"][0]["url"] # signed link: valid for about an hour, so download now
req = urllib.request.Request(asset_url, headers={"User-Agent": "omniakey-example/1"})
with urllib.request.urlopen(req, timeout=120) as resp, open(out_path, "wb") as f:
f.write(resp.read())
return task
def generate_image(prompt, out_path, size="1K", quality="medium"):
body = {
"model": MODEL,
"type": "image",
"operation": "generate",
"input": {"prompt": prompt},
"parameters": {"size": size, "quality": quality},
}
return run_task(body, out_path)
def edit_image(source_path, prompt, out_path, size="1K", quality="medium"):
with open(source_path, "rb") as f:
image = base64.b64encode(f.read()).decode()
body = {
"model": MODEL,
"type": "image",
"operation": "edit",
"input": {"prompt": prompt, "image": {"data": image, "mime_type": "image/jpeg"}},
"parameters": {"size": size, "quality": quality},
}
return run_task(body, out_path)
if __name__ == "__main__":
task = generate_image(
"A small glass greenhouse on a hillside at sunrise, morning fog in the valley, "
"soft watercolor style, a wooden bench outside the door, no people, no text.",
"greenhouse.png",
)
print("generate task", task)
task = edit_image(
"cafe-base.jpg",
"Change the red bicycle to matte black. Keep everything else exactly the same: "
"the table, the cup, the window frame and the daylight. Photorealistic, no text, no logos.",
"cafe-edited.png",
)
print("edit task", task)
每个请求都要带 Authorization 头,值是 Bearer 加你的 key。建任务时还要一个 Idempotency-Key,脚本里用一个新 UUID 填。请求体里 type 是 image,operation 是 generate 或 edit,提示词放在 input.prompt。尺寸、质量和数量放在 parameters,其中 n 只能是 1。建任务返回 HTTP 202 和任务 id,状态先是排队,脚本每 4 秒查一次,直到状态离开排队和处理中。
改图时图片放在 input.image,是一个内联 Base64 对象,还要写明图片类型。请求体连 Base64 一起不能超过 1 MiB,所以源图要先压小。
我们跑的尺寸和读到的结果
四次运行,质量都是 medium,日期都是 2026 年 10 月 29 日。三次回来的尺寸和请求一致,改图那次没有:同样的改图请求,一次回 1024×682,一次回 1024×1024。
- 1K,生成 — 从文件读到的像素: 1024×1024; 日期: 2026 年 10 月 29 日
- 2K,生成 — 从文件读到的像素: 2048×2048; 日期: 2026 年 10 月 29 日
- 1536x1024,生成 — 从文件读到的像素: 1536×1024; 日期: 2026 年 10 月 29 日
- 1K,改图 — 从文件读到的像素: 1024×682; 日期: 2026 年 10 月 29 日
下面的温室是同一个请求体跑出来的 1K 生成。

列表里有两件事值得记住。第一,尺寸以文件为准。那次 1K 改图要的是正方形,回来的却是 1024×682,和我们发过去的 1024×683 JPEG 一个比例。同样参数再跑一次,回来的是 1024×1024。第二,图片接口文档(2026 年 10 月 29 日核对)列出的尺寸是 auto、1K、2K、4K 和 3840x2160。文档说不在列表里的尺寸会在扣费前被拒绝,而我们 2026 年 10 月 29 日那次 1536x1024 没有被拒,文件就是 1536×1024。上线前,先读下载下来的文件。
改图:场景不动,只改一处
改图要回答两件事:改什么,留什么。我们只提一个改动,同时点名必须留下来的东西。
提示词:"Change the red bicycle to matte black. Keep everything else exactly the same: the table, the cup, the window frame and the daylight. Photorealistic, no text, no logos."

自行车变黑了,桌子、杯子、植物和窗框都还在画面里。源图是 1024×683 的 JPEG,输出量出来是 1024×682,这次用了 38.0 秒。每轮都写一份"留下"清单。写提示词的结构可以看 GPT Image 2 提示词指南。
报错和限制
真正决定成败的是两个请求头:Bearer token 和唯一的 Idempotency-Key。这两样对了,重试就简单。
| 请求的情况 | 返回 |
|---|---|
| 建任务不带幂等键 | 400 missing_idempotency_key |
| 同一个键、同样的请求体,发两次 | 200,返回原来的任务,不重复扣费 |
| 同一个键、改了请求体 | 409 idempotency_key_reused |
幂等键最长 255 个字符,这是文档(2026 年 10 月 29 日核对)写的。同一个请求体重发是最安全的重试:拿回原来的任务,不会多扣一次费。请求体连 Base64 一起要留在 1 MiB 以内,所以要先把源图压小。
任务成功后,assets[0].url 是一个签名链接,文档说大约一小时有效。所以要马上下载,或者重新查一次同一个任务换新链接。任务记录保留 24 小时。
2026 年 10 月 29 日,一个请求头把我们绊了一下。用 Python urllib 默认的 User-Agent 发 POST,Cloudflare 直接返回 HTTP 403。正文是 "error code: 1010"。同一个 POST 换成我们自己的 User-Agent 头就进得去。接口对空请求体回了 400 invalid_request,也没有扣费。文档只写了 Authorization 和 Idempotency-Key 这两个头。客户端里记得自己设一个 User-Agent。
API 开发选 GPT Image 2.5 还是 GPT Image 2?
Flare 是上面测过的 2.5 id。GPT Image 2 的 id 是 gpt-image-2,参数在它的 GPT Image 2 模型页 上。已经按 gpt-image-2 调好的脚本,只要还出得来你要的图,就不用改。
要一张照片保住场景、只换一个物体,我们 2026 年 10 月 29 日的运行覆盖的就是 Flare 加 medium。三个生成尺寸和那次 1024×682 的改图,都在这条路上。两个模型的尺寸和同提示词结果,都在 GPT Image 2.5 vs GPT Image 2 的对比 里。拿着数字再决定,当前价格在 价格页。
常见问题
gpt-image-2.5-flare 和 gpt-image-2.5-sunburst 选哪个?
我们四次跑的都是 Flare,改图那次留住了我们要求保留的东西。模型页上还有 Sunburst 这个 2.5 的 id。先用 Flare,等你最难的那张改图在 Sunburst 上也稳了再换。
能要 1536x1024 这种横图吗?
2026 年 10 月 29 日那次 1536x1024 生成,回来就是 1536×1024。图片接口文档里这个模型没列这个值,所以上线前先读文件,再看一眼文档。
改图回来的尺寸和我请求的不一样,为什么?
同一个 1K 改图,一次回来 1024×682,另一次是 1024×1024,请求只是请求。把 PNG 打开,读出宽高再用。
一定要带 User-Agent 吗?
2026 年 10 月 29 日,Python 默认的 User-Agent 拿到了 HTTP 403。Cloudflare 的错误码是 1010。换成自己的 User-Agent 就通了,所以还是带上。
图片链接能放多久?
文档说签名链接大约一小时有效。过期就重新查一次任务拿新链接,任务一成功就下载。
文中提到的模型
相关文章
GPT Image 2 提示词怎么写:结构、示例和实测出图
八条提示词、九张真跑的图:GPT Image 2 哪里做得准、多加了什么、怎么修。
GPT-Image 2.5 对比 GPT-Image 2
GPT-Image 2 每张 1K / 2K / 4K 为 $0.02 / $0.03 / $0.05,2.5 为 $0.025 / $0.035 / $0.055,质量不影响价格。2.5 多出的质量档位并不生效,请求需写明确的宽x高。
虚拟换装 API:用 GPT Image 2 替换服装
一张照片加一句提示词就能换装。下面是请求代码、我们在 2026 年 10 月 28 日跑的三次换装,以及结果会在哪里跑偏。

