林易文档
开放 API

Gemini 生图 API

用林易 Gemini 原生 v1beta 接口完成文生图、图片编辑与图生图,支持 HTTPS 参考图、1K / 2K / 4K、多画幅及 Base64 / URL 输入输出。

林易提供 Gemini 原生 v1beta 兼容接口,可直接调用 Gemini 图片模型完成文生图、图片编辑和图生图。

接口协议

Gemini 生图使用的是 Google Gemini 原生 generateContent 协议,不是 OpenAI 的 /v1/chat/completions,也不是 OpenAI Images 的 /v1/images/generations。

主端点:

POST https://linyiapi.ai/v1beta/models/{model}:generateContent

1. 接口总览

方法路径说明
GET/v1beta/models查询 Gemini 原生模型目录及图片能力矩阵
GET/v1beta/models/{model}查询指定模型、别名和 imageConfig 能力
POST/v1beta/models/{model}:generateContent文生图、图片编辑、图生图主接口
POST/v1beta/models/{model}:streamGenerateContentSSE 流式响应;?alt=sse 为可选兼容参数
GET/v1/models查询当前 Key 的 OpenAI 兼容模型列表,用于核对分组可路由模型
POST/v1/images/batches林易 Gemini 异步批量生图扩展接口;需要系统及分组开关启用,详见Gemini 批量生图 API

Base URL:

https://linyiapi.ai

图片场景通常不需要流式端点

streamGenerateContent 带不带 ?alt=sse 都返回 SSE。图片二进制不会像文本一样逐步增量输出,因此图片生成通常优先使用非流式 generateContent。


2. 鉴权

推荐:Gemini 原生请求头

x-goog-api-key: YOUR_API_KEY

兼容:Bearer 请求头

Authorization: Bearer YOUR_API_KEY

服务端按以下优先级读取 API Key:

  1. x-goog-api-key;
  2. Authorization: Bearer ...;
  3. x-api-key;
  4. /v1beta 路径的 ?key=... 查询参数。

不要把 Key 放进 URL

?api_key=... 已弃用并会返回 400。?key=... 虽然兼容,但容易被浏览器历史、反向代理和访问日志记录,生产环境请使用请求头。

典型鉴权错误:

{
  "error": {
    "code": 401,
    "message": "Invalid API key",
    "status": "UNAUTHENTICATED"
  }
}

API Key 必须绑定到 gemini 平台分组,否则不能调用 Gemini 原生接口。


3. 模型与可用性

Gemini 原生模型目录目前包含以下客户端模型 ID。模型是否能由某个 API Key 实际调用,还取决于该 Key 所在分组的模型配置:

模型 ID建议用途图片编辑说明
gemini-3.1-flash-image默认推荐已通过生产环境 inlineData 图片编辑实测
gemini-3.1-flash-image-preview预览兼容使用同一 generateContent 编辑协议,正式接入前建议单独验证
gemini-3-pro-image质量优先 / 复杂编辑使用同一 generateContent 编辑协议,以当前 Key 可用性为准
gemini-3-pro-image-previewPro 预览兼容使用同一编辑协议,执行模型以服务端响应为准
gemini-3.1-flash-lite-image轻量场景(仅 1K)低延迟场景,以当前 Key 可用性为准
gemini-3.1-flash-lite-image-previewLite 预览兼容(仅 1K)gemini-3.1-flash-lite-image 的预览别名

查询模型目录与当前 Key 可路由模型

curl 'https://linyiapi.ai/v1beta/models' \
  -H 'x-goog-api-key: YOUR_API_KEY'

响应中的 imageConfig.aspectRatios 和 imageConfig.imageSizes 是模型能力矩阵。-preview 别名还可能返回 aliasOf。

用于核对当前 Key 分组可路由模型的 OpenAI 兼容列表:

curl 'https://linyiapi.ai/v1/models' \
  -H 'Authorization: Bearer YOUR_API_KEY'

/v1beta/models 与 /v1/models 用途不同,返回集合可能不一致:前者提供 Gemini 原生目录和能力,后者反映当前 Key 在 OpenAI 兼容层可见的路由模型。最终能否调用仍以真实生成请求为准;未配置的模型会返回 404 NOT_FOUND。

查询单个模型能力:

curl 'https://linyiapi.ai/v1beta/models/gemini-3.1-flash-lite-image-preview' \
  -H 'x-goog-api-key: YOUR_API_KEY'

典型响应:

