Gemini Batch API 的两种提交形态怎么选

2026-08-25

数据截至 2026-08,价格与限额以各官网为准。本文只讲计费与接入机制,不列具体价格数字。

Gemini 的 Batch API 在提交这一步只给了两种形态:一种是把 GenerateContentRequest 对象列表直接内嵌进创建请求里,另一种是把请求写成 JSONL 文件、先上传再引用。官方对分工的说法很直白——内嵌适合总请求体较小的批次,较大的请求集推荐用输入文件。所以选型的判断点不是「我有多少条请求」,而是「这批请求加起来的体积有多大」「里面要不要引用已经上传过的文件」「输出我打算怎么落地解析」。另外还有一条容易被忽略的前置限制:按官方页首的注意事项,Batch API 目前仅适用于 generateContent API。如果你的调用链本来就不在这套接口上,形态怎么选都是白讨论。

动手之前先过这道门槛:你调的是不是 generateContent

这条限制写在官方 Batch API 页面开头的注意事项里:Batch API 目前仅适用于 generateContent API(以官方文档当前版本为准)。

它的杀伤力在于开发顺序:如果你是先把在线调用跑通、再想着「把同样的调用批量化」,这条限制就会卡在中间。如果你在线那一侧用的不是 generateContent,那么这个批量化的想法在第一步就走不通,你得先把调用改回 generateContent 才谈得上提交批次。

Gemini 这边有类似性格的限制不止这一条。缓存那一侧也存在按接口划线的情况——官方明确 Interactions API 只支持隐式缓存,要用显式缓存必须改用 generateContent API,这一格的细节可以看 Interactions API 用不了 Gemini 显式缓存。两件事合在一起看,可以得到一条很实用的操作建议:批量和显式缓存这两项能力,官方点名的都是 generateContent。所以真要用到批量或者显式缓存,接口这一层的账要提前算,不要等到功能都做完了才发现批不了。至于 Gemini 各个接口之间还有哪些能力差异,稳妥的做法是每上一个新功能就回官方文档核一遍这个接口支不支持,而不是默认「在线能跑的,批量也能跑」。接口选型这件事,越早核成本越低:调用链还是草图的时候改一行就行,等到业务逻辑、重试策略、监控埋点全都围着某个接口长好了,再回头换接口,改的就不止是调用那一句了。

形态一:内嵌请求,把请求列表直接塞进创建调用

内嵌形态的做法是把一组 GenerateContentRequest 对象组成列表,放进 BatchGenerateContentRequest 里一次性提交。官方给这种形态标注的适用范围是总请求体较小的批次。

注意官方用的定语是「总请求体较小」,说的是整批内容加起来的体积,不是请求条数。这个区别很要紧:十条各自带着长上下文的请求,体积可能远超过几百条只有一两句话的短请求。所以判断该不该走内嵌,正确的做法是估一下整批 payload 序列化之后有多大,而不是数条数。

内嵌形态的输出是 inlineResponse 对象列表——官方对这一侧输出的描述,落点就在「对象列表」这个形态上。对写代码的人来说这个差别很实在:对象列表本身就是结构化数据,解析这一步不需要先按行切分文件、再逐行反序列化,字段直接取就是了。至于批量任务提交之后结果具体怎么取回、走哪个接口去读、隔多久去看一次,请以官方文档当前版本的说明为准,别照着在线调用的直觉去猜——批量任务是异步的,提交调用返回的那一刻任务还没跑完,这一点和同步接口的心智模型完全不同。

形态二:JSONL 输入文件,官方推荐给较大请求集

第二种形态是准备一个 JSONL 文件,每行一个完整的 GenerateContentRequest。官方对这种形态的推荐语境是「较大的请求集」。

它的输出同样是 JSONL:每行是一个 GenerateContentResponse,或者是一个状态对象

