Gemini API生产级落地指南:多模态调用、认证配置与响应解析

发布时间:2026/6/25 13:06:14

Gemini API生产级落地指南:多模态调用、认证配置与响应解析 1. 项目概述从零开始用好 Gemini API不是调个包那么简单你是不是也试过在 Google Cloud 控制台里点来点去填完 API Key、选完服务、跑通第一行import google.generativeai as genai结果一发请求就卡在403 PERMISSION_DENIED或者好不容易拿到响应发现返回的 JSON 格式乱七八糟根本没法直接塞进你的前端页面又或者明明文档里写着“支持多模态”你传了一张带坐标系的工程图纸过去它却只说“这是一张图片”——连图上标着的“Φ12.5±0.1”都认不出来别急这不是你代码写错了而是绝大多数人踩进的第一个坑把 Gemini 当成另一个 ChatGPT 的 API 来用忽略了它底层是一个严格分层、强约束、重上下文管理的多模态推理引擎。我去年帮三个团队落地 Gemini 集成从智能客服工单识别、到工业质检报告生成、再到教育类 APP 的手写公式解析最深的体会就是Gemini 不是“更聪明的聊天机器人”而是一套需要你亲手校准的精密光学仪器——你得知道光路怎么走、滤镜怎么配、快门怎么按它才给你清晰的成像。这篇笔记不讲“什么是大模型”“为什么多模态重要”这类泛泛而谈的概念只聚焦一件事如何在真实开发环境中让 Gemini API 稳定、可控、可预测地输出你真正需要的结果。它适合已经写过 Python、接触过 REST 或 SDK 调用、但被 Gemini 文档绕晕的工程师也适合产品/设计同学想搞清“这个能力到底能不能接进我的需求流程”甚至适合刚学完 requests 库的新手只要愿意跟着敲几行命令就能看到一张照片被准确识别出其中的表格结构和数值。核心关键词——Gemini API、多模态、Google Cloud、Python SDK、Prompt 工程、响应格式控制——每一个都会落到具体命令、配置项、报错日志和调试技巧上没有一句虚的。2. 整体设计思路与方案选型逻辑2.1 为什么必须放弃“直接调用”的思维惯性很多开发者第一次接触 Gemini会下意识打开官方 Quickstart复制粘贴genai.GenerativeModel(gemini-pro)然后model.generate_content(你好)。这确实能跑通但一旦进入真实场景问题立刻爆发模型版本混乱gemini-pro、gemini-pro-vision、gemini-ultra并非简单的“升级版”而是架构完全不同的三个独立模型。gemini-pro是纯文本流式模型gemini-pro-vision是图像文本联合编码器gemini-ultra则依赖 Google 内部专用硬件集群对外仅开放极有限的 API 接口。我见过最典型的错误是用gemini-pro-vision去处理纯文本问答结果耗时翻倍、费用暴涨而效果反而不如gemini-pro。API 层级错配Gemini 提供两套并行接口——RESTful HTTP 接口和Python SDK。SDK 看似方便但它内部做了大量自动重试、流式缓冲、响应解析等封装。当你需要精确控制超时比如工业场景要求 800ms 内必须返回、或需要捕获原始 HTTP 状态码如429 Too Many Requests的 Retry-After 头时SDK 反而成了黑箱。我们给某汽车厂做的产线缺陷识别系统最终全部切回原生requests调用就为了能实时监控每个请求的 TCP 连接建立时间、SSL 握手延迟、首字节响应时间TTFB这些指标 SDK 一律不暴露。认证机制的隐蔽陷阱Google Cloud 的 API 密钥API Key和 OAuth 2.0 凭据Service Account Key权限粒度完全不同。API Key 本质是“公开令牌”只能调用公开服务如gemini-pro的基础文本生成且无法访问私有数据而 Service Account Key 才能调用gemini-pro-vision处理你上传的本地图片或调用embeddings模型做向量计算。但文档里不会明说“用 API Key 调 vision 接口必然 403”只会写“请确保凭据有效”。我花两天时间排查一个 403 错误最后发现是团队运维同学给的 Key 权限只开了generativelanguage.googleapis.com漏掉了storage.googleapis.com——因为 vision 模型需要先将你上传的图片存入临时 GCS Bucket再传给模型这个存储步骤也需要显式授权。2.2 我们选择的最小可行技术栈轻量、透明、可审计基于上述教训我为所有新项目设定的“黄金组合”是语言层Python 3.10强制要求因低版本对httpx异步支持不完善HTTP 客户端httpx非requests——它同时支持同步/异步调用原生支持 HTTP/2且错误堆栈清晰显示是 DNS 解析失败、还是 TLS 握手超时这对线上故障定位至关重要。认证方式Service Account Key JSON 文件绝对不用 API Key——虽然多一步gcloud auth activate-service-account但它能精确控制roles/generativelanguage.admin、roles/storage.objectAdmin等细粒度权限且密钥可轮换、可禁用符合企业安全审计要求。模型选型策略严格遵循“能力最小化原则”。例如要做客服对话摘要首选gemini-pro要识别用户上传的身份证照片必须用gemini-pro-vision若需将 10 万条商品描述转为向量做相似搜索则必须用text-embedding-004注意这不是 Gemini 模型而是 Google 专为嵌入任务优化的独立模型。提示不要被gemini-ultra的宣传迷惑。截至 2024 年中它未对公众开放 API 接口所有声称“已接入 ultra”的第三方服务实际都是用gemini-pro或gemini-pro-vision加规则引擎模拟的。真要用 ultra目前唯一途径是申请 Google Cloud 的 Private Preview且需提供详细用例说明和合规承诺。2.3 架构设计为什么必须引入“响应解析中间层”Gemini 的原始响应结构极其复杂尤其在多模态场景下。以一张含表格的 PDF 截图为例gemini-pro-vision返回的 JSON 可能包含candidates[0].content.parts[0].text主文本回答candidates[0].content.parts[1].inline_data模型内部生成的、用于解释推理过程的中间图像base64 编码usage_metadatatoken 统计但prompt_token_count和candidates_token_count的计算逻辑与 OpenAI 完全不同Gemini 对图片 token 计算采用自定义分块算法safety_ratings每类风险如 HARM_CATEGORY_SEXUALLY_EXPLICIT的分数和阻断状态如果业务代码直接读取response.text当模型因安全策略拦截内容时你拿到的是空字符串而非明确的错误码。因此我强制所有项目在 SDK 层之上加一层GeminiResponseParserclass GeminiResponseParser: def __init__(self, response: dict): self.raw response property def is_blocked(self) - bool: # 检查 safety_ratings 中是否有 BLOCKED 阻断项 ratings self.raw.get(candidates, [{}])[0].get(safety_ratings, []) return any(rating.get(category) HARM_CATEGORY_DANGEROUS_CONTENT and rating.get(blocked) for rating in ratings) property def text_content(self) - str: # 安全提取文本兼容多 parts 结构 parts self.raw.get(candidates, [{}])[0].get(content, {}).get(parts, []) return .join(part.get(text, ) for part in parts)这个看似简单的封装解决了 70% 的线上告警——当用户上传敏感图片触发安全过滤时系统不再报KeyError: text而是返回结构化的{status: BLOCKED, reason: HARM_CATEGORY_MEDICAL_ADVICE}前端可据此提示“该图片涉及医疗建议暂不支持分析”。3. 核心细节解析与实操要点3.1 环境准备三步完成生产级认证配置很多教程教你pip install google-generativeai然后genai.configure(api_keyxxx)这在本地测试没问题但上线必崩。真正的生产环境配置必须包含以下三步缺一不可第一步创建并下载 Service Account Key登录 Google Cloud Console → 进入你的项目左侧菜单 →IAM Admin→Service Accounts→ 点击右上角CREATE SERVICE ACCOUNT名称填gemini-prod-saID 自动生成如gemini-prod-sayour-project.iam.gserviceaccount.com在Grant this service account access to project步骤添加两个角色Generative Language API User必需调用模型Storage Object Admin必需vision 模型需临时存储图片创建完成后点击服务账号 →KEYS→ADD KEY→Create new key→ 选择JSON→ 下载文件如gemini-prod-sa-12345678.json第二步设置环境变量严禁硬编码将下载的 JSON 文件放在服务器安全目录如/etc/secrets/gemini/并设置权限# 仅 root 和应用用户可读 sudo chown root:appuser /etc/secrets/gemini/gemini-prod-sa-12345678.json sudo chmod 640 /etc/secrets/gemini/gemini-prod-sa-12345678.json在应用启动脚本中加载export GOOGLE_APPLICATION_CREDENTIALS/etc/secrets/gemini/gemini-prod-sa-12345678.json export GOOGLE_CLOUD_PROJECTyour-project-id第三步验证权限是否生效关键不要跳过这步用curl直接测试 API 连通性# 获取访问令牌无需安装 gcloud CLI用原始 HTTP ACCESS_TOKEN$(gcloud auth print-access-token 2/dev/null || echo NO_GCP_AUTH) # 调用健康检查端点不消耗配额 curl -X GET \ -H Authorization: Bearer $ACCESS_TOKEN \ -H Content-Type: application/json \ https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key${YOUR_API_KEY} # 注意这里 YOUR_API_KEY 是你项目中启用 Generative Language API 后生成的密钥非 Service Account Key # 如果返回 {models: [...]}, 说明认证成功若返回 401检查 ACCESS_TOKEN 是否为空或过期实操心得我曾遇到一次诡异故障——本地测试一切正常但部署到 Kubernetes 集群后所有请求返回403 Forbidden。排查三天才发现集群节点的系统时间比标准时间慢了 5 分钟Google Cloud 的 JWT Token 验证对时间偏差极其敏感5min 即拒收。解决方案是在 K8s DaemonSet 中部署chrony同步时间并加入启动检查if [ $(($(date -u %s) - $(gcloud auth print-access-token | cut -d. -f2 | base64 -d | jq .exp))) -gt 300 ]; then echo Time skew detected!; exit 1; fi。3.2 多模态输入图片不是“传个 URL”就完事Gemini Vision 的输入要求远比想象中严格。它不接受任意网络图片 URL只支持三种方式Base64 编码的图片数据推荐最可控Google Cloud Storage (GCS) URI如gs://my-bucket/images/photo.jpgData URI如data:image/jpeg;base64,/9j/4AAQSkZJR...但即使你用了 Base64仍有两大陷阱陷阱一图片尺寸与分辨率限制Gemini Vision 对单张图片有硬性限制最大文件大小20MB最长边像素1280px超过会自动缩放但可能损失关键细节最小边像素64px低于此值会被拒绝我处理过一个医疗影像场景用户上传 4K 内窥镜视频帧3840×2160直接 Base64 会导致请求体超 10MB。解决方案不是简单压缩而是语义化裁剪from PIL import Image import io def smart_crop_for_vision(image_path: str, target_long_edge: int 1280) - bytes: 针对医学影像的智能裁剪保留中心区域避免边缘失真 img Image.open(image_path) w, h img.size if max(w, h) target_long_edge: return _pil_to_jpeg_bytes(img) # 直接转 JPEG # 计算缩放比例保持宽高比 scale target_long_edge / max(w, h) new_w, new_h int(w * scale), int(h * scale) resized img.resize((new_w, new_h), Image.Resampling.LANCZOS) # 关键医学影像常有文字标注在右下角裁剪时保留右下 80% 区域 left int(new_w * 0.1) top int(new_h * 0.1) right new_w bottom new_h cropped resized.crop((left, top, right, bottom)) return _pil_to_jpeg_bytes(cropped) def _pil_to_jpeg_bytes(pil_img: Image.Image) - bytes: buffer io.BytesIO() pil_img.save(buffer, formatJPEG, quality95, optimizeTrue) return buffer.getvalue()这段代码确保1文件大小 2MB2关键信息区如病灶标记、刻度尺不被裁掉3JPEG 压缩质量可控避免 PNG 无损压缩导致体积过大。陷阱二MIME Type 必须精确匹配Gemini 对inline_data.mime_type字段校验极严。常见错误用.jpg后缀但实际是 JPEG 格式 → 正确 MIME 是image/jpeg用.png但图片是 APNG 动画 → Gemini 不支持动画需转为静态 PNG用image/webp但浏览器上传时实际是 JPEG → 必须用imghdr库二次检测import imghdr def detect_mime_type(file_bytes: bytes) - str: 精准检测图片 MIME 类型避免后缀欺骗 img_type imghdr.what(None, hfile_bytes[:32]) # 读前 32 字节 if img_type jpeg: return image/jpeg elif img_type png: return image/png elif img_type webp: return image/webp else: raise ValueError(fUnsupported image type: {img_type}) # 使用示例 with open(upload.jpg, rb) as f: img_bytes f.read() mime_type detect_mime_type(img_bytes)3.3 Prompt 工程不是“写得越详细越好”而是“结构越清晰越稳”Gemini 的 Prompt 设计哲学与 LLaMA 或 Claude 截然不同。它极度依赖结构化指令Structured Instructions而非自然语言描述。例如要让模型从发票图片中提取金额错误写法是“请仔细看这张发票图片找出总金额数字它通常在右下角可能是‘Amount’、‘Total’或‘¥’符号后面。”正确写法必须是你是一个专业的财务票据识别助手。请严格按以下 JSON Schema 输出结果不要任何额外文本 { invoice_number: 字符串发票编号如 INV-2024-001, total_amount: 浮点数总金额如 1234.56, currency: 字符串币种代码如 CNY、USD, issue_date: 字符串日期格式 YYYY-MM-DD }原因在于Gemini 的输出解码器Decoder内置了 JSON Schema 验证逻辑。当你提供明确的 Schema它会优先尝试生成符合结构的 JSON而非自由文本。实测数据显示使用 Schema 指令后JSON 解析失败率从 32% 降至 1.7%。更进一步对于复杂多步骤任务如“先识别表格再计算每行小计最后汇总”必须用Chain-of-Thought思维链显式拆解请按以下步骤处理 STEP 1: 识别图片中的表格结构输出为 Markdown 表格含表头。 STEP 2: 对 STEP 1 的表格逐行计算“单价 × 数量 小计”在每行末尾添加“小计”列。 STEP 3: 在表格底部添加一行“总计”计算所有小计之和。 STEP 4: 仅输出 STEP 3 的结果格式为 JSON{grand_total: 1234.56}这种写法强制模型分步执行避免“一步到位”导致的幻觉。我在处理某电商价签 OCR 时用此方法将总价识别准确率从 89% 提升至 99.2%。4. 实操过程与核心环节实现4.1 从零搭建一个稳定可用的 Gemini 文本生成服务我们以构建一个“技术文档摘要生成器”为例完整演示生产级实现。目标输入一篇 5000 字的 Kubernetes 部署文档输出 300 字以内、保留所有关键参数如replicas、resources.limits.cpu的摘要。Step 1创建模型实例与配置import httpx import json from typing import Dict, Any class GeminiTextService: def __init__(self, project_id: str, location: str us-central1): self.project_id project_id self.location location self.base_url fhttps://{location}-aiplatform.googleapis.com/v1 # 使用 httpx 的连接池复用 TCP 连接 self.client httpx.Client( timeouthttpx.Timeout(30.0, connect10.0), limitshttpx.Limits(max_connections100, max_keepalive_connections20) ) def generate_summary(self, document_text: str) - Dict[str, Any]: # 构造符合 Google Cloud Vertex AI 格式的请求体 payload { contents: [{ role: user, parts: [{ text: f你是一名资深 DevOps 工程师。请为以下 Kubernetes 部署文档生成技术摘要要求 1. 严格控制在 300 字以内 2. 必须包含以下字段的值replicas、containers[].resources.limits.cpu、containers[].ports[].containerPort 3. 用中文输出术语保持英文如 Deployment、Pod、CPU 4. 不要解释、不要补充、不要猜测未提及的参数。 文档内容 {document_text[:10000]} # 截断防超长Gemini Pro 最大输入约 32k tokens }] }], generationConfig: { temperature: 0.1, # 低温确保确定性 maxOutputTokens: 512, topP: 0.95, stopSequences: [\n\n] # 遇到双换行即停止 } } # 发送请求注意Vertex AI 的 endpoint 与 Generative Language API 不同 url f{self.base_url}/projects/{self.project_id}/locations/{self.location}/publishers/google/models/gemini-pro:generateContent headers { Content-Type: application/json, } try: response self.client.post(url, jsonpayload, headersheaders) response.raise_for_status() return response.json() except httpx.HTTPStatusError as e: print(fGemini API error: {e.response.status_code} - {e.response.text}) raiseStep 2响应解析与容错处理def parse_summary_response(self, raw_response: dict) - str: 健壮解析 Gemini 响应处理各种边界情况 try: # 检查是否被安全策略拦截 candidates raw_response.get(candidates, []) if not candidates: return ERROR: No candidates returned by model candidate candidates[0] if candidate.get(finishReason) SAFETY: safety candidate.get(safetyRatings, []) blocked_categories [s[category] for s in safety if s.get(blocked)] return fERROR: Blocked by safety filter: {, .join(blocked_categories)} # 提取文本 parts candidate.get(content, {}).get(parts, []) if not parts: return ERROR: Empty content parts text parts[0].get(text, ).strip() if not text: return ERROR: Empty text response # 长度校验防止模型忽略指令 if len(text) 400: return fWARNING: Response too long ({len(text)} chars), truncated:\n{text[:400]}... return text except Exception as e: return fERROR: Parsing failed - {str(e)} # 使用示例 service GeminiTextService(project_idmy-k8s-project) doc open(k8s-deployment.yaml).read() summary service.parse_summary_response(service.generate_summary(doc)) print(summary)Step 3性能压测与调优用locust模拟 100 并发请求发现平均延迟 2.3sP95 达 4.8s远超预期。通过httpx的httpx-profiling工具分析发现 60% 时间耗在 DNS 解析。解决方案在httpx.Client初始化时指定 DNS 缓存import httpcore self.client httpx.Client( transporthttpcore.AsyncHTTPTransport( pool_limitshttpcore.PoolLimits( max_connections100, max_keepalive_connections20 ), # 强制使用 Google Public DNS避免本地 DNS 污染 trust_envFalse ), # 预热 DNS 缓存 event_hooks{ request: [lambda request: None], response: [lambda response: None] } )优化后 P95 降至 1.2s满足 SLA 要求。4.2 图像理解实战从手机拍摄的电路板照片中提取元器件清单这是工业场景的真实需求。用户用手机拍一张 PCB 照片需识别出电阻、电容、IC 型号及位置坐标。Step 1图片预处理流水线手机照片存在畸变、反光、阴影问题。我们构建三级预处理几何校正用 OpenCV 检测 PCB 四角利用焊盘高对比度透视变换矫正import cv2 import numpy as np def correct_pcb_perspective(image_bytes: bytes) - bytes: img cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 增强边缘 blurred cv2.GaussianBlur(gray, (5, 5), 0) edged cv2.Canny(blurred, 50, 150) # 找最大四边形轮廓假设 PCB 为矩形 contours, _ cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return image_bytes # 退化为原图 largest_contour max(contours, keycv2.contourArea) epsilon 0.02 * cv2.arcLength(largest_contour, True) approx cv2.approxPolyDP(largest_contour, epsilon, True) if len(approx) 4: # 成功找到四边形 pts np.float32([approx[i][0] for i in range(4)]) # 按左上、右上、右下、左下排序 rect np.zeros((4, 2), dtypefloat32) s pts.sum(axis1) rect[0] pts[np.argmin(s)] rect[2] pts[np.argmax(s)] diff np.diff(pts, axis1) rect[1] pts[np.argmin(diff)] rect[3] pts[np.argmax(diff)] # 目标矩形尺寸根据 PCB 尺寸估算 width, height 1200, 800 dst np.array([[0, 0], [width, 0], [width, height], [0, height]], dtypefloat32) M cv2.getPerspectiveTransform(rect, dst) warped cv2.warpPerspective(img, M, (width, height)) _, buffer cv2.imencode(.jpg, warped, [cv2.IMWRITE_JPEG_QUALITY, 95]) return buffer.tobytes() return image_bytesStep 2构造 Vision Promptdef build_vision_prompt() - str: return 你是一个专业的电子工程师正在分析一块印刷电路板PCB照片。请严格按以下 JSON Schema 输出结果 { components: [ { type: string, 元器件类型如 RESISTOR, CAPACITOR, IC, value: string, 标称值如 10kΩ, 100nF, STM32F407VGT6, position: { x: number, 左上角 X 坐标像素, y: number, 左上角 Y 坐标像素, width: number, 宽度像素, height: number, 高度像素 } } ] } 注意 - 只识别清晰可辨的元器件模糊或遮挡的跳过 - IC 型号必须完整如 ESP32-WROOM-32不能简写为 ESP32 - 坐标以图片左上角为原点单位像素 - 不要输出任何解释性文字只输出 JSON。Step 3调用 Vision API 并解析def analyze_pcb_image(self, image_bytes: bytes) - dict: # 预处理 corrected_bytes correct_pcb_perspective(image_bytes) mime_type detect_mime_type(corrected_bytes) # 构造请求 payload { contents: [{ role: user, parts: [ {text: build_vision_prompt()}, { inline_data: { mime_type: mime_type, data: base64.b64encode(corrected_bytes).decode(utf-8) } } ] }], generationConfig: { temperature: 0.0, # 视觉识别必须 0 温度 maxOutputTokens: 2048 } } url f{self.base_url}/projects/{self.project_id}/locations/{self.location}/publishers/google/models/gemini-pro-vision:generateContent headers {Content-Type: application/json} response self.client.post(url, jsonpayload, headersheaders) response.raise_for_status() # 解析 JSON 响应Gemini Vision 会尽力返回合法 JSON raw_json self.parse_summary_response(response.json()) try: return json.loads(raw_json) except json.JSONDecodeError: # 若 JSON 解析失败用正则提取关键字段兜底 import re components [] for match in re.finditer(rtype:\s*([^])[^}]*value:\s*([^])[^}]*x:\s*(\d),\s*y:\s*(\d), raw_json): components.append({ type: match.group(1), value: match.group(2), position: { x: int(match.group(3)), y: int(match.group(4)), width: 50, height: 30 # 默认尺寸 } }) return {components: components}5. 常见问题与排查技巧实录5.1 典型错误速查表错误现象可能原因排查命令/步骤解决方案403 PERMISSION_DENIEDService Account 缺少storage.objectAdmin权限gcloud projects get-iam-policy YOUR_PROJECT_ID --flattenbindings[].members --formattable(bindings.role,bindings.members) | grep your-sa.*gserviceaccount.com在 IAM 页面为 SA 添加Storage Object Admin角色429 TOO_MANY_REQUESTSQPS 超过配额默认 60 QPMgcloud services quota list --projectYOUR_PROJECT_ID | grep generativelanguage提交配额提升申请或在客户端加指数退避重试500 INTERNAL_ERROR图片格式损坏或 MIME 不匹配file -i your_image.jpg检查实际 MIMEhead -c 100 your_image.jpg | hexdump -C查看文件头用convert input.jpg -strip output.jpg清除 EXIF用detect_mime_type()校验{error: {code: 3, message: Invalid argument}}generationConfig参数非法如 temperature1.5检查 官方文档 中各参数范围temperature 必须在 [0.0, 1.0]maxOutputTokens ≤ 8192响应中safetyRatings显示HARM_CATEGORY_HARASSMENT但内容正常模型对某些词过于敏感如“black box”在 prompt 开头添加“你是一个专业、中立的技术助手以下内容均属正常技术讨论不涉及任何有害意图。”添加此声明可降低误判率约 40%5.2 独家避坑技巧那些文档里不会写的细节技巧一用streamTrue抓住“思考过程”而非只等最终答案Gemini 支持流式响应Streaming但默认关闭。开启后你能看到模型逐步生成的 token这对调试极其宝贵# 在 generationConfig 中添加 stream: True # 响应体变为 SSE 格式用 httpx 处理 with self.client.stream(POST, url, jsonpayload, headersheaders) as r: for line in r.iter_lines(): if line.startswith(data: ): data json.loads(line[6:]) if candidates in data: text data[candidates][0][content][parts][0][text] print(fStream chunk: {text[-20:]}) # 打印最后 20 字符当模型卡在某个词如反复输出“the the the”你能立即感知而非等待 30 秒超时。技巧二system_instruction是隐藏王牌但仅限gemini-1.5-pro最新gemini-1.5-pro模型支持system_instruction字段可全局设定角色和约束payload { system_instruction: { parts: [{text: 你是一个严谨的法律文书助手所有输出必须引用《中华人民共和国民法典》具体条款格式为依据民法典第XX条...}] }, contents: [...] }这比在每个 user prompt 里重复写指令更高效且能减少 token 消耗。但注意gemini-pro和gemini-pro-vision不支持此字段强行添加会导致 400 错误。技巧三candidate_count2不是“多选一”而是“强制多样性”设置candidate_count2会让模型生成两个完全不同的回答路径而非微调版本。例如问“如何部署 Redis”一个回答讲 Helm Chart另一个讲 Docker Compose。这在需要 A/B 测试 prompt 效果时极有用# 获取两个候选答案 candidates response[candidates] answer_a candidates[0][content][parts][0][text] answer_b candidates[1][content][parts][0][text] # 用规则或人工评估哪个更符合业务需求5.3 性能与成本监控如何避免账单爆炸Gemini 的计费模型是per character字符 per image图片而非 per token。

相关新闻