{
  "name": "models/gemini-3.1-flash-lite-image-preview",
  "baseModelId": "gemini-3.1-flash-lite-image-preview",
  "displayName": "Gemini 3.1 Flash Lite Image",
  "supportedGenerationMethods": ["generateContent", "streamGenerateContent"],
  "imageConfig": {
    "aspectRatios": ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"],
    "imageSizes": ["1K"]
  },
  "aliasOf": "gemini-3.1-flash-lite-image"
}

模型 ID 可能经过服务端映射

客户端提交的是请求模型 ID。林易支持兼容模型别名,因此请求模型名称不一定等于响应中的最终模型版本。

不要仅根据模型名称猜测是否可用:先用 /v1beta/models/{model} 查询能力,再用 /v1/models 核对当前 Key 的路由列表,并以真实生成请求的最终结果为准。


4. 快速开始:文生图

curl --request POST \
  'https://linyiapi.ai/v1beta/models/gemini-3.1-flash-image:generateContent' \
  --header 'x-goog-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "text": "一只戴着宇航员头盔的橘猫,电影感灯光,精致细节"
          }
        ]
      }
    ],
    "generationConfig": {
      "responseModalities": ["TEXT", "IMAGE"],
      "imageConfig": {
        "aspectRatio": "1:1",
        "imageSize": "1K"
      }
    }
  }'

默认使用 Base64 内联交付,成功后从下面的位置读取图片:

candidates[].content.parts[].inlineData.data

2K / 4K 或高并发场景建议设置 generationConfig.responseDelivery: "uri",改从 fileData.fileUri 读取图片 URL。


5. 文生图请求结构

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "电影感雨夜城市街景,霓虹灯倒映在湿润路面,广角构图"
        }
      ]
    }
  ],
  "generationConfig": {
    "responseModalities": ["TEXT", "IMAGE"],
    "imageConfig": {
      "aspectRatio": "16:9",
      "imageSize": "2K"
    }
  }
}

请求字段

字段类型必填默认值说明
contentsarray是—对话内容数组,至少包含一条用户消息
contents[].rolestring建议—用户输入使用 user
contents[].partsarray是—文本或输入图片片段
parts[].textstring文生图必填—图片提示词或编辑指令
contents[].parts[].inlineData.datastring否—单张参考图与 fileData.fileUri 二选一;多参考图请求可混用两种方式
contents[].parts[].inlineData.mimeTypestring否—Base64 参考图类型:image/png、image/jpeg、image/webp
contents[].parts[].fileData.fileUristring否—参考图的公网 HTTPS 地址;单张参考图与 inlineData.data 二选一
contents[].parts[].fileData.mimeTypestring否—URL 参考图声明类型;推荐与实际图片类型一致
generationConfigobject否—生成参数;整体省略也能生图
generationConfig.responseModalitiesstring[]否图片输出图片端点会按图片模式处理,显式传入时推荐包含 IMAGE
generationConfig.imageConfigobject否—图片分辨率和画幅配置
generationConfig.imageConfig.aspectRatiostring否1:1输出画幅,必须是目标模型支持的枚举
generationConfig.imageConfig.imageSizestring否模型默认大小写不敏感;Flash / Pro 支持 1K、2K、4K,Flash Lite 仅支持 1K
generationConfig.responseDeliverystring否inlineinline 返回 Base64,uri 返回图片 URL

参数层级要正确

画幅和分辨率必须放在 generationConfig.imageConfig;交付方式必须放在 generationConfig.responseDelivery。不要使用 responseFormat.image,也不要把 responseDelivery 放在请求体顶层;错误层级可能不会报错,但参数不会按预期生效。


6. 分辨率和画幅

支持的分辨率

imageSize推荐场景模型支持情况
1K草图、快速预览、批量筛选Flash、Flash Lite、Pro
2K常规交付、文章配图、电商素材Flash、Pro;Flash Lite 不支持
4K精细大图、高质量交付Flash、Pro;Flash Lite 不支持

imageSize 不区分大小写,1k、2k、4k 也能被服务归一化。推荐使用大写,以便与模型能力响应和示例保持一致:

{
  "imageSize": "2K"
}

imageSize 与 aspectRatio 一样都是模型级能力。gemini-3.1-flash-lite-image 及其 -preview 别名仅支持 1K;不要向 Lite 请求 2K 或 4K。

