codecamp

第一条 Gemini API 请求

Gemini API 首请求是 interactions.create(model, input),结果取 output_text,密钥走环境变量 GEMINI_API_KEY。(核验 2026-11-05,F9、F68)

一、第一条 Gemini API 请求:问题不是拿到一句回答,而是知道发了什么、该看哪

大部分人跑通第一条请求就过去了:装包、贴 key、print 出一句话,收工。然后到第二步就卡住——想加多轮,不知道历史放哪;想知道花了多少 token,不知道响应里哪个字段是钱。

所以这一节不看「能不能出字」,看两件事:请求里到底有哪几个字段,响应里到底该盯哪几个字段。

官方给的最小调用只有两个参数(F9):

client.interactions.create(model=..., input=...)

返回值上用 .output_text 直接取文本(F9)。密钥不写在代码里,官方推荐用环境变量 GEMINI_API_KEY(也接受 GOOGLE_API_KEY)(F68)。

三版最小调用长这样,需要你自己的密钥,本机不执行,所以放在不参与自动运行的块里:

## Python
from google import genai
client = genai.Client()
interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="用一句话解释 AI 是怎么工作的",
)
print(interaction.output_text)

## JavaScript
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({});
const interaction = await ai.interactions.create({
  model: "gemini-3.8-flash",
  input: "用一句话解释 AI 是怎么工作的",
});
console.log(interaction.output_text);

## REST
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Api-Revision: 2026-05-20" \
  -d '{"model": "gemini-3.8-flash", "input": "用一句话解释 AI 是怎么工作的"}'

REST 那版有个细节值得单独记住:官方所有 REST 示例都带 Api-Revision: 2026-05-20 这个请求头(F64),但文档正文从没解释它是干什么的,也没说能不能省略。所以照抄最安全;「能不能不带」属于待核(F65),本教程不替你下结论。

二、Gemini API 响应校验:最小可运行示例

真实调用要密钥,本机跑不了;但「响应长什么样、该断言什么」可以离线练。下面用官方 REST 响应样例的字段结构做一份 mock,校验成功的判据。

## EXPECT: 请求 model=gemini-3.8-flash input=1 段 | 响应 status=completed | output_text 非空 | usage total=197 in=8 out=12 | 差额=有(197 与 in+out 不相等,说明还有未计入 output_text 的 token)
REQUEST = {"model": "gemini-3.8-flash", "input": "用一句话解释 AI 是怎么工作的"}
RESPONSE = {
    "id": "v1_demo",
    "status": "completed",
    "output_text": "AI 通过大量文本学习规律,再用这些规律生成新内容。",
    "usage": {"total_tokens": 197, "total_input_tokens": 8, "total_output_tokens": 12},
}

def check(req, resp):
    u = resp["usage"]
    assert resp["status"] == "completed"
    assert resp["output_text"].strip()
    gap = u["total_tokens"] - (u["total_input_tokens"] + u["total_output_tokens"])
    assert gap >= 0, f"total 小于 in+out,先查字段映射:{u}"
    return (f"请求 model={req['model']} input={1} 段 | 响应 status={resp['status']} | "
            f"output_text 非空 | usage total={u['total_tokens']} in={u['total_input_tokens']} "
            f"out={u['total_output_tokens']} | 差额={'有' if gap else '无'}"
            f"(197 与 in+out 不相等,说明还有未计入 output_text 的 token)")

print(check(REQUEST, RESPONSE))

三、解释与边界:三个字段、一个坑、一条边界

三个字段。 model 决定你调谁,input 是本轮输入,密钥走环境变量而不是参数。这三样之外的东西——温度、思考强度、结构化格式——都属于「后面章节的事」,第一条请求先不碰。

一个坑:usage 里三个数对不上是正常的。 官方响应样例是 total_tokens 197、total_input_tokens 8、total_output_tokens 12(F66),加起来只有 20。差额不是文档写错,而是还有你没在 output_text 里看到的部分(思考步骤)。所以做成本核算时不要拿 in + out 当 total,直接读 total_tokens;差额怎么计价,见 10.1。上面的 check 把差额算成了变量 gap,并只对「差额为负」报错——那一定是你字段读错了,不是计费异常。

边界:本节不教流式、不教多轮、不教错误重试策略。 流式见 11.3,多轮见 4.1,重试策略见 11.1。第一节请求只需要成功一次,并且你能读懂它的响应。

还有一条容易被忽略:output_text 是 SDK 的便利属性。REST 原始返回里没有这个字段名,它是从 steps 里拼出来的。所以「Python 里有 .output_text、curl 里找不到 output_text」不是版本问题,是抽象层不同。

四、预期输出与异常分支

真跑输出:

请求 model=gemini-3.8-flash input=1 段 | 响应 status=completed | output_text 非空 | usage total=197 in=8 out=12 | 差额=有(197 与 in+out 不相等,说明还有未计入 output_text 的 token)

首请求失败,基本落在四类里,处理顺序不要乱。密钥缺失或无效:本地报的是环境变量为空,服务端回 401 UNAUTHENTICATED,先查 echo $GEMINI_API_KEY 和进程是否重启过。权限或区域问题:403 PERMISSION_DENIED,回到见 1.2 查区域清单,不要在这里改代码。模型名写错:404 NOT_FOUND 且报错里会带模型名,去见 3.1 用 models.list 查,别猜。配额或频率:429 RESOURCE_EXHAUSTED,退避重试,分流规则见 11.1。

一个反常识的点:status 为 completed 不代表内容一定有用。它只说明这一轮交互正常结束了;内容是否被安全策略截断,要看别的字段(见 11.2)。

五、判据卡:首请求失败的排查顺序

该这么做 不该这么做
先确认环境变量有值,再怀疑代码 把密钥硬编码进脚本「先跑通」
403 先查区域与权限,不改代码 见到失败就加 try/except 吞掉
404 用 models.list 确认真实模型名 照着博客里的模型 ID 反复试
成本核算读 total_tokens 用 in + out 自己加
REST 照抄官方示例的 Api-Revision 头 凭感觉删掉看不懂的请求头

六、来源与核验

  • https://aistudio.google.com/docs/get-started.md(核验 2026-11-05,F9、F64、F66)
  • https://aistudio.google.com/docs/api-key.md(核验 2026-11-05,F68)
  • https://aistudio.google.com/api-reference/api-versions.md(核验 2026-11-05,F8)
  • https://aistudio.google.com/docs/api-errors.md(核验 2026-11-05,F69)

Api-Revision 请求头的作用与必要性属于待核(F65):官方示例一律带它,但文档没有散文说明,正文因此只写「照抄」,不写「必须」或「可省」。REST 路径的 v1 与 v1beta 写法差异同样存在,见 2.3。

七、动手试

  1. 把 RESPONSE 里的 status 改成 "incomplete",重跑。预期会抛 AssertionError;验收标准是你说清「为什么校验 status 比校验文本长度更可靠」。
  2. 把 usage 里的 total_tokens 改成 10,重跑。预期抛 AssertionError: total 小于 in+out,先查字段映射;验收标准是你能说清「total 小于 in + out 只可能是字段映射或响应解析出错,不可能是计费异常」——所以这个断言查的是解析,不是钱。
  3. 用你自己的密钥发一次真实请求(三版任选),把完整响应存成 JSON,找出 output_text 对应的原始字段。验收标准:写下一行「Python 拿到的 .output_text 来自 REST 的哪个字段」,写不出来说明这条链路还没通。
装哪个 Gemini SDK
Gemini API 版本怎么选
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }