在实际的 AI 应用开发中,Gemini 3.8 Flash 和 3.8 Flash Cyber 一旦进入技术方案,真正的工作往往不是“调一个模型”这么简单。很快会碰到认证参数放在哪、模型标识填什么、多轮上下文怎么维护、JSON 输出如何校验、429 和 403 怎么区分、模型切换如何不中断业务等一系列问题。这篇文章围绕 Gemini 3.8 Flash / 3.8 Flash Cyber 的 API 接入,从最小请求开始,逐步走到多轮会话、结构化输出、生产化配置和故障排查,适合后端开发者、AI 应用工程师和正在做模型集成交付的团队作为接入清单使用。下面所有示例都按通用 HTTP 方式编写,不绑定具体 SDK 版本,落地前以你拿到的官方 API 文档为准。
1. 先想清楚 Flash 类模型在业务里承担什么角色
1.1 Flash 模型为什么适合嵌入业务链路
从工程定位看,Flash 系列一般承担“轻量、低延迟、成本敏感”的生成任务,比如文本摘要、信息抽取、内容分类、结构化转换、客服问答等。这类任务通常会被高频调用,响应时间要求较高,不能每次都把最重的模型放到请求链路上。接入 Gemini 3.8 Flash 之前,先列出业务要模型做什么,以及延迟、成本、并发量分别是什么量级。
这里要特别说明一点:关于 “3.8 Flash Cyber” 这个后缀的具体产品定义,不同资料里的说法可能不一致,比如它是否代表更强调安全能力、是否对应某个特定的内容审核场景、是否在上下文窗口或输出限制上有差异,最终都要以官方模型说明和 API 文档为准。本文不预设 Cyber 后缀的具体产品能力,只把它当作一个独立的模型标识来处理接入流程。这样做的好处是,即使模型标识随后调整,你的接入代码、请求结构、解析逻辑和排查方式也不需要推倒重写。
1.2 接入前必须锁定的四类信息
接入任何大模型 API,第一件事不是写代码,而是确认接口契约。接口契约不一致,后面所有排查都会变得混乱。至少要先锁定四类信息。
| 信息 | 说明 | 确认方式 |
|---|---|---|
| 模型标识 | 例如 gemini-3.8-flash 或 gemini-3.8-flash-cyber,路径参数中会用到 | 查看官方模型列表 API 或文档中的 model 名称 |
| API 入口 | Generative Language API 和 Cloud Vertex AI 的请求路径、认证方式不同 | 根据账号体系和部署环境选择,不要混用 |
| 认证方式 | API Key 或服务账号 OAuth 凭据 | 查看文档中的认证小节,并在最小请求中验证 |
| 配额与限制 | 每分钟请求数、每分钟 token 数、最大输出 token 数 | 控制台配额页或文档限制说明 |
实际项目中经常出现的问题不是模型不会返回,而是把 Cloud Vertex AI 的模型名拿到 Generative Language API 上调用,或者反过来。两个入口的 Host、Header、项目 ID 都不一样,但模型标识看起来差不多。所以接入前务必将这四个信息记录到一个固定的接口配置文档中,避免每个人都靠记忆猜。
1.3 学习环境、测试环境和生产环境的差异
学习环境的目标是尽快看到模型返回,生产环境的目标是稳定、可控、可回滚。两者不要混为一谈。
| 维度 | 学习环境 | 生产环境 |
|---|---|---|
| 认证 | 个人 API Key | 项目级服务账号或受管密钥,权限最小化 |
| 请求方式 | curl、简单 Python 脚本 | 独立调用模块,统一超时、重试、日志 |
| 凭据存放 | 本机环境变量 | 密钥管理服务,不在代码仓库出现 |
| 模型标识 | 写死测试值 | 配置项,支持灰度切换 |
| 错误处理 | 看标准输出即可 | 记录错误码、requestId、耗时、token 用量 |
| 数据 | 脱敏测试数据 | 遵守隐私规范,日志脱敏 |
把这种差异提前确认好,能避免一个常见坑:在本地把 API Key 写进了代码,随后提交到仓库,密钥立刻暴露。后面每一节都会围绕这个差异展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先跑通一个最小请求,再写业务代码
2.1 环境准备
这里假设你已经拿到了可用的认证凭据。推荐使用 Python 3.9 以上版本,HTTP 请求用 requests,命令行验证用 curl 和 jq。
| 工具 | 用途 | 验证方式 |
|---|---|---|
| curl | 发送最小 HTTP 请求 | curl --version |
| jq | 解析 JSON 响应 | jq --version |
| Python 3.9+ | 后续编写可复用调用模块 | python3 --version |
| requests | Python HTTP 客户端 | pip show requests |
把认证信息放入环境变量,不要写进代码文件。以 macOS / Linux 为例:
bash复制export GEMINI_API_KEY="你的密钥"
export GEMINI_MODEL="gemini-3.8-flash"
如果是本地开发项目,可以使用 .env 文件,但必须把 .env 加入 .gitignore:
bash复制GEMINI_API_KEY=你的密钥
GEMINI_MODEL=gemini-3.8-flash
还要做一项最基本的网络检查:确认当前开发环境能够访问目标 API 域名。如果公司网络有防火墙或策略限制,需要找网络负责人确认合规访问方案,而不是绕过限制或私自修改网络配置。这一步看起来简单,但在团队协作中很常见:开发环境通、测试环境不通,最后发现是不同环境的出网策略不一致。
2.2 用 curl 验证认证和模型标识
最小请求的价值在于把变量降到最少。第一个请求只验证三件事:网络通、认证对、模型标识可用。
bash复制curl -sS -X POST "https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent" \
-H "x-goog-api-key: ${GEMINI_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"contents": [{
"role": "user",
"parts": [{"text": "只回答两个字:正常"}]
}]
}' | jq '.candidates[0].content.parts[0].text'
这里有几个关键点:
- 认证信息放在
x-goog-api-key请求头中,而不是拼在 URL 的 query 参数中,避免 API Key 进入访问日志或代理日志。 - 模型名作为路径参数,路径格式形如
/v1beta/models/{model}:generateContent,具体以官方文档为准。 contents是数组,contents[0].parts[0].text是用户输入文本。- 用
jq直接提取候选输出,如果提取不到,说明请求或响应结构有问题。
如果你的文档确认当前账号的模型标识不是 gemini-3.8-flash,只需修改 GEMINI_MODEL 环境变量后重试即可。
2.3 最小请求最常见的三种失败
| 现象 | 可能原因 | 处理方向 |
|---|---|---|
| 400 invalid argument | 请求 JSON 结构不对,或参数类型不匹配 | 对照文档逐字段检查 contents 和 generationConfig |
| 403 permission denied | API Key 无效、被停用、无权访问该模型 | 检查密钥有效性和模型访问权限 |
| 404 not found 或 400 model not found | 模型标识拼写错误,或当前区域不支持该模型 | 用模型列表接口确认可用模型名 |
最小请求跑通之后,才建议进入 Python 封装阶段。很多人习惯直接写 Python 代码,出了问题又要拆回 curl 调试,反而浪费时间。
3. 在 Python 里做一个可复用的调用模块
3.1 使用 requests 实现最小调用封装
在业务系统里,不推荐每次调用都重复写一遍 HTTP 逻辑。可以先把最小调用收敛成一个函数,后续加多轮会话、结构化输出、重试和日志都在同一层完成。
python复制import json
import os
import requests
MODEL = os.getenv("GEMINI_MODEL", "gemini-3.8-flash")
API_KEY = os.environ["GEMINI_API_KEY"]
ENDPOINT = f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL}:generateContent"
def ask(prompt: str, temperature: float = 1.0) -> str:
payload = {
"contents": [
{
"role": "user",
"parts": [{"text": prompt}],
}
],
"generationConfig": {
"temperature": temperature,
"maxOutputTokens": 512,
},
}
resp = requests.post(
ENDPOINT,
headers={
"x-goog-api-key": API_KEY,
"Content-Type": "application/json",
},
json=payload,
timeout=30,
)
resp.raise_for_status()
data = resp.json()
candidates = data.get("candidates") or []
if not candidates:
block_reason = (data.get("promptFeedback") or {}).get("blockReason", "unknown")
raise RuntimeError(f"no candidate, blockReason={block_reason}")
parts = (candidates[0].get("content") or {}).get("parts") or []
if not parts:
raise RuntimeError("candidate has empty content")
return "".join(part.get("text", "") for part in parts)
这个函数解决了三个问题:
- 所有凭据从环境变量读取,代码仓库不会出现明文密钥。
- 设置
timeout=30,避免服务端不返回时进程一直挂起。 - 对空候选、空文本做了显式异常,而不是在后续业务代码里才发现返回为空。
需要注意的是,os.environ["GEMINI_API_KEY"] 在环境变量缺失时会直接抛出 KeyError,这是有意为之。如果密钥没有配置,越早失败越好,比线上请求全部 403 更容易定位。
3.2 generationConfig 参数怎么调
generationConfig 是请求体里最常调整的部分。以下参数初始值来自常见 API 约定,具体模型支持的取值范围以文档为准。
| 参数 | 含义 | 常见默认值 | 调大影响 | 调小影响 |
|---|---|---|---|---|
| temperature | 控制随机性 | 1.0 | 输出更多样,但稳定性下降 | 输出更确定,但可能更重复 |
| maxOutputTokens | 输出 token 上限 | 模型决定 | 可承载更长输出,成本和延迟上升 | 输出被截断的风险增大 |
| topP | 核采样概率 | 模型决定 | 候选词更多样 | 输出更聚焦于高概率词 |
| topK | 候选集合大小 | 模型决定 | 输出更多样 | 输出更保守 |
| candidateCount | 返回候选数量 | 1 | 可用于多候选对比,成本成倍增加 | 影响较小 |
新手最容易犯一个错误:把 maxOutputTokens 理解成“输入和输出总长度上限”。实际上它主要控制输出部分。如果输出被截断,finishReason 会返回 MAX_TOKENS,而不是 STOP。排查时先看 finishReason,再判断是参数问题还是提示词问题。
temperature 和 topP 同时调整时,叠加语义在不同模型上可能不一样。建议一开始只固定一个随机性参数,跑完评测再微调另一个,不要同时盲目调两个。
3.3 解析响应的标准姿势
一个典型的生成响应结构如下:
json复制{
"candidates": [
{
"content": {
"role": "model",
"parts": [{"text": "正常"}]
},
"finishReason": "STOP"
}
],
"usageMetadata": {
"promptTokenCount": 15,
"candidatesTokenCount": 20,
"totalTokenCount": 35
},
"promptFeedback": {}
}
解析时必须关注三个字段:
candidates[0].content.parts[*].text:这是正文。candidates[0].finishReason:STOP表示正常结束,MAX_TOKENS表示被截断,SAFETY表示被安全策略拦截。usageMetadata:包含输入和输出 token 数,这是成本核算和监控的关键数据。
不要假设 candidates 数组永远有值。模型返回为空、被安全策略拦截时,candidates 可能是空数组,真正的拦截原因在 promptFeedback.blockReason 里。所以封装层必须同时处理两类异常分支。
4. 多轮会话:上下文的正确维护方式
4.1 contents 数组为什么是会话核心
大模型 API 本身不保存会话状态。每次请求都需要把历史记录按顺序放进 contents 数组,服务端才能知道“前面聊过什么”。contents 中每条消息的 role 只能是 user 或 model,分别对应人类输入和模型回复。
一个常见错误是给模型回复标记了错误角色,比如把模型的输出也当成 user 追加到数组里。这样模型看到的是两个连续的 user 消息,语义隔离会被破坏,后续回答会明显变乱。
4.2 一个多轮调用封装
python复制from typing import List, Optional, Dict
def chat(
messages: List[Dict],
system_instruction: Optional[str] = None,
temperature: float = 0.7,
) -> str:
payload = {
"contents": messages,
"generationConfig": {
"temperature": temperature,
"maxOutputTokens": 512,
},
}
if system_instruction:
payload["systemInstruction"] = {
"parts": [{"text": system_instruction}]
}
resp = requests.post(
ENDPOINT,
headers={
"x-goog-api-key": API_KEY,
"Content-Type": "application/json",
},
json=payload,
timeout=30,
)
resp.raise_for_status()
data = resp.json()
candidates = data.get("candidates") or []
parts = (candidates[0].get("content") or {}).get("parts") or []
reply = "".join(part.get("text", "") for part in parts)
messages.append({"role": "model", "parts": [{"text": reply}]})
return reply
调用方式:
python复制messages = [
{"role": "user", "parts": [{"text": "我要整理本周工单,先列出三类常见问题。"}]}
]
reply1 = chat(messages)
print(reply1)
messages.append({"role": "user", "parts": [{"text": "给每个问题补一个处理建议。"}]})
reply2 = chat(messages)
print(reply2)
这里的关键点是:模型返回的 reply 必须由业务代码追加到 messages,而不是让模型自己把历史写回数组。如果漏了这一步,第二轮请求时模型只会看到用户提问,看不到自己的上一轮回答,上下文自然断裂。
systemInstruction 不能放进 contents 数组,它应该作为独立参数传递。它负责设定模型的人格、角色和固定输出规则,是一种优先级较高的指令。
4.3 上下文太长怎么办
长会话一定会撞上上下文窗口限制。一般按这个顺序处理:
- 记录每轮请求
usageMetadata中的totalTokenCount,估算当前会话平均消耗。 - 设定一个历史轮数上限,超过上限后优先删除最早的用户消息和模型消息。
- 如果业务需要保留更早的信息,可在截断前用模型生成一段摘要,将摘要放在当前会话最前面。
- 高成本场景下,可以拆分为短期会话和长期摘要两层,不要把所有原始历史都塞进每次请求。
一个简单的滑动窗口实现:
python复制def trim_messages(messages: List[Dict], max_messages: int = 10) -> List[Dict]:
if len(messages) <= max_messages:
return messages
return messages[-max_messages:]
这个函数只做最基础的裁剪。真实生产环境建议结合 token 计数精确裁剪,而不是只按消息条数裁剪,因为一条用户消息可能就有几千 token。
5. 结构化输出:让模型结果可以直接入库
5.1 为什么直接解析自然语言不可靠
很多业务系统需要模型输出分类、金额、地址、状态码等字段。如果直接让模型用自然语言回答,用户一句“帮我查一下,我感觉网络不对”,模型可能回“看起来是网络设备的问题,可能需要重启路由器”,这类文本无法直接落库。
所以通常有两种策略:
- 在
generationConfig中设置responseMimeType: "application/json",同时把输出字段说明写进提示词。 - 如果当前模型端点支持
responseSchema,按照官方文档在请求中声明 JSON Schema,让模型按结构约束输出。
第一种兼容性更好,第二种稳定性更强。实际项目中可以先实现第一种,等确认模型支持后再按文档升级为 Schema 约束。
5.2 一个 JSON 输出示例
下面示例不绑定具体 Schema 字段格式,重点演示思路。目标是让模型把工单信息抽取成 JSON:
python复制def extract_ticket(prompt: str) -> str:
payload = {
"contents": [
{
"role": "user",
"parts": [
{
"text": (
"抽取工单信息,输出 JSON。字段如下:\n"
"category: 工单分类,可选值为 billing、network、device\n"
"urgency: 1 到 5 的整数,5 表示最紧急\n"
"summary: 不超过 30 字的摘要\n"
"输入:用户反馈宽带断网且路由器灯不亮。\n"
"输出:"
)
}
],
}
],
"generationConfig": {
"responseMimeType": "application/json",
"temperature": 0.2,
"maxOutputTokens": 256,
},
}
resp = requests.post(
ENDPOINT,
headers={
"x-goog-api-key": API_KEY,
"Content-Type": "application/json",
},
json=payload,
timeout=30,
)
resp.raise_for_status()
return resp.json()["candidates"][0]["content"]["parts"][0]["text"]
一次可能返回的结果:
json复制{
"category": "network",
"urgency": 5,
"summary": "宽带断网且路由器灯不亮"
}
这里把 temperature 调到 0.2,是为了让输出更稳定。结构化抽取任务通常不需要太高的随机性,温度过高会导致同一个工单每次输出分类不同。
5.3 校验、重试和兜底
模型输出 JSON 不代表 JSON 一定合法,也不代表字段一定符合业务约束。常见问题包括:
- JSON 字符串前后出现
json围栏。 - 字段名大小写错误。
urgency输出成字符串"5",而不是数字。category输出了枚举之外的取值。
解析时需要先做一次净化,再做字段校验:
python复制import json
def parse_json_response(raw_text: str):
text = raw_text.strip()
if text.startswith("```"):
text = text.strip("`")
if text.startswith("json"):
text = text[4:]
return json.loads(text.strip())
这版净化逻辑用来处理常见的代码围栏噪声。更可靠的方案是让模型只输出 JSON,不在响应中加任何解释,同时业务层保留解析失败后的重试入口。
重试原则:只重试一次,防止模型反复失败造成高额 token 消耗。两次都失败后,走业务降级逻辑,比如返回默认分类 unknown,或者把工单交给人工处理,而不是让用户看到解析错误。
6. 按错误码分级排查:认证、限流、参数和超时
6.1 403 认证失败
现象:403 permission denied 或 401 unauthorized。
排查顺序:
- 确认环境变量已加载,打印变量长度,而不是打印完整密钥。
- 确认 API Key 有效,且没有被账号停用。
- 确认当前模型标识属于当前账号可访问范围。
- 确认请求头写的是
x-goog-api-key,并且没有把密钥放到日志中。
一个安全建议:API Key 不要出现在 URL query 参数中。如果某些历史代码已经这样写了,尽快改成请求头方式。
6.2 429 限流和配额不足
现象:429 RESOURCE_EXHAUSTED 或类似限流错误。
处理方式:
- 查看错误响应中的配额信息,确认是每分钟请求数超限,还是每分钟 token 数超限。
- 在客户端实现指数退避重试,即以 1 秒、2 秒、4 秒的间隔递增重试,并加入少量随机抖动。
- 分析请求分布,是否集中在某个高峰时段。对可离线处理的请求做批量削峰。
- 对相同或相似的请求做缓存,减少重复调用。
重试不是无限循环。建议最多重试 3 次,并且只在错误明确提示可重试时重试。
6.3 400 或 404 参数错误
现象:请求本身格式错误,或者模型标识不对。
排查方式:
bash复制curl -sS "https://generativelanguage.googleapis.com/v1beta/models" \
-H "x-goog-api-key: ${GEMINI_API_KEY}" | jq -r '.models[].name'
这个模型列表请求能直观看到当前账号下有哪些模型标识可用。如果列表里没有你预期的 gemini-3.8-flash-cyber,说明该账号或区域还没有这个模型,而不是你的代码有问题。
另一种常见 400 原因是 generationConfig 里放了模型不支持的字段,比如某些请求只支持 responseMimeType 而不支持当前版本声明的 responseSchema。这时要回到官方文档核对请求体字段。
6.4 超时和连接错误
现象:客户端报 ConnectionError、ReadTimeout,或者请求在服务端处理很久后断开。
处理方式:
- 为连接和读取分别设置超时,不要让请求无限等待。
- 服务端返回 5xx 时,可以重试;服务端已经处理但返回结果超时的情况,要特别小心重复扣费。
- 在日志中记录请求开始时间、结束时间、状态码、错误信息和
usageMetadata,方便区分是网络问题还是模型性能问题。 - 如果模型响应持续超时,优先检查请求体是否太大、输出 token 是否设置过高、模型是否处于高负载期。
| 错误类型 | 常见错误码 | 首查项 | 处理建议 |
|---|---|---|---|
| 认证失败 | 401 / 403 | 密钥、环境变量、模型权限 | 重新配置凭据,日志脱敏 |
| 限流 | 429 | 配额页、调用频率 | 指数退避、缓存、削峰 |
| 参数错误 | 400 | 请求体字段、模型标识 | 对照文档,模型列表确认 |
| 资源不存在 | 404 | 模型标识、区域 | 换可用模型标识 |
| 服务端错误 | 500 / 503 | 服务状态页 | 退避重试,记录日志 |
| 超时 | 无固定码 | 请求体大小、网络策略 | 设置 timeout,分级重试 |
7. 生产化:成本、安全、评测与模型切换
7.1 成本控制不能只依赖模型本身
大模型使用成本主要来自哪里?答案是 token 消耗。访问量一大,即使单个请求很便宜,总量也会快速上升。控制成本的常见做法:
- 每次响应都读取
usageMetadata,按模型标识和业务场景汇总 token 消耗。 - 对高频、低变化请求做缓存,比如常见问题分类结果。
- 对非实时任务做离线批量处理,把并发高峰打散。
- 建立降级链路:模型超时或失败时,回落到规则模板、关键词匹配或本地小模型。
- 在业务侧设置单用户调用上限,防止异常脚本或恶意请求把配额打满。
7.2 输入输出安全不能交给模型自动完成
模型的安全策略能拦截一部分风险内容,但不能替代业务侧的安全设计。真正要落实的是:
- 不要把不可信用户输入直接拼进
systemInstruction,避免提示词注入。 - 模型输出用于执行命令、写入数据库、下发配置之前,必须先经过业务校验。
- 日志中不记录完整输入输出,特别是含个人信息的文本。需要记录时做脱敏或只记录 token 量。
- 对模型输出做抽检和人工复核,尤其是客服回复、内容生成等对外可见场景。
7.3 模型评测和回归要跟着版本走
每次切换模型标识、调整提示词或修改参数后,都要跑一遍固定评测集。评测集不用很大,但必须覆盖你业务中的典型场景。
| 评测维度 | 观察指标 | 目标 |
|---|---|---|
| 格式合规率 | JSON 可解析的比例 | 接近 100% |
| 字段准确率 | 抽取字段与人工标注一致的比例 | 按业务要求 |
| 延迟 | 平均响应时间、P95 | 不超出业务容忍范围 |
| 成本 | 单次调用 token 数 | 在预算内 |
| 拒绝与拦截 | 安全策略触发比例 | 符合预期,不误伤正常请求 |
评测不是一次性的。模型服务端更新、标识切换、提示词变化都会影响输出质量,因此评测集要能反复运行。
7.4 Cyber 标识和灰度切换的配置化
不要把模型标识写死在代码里。推荐的做法是把它放入配置中心或环境变量,不同环境使用不同模型标识。例如预发环境用 gemini-3.8-flash-cyber,生产环境先用 gemini-3.8-flash,验证稳定后再灰度切到 Cyber。
灰度策略可以这样设计:
- 先切 10% 流量到新模型标识,观察错误率、延迟、token 消耗。
- 对比两类指标:旧模型的格式合规率和字段准确率、新模型的对应指标。
- 发现问题后立即把模型标识切回旧值,配置回滚比重发代码快得多。
- 灰度至少覆盖一天的业务周期,避免只验证了低峰期表现。
不同模型标识之间的上下文窗口和输出限制可能不同。灰度前要重新核对配额和 maxOutputTokens,不要假设所有模型完全等价。
8. 最佳实践清单和下一步扩展方向
8.1 接入前检查清单
| 检查项 | 通过标准 |
|---|---|
| 模型标识 | 已在模型列表接口确认可用 |
| 认证方式 | 凭据通过环境变量或密钥管理注入 |
| 网络策略 | API 域名在目标环境可访问 |
| 最小请求 | curl 调用返回正常文本 |
| 异常处理 | 空候选、空文本、403、429 都有明确处理 |
| 多轮会话 | role 和 contents 顺序正确 |
| 结构化输出 | JSON 可解析,字段校验通过 |
| 日志脱敏 | 密钥和完整输入输出不入日志 |
| 成本记录 | 每次调用记录 token 消耗 |
| 灰度回滚 | 模型标识可配置,随时可回滚 |
这张清单可以直接用作模型接入评审的检查表。每一项不通过,都不建议进入生产流量。
8.2 可以从这里继续深入的方向
完成上述接入之后,下一步通常是做能力扩展。
一是 RAG 检索增强。把知识库切块、向量化,再把检索结果作为上下文传入模型,解决模型对私域知识不了解的问题。
二是 Function Calling 和工具调用。让模型在回答前先查订单、查库存、查设备状态,把生成能力和业务系统连接起来。
三是可观测体系。把延迟、 token 量、错误码、模型标识统一上报,形成模型调用的监控大盘,这样模型质量问题能在早期被发现。
四是多模型路由。不同请求路由到不同模型,重要请求用更重的模型,简单请求用 Flash 模型,做到成本与质量的平衡。
8.3 给初学者的练习建议
如果这是你第一次接入 Gemini 3.8 Flash / 3.8 Flash Cyber 这类轻量级大模型,不要一上来就写完整业务代码。按这个顺序练习:
- 用 curl 完成一次最小请求,手写出完整的请求 JSON。
- 修改
temperature和maxOutputTokens,观察输出变化。 - 封装 Python 调用模块,加入空候选和异常处理。
- 实现一个三轮对话,验证 contents 顺序是否正确。
- 让模型输出 JSON,自己写解析和校验函数。
最后需要记住的判断是:接入一个模型不会因为第一次返回文本就结束,能真正接到业务里的关键是让响应可解析、可验证、可回滚。把模型标识、参数、配额和响应结构都当成接口契约的一部分来对待,后续无论是切换模型版本还是排查线上问题,都会顺畅很多。