Flash / Pro 省略 imageSize 时当前默认使用 2K;Flash Lite 只支持 1K。为避免调用方误判费用或画质,生产请求建议显式传入,并先读取目标模型的 imageConfig.imageSizes。

支持的画面比例

aspectRatio 是模型级能力。仅 Flash 标准版支持四种超长画幅;Pro 与 Flash Lite 只支持通用比例。

通用 10 种比例:

1:1
2:3
3:2
3:4
4:3
4:5
5:4
9:16
16:9
21:9

Flash 扩展 4 种比例:

1:4
1:8
4:1
8:1

模型比例矩阵

客户端模型 ID确认支持的比例数量imageSize
gemini-3.1-flash-image通用 10 种 + Flash 扩展 4 种141K / 2K / 4K
gemini-3.1-flash-image-preview通用 10 种 + Flash 扩展 4 种141K / 2K / 4K
gemini-3.1-flash-lite-image仅通用 10 种10仅 1K
gemini-3.1-flash-lite-image-preview仅通用 10 种10仅 1K
gemini-3-pro-image仅通用 10 种101K / 2K / 4K
gemini-3-pro-image-preview仅通用 10 种101K / 2K / 4K

Pro 与 Flash Lite 不支持扩展比例

对 Pro 或 Flash Lite 模型及其 -preview 别名传入 1:4、1:8、4:1、8:1,会返回 INVALID_ARGUMENT、400,或在当前 Key 未配置该模型时返回 404 NOT_FOUND。例如:

{
  "error": {
    "code": 400,
    "message": "generationConfig.imageConfig.aspectRatio has an unsupported value",
    "status": "INVALID_ARGUMENT"
  }
}

Flash Lite 仅支持 1K

向 Flash Lite 或其 Preview 别名请求 2K / 4K 会被入口拒绝:

{
  "error": {
    "code": 400,
    "message": "Image size '2K' is not supported. Supported: 1K",
    "status": "INVALID_ARGUMENT"
  }
}

这是请求参数错误,不应重试。请改为 1K,或切换到支持 2K / 4K 的 Flash / Pro 模型。

上述矩阵以 Gemini 原生模型能力接口和实际请求校验为准。建议客户端启动时读取 /v1beta/models/{model} 的 imageConfig,不要长期硬编码比例与分辨率列表。未知或新模型在完成验证前,应使用通用 10 种。

不指定 aspectRatio 时,当前默认使用 1:1。不要传任意小数或任意 WIDTHxHEIGHT;必须使用目标模型接受的比例枚举。

示例(适用于支持 4K 的 Flash / Pro 模型):

{
  "generationConfig": {
    "responseModalities": ["TEXT", "IMAGE"],
    "imageConfig": {
      "aspectRatio": "9:16",
      "imageSize": "4K"
    }
  }
}

分辨率档位不是固定像素宽高

1K、2K、4K 是模型分辨率档位。图片的实际宽高由模型根据档位和画幅计算,客户端不应固定假设一定是 1024×1024、2048×2048 或 4096×4096。


7. 图片编辑 / 图生图

Gemini 支持图片编辑,只是没有类似 GPT 的独立 /v1/images/edits 端点。

文生图和图片编辑都调用:

POST /v1beta/models/{model}:generateContent

两者的区别是:

场景contents[].parts[] 内容
文生图只有文本提示词
图片编辑 / 图生图文本编辑指令 + inlineData Base64 或 fileData.fileUri HTTPS 参考图

生产环境已验证

使用 gemini-3.1-flash-image,通过 Base64 和公网 HTTPS URL 两种方式提交参考图,均已成功返回:

  • HTTP 200;
  • finishReason: STOP;
  • 非空图片结果;
  • usageMetadata 用量信息。

参考图输入使用 inlineData.data 或 fileData.fileUri;默认图片输出读取 inlineData.data,设置 generationConfig.responseDelivery: "uri" 后读取输出的 fileData.fileUri。当前图片服务通常返回 WebP,但客户端必须以每次响应的 mimeType 为准。响应可能只包含图片 part、不包含文本 part,客户端不能要求响应中必须同时存在文字。

7.1 最小图片编辑请求

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "保留人物、构图和光线,把背景修改成雨夜霓虹街道"
        },
        {
          "inlineData": {
            "mimeType": "image/png",
            "data": "INPUT_IMAGE_BASE64"
          }
        }
      ]
    }
  ],
  "generationConfig": {
    "responseModalities": ["TEXT", "IMAGE"],
    "imageConfig": {
      "aspectRatio": "1:1",
      "imageSize": "1K"
    }
  }
}

