Gemini generateContent

Gemini 原生协议接口——generateContent 与 streamGenerateContent,请求体结构、流式 SSE、usageMetadata 与 OpenAI 用量字段对照。

积木提供 Gemini 原生协议接入,Google 官方 SDK 把 base_url 指向积木即可直接使用。 鉴权见 鉴权与令牌,通用错误码见 错误处理与请求追踪; Gemini 风格的两种鉴权方式同样可用: x-goog-api-key: <令牌> 请求头,或 ?key=<令牌> 查询参数(均已实测)。

端点

POST/v1beta/models/{model}:generateContent
POST/v1beta/models/{model}:streamGenerateContent?alt=sse
POST/v1beta/models/{model}:embedContent
POST/v1beta/models/{model}:batchEmbedContents
GET/v1beta/models

模型名在 URL 路径里,不在请求体中——协议请求体没有 model 字段, 模型选择始终以 URL 路径为准,不要在 body 里传 model。 嵌入接口与 OpenAI 兼容的 /v1/embeddingsEmbeddings,本文以 generateContent 为主。

模型发现

GET/v1beta/models

返回当前令牌可用的模型,采用 Gemini 原生 ListModels 信封。 列表受该令牌的模型限制与账号可用范围过滤——不是全局模型目录,也不限于 Gemini 模型 (所有已开通渠道的模型都会出现在这里,只是被渲染成 Gemini 的结构)。

支持三种鉴权形式:x-goog-api-key 头、Authorization: Bearer <token>、以及 ?key=<token> 查询参数。 不带凭据时返回 401。

响应200
{
  "models": [
    {
      "name": "gemini-3.5-flash",
      "baseModelId": null,
      "version": null,
      "displayName": "gemini-3.5-flash",
      "description": null,
      "inputTokenLimit": null,
      "outputTokenLimit": null,
      "supportedGenerationMethods": null,
      "thinking": null,
      "temperature": null,
      "maxTemperature": null,
      "topP": null,
      "topK": null
    }
  ],
  "nextPageToken": null
}
只有 namedisplayName 有值,其余十一个字段恒为 null 两者都取模型 ID,因此内容相同。 不要基于这里的 supportedGenerationMethodsinputTokenLimitthinking 做能力判断——它们只是保持响应结构与 Google 官方兼容的占位字段,不是真实元数据。 能力与上下文上限请查模型能力

没有分页,也没有单模型查询。 nextPageToken 恒为 nullpageSize 被忽略——一次请求返回完整列表。 GET /v1beta/models/{model} 未实现,返回 404 Invalid URL/v1beta/models/{model}:{action} 这种路径形态保留给上面的生成类端点。

# 列出模型(x-goog-api-key 形式)
curl "https://api.jimu.chat/v1beta/models" \
  -H "x-goog-api-key: $JIMU_API_KEY"

# 等价的 Bearer 形式
curl "https://api.jimu.chat/v1beta/models" \
  -H "Authorization: Bearer $JIMU_API_KEY"

同一份列表的 OpenAI 结构变体是 GET /v1beta/openai/models,返回 {"data": [...], "object": "list", "success": true} 信封且能力字段完整——见模型列表

请求体

