Gemini generateContent
Gemini 原生协议接口——generateContent 与 streamGenerateContent,请求体结构、流式 SSE、usageMetadata 与 OpenAI 用量字段对照。
积木提供 Gemini 原生协议接入,Google 官方 SDK 把 base_url 指向积木即可直接使用。
鉴权见 鉴权与令牌,通用错误码见 错误处理与请求追踪;
Gemini 风格的两种鉴权方式同样可用:
x-goog-api-key: <令牌> 请求头,或 ?key=<令牌> 查询参数(均已实测)。
端点
/v1beta/models/{model}:generateContent/v1beta/models/{model}:streamGenerateContent?alt=sse/v1beta/models/{model}:embedContent/v1beta/models/{model}:batchEmbedContents/v1beta/models模型名在 URL 路径里,不在请求体中——协议请求体没有 model 字段,
模型选择始终以 URL 路径为准,不要在 body 里传 model。
嵌入接口与 OpenAI 兼容的 /v1/embeddings 见 Embeddings,本文以 generateContent 为主。
模型发现
/v1beta/models返回当前令牌可用的模型,采用 Gemini 原生 ListModels 信封。
列表受该令牌的模型限制与账号可用范围过滤——不是全局模型目录,也不限于 Gemini 模型
(所有已开通渠道的模型都会出现在这里,只是被渲染成 Gemini 的结构)。
支持三种鉴权形式:x-goog-api-key 头、Authorization: Bearer <token>、以及 ?key=<token> 查询参数。
不带凭据时返回 401。
{
"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
}
name 与 displayName 有值,其余十一个字段恒为 null。 两者都取模型 ID,因此内容相同。
不要基于这里的 supportedGenerationMethods、inputTokenLimit、thinking 做能力判断——它们只是保持响应结构与 Google 官方兼容的占位字段,不是真实元数据。
能力与上下文上限请查模型能力。没有分页,也没有单模型查询。 nextPageToken 恒为 null,pageSize 被忽略——一次请求返回完整列表。
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" }
]
}
systemInstruction/system_instruction、inlineData/inline_data、mimeType/mime_type、
thinkingConfig/thinking_config(含其内部 thinkingBudget/includeThoughts/thinkingLevel)、
以及 generationConfig 的各字段(如 maxOutputTokens/max_output_tokens、stopSequences/stop_sequences)。
白名单之外的字段(如 safetySettings、toolConfig、fileData、functionCall)只接受 camelCase,
写成 snake_case 会被静默忽略。contents 与 parts
contentsarray必填对话内容数组。role 为 user 或 model;首条缺省 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=关闭思考)、includeThoughts、thinkingLevel
speechConfig / imageConfigobject语音/图像生成的厂商配置,可用范围以所用模型为准
safetySettings
数组,每项 { "category": "...", "threshold": "..." }。category 为
HARM_CATEGORY_HARASSMENT、HARM_CATEGORY_HATE_SPEECH、HARM_CATEGORY_SEXUALLY_EXPLICIT、
HARM_CATEGORY_DANGEROUS_CONTENT 等;threshold 为 BLOCK_NONE、BLOCK_LOW_AND_ABOVE、
BLOCK_MEDIUM_AND_ABOVE、BLOCK_ONLY_HIGH 等,可用范围随模型而异。
tools 与 toolConfig
tools 数组支持五种工具:functionDeclarations(函数声明)、googleSearch(联网搜索)、
googleSearchRetrieval(搜索检索,旧版形式)、codeExecution(代码执行)、urlContext。
toolConfig 可含 functionCallingConfig(控制函数调用模式:AUTO / ANY / NONE
与 allowedFunctionNames)与 retrievalConfig(检索配置:latLng、languageCode)。
响应结构
非流式响应为 GenerateContentResponse(以下为生产实测返回的精简形态):
{
"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 保持上游返回值,通常为 model。parts 可能含 text、thought(思考段)、thoughtSignature、inlineData(图像输出)等
candidates[].finishReasonstring结束原因 STOP、MAX_TOKENS、SAFETY、RECITATION 等
candidates[].safetyRatingsarray安全评级数组
promptFeedbackobject输入被拦截时出现,含 blockReason;此时 candidates 为空
usageMetadataobject用量统计,见下表
modelVersion / responseIdstring上游附加字段。本端点响应为字节级透传,协议结构之外的字段(如这两个)也会原样带出,以实际上游返回为准
usageMetadata 与三套用量字段对照
Gemini usageMetadata | OpenAI usage | Anthropic usage |
|---|---|---|
promptTokenCount | prompt_tokens | input_tokens |
candidatesTokenCount | completion_tokens | output_tokens |
thoughtsTokenCount | completion_tokens_details.reasoning_tokens | (无对应) |
cachedContentTokenCount | prompt_tokens_details.cached_tokens | cache_read_input_tokens |
totalTokenCount | total_tokens | (需自行相加) |
promptTokensDetails[] | prompt_tokens_details(模态拆分) | (无对应) |
平台内部计费归一化:prompt_tokens = promptTokenCount,
completion_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": "写一首短诗"}]}]}'