☰
告别限流与高成本:用Vertex AI Batch任务实现批量图像生成
2026/10/17 4:45:50 网站建设 项目流程

在处理批量生成场景时,大多数人第一反应是写脚本循环调用在线推理接口,但一旦请求量上来,限流、超时、成本失控这些问题会一起找上门。我在中途切换到 Vertex AI 的 Batch 任务,用 gemini-3-pro-image-preview 跑图像生成,把一千多个并发请求压缩成一次异步作业,整个流程才真正顺下来。这篇就把创建 Batch 任务的完整思路、配置细节和踩坑记录整理出来。

1. 为什么用 Batch 任务:在线推理扛不住批量场景

1.1 在线调用与批量任务的核心差异

在线推理接口设计目标是低延迟、高并发、单次请求快速返回,适用于聊天对话、实时审核这类场景。但批量生成场景恰恰相反,任务量大、实时性要求低、结果需要落盘保存,比如给商品库批量生成场景图、给文章批量生成配图、批量生成短视频封面。

如果你用在线接口跑一千个图像生成请求,通常要面对三个问题:第一是限流,在线接口对每分钟请求数有严格配额,超了就返回 429;第二是成本,在线接口按调用次数计费,多次重试会显著推高账单;第三是稳定性,长任务跑几个小时后脚本中断、网络超时、进程被杀,断点续跑要写一堆额外代码。

Vertex AI 的 Batch 任务把这些问题打包解决。你把输入数据以 JSONL 格式扔到 Cloud Storage,提交一个 BatchPredictionJob 到 Vertex AI,平台按你的模型、输入数据、输出路径创建任务,跑完后把结果写回存储桶。整个过程不需要写脚本,不需要手动并发控制,失败自动重试,费用也低于在线调用。

1.2 一个实际场景:商品图批量生成项目

我从一个实际项目说起。某团队要做一套商品营销素材,需要为一千多个商品分别生成"商品在真实场景中的展示图",用文本描述商品特征和环境要求,模型输出符合要求的场景图像。

最初方案是用在线接口逐条调用,结果不到三百条就碰到限流,而且有些请求因为超时失败重试,代码里全是重试逻辑。后来我把整个流程转到 Batch:

  • 输入:一千三百多条 JSONL 数据,每条包含商品的文本描述和画面要求
  • 模型:gemini-3-pro-image-preview(预览版图像生成模型)
  • 输出:每行对应一个生成结果,包含图像数据或图像路径

提交一个任务,平台自动分配资源批量跑完,全过程我只需要查看状态和处理结果文件。

1.3 什么场景适合 Batch,什么场景不适合

Batch 不是万能药,选错场景反而更慢。我按自己的标准做了个判断表:

场景特征适合 Batch适合在线调用
请求量单次任务大量请求(上百条起)少量请求或调用频率低
实时性分钟级或小时级出结果可接受需要秒级或毫秒级返回
数据形态输入输入为文件,可预处理成 JSONL输入依赖交互上下文或用户实时输入
成本敏感高,Batch 单价更低低
任务可重复可重跑任务,支持幂等需要严格控制调用次数

如果一次任务只有十来个请求,等 Batch 排队候的时间可能比在线调用的时间还长,这时候直接循环调用更省事。但如果请求量到了几百上千条,Batch 任务在成本、稳定性、管理复杂度上的优势就非常明显。

2. 前置准备:环境、权限与输入数据格式

2.1 开启服务与账号准备

创建 Batch 任务之前,必须先确认三件事:目标项目开启了 Vertex AI API 和 Cloud Storage API;当前账号有足够权限创建 BatchPredictionJob 和读写存储桶;已确认可用区域列表中有支持模型区域的配额。

我自己踩过一次:项目是新建的,Vertex AI API 没开启,调用 SDK 时报了 403 权限错误,浪费了半小时。建议动手前先在控制台确认Vertex AI API、Cloud Storage API、IAM Service Account Credentials API三个服务均为可用状态:

  • 项目:选择一个已有项目或新建项目,记下项目 ID
  • 区域:优先选择已上线该模型支持的区域,不同区域配额独立,某些区域资源池更充裕
  • 权限:账号需要aiplatform.batchPredictionJobs.create权限,服务账号需要有读取输入存储桶、写入输出存储桶的权限

2.2 准备 Cloud Storage 桶与输入目录

Batch 任务的输入输出都放在 Cloud Storage 中。建议为每个任务建独立的桶或独立目录,避免不同任务的输入输出互相混在一起。目录结构可以参考:

