跳转到内容

香蕉生图指南 ​

通过 Gemini 兼容接口调用 Nano Banana 系列图像模型。本页介绍文生图、图生图及参数用法;不同模型的宽高比、参考图数量和分辨率支持可能不同,未确认的能力不作统一承诺。

  • Base URL — https://api.llmnex.com
  • 香港加速端点 — https://hk.llmnex.com
  • 协议 — Gemini generateContent
  • 可用模型 — 以当前 Key 的模型列表为准
  • 分辨率 — 按具体模型确认,不保证所有模型具有相同输出尺寸

概览 ​

请求采用 Gemini 兼容格式,基础地址使用 https://api.llmnex.com,API Key 使用本站签发的 Key;还需按本页配置输出模态与模型支持的参数。香港加速可使用 https://hk.llmnex.com,路径和鉴权方式不变。https://www.llmnex.com 仅用于控制台,不用于 API 接入。

项值
Base URLhttps://api.llmnex.com
香港加速端点https://hk.llmnex.com
生图端点POST /v1beta/models/{model}:generateContent
流式端点POST /v1beta/models/{model}:streamGenerateContent
返回形态下文 IMAGE 生图示例使用 inlineData 内嵌 base64;按响应的 mimeType 识别图片格式
单次出图示例按 1 张图片处理,不依赖 candidateCount 请求多图
用量统计非流式响应带 usageMetadata(token 数),见 响应结构

模型名可用于确认调用目标和计费方式,但不能据此推断全部能力。尤其是 gemini-nano-banana-2.1,目前仅确认模型名称及后端 Nano Banana 2.1,其余能力请向服务方确认。

鉴权 ​

两种鉴权方式任选其一。使用 Google 官方 SDK 时,还需按所用 SDK 的配置方式设置基础地址、API Key 和输出模态;本页提供 HTTP 示例,不保证所有 SDK 版本仅替换地址即可使用。

http
Authorization: Bearer YOUR_API_KEY
http
x-goog-api-key: YOUR_API_KEY

密钥保管

Key 形如 sk-xxxxxxxx。请放在服务端调用,不要写进前端代码或客户端 App。

快速开始 ​

生图必须明确指定 IMAGE

为兼容首字快速响应,后端已兼容 TEXT 模式。要生成图片,必须在 generationConfig.responseModalities 中明确包含 "IMAGE",建议使用 "responseModalities": ["IMAGE"]。省略该参数或仅指定 TEXT 时,Pro 模型可能生成文字,而不是图片。

bash
curl -X POST "https://api.llmnex.com/v1beta/models/gemini-3-pro-image-c:generateContent" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --max-time 300 \
  -d '{
    "contents": [
      { "parts": [ { "text": "a red ceramic teapot on a wooden table, soft daylight" } ] }
    ],
    "generationConfig": { "responseModalities": ["IMAGE"] }
  }'
bash
set -o pipefail
curl -fsS -X POST "https://api.llmnex.com/v1beta/models/gemini-3-pro-image-c:generateContent" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" --max-time 300 \
  -d '{"contents":[{"parts":[{"text":"a red ceramic teapot"}]}],"generationConfig":{"responseModalities":["IMAGE"]}}' \
  | python3 -c "import sys,json,base64;
d=json.load(sys.stdin);
candidates=d.get('candidates') or [];
parts=(candidates[0].get('content',{}).get('parts') or []) if candidates else [];
b=next((p.get('inlineData',{}).get('data') for p in parts if p.get('inlineData',{}).get('data')),None);
if not b: sys.exit('响应中未找到图片,请检查 responseModalities、模型支持情况及响应内容');
image=base64.b64decode(b,validate=True);
open('out.png','wb').write(image);
print('saved out.png')"

模型与分辨率 ​

模型名后缀区分计费方式,不再表示固定分辨率。 带 -c 按次计费,不带 -c 按 token 计费。实际可用名称请先 查询模型列表,具体价格与扣费以控制台及账单为准。