这里的「或者是状态对象」值得单独说一句。它意味着输出文件里并不保证每一行都是一份可以直接当成模型回复来用的结果——某些行返回的是描述该条请求处理状况的对象。所以解析输出 JSONL 的代码必须做分支判断:拿到一行先看它是哪一类,是响应就走正常的结果处理,是状态对象就走异常收集那一路。如果你的解析代码上来就按响应结构去取字段,遇到状态对象那一行就会崩,而且往往是跑完一大批之后才崩,重跑的代价不小。

JSONL 这一侧官方还额外说明了一件事:多模态输入可以在 JSONL 里引用其他已上传的文件。也就是说图片、音视频这类素材不必塞进请求体本身,而是先各自上传,再在 JSONL 的对应行里引用过去。批次里涉及多模态素材时,官方明确写出来的就是这条 JSONL 路径,照它走最稳妥。这条对工程组织方式也有影响:素材上传和请求组装被拆成了两段,可以先把素材批量传完、拿到引用,再去生成 JSONL 文本,两段各自失败各自重试,不会因为一个素材传坏就要重做整份请求文件。

上传这一步:File API 与 resumable 协议

JSONL 文件不是直接贴在创建请求里的,它要通过 File API 上传。走 REST 的话,官方给的是可续传上传(resumable upload),请求头是 X-Goog-Upload-Protocol: resumable

可续传上传的含义写在名字里:上传过程支持从断点继续,中途断了不必整份从头重来。请求头里的 X-Goog-Upload-Protocol: resumable 就是走这条路径的标记,具体的会话建立与分段流程按官方 File API 文档的说明实现。

对实现的直接影响是:走 REST 手写这一段时,别把上传当成一个普通的 POST 表单来写。上传是一段独立于「创建批量任务」的前置流程,它有自己的失败模式和重试语义,需要单独的错误处理。上传成功之后拿到的文件引用,才是创建批次时要填进去的来源。

如果用官方 SDK,创建批量任务的入口是这样的形态:Python 侧是 client.batches.create(model=..., src=..., config={'display_name': ...}),JavaScript 侧是 ai.batches.create({model, src, config: {displayName}}),REST 侧是 POST /v1beta/models/{model}:batchGenerateContent。三者的结构是对齐的:指定模型、指定来源、可选地给任务起个显示名。

那个 display_name 别嫌它可有可无。批量任务是异步的,你提交完就走了,过一段时间回来看结果。如果一次跑好几个批次,任务列表里全是自动生成的标识,靠人眼根本对不上哪个是哪个。把业务语义写进显示名,是提交时多打几个字、后面省一堆事的做法。

两种形态共用的对账机制:自定义 key

不管你选哪种提交形态,都要面对同一个问题:结果回来之后,怎么知道哪条响应对应哪条请求。

Gemini 给的机制是用户自定义的 key 字段——你在请求侧给每条请求打上自己的 key,响应会用同名 key 标注。这是批量任务对账的关键。

之所以说它关键,是因为批量场景下不能想当然地靠顺序对齐。输出是一批一批回来的,中间还可能夹着前面说的状态对象,如果你的对账逻辑是「输出第 n 行对应输入第 n 行」,那么一旦有任何一条走了不同的返回结构,后面全部错位,而且这种错位不会报错——数据默默地对错了人,比直接失败危险得多。

所以 key 这个字段在批量任务里不是可选项,是必填的工程纪律。key 的具体用法和对账时的写法,另有一篇专门讲:Gemini 批量任务怎么把响应对回请求

Batch 的限流是完全另一套账

这一条对做容量规划的人来说是好消息,但前提是你知道它存在。

官方明确:Batch API 的限流完全独立于非批量调用。也就是说你跑批不会去挤在线服务那份 RPM/TPM/RPD 的配额,反过来在线流量高峰也不直接吃掉你的批量能力。

但独立不等于没有约束。官方给 Batch 另外列了四类约束:并发作业数、输入文件大小、文件存储总量、每个模型的排队 token 数(各项的具体数值以官方文档为准,本文不列数字)。