gs://my-bucket/batch-jobs/gemini-img-prod/ ├── inputs/ │ └── requests.jsonl └── outputs/
  • inputs/requests.jsonl:任务输入数据
  • outputs/:任务输出目录,任务完成后平台把结果写在这里

输入和输出目录不建议放在同一个路径,因为平台的输出会以任务名字生成子目录,混放会导致后续清理困难。创建桶时建议就近选择 Batch 任务所在区域,跨区域读写会有一定网络延迟和流量费用,量大的时候这笔费用不可忽略。

2.3 JSONL 输入数据的格式要求

Vertex AI 的 Batch 任务输入格式是 JSONL,每行一个 JSON 对象,对应一次推理请求。与在线接口的 single-turn 对话格式不同,Batch 场景的请求体可以只包含用户请求内容,也可以包含系统指令。

以 gemini-3-pro-image-preview 为例,该模型接收文本提示并生成图像,输入 JSONL 中每行包含提示词和可选参数:

{"prompt": "A bottle of perfume displayed on a wooden table, soft morning light, high detail, commercial product photography"} {"prompt": "Fashion sneakers on a city street, dynamic angle, golden hour, advertising photography style"} {"prompt": "Wireless headphones on a minimalist desk, studio softbox lighting, clean background", "negative_prompt": "blurry, low quality", "image_size": "1024x1024"}

实际支持的字段集合请以模型文档为准。需要注意的点有四个:

  • 每行必须是合法的 JSON,不能有多余逗号或换行
  • 字段名不要自己发明,预设提示词就用引擎支持的字段名
  • 文件最后一行要换行或确保没有语法错误,否则可能触发解析失败
  • JSONL 文件大小达到更大规模或包含特殊字符时,建议先上传后验证,再提交任务

我第一次写输入文件时,用 Excel 拼 JSONL,结果某些描述中的引号没有转义,任务直接报输入数据格式错误。后面我改用 Python 脚本生成 JSONL:

import json items = [ {"id": "p_001", "prompt": "A perfume bottle on a wooden table, product photography"}, {"id": "p_002", "prompt": "Sneakers on a city street, action shot"} ] with open("requests.jsonl", "w", encoding="utf-8") as f: for item in items: f.write(json.dumps({"id": item["id"], "prompt": item["prompt"]}, ensure_ascii=False) + "\n")

这里在每行加了一个id字段,便于任务结束后把输出结果关联回原始商品记录,务必保留原始数据的关联键。

2.4 权限配置的几个容易忽略的点

Batch 任务提交后,Vertex AI 会以服务账号身份运行任务,读取输入文件、写入输出文件都通过该服务账号权限校验。最常见的问题是任务提交后一直报权限错误,控制台看到错误信息定位到存储桶读写权限不够。

配置思路:

  • 如果使用默认 Compute Engine 服务账号,需要给该服务账号添加存储桶读取和写入的 IAM 权限
  • 更推荐创建一个专用服务账号,只赋予该任务关联的两个存储桶访问权,遵循最小权限原则
  • 服务账号所在的存储桶需要显式授权,不仅需要在账号绑定了角色,还需要在存储桶的 IAM 策略中确认

我在实践中会提前测试权限:

# 先用 gcloud 检查能否读取输入文件 gcloud storage cat gs://my-bucket/batch-jobs/gemini-img-prod/inputs/requests.jsonl | head -n 1 # 再测试输出目录可写 echo "test" | gcloud storage cp - gs://my-bucket/batch-jobs/gemini-img-prod/outputs/test.txt

能读能写再提交任务,能省下不少排查时间。

3. 核心实操:在 Console 界面创建 Batch 任务

3.1 进入 Batch 创建页面:入口与基本信息填写

Console 创建 Batch 任务适合第一次体验、验证数据格式和参数配置。登录 Vertex AI 控制台后,从左侧菜单找到"Batch 预测"或"批量任务"入口,点击"创建批处理任务"按钮。

页面第一步让你填写基本信息。关键字段有三类:

  • 名称:给任务起一个能识别用途的名字,例如 gemini-img-batch-0705,方便后续管理
  • 区域:选择云环境区域,建议和存储桶所在区域一致
  • 模型:选择你要用的模型,这里选 gemini-3-pro-image-preview 对应的自训练模型或基础模型

选择模型时注意版本名称的区分。预览版模型通常有-preview后缀,与稳定版模型可能使用不同的模型 ID。模型名称必须完整准确,一个字符都不能错,否则任务开始前就会报模型未找到。

