跳到正文
OpenRouter Blog·· 26 天前精选AI 评分62

OpenRouter 教程:用 Gemini 图像模型在代码中编辑图片

Nano Banana API: Edit Images with Gemini in Code

AI 导读

OpenRouter 发布教程,演示如何通过其 API 调用 google/gemini-3.1-flash-image(即 Nano Banana 2)编辑图片:把源图放进 input_references、编辑指令放进 prompt,返回结果从 data[0].b64_json 解码保存。

推荐理由

OpenRouter 官方给出通过单一 API 调用 Gemini 图像模型做图像编辑的完整代码路径,可迁移到自有图像工作流。

正文 · AI 翻译

本指南展示如何在代码中用文本提示编辑图像。你通过 OpenRouter API 将源图像和编辑提示发送到 google/gemini-3.1-flash-image,编辑后的图像会在响应中返回。“Nano Banana”是 Google Gemini 图像模型的昵称。此 slug 为 Nano Banana 2,是该系列中默认的快速模型。由于你通过 一个 API 访问它,之后只需更改一个字段即可使用其他编辑模型。

图像编辑修改现有图像。图像生成根据文本创建新图像。本指南涵盖编辑,因此这里的每个请求都包含源图像。要从文本创建图像,请参阅图像生成文档或图像生成教程。

Before-and-after example of a natural-language image edit: a portrait photo, the prompt "Add a red wool scarf around the person's neck. Keep everything else the same.", and the edited result with the scarf added and everything else intact

Tl;dr

  • 编辑只需一个请求。将源图像放入 input_references,将指令放入 prompt,然后从 data[0].b64_json 读取编辑后的图像并将其解码到磁盘。
  • google/gemini-3.1-flash-image 是 Nano Banana 2,默认的快速 Gemini 图像模型。使用前请确认模型接受图像输入,因为编辑支持各不相同。
  • 对于本地或私有文件,将输入作为 base64 数据 URL 发送;对于托管图像,使用普通 HTTP(S) URL。
  • 以小步骤进行编辑。将每个返回的图像作为下一个源图像发回,每次调用一条指令,这样更改会叠加。
  • 通过编辑一个字段来更改编辑模型。

前提条件

你需要三样东西:

  1. 来自密钥页面的 OpenRouter API 密钥,以及基础 URL https://openrouter.ai/api/v1。
  2. 一个 HTTP 客户端。示例使用 Python requests 和 TypeScript fetch。你也可以使用 curl 或 OpenRouter SDK。任何发送带 Authorization 头的 JSON POST 的客户端都可以。
  3. 一个源图像,可以是本地文件或公共 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 Blog · openrouter.ai