OpenRouter 教程:用 Gemini 图像模型在代码中编辑图片
Nano Banana API: Edit Images with Gemini in Code
OpenRouter 发布教程,演示如何通过其 API 调用 google/gemini-3.1-flash-image(即 Nano Banana 2)编辑图片:把源图放进 input_references、编辑指令放进 prompt,返回结果从 data[0].b64_json 解码保存。
OpenRouter 官方给出通过单一 API 调用 Gemini 图像模型做图像编辑的完整代码路径,可迁移到自有图像工作流。
本指南展示如何在代码中用文本提示编辑图像。你通过 OpenRouter API 将源图像和编辑提示发送到 google/gemini-3.1-flash-image,编辑后的图像会在响应中返回。“Nano Banana”是 Google Gemini 图像模型的昵称。此 slug 为 Nano Banana 2,是该系列中默认的快速模型。由于你通过 一个 API 访问它,之后只需更改一个字段即可使用其他编辑模型。
图像编辑修改现有图像。图像生成根据文本创建新图像。本指南涵盖编辑,因此这里的每个请求都包含源图像。要从文本创建图像,请参阅图像生成文档或图像生成教程。

Tl;dr
- 编辑只需一个请求。将源图像放入
input_references,将指令放入prompt,然后从data[0].b64_json读取编辑后的图像并将其解码到磁盘。 google/gemini-3.1-flash-image是 Nano Banana 2,默认的快速 Gemini 图像模型。使用前请确认模型接受图像输入,因为编辑支持各不相同。- 对于本地或私有文件,将输入作为 base64 数据 URL 发送;对于托管图像,使用普通 HTTP(S) URL。
- 以小步骤进行编辑。将每个返回的图像作为下一个源图像发回,每次调用一条指令,这样更改会叠加。
- 通过编辑一个字段来更改编辑模型。
前提条件
你需要三样东西:
- 来自密钥页面的 OpenRouter API 密钥,以及基础 URL
https://openrouter.ai/api/v1。 - 一个 HTTP 客户端。示例使用 Python
requests和 TypeScriptfetch。你也可以使用 curl 或 OpenRouter SDK。任何发送带 Authorization 头的 JSON POST 的客户端都可以。 - 一个源图像,可以是本地文件或公共 URL。
使用哪个模型
本指南中的默认值是 google/gemini-3.1-flash-image,即 Nano Banana 2。它接受图像作为输入并返回编辑后的图像。Nano Banana 系列有四个当前成员:Nano Banana 2(google/gemini-3.1-flash-image)是本指南中的默认值,Nano Banana 2 Lite(google/gemini-3.1-flash-lite-image)最便宜且最快,Nano Banana Pro(google/gemini-3-pro-image)更慢但质量更高,而最初的 Nano Banana(google/gemini-2.5-flash-image)是这个昵称起源的较旧模型。
图像目录经常变化。模型会被添加、弃用和重新定价,因此你今天固定的 slug 以后可能会被停用。在基于某个模型构建之前,请确认它接受图像输入并支持你需要的编辑功能。你可以在图像模型集合中浏览支持编辑的模型。有关目录的详细介绍,请参阅图像生成模型。
下面的示例使用每个请求中显示的 slug,因此你可以按原样运行它们,并在之后更改模型。将你的密钥保存在环境变量中,而不是代码中:
export OPENROUTER_API_KEY="sk-or-..."你的第一次图像编辑
要编辑图像,请在单个请求中发送源图像和文本指令。编辑后的图像会在响应中返回。以下是一个在 Python 中编码本地文件的可运行请求:
import base64, os, requests
api_key = os.environ["OPENROUTER_API_KEY"]
# Encode a local source image as a base64 data URL.
with open("portrait.jpg", "rb") as f:
encoded = base64.b64encode(f.read()).decode()
source = f"data:image/jpeg;base64,{encoded}"
resp = requests.post(
"https://openrouter.ai/api/v1/images",
headers={"Authorization": f"Bearer {api_key}"},
json={
"model": "google/gemini-3.1-flash-image",
"prompt": "Add a red wool scarf around the person's neck. Keep everything else the same.",
"input_references": [
{"type": "image_url", "image_url": {"url": source}}
],
},
)
resp.raise_for_status()TypeScript 中的相同请求:
import { readFileSync } from "node:fs";
const apiKey = process.env.OPENROUTER_API_KEY!;
const encoded = readFileSync("portrait.jpg").toString("base64");
const source = `data:image/jpeg;base64,${encoded}`;
const resp = await fetch("https://openrouter.ai/api/v1/images", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "google/gemini-3.1-flash-image",
prompt: "Add a red wool scarf around the person's neck. Keep everything else the same.",
input_references: [{ type: "image_url", image_url: { url: source } }],
}),
});两种语言中的请求体相同。将参考图像放入 input_references,将指令放入 prompt。这就是整个请求。
编码输入图像:base64 或 URL
input_references 字段接受 base64 数据 URL 或 HTTP(S) URL。上面的示例编码本地文件。如果你的图像已经公开托管,请直接传递链接并跳过编码:
"input_references": [
{"type": "image_url", "image_url": {"url": "https://example.com/portrait.jpg"}}
]当图像是公开托管时使用 URL,因为这样可以保持请求体较小。对于本地或私有文件使用 base64。Gemini 接受 image/png、image/jpeg、image/webp、image/heic 和 image/heif 输入。支持的格式因模型而异,因此发送前请查看模型页面。
从响应中获取编辑后的图像
API 会在 data 数组中以 base64 数据的形式返回编辑后的图像。解码 b64_json 值并将其写入文件:
data = resp.json()["data"][0]
with open("edited.png", "wb") as out:
out.write(base64.b64decode(data["b64_json"]))TypeScript 版本:
import { writeFileSync } from "node:fs";
const { data } = await resp.json();
writeFileSync("edited.png", Buffer.from(data[0].b64_json, "base64"));打开 edited.png 查看结果。如果你想使用类型化客户端而不是原始 HTTP,OpenRouter SDK 提供了一个 images 资源,它调用的是同一个端点:
from openrouter import OpenRouter
client = OpenRouter(api_key=api_key)
result = client.images.generate(
model="google/gemini-3.1-flash-image",
prompt="Add a red wool scarf around the person's neck. Keep everything else the same.",
input_references=[{"type": "image_url", "image_url": {"url": source}}],
)使用 pip install openrouter 安装 SDK。它会复用之前定义的 api_key,因此无需额外设置。
编写编辑提示词
生成提示词描述一张全新的图像。编辑提示词则说明要更改什么、要保留什么。先说明更改内容,再指明必须保持不变的部分:
- 物体替换:“将咖啡杯替换为一杯橙汁。保持手部位置和背景不变。”
- 背景更改:“将背景更改为夜晚的雪中街道。保持主体完全不变。”
- 风格迁移:“将这张照片渲染为水彩画。保留构图和主体的姿势。”
- 文字修复:“将标牌文字改为‘OPEN’。匹配原始字体和颜色。”
你也可以将提示词写成一小段 JSON 文本:
"prompt": "{\"edit\": \"add sunglasses\", \"preserve\": [\"face\", \"hair\", \"lighting\"], \"style\": \"photorealistic\"}"API 会将其视为纯文本,因此这不是一种特殊模式。这种结构有助于模型区分哪些内容发生变化、哪些内容保持不变。在你自己的图像上同时尝试句子形式和 JSON 形式,保留效果更好的那一种。
再次编辑结果
一次编辑并不总能得到你想要的结果。要进行另一轮处理,请将返回的图像作为下一个源图像发送回去。从响应中取出 b64_json 值,将其转换为 data URL,并在下一个 input_references 中传入:
def edit(source_data_url, prompt):
resp = requests.post(
"https://openrouter.ai/api/v1/images",
headers={"Authorization": f"Bearer {api_key}"},
json={
"model": "google/gemini-3.1-flash-image",
"prompt": prompt,
"input_references": [
{"type": "image_url", "image_url": {"url": source_data_url}}
],
},
)
resp.raise_for_status()
item = resp.json()["data"][0]
media_type = item.get("media_type", "image/png")
return f"data:{media_type};base64,{item['b64_json']}"
step1 = edit(source, "Add a red wool scarf. Keep everything else the same.")
step2 = edit(step1, "Now make the scarf navy blue instead of red.")
step3 = edit(step2, "Add soft morning light coming from the left.")每次调用都会编辑上一次的结果,因此之前的更改会延续下去。每次调用只给出一条指令。小改动更容易检查,出错时也更容易重做。模型不会记住你之前的提示词,因此在每个新提示词中都要重复说明应保持不变的部分。
更换编辑模型
要将同一个编辑请求发送给不同的模型,请更改 model 字段。源图像、提示词和响应处理代码保持不变:
json={
"model": "openai/gpt-5-image", # was google/gemini-3.1-flash-image
"prompt": "Add a red wool scarf. Keep everything else the same.",
"input_references": [
{"type": "image_url", "image_url": {"url": source}}
],
},使用 google/gemini-3.1-flash-image 作为快速的默认选项。当你想要最低价格时,使用 google/gemini-3.1-flash-lite-image。当你想要更高质量并能接受更高延迟时,使用 google/gemini-3-pro-image。原来的 google/gemini-2.5-flash-image 仍可使用相同的请求结构,但上述较新的模型是更好的默认选择。当你想要在自己的图像上比较质量、成本或速度时,可使用其他提供商的模型,例如 openai/gpt-5-image。这种单字段更改仅适用于接受图像输入并支持相同 input_references 结构的模型,因此在切换之前请确认该模型具备编辑能力。
要按环境而不是在代码中设置模型及其选项,请使用 OpenRouter Presets。
错误与成本
这些失败很常见,值得提前规划:
- 不支持的输入。模型可能会拒绝它不支持的图像格式,也可能会拒绝它无法访问的 URL。发送前请检查文件类型和 URL。
- 图像过大。大文件可能会超时或失败。请先缩小图像,因为大多数编辑并不需要 4000 万像素的源图像。
- 返回文本而不是图像。像“这张照片里有什么?”这样的问题可能会让模型用文本回答,而不是生成图像。API 会将其作为
400错误返回,例如Gemini could not generate an image (STOP),而不是空响应。请编写指令而不是提问,并在解码前检查 HTTP 状态。
当有使用数据时,响应会以美元报告每个请求的成本。记录它以跟踪支出:
usage = resp.json().get("usage")
if usage:
print(f"This edit cost ${usage['cost']}")对于批处理任务,请遵守速率限制。对 429 和 5xx 响应进行重试,并在每次尝试之间逐步增加延迟,同时限制同时运行的编辑数量。在开始下一次编辑之前保存每个返回的图像,这样一次失败就不会丢失已完成的工作。
后续步骤
复制第一个请求,使用你自己的图像,然后运行一次编辑。如果想改为从文本创建图像,请参阅图像生成文档。要查找当前支持编辑的模型,请浏览图像模型集合。
常见问题
我可以用 Gemini API 编辑图像吗?
可以。通过 OpenRouter API 在一个请求中向 google/gemini-3.1-flash-image 发送源图像和文本指令,编辑后的图像会以 base64 形式在响应中返回。该模型是 Nano Banana 2。整个请求一屏就能放下,你可以在 Python、TypeScript 或 curl 中运行它。
图像生成和图像编辑有什么区别?
图像编辑会修改现有图像。图像生成则根据文本创建新图像。每个编辑请求都在 input_references 中包含一张源图像,以及一条说明要更改什么、保留什么的指令。如果你的请求没有源图像,仅根据文本提示进行,那就是生成。
我该如何向 API 发送图像,用 URL 还是 base64?
input_references 字段接受用于本地或私有文件的 base64 数据 URL,或用于公开托管图像的普通 HTTP(S) URL。当图像已经在线时,使用 URL 形式可以让请求更小;当文件在你的机器上时,使用 base64 形式。Gemini 接受 png、jpeg、webp、heic 和 heif 输入(image/png、image/jpeg、image/webp、image/heic、image/heif)。支持的格式因模型而异,因此发送前请查看模型页面。
我可以使用 Gemini 以外的模型来编辑图像吗?
可以。更改 model 字段,其余请求保持不变。请先查看图像模型集合,因为编辑支持、价格和速度因模型而异。
我该如何提示 AI 模型编辑图像?
先描述更改,然后说明要保留什么,例如“把背景改成夜晚的雪街。主体保持原样。”每个请求一条指令效果最好。为了获得精确结果,请分小步编辑,并将每个返回的图像作为下一个提示的源图像发回。
参考资料
- OpenRouter API 密钥:创建并管理每个请求中使用的密钥。
- 图像模型集合:支持编辑的完整模型集合及其输入支持。
- 图像生成文档:从文本创建图像的配套指南。
- 预设指南:按环境固定模型及其选项,而不是在代码中设置它们。
来源:OpenRouter Blog · openrouter.ai