3.2 配置数据来源与输出路径

创建页面最重要的部分是配置数据来源和输出位置。

  • 数据来源:选择 Cloud Storage 文件。这里输入文件所在桶和路径,格式必须是 JSONL。页面一般会提供浏览功能的文件选择器,帮助验证路径是否存在
  • 输出路径:选择 Cloud Storage 目录。任务结束后输出文件会写在这个目录下。不同任务建议使用独立输出目录,任务命名不同生成的子目录也不同,但要养成习惯自己统一管理
  • 输出格式:Batch 统一输出 JSONL。每行对应一个输入的推理结果

我强烈建议在实际任务前,先准备一个十条以内的测试文件,跑一个小任务验证路径、格式全链路。我就有过一次教训:输入文件弄成每行一个 JSON 数组而不是 JSON 对象,控制任务页报错信息不直观,只提示"输入数据格式错误",后来手动打开 JSONL 检查才定位问题。

3.3 启动任务并查看运行状态

配置完成后点击创建,任务进入加载队列。Batch 任务从提交到完成需要经历几个状态:

状态含义
排队中任务已创建,等待资源分配
运行中平台正在逐批处理数据
已完成全部输入数据处理完成,输出已写入
失败出现错误,不会继续处理后续数据

控制台的任务列表会实时显示状态、时间等信息。如果排队时间过长,通常和区域资源池繁忙有关,可以换区域重试,或者等待一段时间再看。如果已运行,可以点进任务详情查看进度。

3.4 任务完成后的输出文件解读

完成后到输出目录查看文件。输出通常也是 JSONL 格式,每行对应输入 JSONL 的一行。输出结果中一般包含:

  • 对应的请求 ID 或输入数据(用于关联原始请求)
  • 模型生成的文本或图像表示
  • 推理元数据,如 token 数或处理耗时

图像模型一般返回一个引用 GCS 内图像文件的路径或 base64 编码。第一种我优先选择,因为如果批量返回 base64 全部塞进一个 JSONL,文件会非常大,读取和后续处理都不方便。使用 GCS 路径模式则每个图像单独落盘,JSONL 中只有元数据,后续处理灵活很多。

4. 自动化创建方式:Python SDK 与命令行

4.1 我为什么不用控制台按钮

控制台适合偶发性使用,一旦我要在脚本流程中反复提交任务,例如按商品类目拆分成多个批次,控制台操作就太慢了。我建议用命令行或 Python SDK 提交任务,这样输入文件、输出目录、任务名称都是脚本参数,跑一次就能拿到结果。

用 Python SDK 的好处是可以在同一个脚本里完成读配置、生成 JSONL、上传 GCS、提交任务、轮询状态、解析结果,整个链路工程化。

4.2 初始化客户端与环境变量

用 SDK 前先装依赖:

pip install google-cloud-aiplatform google-cloud-storage

初始化时需要指定项目 ID 和区域:

import vertexai from google.cloud import aiplatform PROJECT_ID = "your-project-id" REGION = "us-central1" vertexai.init(project=PROJECT_ID, location=REGION) aiplatform.init(project=PROJECT_ID, location=REGION)

区域和项目分别设置容易漏,尤其是多个项目切换时,我踩过坑:忘改 region 导致任务提交到错误区域,一直等不到资源。建议用环境变量统一管理:

export GOOGLE_CLOUD_PROJECT="your-project-id" export CLOUD_ML_REGION="us-central1"

4.3 提交任务:核心代码逐步拆解

提交一个 BatchPredictionJob 的完整流程包括准备输入数据、上传到 GCS、提交任务、轮询结果。下面给一个可复制的参考脚本:

from google.cloud import aiplatform PROJECT_ID = "your-project-id" REGION = "us-central1" BUCKET_URI = "gs://your-bucket/batch-jobs/gemini-img-prod" INPUT_URI = f"{BUCKET_URI}/inputs/requests.jsonl" OUTPUT_URI = f"{BUCKET_URI}/outputs" job = aiplatform.BatchPredictionJob.create( project=PROJECT_ID, location=REGION, display_name="gemini-img-demo-batch", model_name="publishers/google/models/gemini-3-pro-image-preview", gcs_source=INPUT_URI, gcs_destination_prefix=OUTPUT_URI, model_parameters={}, job_resources_mig_config=None, ) job.wait_for_completion() print(job.state) print(job.output_info)