7.2 Base64 参考图字段

字段类型必填说明
contents[].parts[].textstring是编辑指令,应明确哪些内容需要保留、哪些内容需要修改
inlineData.mimeTypestring是白名单:image/png、image/jpeg、image/webp
inlineData.datastring是推荐传裸 Base64;也兼容 data:image/...;base64, Data URL 前缀
imageConfig.aspectRatiostring否输出画幅;需要保留输入比例时填写对应比例
imageConfig.imageSizestring否输出档位,以模型能力为准;Flash Lite 及其 Preview 别名仅支持 1K

推荐裸 Base64,也兼容 Data URL

推荐直接传不带前缀的裸 Base64:

/9j/4AAQSkZJRgABAQ...

如果现有客户端生成的是 Data URL,服务也会自动处理:

data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...

Base64 会增加请求体积。输入图片较大或并发较高时,建议改用下一节的 HTTPS URL 参考图。

7.3 使用 HTTPS URL 作为参考图

参考图已存放在自己的对象存储或 CDN 时,可以通过 fileData.fileUri 直接提交公网 HTTPS 图片地址,无需把图片编码进请求体。

下面的示例同时启用 URL 输出,实现参考图 URL 输入、生成图 URL 输出:

curl --request POST \
  'https://linyiapi.ai/v1beta/models/gemini-3.1-flash-image:generateContent' \
  --header 'x-goog-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "text": "把背景改成星空,保留主体与构图,不要添加文字"
          },
          {
            "fileData": {
              "mimeType": "image/png",
              "fileUri": "https://your-cdn.example.com/path/to/input.png"
            }
          }
        ]
      }
    ],
    "generationConfig": {
      "responseDelivery": "uri",
      "responseModalities": ["TEXT", "IMAGE"],
      "imageConfig": {
        "aspectRatio": "1:1",
        "imageSize": "1K"
      }
    }
  }'

成功时,生成图 URL 位于:

candidates[].content.parts[].fileData.fileUri

响应中的图片片段示例:

{
  "fileData": {
    "mimeType": "image/webp",
    "fileUri": "https://IMAGE_HOST/path/to/generated-image.webp"
  }
}

URL 参考图限制

  • 当前仅接受公网可达的 HTTPS URL,不要使用 HTTP、本机地址或内网地址;
  • 单张图片最大 50 MB;最多跟随 3 次重定向;拉取总超时约 30 秒;
  • 支持的实际图片格式为 PNG、JPEG、WebP,服务会校验图片真实内容,不只依赖声明的 mimeType;
  • 图片源站必须允许服务端直接访问,不能依赖浏览器 Cookie、登录态或交互式验证;
  • URL 被安全策略拒绝、源站返回非 200、图片过大或格式不支持时,接口返回 400 INVALID_ARGUMENT,这类错误不应重试,应该先修正 URL 或源站访问策略。

典型的 400 错误信息包括:

image_url rejected: ...
Failed to fetch image_url: 403
image too large, max 50MB

inlineData 与 fileData.fileUri 可以二选一,也可以在多参考图请求中混用;单次请求的参考图总数最多 6 张。

7.4 Base64 curl 完整示例

先把本地图片转换为不换行的 Base64:

IMAGE_BASE64=$(base64 < input.jpg | tr -d '\n')

然后调用图片模型:

curl --request POST \
  'https://linyiapi.ai/v1beta/models/gemini-3.1-flash-image:generateContent' \
  --header 'x-goog-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw "{
    \"contents\": [{
      \"role\": \"user\",
      \"parts\": [
        {
          \"text\": \"保留杯子、构图、光线和背景不变,只把杯子从蓝色改成紫色,并在杯身增加三个白色星形图案,不要添加文字\"
        },
        {
          \"inlineData\": {
            \"mimeType\": \"image/jpeg\",
            \"data\": \"${IMAGE_BASE64}\"
          }
        }
      ]
    }],
    \"generationConfig\": {
      \"responseModalities\": [\"TEXT\", \"IMAGE\"],
      \"imageConfig\": {
        \"aspectRatio\": \"3:2\",
        \"imageSize\": \"1K\"
      }
    }
  }"

7.5 Python 图片编辑示例

import base64
import requests

api_key = "YOUR_API_KEY"
model = "gemini-3.1-flash-image"
input_path = "input.jpg"

with open(input_path, "rb") as f:
    image_base64 = base64.b64encode(f.read()).decode("utf-8")