模型族后端特点
gemini-3-pro-imageNano Banana ProPro 系列,效果与耗时依请求而异,不作绝对排名
gemini-3.1-flash-imageNano Banana 2Flash 系列,效果与耗时请结合业务验证
gemini-nano-banana-2.1Nano Banana 2.1新增香蕉模型,具体能力以模型说明为准

模型命名示例(实际可用名称以当前 Key 的列表为准):

模型名称计费方式
gemini-3-pro-image-c按次计费
gemini-3-pro-image按 token 计费

旧版固定分辨率后缀模型已下线,请更新调用时的完整模型名,不要在未确认计费方式时自动切换。

后缀 -c:分辨率交给调用方 ​

-c 结尾的模型不锁定分辨率,由你在请求里用 generationConfig.imageConfig.imageSize 指定。不传则为 1K。

json
{
  "contents": [ { "parts": [ { "text": "a plain grey cube" } ] } ],
  "generationConfig": {
    "responseModalities": ["IMAGE"],
    "imageConfig": { "imageSize": "4K" }
  }
}

本页 -c 示例使用的 imageSize 取值为 1K / 2K / 4K。不要传入 512 等未列出的值,也不要依赖无效值自动回落;具体模型的支持范围请先确认。

不带 -c 的模型

不带 -c 的模型按 token 计费。其分辨率参数支持情况请以具体模型说明为准,不要沿用已下线模型的固定分辨率规则。

关于 4K

4K 表示分辨率档位,不是固定宽高保证。请读取返回图片的实际尺寸,不要硬编码为 4096 × 4096,也不要假设不同模型具有相同尺寸规则。

请求体结构 ​

与 Gemini 官方格式一致。生图请求除 contents 外,还必须明确设置 generationConfig.responseModalities 包含 "IMAGE",不要仅依赖提示词要求模型画图。

字段类型说明
contents[].parts[].textstring提示词。多个 text part 会用空格拼接
contents[].parts[].inlineDataobject内嵌参考图,见「图生图」;数量限制需按具体模型确认
generationConfig.responseModalitiesstring[]生图必须明确包含 "IMAGE",建议 ["IMAGE"];后端兼容 TEXT 模式,省略或仅传 TEXT 时 Pro 模型可能生成文字
generationConfig.imageConfig.aspectRatiostring宽高比,如 "16:9"。默认 1:1
generationConfig.imageConfig.imageSizestring-c 模型可选 1K/2K/4K;不带 -c 的模型请确认具体参数支持情况
json
{
  "contents": [
    { "parts": [ { "text": "a lighthouse on a cliff at dawn, cinematic" } ] }
  ],
  "generationConfig": {
    "responseModalities": ["IMAGE"],
    "imageConfig": { "aspectRatio": "16:9" }
  }
}

宽高比 ​

旧文档列出的比例包括:1:1 16:9 9:16 4:3 3:4 3:2 2:3 5:4 4:5 21:9 1:4 4:1 1:8 8:1。这不是所有当前模型的统一支持列表,使用前请确认目标模型支持的比例。

以下尺寸仅为旧文档的 1K 历史样例,未标明适用模型,不作为当前模型的输出保证;实际尺寸以返回图片为准:

aspectRatio1K 历史样例尺寸典型用途
1:11024 × 1024头像、商品图
16:91376 × 768横版封面、视频首帧
9:16768 × 1376竖屏短视频、手机壁纸
4:31200 × 896传统照片比例
21:91584 × 672超宽横幅
4:5928 × 1152社交媒体竖图

提示

不要按上述样例推算 2K / 4K 的固定尺寸,也不要依赖未支持的比例自动回落。参数不受支持时,请修正请求,而不是假设服务一定忽略该值。

超长比例需单独确认

旧文档标注 gemini-3-pro-image 系列不支持 1:4、4:1、1:8、8:1;在重新确认前,Pro 请求请避开这四种比例。其他模型(包括 Nano Banana 2.1)的支持情况及像素规则需向服务方确认,不沿用旧样例的倍数或报错规则。