说明一下参数选择逻辑:

  • display_name:任务名,建议包含日期、用途、批次号,清理数据时一看便知
  • model_name:完整模型路径。预览版模型必须写 publisher 前缀,格式为publishers/google/models/模型名。写错前缀大概率报错
  • gcs_source:输入文件 URI
  • gcs_destination_prefix:输出目录

注意不同版本的 SDK 对BatchPredictionJob.create参数兼容性有差异,新版可能要求传入gcs_destination_prefix而非gcs_destination_prefix,如果 IDE 没有自动补全,建议先跑一个最小示例验证 SDK 版本。

4.4 更细粒度的输入输出配置

如果我的输入文件很大,还需要更细的配置。Vertex AI 的 Batch 输入支持分片参数,例如:

  • instances_format:默认 JSONL,也可以指定 CSV
  • predictions_format:输出格式,默认 JSONL
  • model_parameters:模型推理参数,不同模型配置不同

对于图像生成模型,常见的model_parameters可能包括图像尺寸、生成数量、质量参数。实际参数名需要查模型文档。建议先用控制台跑一个最小任务,稳定后固化到脚本里。

job = aiplatform.BatchPredictionJob.create( display_name="gemini-img-batch-v2", model_name="publishers/google/models/gemini-3-pro-image-preview", instances_format="jsonl", predictions_format="jsonl", gcs_source=INPUT_URI, gcs_destination_prefix=OUTPUT_URI, model_parameters={ # "image_size": "1024x1024", # "negative_prompt": "blurry, low quality", }, )

4.5 任务提交后的状态轮询与结果拉取

job.wait_for_completion()会同步阻塞跑完整个任务,比较适合脚本处理。但如果你在交互式环境中使用,建议轮询:

import time while True: job.refresh() if job.state in ["JOB_STATE_SUCCEEDED", "JOB_STATE_FAILED", "JOB_STATE_CANCELLED"]: break print(f"Current state: {job.state}") time.sleep(60)

轮询间隔建议至少三十秒,太频繁会白白消耗 API 配额。任务结束后从job.output_info拿到输出目录,后续解析 JSONL 文件即可。

4.6 利用命令行辅助监控

如果你习惯了命令行,也可以直接用 gcloud 提交和监控:

# 创建任务 gcloud ai batch-prediction-jobs create \ --display-name=gemini-img-cli-batch \ --model-name=publishers/google/models/gemini-3-pro-image-preview \ --job-input-uri=gs://your-bucket/batch-jobs/gemini-img-prod/inputs/requests.jsonl \ --job-output-uri=gs://your-bucket/batch-jobs/gemini-img-prod/outputs # 查看任务状态 gcloud ai batch-prediction-jobs describe \ --region=us-central1 \ <job-name>

--job-output-uri参数注意要传到输出目录层级。CLI 创建任务不会自动创建输出目录,需要事先手动建好。

5. 关键参数、成本与预览版模型的特别事项

5.1 Preview 模型和正式版的差异

名称里带preview意味着模型处于预览阶段,与正式版有几点显著区别:

第一,配额独占但有限。预览版模型通常不在通用配额池里,而是单独供给,意味着并发能力可能不如正式版,排队长。第二,行为可能变化。开发者常根据预览版的反馈调整模型行为,同一个提示词在不同时间点跑出来的风格可能有细微变化。第三,可用性不承诺。预览模型通常不建议直接用于生产核心链路,建议需要跑正式数据处理前先确认模型是否已经转正。

我实际项目中会把预览版任务和正式版任务分开标记,方便以后切换模型时重新跑任务。

5.2 选择机器类型:别一上来就选最大的

Batch 预测任务同样需要考虑机器资源,BatchPredictionJob 支持指定机器类型,常见的是n1-standard-*系列或 GPU 机型。很多教程默认选最大规格的 GPU 实例,我认为不够合理。

图像生成模型通常依赖 GPU,但选择机型前需要想清楚两件事:你需要的算力类型和并发数。Batch 任务本身会对输入数据分片处理,单个实例能处理多少个请求和输入图片尺寸、文本长度相关。

经验值参考:

  • 文本提示为主、图像尺寸为默认值时,用基础机器配单 GPU 即可
  • 输出图像数量多或分辨率较大的推理请求,考虑更高规格 GPU
  • 不确定时先用小规模测试,记录单个请求的平均耗时可计算出大致总量

5.3 成本估算:别等到账单出来才后悔

Batch 虽然比在线调用便宜,但批量任务的成本基数大,一旦浪费很可观。我算过一笔账:一千三百条输入,平均请求约消耗若干 token、生成一张中等分辨率图像,总成本分解为计算费用和存储费用,估算约几十元到一个区间。

省钱技巧:

  • 先用最小数据集测试,通常十条以内,测完再跑全量
  • 输出只保留需要的字段,不必要的元数据写入会占用存储空间
  • 输出目录定期清理,任务重跑产生的旧版本结果要及时删除
  • 优先用 Batch 专用资源池而不是按需资源池,费用单价会更低

5.4 任务配额限制:排队不是故障

Batch 任务提交后显示排队是正常现象,尤其预览版模型。我遇到过一次排队超过两小时的任务,原因就是区域资源池紧张,没有报错,只是等待。处理办法有两个:等待,或者换一个配额更充裕的区域重新提交。

在自动化脚本中加入超时告警会很有价值。如果任务排队超过两小时,CI 里设置告警提醒。

6. 常见问题与排查技巧实录

6.1 任务一直排队,画面看起来像卡住了

有段时间我在常用区域跑图像 Batch 任务,任务始终是排队状态,一度以为自己配置错了,反复取消重新创建。后经验证,与其他区域对比后发现,常用区域当时资源池确实紧张。

后续建议:

  • 查看区域内配额使用情况和模型独占配额剩余量
  • 对比其他区域相同任务提交后的排队时间
  • 设置超时脚本,如果超过一定时长自动取消并改区域重提

6.2 数据格式错误导致任务秒失败

有次任务提交后很快就显示失败,查看日志提示"输入数据解码失败"。排查发现输入文件不是 JSONL,而是一个 JSON 数组文件。另一个情况是文件字段名写错,比如"prompts"写成了"prompt",模型直接报缺少必填字段。

排查技巧:用 Python 先验证一遍 JSONL 完整性:

import json with open("requests.jsonl", "r", encoding="utf-8") as f: for i, line in enumerate(f): try: obj = json.loads(line) except json.JSONDecodeError as e: print(f"Line {i+1} error: {e}") break

一个小技巧:先用少量测试数据快速验证,不要一上来上传完整全量文件。

6.3 任务显示成功但输出为空

有一次任务跑完,状态显示成功,但输出目录里只看到失败列表,输出内容为空。这个情况多半出在输入数据解析上:某些行的数据处理失败被单独记录到错误列表,但没有中断任务。

排查思路:

  • 查看输出目录中是否有失败或错误列表文件
  • 对比输入行数和输出行数,找出差量对应的请求
  • 针对失败请求逐个分析,通常和提示词内容或非法参数值有关

6.4 权限不足导致任务失败

提交任务后查看状态,很快变成失败,日志提示存储对象无访问权限。这通常是服务账号和存储桶权限不匹配。

一条我常用的排查路径:

确认服务账号 → 确认账号有 Storage Object Viewer/Admin → 确认 Bucket 的 IAM 策略绑定了该账号 → 手动测试读写

权限修改是分钟级生效,我已经遇到过刚改完权限还没生效就提交任务的情况,通常会额外等待几分钟。

6.5 代码版本差异:不同 SDK 版本参数不兼容

新版 SDK 中部分参数已弃用或改名,我最怕的是网上的教程代码一跑直接报 TypeError。实际解决方式以 SDK 为准,最简单的做法是创建任务前先输出函数的签名帮助:

help(aiplatform.BatchPredictionJob.create)

把签名和参数说明打印出来,一条条核对。

6.6 预览版模型更换带来的任务不可用

预览版模型可能有多个版本参数更新,某天提交任务时报模型不可用,也许只是因为模型版本升级了。排查方式:查看模型列表确认当前可用的版本名称,把代码里的模型名更新到新版本,历史结果保留,不用重跑。

7. 我在实操中的一点体会

跑完这个项目,最大的体会是:Batch 任务的思维方式不是"写循环",而是"描述数据"。你把输入文件准备好、路径配好、模型选好,剩下的事情交给平台编排,整个流程的可观测性反而比在线调用更好。任务失败有日志,成功有结果文件,重跑只需要覆盖输入文件或换个输出目录,不需要碰代码。

如果让我给刚接触 Batch 的人一条建议:不要照抄完整教程就上全量数据。先拿三条提示词建一个最小的任务,从提交到拿到输出走通全流程,确认输入输出格式和模型行为,再去跑几百条、上千条。这个测试任务跑一次花不了几分钟,但能帮你避开大部分后续问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询