payload = {
    "contents": [{
        "role": "user",
        "parts": [
            {
                "text": "保留主体和构图,把背景改成雨夜霓虹街道"
            },
            {
                "inlineData": {
                    "mimeType": "image/jpeg",
                    "data": image_base64,
                }
            },
        ],
    }],
    "generationConfig": {
        "responseModalities": ["TEXT", "IMAGE"],
        "imageConfig": {
            "aspectRatio": "3:2",
            "imageSize": "1K",
        },
    },
}

response = requests.post(
    f"https://linyiapi.ai/v1beta/models/{model}:generateContent",
    headers={
        "x-goog-api-key": api_key,
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=300,
)
response.raise_for_status()
result = response.json()

saved = False
for candidate in result.get("candidates", []):
    for part in candidate.get("content", {}).get("parts", []):
        inline_data = part.get("inlineData", {})
        if inline_data.get("data"):
            mime_type = inline_data.get("mimeType", "image/png")
            extension = "jpg" if "jpeg" in mime_type else "webp" if "webp" in mime_type else "png"
            with open(f"gemini-edited.{extension}", "wb") as f:
                f.write(base64.b64decode(inline_data["data"]))
            saved = True
            break
    if saved:
        break

if not saved:
    raise RuntimeError("HTTP 请求成功,但响应中没有编辑后的图片")

7.6 编辑提示词建议

图片编辑提示词最好明确区分“保留项”和“修改项”:

保留:主体身份、姿势、镜头角度、构图和光线。
修改:把背景改成雨夜霓虹街道。
禁止:不要增加文字,不要改变人物脸部。

相比只写“把它改好看一些”,这种结构更容易获得稳定结果。

7.7 多张参考图

部分 Gemini 图片模型可以在同一个 parts[] 中接收多张 inlineData 或 fileData.fileUri 参考图,用于风格参考、人物参考或素材融合;两种输入方式可以混用。当前服务单次请求最多处理 6 张参考图;请不要超过该数量,避免多余图片被忽略。总请求体仍受网关大小限制,正式使用前应针对目标模型、图片尺寸和压缩方式单独验证。

不要仅因为 /v1beta/models 返回了某个图片模型,就假定它支持无限数量或无限大小的参考图。


8. 图片交付方式

实时生图和图片编辑支持两种响应交付方式。responseDelivery 是林易在 Gemini 兼容协议上的扩展字段。配合第 7.3 节的 fileData.fileUri URL 参考图输入,可实现 URL 输入、URL 输出,客户端请求和响应中都不需要携带图片 Base64:

responseDelivery图片字段适用场景
inlineparts[].inlineData.data默认模式;直接获得 Base64,适合小图或必须内联处理的客户端
uriparts[].fileData.fileUri推荐用于 2K / 4K 和高并发场景,避免大段 Base64 穿过网关

8.1 URL 交付(推荐大图使用)

responseDelivery 必须放在 generationConfig 内:

curl --request POST \
  'https://linyiapi.ai/v1beta/models/gemini-3.1-flash-image:generateContent' \
  --header 'x-goog-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "contents": [
      {
        "role": "user",
        "parts": [{"text": "极简绿色方块,白色背景,无文字"}]
      }
    ],
    "generationConfig": {
      "responseDelivery": "uri",
      "imageConfig": {
        "aspectRatio": "1:1",
        "imageSize": "1K"
      }
    }
  }'

成功响应中的图片片段:

{
  "fileData": {
    "mimeType": "image/webp",
    "fileUri": "https://IMAGE_HOST/path/to/generated-image.webp"
  }
}

客户端从以下路径读取图片 URL:

candidates[].content.parts[].fileData.fileUri

公开网关请使用请求体参数

请使用 generationConfig.responseDelivery: "uri"。不要把 responseDelivery 放在请求体顶层;顶层字段会被忽略。当前也不要依赖 x-image-delivery: uri 请求头,因为该请求头经过公开网关时可能不会稳定透传到图片服务。

图片 URL 的主机名和路径由服务端决定。客户端不要硬编码存储域名,也不要把 URL 当作永久存储凭证;如需长期保存,请在业务侧及时归档。

8.2 Base64 内联交付

省略 responseDelivery,或显式设置为 inline:

{
  "generationConfig": {
    "responseDelivery": "inline",
    "imageConfig": {
      "aspectRatio": "1:1",
      "imageSize": "1K"
    }
  }
}