图生图 ​

在 parts 里加入 inlineData 即为图生图。文字描述你想要的改动,参考图提供内容或风格来源。

json
{
  "contents": [
    {
      "parts": [
        { "text": "把这张照片改成水彩画风格,保留构图" },
        {
          "inlineData": {
            "mimeType": "image/png",
            "data": "iVBORw0KGgoAAAANSUhEUg..."
          }
        }
      ]
    }
  ],
  "generationConfig": { "responseModalities": ["IMAGE"] }
}
约束值
参考图数量示例使用 1 张;多图支持及数量上限需按具体模型确认
格式PNG / JPEG / WebP,由 mimeType 声明
编码纯 base64,不要带 data:image/png;base64, 前缀
输出分辨率-c 模型由 imageSize 指定,与输入图尺寸无关

不生效的参数 ​

以下是旧文档记录的兼容限制,尚未逐模型重新验证。接入时请保守处理,不依赖这些参数;不保证所有模型都会接受参数或返回相同结果:

参数实际行为
generationConfig.candidateCount本页示例按 1 张图处理,不依赖该参数请求多图
generationConfig.seed接受,但不保证跨请求复现,同 seed 同提示词也可能出不同的图
tools 里的 googleSearch不联网,响应无 groundingMetadata
generationConfig.thinkingConfig不生效,响应无思考 token 计数
contents[].parts[].fileData(URL 参考图)不读取,参考图请用 inlineData 内嵌

流式返回(不建议使用) ​

建议用非流式的 :generateContent

以下为旧文档记录的 IMAGE 生图流式行为,未逐模型复测;不适用于 TEXT 首字快速响应,也不承诺新模型行为完全相同。

图像是一次性生成的,没有中间产物可以流式推送。这个端点会先等整张图出完, 再把最终结果包成单个 SSE chunk 发出 —— chunk 里的内容与 generateContent 的响应体一致,只是没有 usageMetadata。

也就是说,你付出了 SSE 解析的成本,却拿不到任何流式的好处:

  • 不会更早看到画面,等待时间与非流式完全一致
  • 不能保持连接活跃 —— 出图期间服务端不发送任何字节,防不了中间层空闲超时
  • 整张图的 base64 挤在一行 data: 里,常见 7–11 MB,部分 SSE 客户端和反向代理 对单行长度有限制,反而更容易被截断
  • 出错时不走 SSE,直接返回 JSON 错误体,客户端要额外处理两种响应格式
  • 不返回 usageMetadata,需要用量统计必须用非流式

建议为客户端及中间层配置足够的超时余量;仅增加客户端超时不能保证避开代理或网关的超时,见下方「超时与耗时」。

保留该端点是为了兼容已有代码。用法是把端点换成 :streamGenerateContent, 返回 SSE 格式,每行以 data: 开头。

bash
curl -N -X POST "https://api.llmnex.com/v1beta/models/gemini-3-pro-image-c:streamGenerateContent" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" --max-time 300 \
  -d '{"contents":[{"parts":[{"text":"a plain grey cube"}]}],"generationConfig":{"responseModalities":["IMAGE"]}}'

响应结构 ​

以下为明确指定 responseModalities: ["IMAGE"] 后成功返回图片的非流式响应示例(gemini-3-pro-image-c),不是 TEXT 模式或错误响应的结构保证:

json
{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [
          {
            "inlineData": {
              "mimeType": "image/png",
              "data": "iVBORw0KGgoAAAANSUhEUgAABAAA..."
            }
          }
        ]
      },
      "finishReason": "STOP",
      "index": 0
    }
  ],
  "responseId": "ee2bcd924c5d",
  "upstreamJobId": "d427bc37-0f6c-458b-93c9-d40a0b5412f7",
  "usageMetadata": {
    "promptTokenCount": 4,
    "promptTokensDetails": [ { "modality": "TEXT", "tokenCount": 4 } ],
    "candidatesTokenCount": 1120,
    "candidatesTokensDetails": [ { "modality": "IMAGE", "tokenCount": 1120 } ],
    "totalTokenCount": 1124
  }
}