这四类约束的形状和常规限流不一样,值得逐个体会一下它们各自会在什么时候咬人:

  • 并发作业数限制的是同时在跑的批次个数。切分策略如果是「把大任务拆成很多个小批次一起交上去」,最先撞的就是这一条。
  • 输入文件大小约束单个 JSONL 的体积上限,直接决定了你的 JSONL 要不要分片,以及每片放多少行。
  • 文件存储总量约束的是账下文件占用的总空间。这一条的隐蔽之处在于它是累积的——跑完的批次留下的输入文件不清理,长期下来会把额度占满,而出问题的时候排查视线往往先落在新任务身上,很难第一时间想到是历史文件把空间吃完了。
  • 每模型排队 token 数约束的是同一模型下排队等待的总量,说明排队深度是按模型分别计的。

常规调用那侧的 RPM/TPM/RPD 是怎么回事,站内有一篇跨厂商通用的 API 限流 RPM 与 TPM 机制 可以对照着看;Gemini 这边还有一条容易踩的:限流是按项目应用的,不是按 API 密钥应用的。

计费这一层:它属于哪一档,以及跑批时要特别留意的账单问题

Gemini 把服务分成几个独立计价的档位:标准、批量(Batch)、Flex、优先级(Priority)。Batch 是其中一档,官方说明它按低于标准价计费,具体比例请以官方定价页为准,本文不写。

官方给 Batch 的定位是异步处理大批量请求,并给出了一个目标周转时间(具体时长以官方文档为准),同时注明多数情况下会更快完成。适用场景官方也点了名:数据预处理、跑评估这类不需要立即响应的大规模非紧急任务。反过来说,凡是用户在前台等着结果的链路,都不该往 Batch 上放。

跑批在账单上要特别留意的是结算延迟这一环。官方明确写了结算流水线存在延迟(具体时长以官方文档为准),并且特别点名:批量模式与 Agent 这类长时间运行的任务,尤其容易在系统停止之前继续消耗

这句话的含义要读透。它说的是,当你触碰到某个应当让系统停下来的条件时,系统并不是在那一刻就精确刹住的,延迟窗口里的消耗照样发生。在线调用是一个请求一个请求来的,延迟窗口里能多跑掉的量有限;批量任务不一样,它本来就是一次提交、持续消耗,同样长度的延迟窗口在批量场景下能滚出去的量要大得多。

把这一条和另一条官方事实叠在一起看,风险会更清楚:预付款方案下,余额归零时该结算账号下所有项目的所有 API 密钥会同时停止工作。也就是说一个没算准的大批次,影响的不只是这个批次本身。这一格的完整机制在 Gemini 结算延迟导致的超额 里讲得更细。

所以到底怎么选:三个判断点

把上面的官方事实归拢一下,形态选择其实只要问三个问题:

第一,这批请求的总体积大不大。 官方给内嵌划的适用范围是总请求体较小,给 JSONL 划的是较大请求集。估体积,不是数条数。

第二,里面有没有要引用的已上传文件。 官方明确写出来的是:多模态输入可以在 JSONL 里引用其他已上传的文件。批次涉及多模态素材时,按官方给出的这条路径走 JSONL。

第三,你打算怎么消费输出。 内嵌的输出是 inlineResponse 对象列表,拿到就能在内存里接着处理;JSONL 的输出是文件,每行是响应或状态对象,你得写一段带分支判断的解析。要落地存档、要支持部分重跑,文件形态反而更顺手。

最后:动手之前值得再对齐一遍的三件事

第一件是接口。Batch 只对 generateContent 生效这条限制,官方把它放在页面开头的注意事项里,位置在所有代码示例之前——先确认调用链用的是不是 generateContent,再谈批量化,顺序反了就要返工。

第二件是对账。输出 JSONL 里可能出现状态对象,顺序对齐随时会错位,而且是静默错位。老老实实用自定义 key

第三件是别把 Batch 的限流当成没有限流。它确实独立于常规调用,但并发作业数、输入文件大小、文件存储总量、每模型排队 token 数这四类约束一样会拦你,其中文件存储总量是累积型的——跑完的批次记得清理输入文件,否则占用只会一直往上加。

本文所有机制描述均来自 Gemini 官方文档,具体数值、限额与定价请以官方页面当前版本为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。