图片数据路径:

candidates[].content.parts[].inlineData.data

Base64 会比原始二进制更大。对于 2K / 4K、图生图和高并发任务,优先使用 URI 交付可以明显降低客户端、网关和应用服务器的内存与网络开销。


9. 成功响应

典型响应:

{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [
          {
            "text": "已根据要求生成图片。"
          },
          {
            "inlineData": {
              "mimeType": "image/webp",
              "data": "BASE64_IMAGE_DATA"
            }
          }
        ]
      },
      "finishReason": "STOP",
      "index": 0
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 15,
    "candidatesTokenCount": 0,
    "totalTokenCount": 15,
    "creditsConsumed": 20
  },
  "modelVersion": "gemini-3.1-flash-image",
  "createTime": 1780000000,
  "responseId": "RESPONSE_ID"
}

关键响应字段

字段说明
candidates[]候选输出列表
candidates[].content.parts[]文本或图片片段
parts[].inlineData.mimeType返回图片 MIME 类型
parts[].inlineData.datainline 模式返回的图片 Base64 内容
parts[].fileData.mimeTypeuri 模式返回的图片 MIME 类型
parts[].fileData.fileUriuri 模式返回的图片 URL
candidates[].finishReason结束原因;常见成功值为 STOP
usageMetadata.promptTokenCount输入 Token 数
usageMetadata.totalTokenCount请求 Token 汇总
usageMetadata.creditsConsumed本次请求返回的 credits 消耗值
modelVersion服务实际执行的模型版本
createTime服务端创建时间
responseId响应标识;报障时建议一并提供

正确判断生图成功

客户端应同时检查:

  1. HTTP 状态码为 2xx;
  2. candidates 非空;
  3. 至少一个 parts[] 含有非空 inlineData.data 或 fileData.fileUri;
  4. inline 模式下 Base64 能成功解码,uri 模式下 URL 格式合法;
  5. 必要时检查 finishReason。

HTTP 200 不等于一定生成了图片

服务可能返回 HTTP 200,但响应中既没有 inlineData.data,也没有 fileData.fileUri。这类请求必须按“业务生图失败”处理,不能计入成功图片数。


10. Node.js 示例

import { writeFile } from 'node:fs/promises';

const BASE_URL = process.env.GEMINI_BASE_URL || 'https://linyiapi.ai';
const API_KEY = process.env.GEMINI_API_KEY;
const MODEL = 'gemini-3.1-flash-image';

if (!API_KEY) throw new Error('缺少 GEMINI_API_KEY');

const payload = {
  contents: [
    {
      role: 'user',
      parts: [
        { text: '日落时分的海边灯塔,水彩插画,温暖色调,细腻纸张纹理' },
      ],
    },
  ],
  generationConfig: {
    responseDelivery: 'uri',
    responseModalities: ['TEXT', 'IMAGE'],
    imageConfig: {
      aspectRatio: '16:9',
      imageSize: '2K',
    },
  },
};

const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 300_000);