成功生图时,从 candidates[0].content.parts 中遍历查找 inlineData.data,不要写死 parts[0]。先检查 HTTP 状态,再检查候选内容及图片是否存在;响应缺少图片时应报告错误,不要直接解码或写文件。

字段类型说明
candidates[]array示例取第一个候选;使用前检查是否存在
candidates[].content.rolestring示例为 model
candidates[].content.parts[].inlineData.mimeTypestring示例为 image/png,以实际响应为准
candidates[].content.parts[].inlineData.datastring图片的 base64 数据,需检查存在后再解码
candidates[].finishReasonstring正常出图为 STOP
candidates[].indexinteger示例为 0
responseIdstring本站请求 ID,与响应头 X-Oneapi-Request-Id 相同
upstreamJobIdstring上游任务号,报障时连同 responseId 一起附上
usageMetadataobject本次消耗的 token 数,见下

上述示例只展示 IMAGE 生图结果。后端兼容 TEXT 模式,省略输出模态或仅指定 TEXT 时,Pro 模型可能在 parts[].text 返回文字;因此不能假定每个成功响应都有图片。promptFeedback、modelVersion、safetyRatings 等可选字段是否返回,请以实际响应为准,不作为取图的必需条件。

usageMetadata ​

usageMetadata 是本次请求消耗的 token 数,结构与官方一致:promptTokenCount(提示词与参考图)、 candidatesTokenCount(生成的图片)、totalTokenCount,以及 *Details 里按模态的拆分。 不同模型的用量字段与计算方式可能不同,不要按固定图片 token 数估算实际扣费。

三点说明

  • 旧文档记录的 IMAGE 流式请求(:streamGenerateContent)不返回 usageMetadata,尚未逐一确认所有模型与 TEXT 模式;需要用量统计建议使用非流式,并检查实际返回字段。
  • 旧文档将 promptTokenCount 标为估算值;各模型的用量精度与计算规则尚未逐一确认,请将其作为参考。
  • usageMetadata 是用量统计,不等于计费方式。带 -c 的模型按次计费,不带 -c 的模型按 token 计费,实际扣费以账户账单为准。

4K 图的响应体很大

旧文档中的 4K base64 响应样例约 25–28 MB,实际大小随模型与图片内容变化。请检查 HTTP 客户端与中间层的响应体上限, 并给传输留出时间:下方的耗时表是服务端出图时间,不含下载,弱网下 4K 建议把超时设到 600 秒。

超时与耗时 ​

当前生图速度较此前大幅提升,常见耗时参考如下,不代表时延保证。

为高峰期排队、重试和图片传输留出余量,客户端超时仍建议设到 300 秒。常见耗时不等于最长耗时,较短的超时设置仍可能导致请求中断。

档位服务端出图耗时参考
1K约 15–25 秒
2K约 15–35 秒
4K约 20–45 秒

以上是服务端出图时间,图片传输另计;响应体大小随模型与图片内容变化。 耗时受上游负载影响,高峰期可能拉长。服务内部已有重试机制,客户端不要叠加激进重试;参数、鉴权、权限及审核问题应先修正请求,临时故障的重试建议见下方错误处理。

错误处理 ​

HTTP含义怎么办
400请求体不合法,如 contents 缺失或为空检查 JSON 结构
401Key 无效或已过期检查 Authorization 头
429请求受限退避 2–5 秒后可尝试重试一次,不保证成功,不要循环重试
451内容被安全审核拦截终态,重试无用。 改提示词或参考图
500上游临时不可用,或网关内部错误稍后重试一次;持续出现请联系我们
503model_not_found —— 模型名写错,或你的 Key 没有该模型的权限见下
503其他消息(如 upstream session error)上游连接临时故障,退避后重试一次

请保留响应头 X-Oneapi-Request-Id;存在时在报障信息中附上,便于定位请求。不要公开 API Key。