{
  "contents": [
    {
      "role": "user",
      "parts": [
        { "text": "用一句话介绍杭州" }
      ]
    }
  ],
  "systemInstruction": {
    "parts": [{ "text": "你是一个简洁的中文助手" }]
  },
  "generationConfig": {
    "temperature": 0.7,
    "maxOutputTokens": 1024,
    "thinkingConfig": { "thinkingBudget": 0 }
  },
  "safetySettings": [
    { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE" }
  ]
}
部分字段支持 snake_case 与 camelCase 双写法。 双兼容是逐字段显式实现的,白名单如下: systemInstruction/system_instructioninlineData/inline_datamimeType/mime_typethinkingConfig/thinking_config(含其内部 thinkingBudget/includeThoughts/thinkingLevel)、 以及 generationConfig 的各字段(如 maxOutputTokens/max_output_tokensstopSequences/stop_sequences)。 白名单之外的字段(如 safetySettingstoolConfigfileDatafunctionCall)只接受 camelCase, 写成 snake_case 会被静默忽略。

contents 与 parts

contentsarray必填

对话内容数组。roleusermodel;首条缺省 role 时服务端自动补 user

parts[].textstring

文本

parts[].inlineDataobject

内联文件 { "mimeType": "image/png", "data": "<base64>" },支持图片/音频/视频/文档

parts[].fileDataobject

文件引用 { "mimeType": "...", "fileUri": "https://..." };YouTube 链接缺省 mimeType 时按 video/webm 处理

parts[].functionCallobject

模型发起的函数调用 { "name": "...", "args": {...} }

parts[].functionResponseobject

函数执行结果回传 { "name": "...", "response": {...} }

parts[].executableCode / codeExecutionResultobject

代码执行工具相关

generationConfig

全部可选,常用字段:

temperaturenumber

采样温度

topP / topKnumber

核采样 / top-k

maxOutputTokensinteger

最大输出 token(含思考 token)

candidateCountinteger

候选数

stopSequencesstring[]

停止序列

responseMimeTypestring

application/json 强制 JSON 输出

responseSchema / responseJsonSchemaobject

结构化输出约束

presencePenalty / frequencyPenaltynumber

惩罚项

seedinteger

随机种子

responseModalitiesstring[]

输出模态,如 ["TEXT","IMAGE"](图像生成模型)

thinkingConfigobject

思考配置:thinkingBudget(0=关闭思考)、includeThoughtsthinkingLevel

speechConfig / imageConfigobject

语音/图像生成的厂商配置,可用范围以所用模型为准

safetySettings

数组,每项 { "category": "...", "threshold": "..." }。category 为 HARM_CATEGORY_HARASSMENTHARM_CATEGORY_HATE_SPEECHHARM_CATEGORY_SEXUALLY_EXPLICITHARM_CATEGORY_DANGEROUS_CONTENT 等;threshold 为 BLOCK_NONEBLOCK_LOW_AND_ABOVEBLOCK_MEDIUM_AND_ABOVEBLOCK_ONLY_HIGH 等,可用范围随模型而异。

tools 与 toolConfig

tools 数组支持五种工具:functionDeclarations(函数声明)、googleSearch(联网搜索)、 googleSearchRetrieval(搜索检索,旧版形式)、codeExecution(代码执行)、urlContexttoolConfig 可含 functionCallingConfig(控制函数调用模式:AUTO / ANY / NONEallowedFunctionNames)与 retrievalConfig(检索配置:latLnglanguageCode)。

以上工具与厂商配置字段按 Gemini 协议定义转发,实际可用范围以所用模型的能力为准。

响应结构

非流式响应为 GenerateContentResponse(以下为生产实测返回的精简形态):

响应200
{
  "candidates": [
    {
      "content": { "role": "model", "parts": [{ "text": "好" }] },
      "finishReason": "STOP"
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 7,
    "candidatesTokenCount": 1,
    "totalTokenCount": 95,
    "thoughtsTokenCount": 87
  },
  "modelVersion": "gemini-default",
  "responseId": "GsZoapXEDubVz7IPq-uHoAI"
}
candidates[].contentobject

模型输出。role 保持上游返回值,通常为 modelparts 可能含 textthought(思考段)、thoughtSignatureinlineData(图像输出)等

candidates[].finishReasonstring

结束原因 STOPMAX_TOKENSSAFETYRECITATION

candidates[].safetyRatingsarray

安全评级数组

promptFeedbackobject

输入被拦截时出现,含 blockReason;此时 candidates 为空

usageMetadataobject

用量统计,见下表

modelVersion / responseIdstring

上游附加字段。本端点响应为字节级透传,协议结构之外的字段(如这两个)也会原样带出,以实际上游返回为准

usageMetadata 与三套用量字段对照

Gemini usageMetadataOpenAI usageAnthropic usage
promptTokenCountprompt_tokensinput_tokens
candidatesTokenCountcompletion_tokensoutput_tokens
thoughtsTokenCountcompletion_tokens_details.reasoning_tokens(无对应)
cachedContentTokenCountprompt_tokens_details.cached_tokenscache_read_input_tokens
totalTokenCounttotal_tokens(需自行相加)
promptTokensDetails[]prompt_tokens_details(模态拆分)(无对应)

平台内部计费归一化:prompt_tokens = promptTokenCountcompletion_tokens = candidatesTokenCount + thoughtsTokenCount(思考 token 计入输出)。 注意 Gemini 的 totalTokenCount 包含思考 token,与直觉的「输入+可见输出」不等。

流式输出

POST /v1beta/models/{model}:streamGenerateContent?alt=sse
alt=sse 必须显式携带。 服务端按查询参数判定流式:只写 :streamGenerateContent 而不带 ?alt=sse 的请求会被当作非流式处理(上游按 :generateContent 转发)。 Google 官方 SDK 的流式调用天然带 alt=sse,手写 HTTP 时最容易漏掉它。

响应为标准 SSE,每个 data: 帧都是一个完整的 GenerateContentResponse JSON:

data: {"candidates": [{"content": {"role": "model","parts": [{"text": "好"}]}}],"usageMetadata":{"promptTokenCount": 7,...}}

data: {"candidates": [{"content": {"role": "model","parts": [{"text": ""}]},"finishReason": "STOP"}],"usageMetadata":{...}}

本端点的流式响应没有专用结束事件:记录最后一帧出现的 candidates[0].finishReason (正常为 STOP),并以 SSE 连接关闭确认流结束——二者齐备才算生成结束。 不像 OpenAI 的 data: [DONE] 或 Anthropic 的 message_stop,不要跨协议复用结束判断, 在本端点等待 [DONE] 会永远等不到;也不要一看到 finishReason 就提前断开, 尾随帧仍可能携带最终用量。

增量文本在各帧的 candidates[0].content.parts 中拼接。usageMetadata 不保证每帧都有 (可能仅在部分帧或末帧出现),建议保存最近一次存在且有效的值,流结束后以最终有效值为准。

服务端行为:哪些会改写,哪些原样透传

请求方向(默认改写):

  • 请求体经结构化解析后重新组装,未在协议结构中的自定义字段会被丢弃
  • 首条 contents 缺省 role 时自动补 user
  • 内容为空的 systemInstruction 会被移除

响应方向(字节级透传):

  • 非流式:上游响应字节原样返回,服务端只做用量提取,不增删字段
  • 流式:SSE 帧逐条转发
  • 错误响应:上游错误经网关错误格式封装,见 错误处理

多模态输入

{
  "contents": [
    {
      "role": "user",
      "parts": [
        { "text": "这张图里有什么" },
        { "inlineData": { "mimeType": "image/jpeg", "data": "<base64 编码的图片>" } }
      ]
    }
  ]
}

inlineData 也接受 snake_case 写法 { "inline_data": { "mime_type": "...", "data": "..." } }。 文件也可用 fileData.fileUri 以 URL 引用。

调用示例

# 非流式
curl "https://api.jimu.chat/v1beta/models/gemini-3.5-flash:generateContent" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $JIMU_API_KEY" \
  -d '{
    "contents": [{"role": "user", "parts": [{"text": "用一句话介绍杭州"}]}],
    "generationConfig": {"maxOutputTokens": 256}
  }'

# 流式(注意 alt=sse)
curl -N "https://api.jimu.chat/v1beta/models/gemini-3.5-flash:streamGenerateContent?alt=sse" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $JIMU_API_KEY" \
  -d '{"contents": [{"role": "user", "parts": [{"text": "写一首短诗"}]}]}'