OpenRouter 教程:用代码调用 Nano Banana 2 编辑图像
Nano Banana API: Edit Images with Gemini in Code
精选理由
原文给出完整可运行的图像编辑请求代码和提示词写法,读者可以照搬并把模型换成其他供应商做对比。
AI 摘要
OpenRouter 发布教程,演示通过 API 向 google/gemini-3.1-flash-image(即 Nano Banana 2)发送源图和文本指令完成图像编辑,编辑结果以 base64 形式在响应中返回。教程给出 Python 和 TypeScript 示例、提示词写法、多轮小步编辑方法,以及更换模型只需改一个字段,并介绍了 Nano Banana 系列四个成员的价格与质量差异。
正文 · AI 翻译
本指南展示如何在代码中通过文本提示词编辑图像。你通过 OpenRouter API 将源图像和编辑提示词发送给 google/gemini-3.1-flash-image,编辑后的图像会在响应中返回。"Nano Banana" 是 Google Gemini 图像模型的昵称。此 slug 为 Nano Banana 2,是该系列中默认的快速模型。由于你通过 一个 API 访问它,之后只需更改一个字段即可使用不同的编辑模型。
图像编辑是对现有图像进行修改。图像生成是根据文本创建新图像。本指南涵盖的是编辑,因此这里的每个请求都包含一张源图像。如需根据文本创建图像,请参阅 图像生成文档或 图像生成教程。
简而言之
编辑只需一次请求。将源图像放入 input_references,将指令放入 prompt,然后从 data[0].b64_json 读取编辑后的图像并将其解码到磁盘。
google/gemini-3.1-flash-image 是 Nano Banana 2,默认的快速 Gemini 图像模型。在使用某个模型之前,请确认它接受图像输入,因为编辑支持情况各不相同。
对于本地或私有文件,将输入作为 base64 数据 URL 发送;对于托管图像,则使用普通的 HTTP(S) URL。
以小步进行编辑。将每次返回的图像作为下一次的源图像发回,每次调用只给一条指令,这样修改就会逐步叠加。
只需编辑一个字段即可更改编辑模型。
前置条件
你需要三样东西:
一个来自密钥页面的 OpenRouter API key,以及基础 URL https://openrouter.ai/api/v1。
一个 HTTP 客户端。示例使用 Python requests 和 TypeScript fetch。你也可以使用 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 会将编辑后的图像以 base64 数据的形式返回在 data 数组中。解码 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 keys:创建并管理每次请求中使用的密钥。
图像模型集合:具备编辑能力的完整模型集及其输入支持。
图像生成文档:从文本创建图像的配套指南。
预设指南:按环境固定模型及其选项,而无需在代码中设置。
原文
Original Title
Nano Banana API: Edit Images with Gemini in Code
Source
OpenRouter:Announcements(RSS)
Site
openrouter.ai
Published
2026-09-09 08:00