json
{
  "error": {
    "message": "image_unsafe: The generated images appear to be unsafe.",
    "type": "invalid_request_error"
  }
}

不要对 451 自动重试

451 表示内容安全拦截,请修改提示词或参考图,不要对同一请求自动重试。不保证重复请求会得到相同审核结果,也不据此推断是否扣费。

503 No available channel for model ...

先排查模型名拼写、是否已下线及当前 Key 的权限,用 GET /v1/models 确认可用名称,不要直接自动重试。列表里没有目标模型时,联系服务方确认;列表中存在但仍报错时,也应附上请求 ID 排查,不能仅凭这条消息排除服务侧问题。

完整示例 ​

Python 示例需安装 requests,Node.js 示例使用支持内置 fetch 的运行环境。以下示例按 PNG 响应保存为 out.png;如实际 mimeType 不同,请使用对应文件扩展名。成功写入会覆盖当前目录的同名文件,请先备份。

python
import base64, requests

API_KEY = "YOUR_API_KEY"
BASE    = "https://api.llmnex.com"
MODEL   = "gemini-3-pro-image-c"

resp = requests.post(
    f"{BASE}/v1beta/models/{MODEL}:generateContent",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "contents": [{"parts": [{"text": "a lighthouse on a cliff at dawn"}]}],
        "generationConfig": {"responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": "16:9", "imageSize": "2K"}},
    },
    timeout=300,          # 为排队、重试和传输留出余量
)
resp.raise_for_status()

candidates = resp.json().get("candidates") or []
parts = (candidates[0].get("content", {}).get("parts") or []) if candidates else []
b64 = next((p.get("inlineData", {}).get("data") for p in parts if p.get("inlineData", {}).get("data")), None)
if not b64:
    raise RuntimeError("响应中未找到图片,请检查 responseModalities、模型支持情况及响应内容")
image = base64.b64decode(b64, validate=True)
with open("out.png", "wb") as f:
    f.write(image)
print("saved out.png")
javascript
import { writeFile } from "node:fs/promises";

const API_KEY = "YOUR_API_KEY";
const MODEL   = "gemini-3-pro-image-c";

const res = await fetch(
  `https://api.llmnex.com/v1beta/models/${MODEL}:generateContent`,
  {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      contents: [{ parts: [{ text: "a lighthouse on a cliff at dawn" }] }],
      generationConfig: { responseModalities: ["IMAGE"], imageConfig: { aspectRatio: "16:9", imageSize: "2K" } },
    }),
    signal: AbortSignal.timeout(300_000),   // 5 分钟
  }
);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);

const payload = await res.json();
const parts = payload.candidates?.[0]?.content?.parts ?? [];
const b64 = parts.find((p) => p.inlineData?.data)?.inlineData.data;
if (!b64) throw new Error("响应中未找到图片,请检查 responseModalities、模型支持情况及响应内容");
await writeFile("out.png", Buffer.from(b64, "base64"));
console.log("saved out.png");
python
import base64, requests

src = base64.b64encode(open("input.png", "rb").read()).decode()

resp = requests.post(
    "https://api.llmnex.com/v1beta/models/gemini-3-pro-image-c:generateContent",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"contents": [{"parts": [
        {"text": "把这张照片改成水彩画风格,保留构图"},
        {"inlineData": {"mimeType": "image/png", "data": src}},
    ]}], "generationConfig": {"responseModalities": ["IMAGE"]}},
    timeout=300,
)
resp.raise_for_status()
candidates = resp.json().get("candidates") or []
parts = (candidates[0].get("content", {}).get("parts") or []) if candidates else []
b64 = next((p.get("inlineData", {}).get("data") for p in parts if p.get("inlineData", {}).get("data")), None)
if not b64:
    raise RuntimeError("响应中未找到图片,请检查 responseModalities、模型支持情况及响应内容")
image = base64.b64decode(b64, validate=True)
with open("out.png", "wb") as f:
    f.write(image)

LLMNEX · 模型接入指南