try {
  const response = await fetch(
    `${BASE_URL}/v1beta/models/${encodeURIComponent(MODEL)}:generateContent`,
    {
      method: 'POST',
      headers: {
        'x-goog-api-key': API_KEY,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(payload),
      signal: controller.signal,
    },
  );

  const text = await response.text();
  let data;
  try {
    data = JSON.parse(text);
  } catch {
    throw new Error(`服务返回非 JSON 内容:HTTP ${response.status}`);
  }

  if (!response.ok) {
    throw new Error(
      `HTTP ${response.status}: ${data?.error?.message || JSON.stringify(data)}`,
    );
  }

  const parts = data.candidates?.flatMap((candidate) => candidate.content?.parts || []) || [];
  const imagePart = parts.find((part) => part.inlineData?.data || part.fileData?.fileUri);

  if (!imagePart) {
    const reasons = data.candidates?.map((candidate) => candidate.finishReason).filter(Boolean);
    throw new Error(`请求完成但没有图片,finishReason=${reasons?.join(',') || 'unknown'}`);
  }

  if (imagePart.fileData?.fileUri) {
    console.log('图片 URL:', imagePart.fileData.fileUri);
  } else {
    const mimeType = imagePart.inlineData.mimeType || 'application/octet-stream';
    const extension = mimeType === 'image/jpeg'
      ? 'jpg'
      : mimeType === 'image/webp'
        ? 'webp'
        : 'png';

    await writeFile(
      `gemini-output.${extension}`,
      Buffer.from(imagePart.inlineData.data, 'base64'),
    );
    console.log(`图片已保存为 gemini-output.${extension}`);
  }

  console.log('responseId:', data.responseId || null);
  console.log('usageMetadata:', data.usageMetadata || null);
} finally {
  clearTimeout(timer);
}

11. Python 示例

import base64
import os
from pathlib import Path
import requests

BASE_URL = os.getenv("GEMINI_BASE_URL", "https://linyiapi.ai")
API_KEY = os.environ["GEMINI_API_KEY"]
MODEL = "gemini-3.1-flash-image"

payload = {
    "contents": [
        {
            "role": "user",
            "parts": [
                {"text": "未来主义建筑群,清晨薄雾,超广角摄影,真实材质"}
            ],
        }
    ],
    "generationConfig": {
        "responseDelivery": "uri",
        "responseModalities": ["TEXT", "IMAGE"],
        "imageConfig": {
            "aspectRatio": "16:9",
            "imageSize": "2K",
        },
    },
}

response = requests.post(
    f"{BASE_URL}/v1beta/models/{MODEL}:generateContent",
    headers={
        "x-goog-api-key": API_KEY,
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=300,
)

data = response.json()
if not response.ok:
    message = data.get("error", {}).get("message", data)
    raise RuntimeError(f"HTTP {response.status_code}: {message}")

image_part = None
for candidate in data.get("candidates", []):
    for part in candidate.get("content", {}).get("parts", []):
        if part.get("inlineData", {}).get("data") or part.get("fileData", {}).get("fileUri"):
            image_part = part
            break
    if image_part:
        break

if not image_part:
    reasons = [candidate.get("finishReason") for candidate in data.get("candidates", [])]
    raise RuntimeError(f"请求完成但没有返回图片,finishReason={reasons}")

file_uri = image_part.get("fileData", {}).get("fileUri")
if file_uri:
    print("图片 URL:", file_uri)
else:
    inline_data = image_part["inlineData"]
    mime_type = inline_data.get("mimeType", "application/octet-stream")
    extension = {
        "image/jpeg": "jpg",
        "image/webp": "webp",
    }.get(mime_type, "png")
    Path(f"gemini-output.{extension}").write_bytes(
        base64.b64decode(inline_data["data"])
    )
    print(f"图片已保存为 gemini-output.{extension}")

print("responseId:", data.get("responseId"))
print("usageMetadata:", data.get("usageMetadata"))

12. 常见错误

Gemini 原生端点通常返回 Google 风格错误:

{
  "error": {
    "code": 429,
    "message": "service rate limit exceeded",
    "status": "RESOURCE_EXHAUSTED"
  }
}
HTTP 状态常见原因建议
400请求结构、画幅、分辨率、参考图 URL 或图片格式错误按错误信息修正请求,不要直接重试
401API Key 缺失、无效或禁用检查 Key 和请求头
402 / 403余额、订阅、计费资格或权限不足检查账户和分组权限
404模型不存在,或当前 Key 分组未配置该模型对照 /v1/models 与 /v1beta/models/{model} 检查模型 ID
413图生图请求体过大压缩输入图片,或改用已开放的 URL 输入能力
429用户并发限制或服务限流优先遵循 Retry-After,否则指数退避并降低并发 / RPM
500服务内部错误记录错误码和请求 ID,有限重试
502请求转发失败或服务暂时不可用退避重试,必要时联系管理员
503服务容量暂时不足或过载延迟重试并降低流量
504请求处理超时作为独立请求重新发起

遇到容量或暂时不可用错误时,请停止密集重试,并将 HTTP 状态、错误码、responseId 或请求 ID 提供给管理员。


13. 超时、重试和并发

客户端超时建议

分辨率建议总超时
1K不低于 120 秒
2K不低于 180 秒
4K建议 300 秒

这只是接入建议,不代表固定 SLA。若请求还经过自有 Nginx、CDN 或 API 网关,需要同步调整这些组件的读取超时。

近期链路实测可作为前端交互设计参考,但不能视为 SLA:

场景实测参考
Flash Lite 1K 单张约 5~8 秒
Flash 1K 单张约 8~16 秒
Pro 4K 单张约 44 秒
并发 16、Flash 1Kp50 约 17.3 秒,p95 约 18.8 秒

容量繁忙时请求可能先进入队列,当前默认排队上限约为 90 秒。客户端总超时应覆盖“排队时间 + 生成耗时”,可按下面的方式估算:

客户端超时 ≥ 最大排队时间 + 对应分辨率的 p95 生成耗时 + 网络余量

重试建议

建议重试:

  • 429;如果响应包含 Retry-After,优先按该响应头等待;
  • 502、503、504;
  • 网络中断、连接重置和读取超时;
  • HTTP 200 但没有图片时,可有限重试一次并保存原始响应。

通常不要重试:

  • 400;
  • 401;
  • 明确的余额或权限错误;
  • 请求参数或内容策略错误。

推荐最多重试 2~3 次,并使用指数退避:

第 1 次:1~2 秒随机抖动
第 2 次:3~5 秒随机抖动
第 3 次:8~12 秒随机抖动

多张实时图片

实时接口当前按“一次请求一张主要图片”使用。需要多张时应拆成多个独立请求,并同时限制:

  • 最大在途并发;
  • 每分钟请求数(RPM);
  • 单用户任务数;
  • 超时与最大重试次数。

如果需要提交几十到数百条提示词并异步等待结果,请使用Gemini 批量生图 API。


14. 用量与计费

响应中的 usageMetadata 可用于分析 Token 和本次请求的 credits 消耗,但不一定等于最终货币扣费金额。当前图片响应可能包含 promptTokenCount、candidatesTokenCount、totalTokenCount 和 creditsConsumed;客户端不应假设一定存在 candidatesTokensDetails。

实际扣费可能受以下因素影响:

  • 请求模型 ID 与实际映射模型;
  • 1K、2K、4K 图片档位;
  • 分组图片单价;
  • 用户分组倍率和平台计费配置;
  • 部署环境中的计费规则。

最终金额请以林易控制台的用量明细和账户余额变化为准。

进行质量或并发测试时,建议记录:

  1. 测试前余额;
  2. 测试后余额;
  3. 成功请求数;
  4. 实际返回图片数;
  5. 模型、分辨率和画幅;
  6. 余额差额;
  7. 单张成功图片平均成本。

用量记录可能异步落账,测试结束后可等待一段时间再核对最终金额。


15. 安全建议

  • API Key 只保存在服务端环境变量或密钥管理系统;
  • 不要在浏览器前端、移动端安装包或公开代码仓库中写入 Key;
  • 日志不要打印完整 API Key 和完整图片 Base64;
  • 校验输入图片 MIME 类型、文件大小和 Base64 合法性;
  • URL 参考图只使用公网 HTTPS 地址;如 URL 包含访问签名,应限制签名权限和有效期;
  • 保存响应时根据 inlineData.mimeType 或 fileData.mimeType 选择扩展名,不要默认按 PNG 保存;
  • 使用 URI 交付时不要硬编码对象存储域名,并按业务需要及时归档图片;
  • 为每个业务请求记录自己的 trace ID、请求时间、模型、分辨率和 HTTP 状态;
  • 超时后不要在极短时间内重复创建大量相同请求。

16. 接入验收清单

  • 能区分 /v1beta/models 的 Gemini 能力目录和 /v1/models 的当前 Key 路由模型列表;
  • 能使用 x-goog-api-key 或 Bearer 请求头鉴权;
  • 能完成一张 1K / 1:1 文生图;
  • 能完成 Flash / Pro 的 2K 和 4K 文生图;
  • 对 Flash Lite 仅提交 1K,不会发送 2K / 4K;
  • 能完成至少一次 Base64 参考图的图片编辑 / 图生图;
  • 能使用 fileData.fileUri 提交公网 HTTPS 参考图;
  • URL 参考图与 responseDelivery: "uri" 组合时,可以实现 URL 输入、URL 输出;
  • 内网、本机、不可访问或非图片 URL 会被识别为 400 参数错误;
  • 多参考图请求不超过 6 张,并限制 Base64 请求体或 URL 源文件大小;
  • 能识别 inlineData.data 与 fileData.fileUri 两种图片交付形式;
  • 能根据响应 mimeType 保存 WebP / JPEG / PNG,不硬编码扩展名;
  • 能把 HTTP 200 但既没有 Base64 也没有图片 URL 的情况标记为失败;
  • 日志记录 responseId,便于问题排查;
  • 已设置图片请求超时;
  • 已对 429 和 5xx 实现有限次数指数退避;
  • 已确认价格、余额、并发和 RPM;
  • 日志不会泄露 API Key 或完整 Base64。

下一步

On this page