香蕉生图 API 接入教程:Nano Banana(gemini-nano-banana-2.1)文生图、图生图与 4K 调用示例 更新于 2026-11-04
想在自己的程序、工作流或插件里调用香蕉生图(Nano Banana / Gemini 生图)?API 快连的香蕉生图走 Gemini 原生的 generateContent 接口,和 OpenAI 的 images 接口不是一套写法。这篇讲清楚五个香蕉分组用什么模型名、请求怎么写、1K/2K/4K 和画面比例怎么设、图生图怎么传参考图、返回的图片怎么取,并给出 curl、Python、Node.js 示例和常见报错的解决办法。
📌 一句话答案: 用香蕉生图分组的 Key,POST 到 https://apikl.ai/v1beta/models/gemini-nano-banana-2.1:generateContent(模型名换成你分组里的),请求头带 x-goog-api-key: 你的Key,请求体按 Gemini 格式写 contents 和 generationConfig;图片在返回的 candidates[0].content.parts[].inlineData.data 里(base64,与 Google 官方格式相同);线路调整时偶尔可能改为图片链接,建议取图代码两种都处理。不要 用 /v1/images/generations,那是 GPT 生图的接口。
项目 内容 接口地址 https://apikl.ai/v1beta/models/模型名:generateContent;默认线路卡住或超时,把域名换成直连线路 dc.apikl.ai,路径不变请求方式 POST,JSON 请求体,不支持流式 鉴权 请求头 x-goog-api-key: 你的API Key(也认 Authorization: Bearer 你的API Key) 接口格式 与 Google Gemini API 的 generateContent 相同,可以直接用 Google 官方 SDK(google-genai) 返回 candidates[0].content.parts 里带 inlineData 的那一段就是图片(base64),可能还附带一段文字说明;线路调整时偶尔会改为图片链接(fileData.fileUri 和文字里的 ),示例代码已兼容
先选分组:香蕉生图用哪个模型名
API 快连里一把 Key 只能调它所在分组的模型 。香蕉生图有五个分组,先在 控制台 创建 Key 时选好分组,再按下表把模型名写进网址:
控制台分组 网址里的模型名 出图耗时参考 gemini-nano-banana-2.1(香蕉生图) gemini-nano-banana-2.12K 约 30–45 秒,4K 约 1 分钟 gemini-3.1-flash-image(香蕉生图) gemini-3.1-flash-image1K 约 20 秒 gemini-3-pro-image(香蕉生图) gemini-3-pro-image1K 约 30 秒 gemini-3.1-flash-image-preview(香蕉生图) gemini-3.1-flash-image-preview最快,1K 约 10 秒,2K 约 20 秒,4K 约 40 秒 gemini-3-pro-image-preview(香蕉生图) gemini-3-pro-image-preview2K 约 45 秒,4K 约 1 分钟,偶尔到 1 分半
⚠️ 模型名写在
网址路径里 (
/v1beta/models/模型名:generateContent),不是写在请求体里。模型名和 Key 的分组对不上,会返回
404 Model "xxx" is not available for this group。注意带不带
-preview 是两个不同的分组。各分组的价格以
模型广场 为准,按出图张数计费。
五个分组目前都按 Google 官方格式返回 base64 图片 (inlineData)。线路调整时偶尔可能改为返回图片链接,所以取图代码建议两种都处理 (本文所有示例都已处理),这样线路怎么变你的程序都不用改。图片链接能保留多久没有保证,拿到后请尽快下载保存,不要直接把链接长期存进你的业务数据里。
文生图:一条 curl 出图
把 sk-你的密钥 换成 gemini-nano-banana-2.1(香蕉生图) 分组的 Key,在终端运行(用其它香蕉分组就把网址里的模型名换掉):
BASH 复制
curl -sS "https://apikl.ai/v1beta/models/gemini-nano-banana-2.1:generateContent" \ -H "x-goog-api-key: sk-你的密钥" \ -H "Content-Type: application/json" \ --max-time 300 \ -d '{ "contents": [{"role": "user", "parts": [{"text": "一只橘猫坐在窗台上,午后阳光,写实摄影"}]}], "generationConfig": { "responseModalities": ["TEXT", "IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"} } }' \ -o result.json
返回的 JSON 存在 result.json 里,结构大致如下,图片是 inlineData.data 里的 base64:
JSON 复制
{ "candidates": [{ "content": { "role": "model", "parts": [ {"text": "这是为你生成的图片……"}, {"inlineData": {"mimeType": "image/png", "data": "iVBORw0KGgo……(图片的 base64)"}} ] }, "finishReason": "STOP" }], "usageMetadata": {"promptTokenCount": 12, "candidatesTokenCount": 1290} }
如果遇到线路返回的是图片链接,结构是这样的:fileData.fileUri 给一个链接,后面的文字里用 Markdown 格式  再给一遍,是同一张图 ,下载一次就行。链接能保留多久没有保证,拿到后尽快下载:
JSON 复制
{ "candidates": [{ "content": { "role": "model", "parts": [ {"fileData": {"mimeType": "image/png", "fileUri": "https://图片地址/xxxx.png"}}, {"text": ""} ] }, "finishReason": "STOP" }], "usageMetadata": {"promptTokenCount": 7, "candidatesTokenCount": 643} }
用下面这段 Python 把图片存成文件,两种返回都能处理:
Python 复制
# 把 result.json 里的图片保存成文件:base64 图片和图片链接两种返回都能处理 import base64, json, os, re, urllib.parse, urllib.request LINK = re.compile(r"!\[[^\]]*\]\((https?://[^)\s]+)\)") # 文字里的  data = json.load(open("result.json", encoding="utf-8")) if "candidates" not in data: raise SystemExit(f"没有出图:{data}") images, urls = [], [] for part in data["candidates"][0]["content"]["parts"]: if part.get("thought"): continue # 跳过思考过程里的草图 if "inlineData" in part: images.append(base64.b64decode(part["inlineData"]["data"])) elif "fileData" in part: urls.append(part["fileData"]["fileUri"]) elif "text" in part: found = LINK.findall(part["text"]) urls += found if not found: print("模型说明:", part["text"]) n = 0 for img in images: n += 1 with open(f"out-{n}.png", "wb") as f: f.write(img) print("已保存", f"out-{n}.png") for url in dict.fromkeys(urls): # 同一张图可能出现两次,去重 n += 1 ext = os.path.splitext(urllib.parse.urlparse(url).path)[1] or ".png" urllib.request.urlretrieve(url, f"out-{n}{ext}") print("已下载", f"out-{n}{ext}", url) if n == 0: print("这次没有返回图片,换个提示词再试")
Windows 用户:PowerShell 里的 curl 是别名,参数写法不同,单引号里的 JSON 也容易被拆坏,请改用 curl.exe,或者直接用下面的 Python / Node.js 示例。
常用参数
参数 说明 contents[].parts必填。文字要求放 {"text": ...},参考图放 {"inlineData": ...},中文英文都可以 generationConfig.responseModalities写 ["TEXT", "IMAGE"],表示要返回图片 generationConfig.imageConfig.imageSize清晰度:1K / 2K / 4K,K 要大写 ;不填按 2K generationConfig.imageConfig.aspectRatio画面比例,例如 1:1、16:9、9:16、4:3、3:4、3:2、2:3、21:9;不填由模型决定(图生图时一般跟参考图走)
一次请求按 1 张图来设计 。要多张就并行发多个请求,注意别超过账号的并发限制。
不要用流式 :把 :generateContent 换成 :streamGenerateContent 会返回 Streaming is not supported for image models.。
超时设 5 分钟以上 :上面的表里 4K 图常要 1 分钟左右,程序超时别设 30 秒或 60 秒。
图生图:传参考图改图
香蕉生图的图生图还是同一个接口 ,不用换地址:在 parts 里先放参考图(inlineData,base64,不要带网页里常见的 data:image/… 开头前缀),再放文字要求。多张参考图就放多个 inlineData,在提示词里说清楚第几张图是什么:
JSON 复制
{ "contents": [{ "role": "user", "parts": [ {"inlineData": {"mimeType": "image/png", "data": "第一张参考图的 base64"}}, {"inlineData": {"mimeType": "image/jpeg", "data": "第二张参考图的 base64"}}, {"text": "让第一张图里的模特穿上第二张图里的外套,白色背景"} ] }], "generationConfig": { "responseModalities": ["TEXT", "IMAGE"], "imageConfig": {"aspectRatio": "3:4", "imageSize": "2K"} } }
mimeType 要和图片实际格式一致:png 填 image/png,jpg 填 image/jpeg,webp 填 image/webp。
参考图别太大 :base64 会让体积变大三分之一,图太大、太多或网络慢时会返回 400 Failed to read request body 或 413 Request Entity Too Large。建议每张先压到 2–3 MB 以内(长边 2048 左右足够),一次 1–4 张。
参考图里有真人照片、名人、版权角色时更容易被安全审核拦下,见下面的常见报错。
用 Python 调用
把 Key 放进环境变量 APIKL_KEY(macOS / Linux:export APIKL_KEY=sk-你的密钥;Windows PowerShell:$env:APIKL_KEY="sk-你的密钥")。下面用最常见的 requests 库,一段代码同时演示文生图和图生图:
Python 复制
# pip install requests import base64, os, re, urllib.parse, requests KEY = os.environ["APIKL_KEY"] MODEL = "gemini-nano-banana-2.1" # 换成你这把 Key 所在分组的模型名 URL = f"https://apikl.ai/v1beta/models/{MODEL}:generateContent" LINK = re.compile(r"!\[[^\]]*\]\((https?://[^)\s]+)\)") # 文字里的  def save_images(data, prefix): """取出图片并保存:base64(inlineData)直接解码,链接(fileData 或文字里的 )下载""" images, urls = [], [] for part in data["candidates"][0]["content"]["parts"]: if part.get("thought"): continue # 跳过思考过程里的草图 if "inlineData" in part: images.append(base64.b64decode(part["inlineData"]["data"])) elif "fileData" in part: urls.append(part["fileData"]["fileUri"]) elif "text" in part: urls += LINK.findall(part["text"]) n = 0 for img in images: n += 1 with open(f"{prefix}-{n}.png", "wb") as f: f.write(img) for url in dict.fromkeys(urls): # 同一张图可能出现两次,去重 n += 1 ext = os.path.splitext(urllib.parse.urlparse(url).path)[1] or ".png" img = requests.get(url, timeout=120) img.raise_for_status() with open(f"{prefix}-{n}{ext}", "wb") as f: f.write(img.content) return n def generate(parts, size="2K", ratio=None, prefix="out"): image_config = {"imageSize": size} if ratio: image_config["aspectRatio"] = ratio body = { "contents": [{"role": "user", "parts": parts}], "generationConfig": { "responseModalities": ["TEXT", "IMAGE"], "imageConfig": image_config, }, } r = requests.post(URL, headers={"x-goog-api-key": KEY}, json=body, timeout=300) data = r.json() if r.status_code != 200 or "candidates" not in data: raise RuntimeError(f"没有出图 {r.status_code}: {data}") return save_images(data, prefix) # 文生图:16:9 的 2K 图 generate([{"text": "一只橘猫坐在窗台上,午后阳光,写实摄影"}], size="2K", ratio="16:9", prefix="cat") # 图生图:先放参考图,再放文字要求 with open("photo.png", "rb") as f: photo = base64.b64encode(f.read()).decode() generate( [ {"inlineData": {"mimeType": "image/png", "data": photo}}, {"text": "把这张照片改成水彩画风格,保留人物姿势"}, ], size="2K", prefix="watercolor", )
用 Google 官方 SDK(google-genai)
已经在用 Google 官方 SDK 的程序,只要把 base_url 指向 https://apikl.ai(不带 /v1beta ,SDK 会自己拼),api_key 换成 API 快连的 Key:
Python 复制
# pip install google-genai import os, re, urllib.request from google import genai from google.genai import types client = genai.Client( api_key=os.environ["APIKL_KEY"], http_options=types.HttpOptions(base_url="https://apikl.ai", timeout=300_000), # 毫秒 ) resp = client.models.generate_content( model="gemini-nano-banana-2.1", contents="一只橘猫坐在窗台上,午后阳光,写实摄影", config=types.GenerateContentConfig( response_modalities=["TEXT", "IMAGE"], image_config=types.ImageConfig(aspect_ratio="16:9", image_size="2K"), ), ) urls = [] for i, part in enumerate(resp.candidates[0].content.parts): if part.thought: continue if part.inline_data: # base64 图片,SDK 已解码成字节 with open(f"cat-{i}.png", "wb") as f: f.write(part.inline_data.data) elif part.file_data: # 图片链接 urls.append(part.file_data.file_uri) elif part.text: # 文字里的  urls += re.findall(r"!\[[^\]]*\]\((https?://[^)\s]+)\)", part.text) for j, url in enumerate(dict.fromkeys(urls), 1): # 去重后下载 urllib.request.urlretrieve(url, f"cat-link-{j}.png")
用 Node.js 调用(不装 SDK)
Node.js 18 及以上自带 fetch,不用装任何包。保存成 banana.mjs,运行 APIKL_KEY=sk-你的密钥 node banana.mjs(Windows PowerShell 先设环境变量,再运行 node banana.mjs):
Node.js 复制
// Node.js 18 及以上,自带 fetch;保存为 banana.mjs 运行 import { readFileSync, writeFileSync } from "node:fs"; const MODEL = "gemini-nano-banana-2.1"; // 换成你这把 Key 所在分组的模型名 const URL = `https://apikl.ai/v1beta/models/${MODEL}:generateContent`; async function generate(parts, prefix, imageConfig = { imageSize: "2K" }) { const res = await fetch(URL, { method: "POST", headers: { "x-goog-api-key": process.env.APIKL_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ contents: [{ role: "user", parts }], generationConfig: { responseModalities: ["TEXT", "IMAGE"], imageConfig }, }), signal: AbortSignal.timeout(300_000), }); const data = await res.json(); if (!res.ok || !data.candidates) throw new Error(`没有出图 ${res.status}: ${JSON.stringify(data)}`); // 图片有两种返回:inlineData 里的 base64,或者链接(fileData 或文字里的 ) const urls = new Set(); // Set 自动去重,同一张图可能出现两次 let n = 0; for (const part of data.candidates[0].content.parts) { if (part.thought) continue; // 跳过思考过程里的草图 if (part.inlineData) { n += 1; writeFileSync(`${prefix}-${n}.png`, Buffer.from(part.inlineData.data, "base64")); } else if (part.fileData) { urls.add(part.fileData.fileUri); } else if (part.text) { for (const m of part.text.matchAll(/!\[[^\]]*\]\((https?:\/\/[^)\s]+)\)/g)) urls.add(m[1]); } } for (const url of urls) { const img = await fetch(url, { signal: AbortSignal.timeout(120_000) }); if (!img.ok) throw new Error(`图片下载失败 ${img.status}: ${url}`); n += 1; const ext = new globalThis.URL(url).pathname.match(/\.\w+$/)?.[0] ?? ".png"; writeFileSync(`${prefix}-${n}${ext}`, Buffer.from(await img.arrayBuffer())); } return n; } // 文生图 await generate([{ text: "一只橘猫坐在窗台上,午后阳光,写实摄影" }], "cat", { aspectRatio: "16:9", imageSize: "2K" }); // 图生图 const photo = readFileSync("photo.png").toString("base64"); await generate( [{ inlineData: { mimeType: "image/png", data: photo } }, { text: "把这张照片改成水彩画风格,保留人物姿势" }], "watercolor", );
让 Codex、Cursor 等 AI 帮你写对接代码
让 AI 编程工具接香蕉生图时,它们常常默认按 OpenAI 的 /v1/images/generations 去写,结果返回 404 Images API is not supported for this platform。把这篇文章的网址发给它,或者在要求里写清楚这几点:
用 Gemini 原生接口 POST https://apikl.ai/v1beta/models/gemini-nano-banana-2.1:generateContent,请求头 x-goog-api-key;
请求体 generationConfig 里写 responseModalities 和 imageConfig.imageSize;不开流式;超时 5 分钟;
图生图把参考图以 inlineData 放在同一个请求的 parts 里;
从 candidates[0].content.parts 里取图:有 inlineData.data 就 base64 解码保存(正常情况);兼容处理图片链接,有 fileData.fileUri 或文字里的  就下载链接(同一个链接去重);跳过 thought: true 的段落。
只想用 Gemini 文字模型(聊天、写代码)请看 Gemini API / CLI 接入教程 ;GPT 生图(gpt-image-2.5 等)用的是 OpenAI 格式,见 GPT Image 2.5 生图 API 接入教程 。
常见报错
报错 原因 怎么办 404 Images API is not supported for this platform用了 OpenAI 的 /v1/images/generations 或 /v1/images/edits 改用 /v1beta/models/模型名:generateContent 404 Model "xxx" is not available for this group404 Model "xxx" is not supported by any configured account in this group网址里的模型名和 Key 的分组对不上(常见是多写或漏写了 -preview) 对照上面的分组表改模型名,或换对应分组的 Key 400 Unable to show the generated image ...400 ... rejected by content or copyright safeguards451 ... model returned no image提示词或生成结果触发了 Google 的内容安全审核 调整提示词,避开敏感、真人名人、版权角色等内容后重试 400 The model could not generate output because the input image violates ...参考图本身没通过安全审核 换一张参考图 400 Failed to read request body413 Request Entity Too Large参考图太大、太多,或网络慢没传完 压缩参考图、减少张数;换直连线路 dc.apikl.ai 400 Streaming is not supported for image models.用了 :streamGenerateContent 改回 :generateContent 403 Insufficient account balance403 insufficient balance余额不足(并发多时会为进行中的请求预留额度) 充值,或减少同时进行的请求 429 ...502 Upstream service temporarily unavailable高峰期线路繁忙 稍等几秒重试;程序里加 2–3 次重试 超时 / 524 客户端超时设得太短,或默认线路网络不稳 超时设到 5 分钟以上,或换直连线路
生图失败一般不扣费;使用记录里能看到每张图的扣费明细。更多状态码见 API 报错大全 。
常见问题
能用 OpenAI 的 SDK 或 /v1/chat/completions 调香蕉生图吗?
不建议。OpenAI 的 images 接口对香蕉模型直接返回 404;对话接口返回图片的格式各家不统一,程序不好解析。写程序请统一用本文的 generateContent 原生接口。
五个香蕉分组怎么选?
要快先试 gemini-3.1-flash-image 或 gemini-3.1-flash-image-preview;更看重画质和复杂指令可以对比 gemini-nano-banana-2.1、gemini-3-pro-image 和 gemini-3-pro-image-preview 的出图效果。各分组价格以模型广场为准,建议用同一个提示词各跑一张再决定。
一把 Key 能同时调香蕉生图和 GPT 生图吗?
不能。一把 Key 只绑一个分组,香蕉生图分组的 Key 只能调这个分组的模型。需要多个模型,就在控制台建多把 Key,账户余额是共用的。
返回里只有文字没有图片怎么办?
先确认请求里写了 responseModalities 包含 IMAGE;再看文字里有没有  这样的链接,有的话图片就在链接里,下载即可(见上面的取图代码)。都没有的话,多半是提示词被模型婉拒了,看返回的文字说明调整提示词再试。