资讯动态

Vertex AI Batch 任务实战:用 Gemini 图像模型批量生成统一风格图片

发布时间:2026/10/17 4:45:53 来源:尧图企业网站定制
最近要给一批素材图做统一风格的批量生成单张走在线接口又慢又容易撞限流后来索性在 Vertex AI 上开了 Batch 任务用 gemini-3-pro-image-preview 这个多模态模型跑离线推理。试下来这条路非常省心只要把输入文件准备好、任务提交成功剩下就是等结果写回存储桶。这篇文章我把整个创建过程、参数解释、遇到的坑一次说清楚给准备用 Batch 跑生成式模型的朋友一个可以直接照做的参考。如果你以前只用过在线预测接口对 Batch 任务不熟建议先把前两节看完弄清楚它跟在线接口的差别再动手。如果已经有一定了解可以直接跳到第三节看具体的创建代码和参数配置。1. 先弄明白 Batch 任务解决什么问题1.1 在线推理和批量推理怎么选Vertex AI 上调用生成式模型常规做法是发起一个在线推理请求比如单张图片传进去、模型返回一个结果整个过程在秒级完成。这种方式的优点是实时性高、交互感强适合聊天助手、即时审核、用户上传素材立刻处理这类场景。缺点也明显单条请求有速率限制并发过高会被限流而且大量数据逐条调用时网络中断、超时重试这些事会让人崩溃。Batch 任务走的是另一条路。它不是实时请求而是把一堆待处理的数据打包成一个任务提交给平台平台拿到任务后按队列调度资源、批量消费数据处理完把结果统一写到指定位置。整个过程是异步的提交完之后你可以去做别的事隔段时间再回来看任务状态和输出结果。对“一次性处理几千张图片”“定期跑一次数据清洗”“把全量历史数据重新生成描述”这类场景Batch 几乎是首选。原因很简单不需要自己维护并发控制不用写一堆重试逻辑平台会把任务分片、调度、失败重试这些事情处理好。成本上也更容易预估因为你可以提前把输入文件梳理清楚算好大概的处理量和输出量。1.2 gemini-3-pro-image-preview 适合什么样的批量场景gemini-3-pro-image-preview 是 Gemini 系列里偏多模态生成的预览版本能处理图像生成、图像编辑、图文混合理解这类任务。放到 Batch 里跑最常见的是这几类需求给一批图片做风格化处理比如统一转换成赛博朋克风、水彩风、3D 渲染风批量生成图片描述或标签方便后续做检索、归档把文字描述批量转成配图比如产品海报文案配图对一批图片做内容审核或质量评估输出结构化评分。预览版模型的好处是迭代快、新功能多但也要留意版本可能不稳定正式生产环境还需要评估。我这次主要跑的是图片风格化输入是一批素材图输出是生成后的图片引用和对应的提示词回显。接下来所有示例都会围绕这个场景展开。提示Batch 任务适合离线、延迟不敏感的场景。如果用户在前端点一下按钮就必须马上拿到结果还是老老实实用在线接口Batch 的排队机制不适合实时交互。2. 搭建环境前的准备工作2.1 开通权限和确认配额第一次用 Batch 任务最容易忽略的不是代码本身而是账号权限和配额。任务要读取云存储桶里的输入文件、把结果写回另一个存储桶这个过程中平台会使用任务创建者的身份去访问存储资源或者使用你指定的服务账号去访问。所以准备工作第一步确认你的账号有 Vertex AI 任务创建权限、存储桶读取权限、存储桶写入权限。如果权限不够任务提交后会很快失败报错信息通常带有权限相关描述但等你看到报错再回头配权限白白浪费一轮时间。第二步是确认 Batch 推理配额。生成式模型和图像模型的 Batch 任务通常有独立的配额跟在线请求配额不是一回事。我遇到过的情况是在线接口调用完全正常但 Batch 任务一直排队不运行查了配额才发现 Batch 的并发处理单元配额不够。建议在配额页面里先搜一下 Batch 相关条目确认当前项目还有余量。第三步是确认模型在你使用的区域可用。预览版模型不一定部署在所有区域有些区域可能只开放了在线接口、没开放 Batch有些则反过来。创建任务之前先到模型列表页看一下支持的“可用区域”说明避免代码写好了才发现区域不对。2.2 准备输入数据JSONL 格式细节Batch 任务支持多种输入格式其中 JSONL 是最直观也最常用的一种。JSONL 的全称是 JSON Lines要求每一行都是一个独立的、合法的 JSON 对象不能有逗号分隔不能把多个对象写在一行里。对 gemini-3-pro-image-preview 这类多模态模型每一行通常包含一次请求的参数比如提示词、图片地址、生成参数。我个人习惯把请求参数包在一个 request 字段里这样结构清晰也方便在输出文件里把原始请求和预测结果对应起来。下面是一个输入文件的示例片段{request: {prompt: 把这张图片改成赛博朋克风保留主体结构, image: gs://INPUT_BUCKET/image_001.jpg, aspect_ratio: 1:1}} {request: {prompt: 把这张图片改成水彩手绘风背景虚化, image: gs://INPUT_BUCKET/image_002.jpg, aspect_ratio: 16:9}} {request: {prompt: 去掉图片背景生成透明底版本, image: gs://INPUT_BUCKET/image_003.jpg, aspect_ratio: 1:1}}写输入文件时要特别注意几点第一确保每一行都是纯 JSON 字符串不要用 Python 的 print 输出一整个列表再重定向到文件那会生成 JSON 数组而不是 JSONL。第二图片路径必须可以被任务执行环境访问到。如果图片在存储桶里直接用平台内部的 URI 路径提交通常没问题如果你用外链地址要确保这个外链不需要额外鉴权或者你已经在任务参数里配好了访问凭证。第三文件总大小和行数会影响任务拆分的粒度。我一般习惯把一个大文件拆成几个中小文件每个几千行左右这样平台能把不同文件分给不同的执行单元并行处理整体速度更快。这个不是硬性要求但在实测中确实能感受到并行度的差别。2.3 准备输出存储并处理重名问题输出位置需要在创建任务之前就想好。我会单独建一个输出目录而不是把结果直接写在输入目录下否则任务跑完以后输出文件和输入文件混在一起后续查找和清理都麻烦。一个特别容易踩的坑是输出前缀重名。Batch 任务支持指定输出文件路径前缀如果前缀重复新一轮任务会直接把上一轮的结果覆盖掉。我第一次跑全量数据的时候就用了一个固定前缀结果第二次重跑时旧结果没了想对比一下两次生成的差异都做不到。后来我改成每次任务都用带时间戳的前缀比如batch_results/20250120_1530/,这样每次的结果都独立保存重跑几次也不怕。提示输出路径前缀尽量精确到任务级别不要只写一个桶名。桶名作为前缀时任务结果会直接散落在桶根目录文件一多非常难管。3. 创建 Batch 任务的完整操作3.1 用 Python SDK 创建任务环境准备好之后创建任务本身并不复杂。我用的是 Vertex AI 的 Python SDK核心代码大概是这样from google.cloud import aiplatform aiplatform.init(projectPROJECT_ID, locationLOCATION) job aiplatform.BatchPredictionJob.create( model_namegemini-3-pro-image-preview, job_display_namebatch_image_style_transfer, instances_formatjsonl, predictions_formatjsonl, gcs_source[gs://INPUT_BUCKET/requests.jsonl], gcs_destination_prefixgs://OUTPUT_BUCKET/batch_results/20250120_1530, model_parameters{ temperature: 0.8, maxOutputTokens: 4096, }, ) job.wait() print(job.resource_name) print(job.status)这段代码有几个地方需要说明一下。model_name这个参数可以直接填模型标识也可以填模型的完整资源名。如果模型是平台预置的直接用简写通常可以识别如果是你自己部署的模型这里就要填完整资源名。我的建议是统一填完整资源名从模型详情页里复制出来避免同一个名字在不同区域解析出来的结果不一样。instances_format和predictions_format一致地设成jsonl输入输出都走文件。如果后续要接入数据分析也可以把输出格式配成 BigQuery 表但 JSONL 在排查问题时更灵活我先用文件方式跑通全流程。gcs_source这个参数接收的是一个列表,意味着你可以传多个输入文件。我前面提到的大文件拆分到这里就派上用场了。把拆好的几个文件作为列表传进去平台会当成一个任务来调度但并行度会更好。model_parameters里的参数要参考模型支持的具体字段。图像生成类模型通常支持温度参数、输出长度上限、图像宽高比、生成数量等。temperature控制随机性数值越大生成结果越多变maxOutputTokens控制单条输出的上限防止模型因为生成长文本或者额外解释把成本撑爆。具体支持哪些字段以模型的参数文档为准。job.wait()会阻塞当前进程直到任务结束。如果脚本运行在本地阻塞太久反而不方便我更常用的做法是不调用wait()先把任务提交成功拿到resource_name存到本地过段时间再查状态。这样任务在云端跑本地不用一直挂着一个进程。3.2 用 REST API 创建任务如果不方便用 Python SDK或者你需要在其他语言里集成可以直接调用 REST API。创建 Batch 预测任务的请求大致是这样{ displayName: batch_image_style_transfer, model: MODEL_RESOURCE_NAME, inputConfig: { instancesFormat: jsonl, gcsSource: { uris: [gs://INPUT_BUCKET/requests.jsonl] } }, outputConfig: { predictionsFormat: jsonl, gcsDestination: { outputUriPrefix: gs://OUTPUT_BUCKET/batch_results/20250120_1530 } }, modelParameters: { temperature: 0.8, maxOutputTokens: 4096 } }MODEL_RESOURCE_NAME需要替换成模型详情页里完整的资源路径。发送请求的时候方法是用 HTTP POST 提交到 Batch 预测任务的创建接口路径里带上项目 ID 和区域信息。这个方式和 Python SDK 底层是同一套逻辑区别只是你要自己处理鉴权和请求细节。REST 方式的优点是不依赖具体语言的 SDK任何能发起 HTTP 请求的脚本都能用。缺点是代码里要自己处理 token 刷新和错误响应解析没有 SDK 那么省事。我的建议是如果你本身就在写 Python优先用 SDK如果你的主语言是 Go、Java、Node.js或者想快速在命令行里验证接口REST 方式更直接。3.3 关键参数逐个说清楚把参数拆开来看每个配置背后都有取舍displayName任务显示名。这个一定要取一个好认的名字任务多的时候全靠它来区分。我习惯把业务含义和执行批次放进去比如batch_image_style_transfer_20250120。model模型资源名。填错了任务创建阶段就会失败而且报错有时候是权限错误容易误导排查方向。instancesFormat输入格式。JSONL 是我最推荐给生成式模型的格式因为它能保留每行请求的独立性也方便定位某一行出错。如果输入是表格类数据可以考虑其他格式但需要额外做格式转换。gcsSource输入文件位置。可以传多个 URI对应多个文件。gcsDestinationPrefix输出前缀。我强烈建议带时间戳或任务批次标识避免覆盖历史结果。modelParameters模型推理参数。这里的参数是传给模型的不是平台的任务参数所以不要把任务级的超时配置写在这里。有一点很多人会忽略任务级的一些限制比如单个任务的输入文件数量、文件大小上限是平台层面的约束不会写在模型参数里。建议在准备大批量数据之前先查清楚当前 Batch 任务的输入限制再决定是拆成几个任务还是一个任务。4. 监控任务状态与读取结果4.1 任务状态怎么看任务提交成功会返回一个任务资源名。拿到这个名字以后可以用 SDK 或控制台查看状态。SDK 的方式很直接job aiplatform.BatchPredictionJob( job_nameprojects/PROJECT_ID/locations/LOCATION/batchPredictionJobs/JOB_ID ) job.refresh() print(job.status)任务状态通常会经过几个阶段提交后进入排队状态然后转为运行中最后变成成功或失败。排队状态本身是正常的尤其在高峰期或者配额不多的时候可能需要在队列里等一阵子。如果长时间处于排队状态我的排查顺序是先看配额是否足够再看输入文件路径能不能被正常访问最后确认模型区域是否正确。我踩过的一个坑是傻傻地开着脚本等任务结束结果本地网络断了脚本退出任务还在后台跑。后来我改成先提交任务、保存资源名然后定时轮询状态。轮询代码用简单的循环加睡眠就能实现不需要引入复杂框架。但轮询间隔不要小于 30 秒否则频繁刷状态接口容易触发限流。如果你在用控制台任务列表里能看到每个任务的状态、创建时间、完成时间、输出路径。运行中任务还能点进去看日志排查报错非常方便。日志里通常会有任务执行器的输出比如第几行数据处理失败、错误信息是什么。4.2 结果文件长什么样任务成功结束后输出前缀目录下会生成结果文件通常是prediction-000000001.jsonl这种命名多个执行单元会生成多个文件。打开结果文件每一行大致是这样的结构{ instance: { request: { prompt: 把这张图片改成赛博朋克风保留主体结构, image: gs://INPUT_BUCKET/image_001.jpg, aspect_ratio: 1:1 } }, prediction: { generated_image: gs://OUTPUT_BUCKET/batch_results/generated_001.png, prompt_feedback: success } }instance是原始输入请求的回显prediction是模型返回的结果。把instance放回来对这个这个用途非常实用拿到结果之后不用再去查原始文件就能知道某条输出对应的是哪条输入。处理结果文件时我通常先写一个小脚本把结果汇总起来提取关键字段放到一张表里方便查看成功率和失败原因。汇总的时候要注意prediction里的字段名可能和直接调用在线接口时不一样建议先用几条小样本任务跑一次看清真实输出结构再写全量解析逻辑。4.3 失败任务的处理策略Batch 任务失败有两种情况整个任务失败以及部分行处理失败但任务最终还是成功结束。整个任务失败时日志里会给出明确的错误码和阶段信息。这时候优先看创建配置有没有问题比如模型资源名、输入格式、输出路径权限。排掉这些之后再看是不是某一条输入数据触发了全任务终止比如模型在解析某条请求时遇到不可恢复的错误。部分行失败时任务状态仍然可能是成功的因为平台允许部分数据处理失败。这种情况的结果文件里通常会有对应的错误记录或者平台会额外生成一个错误报告文件。我的处理方法是先统计失败行号再抽取几条失败数据单独测试看是提示词问题、图片路径问题还是模型本身对输入不支持。定位清楚原因后把失败行修正后组装成一个小任务重新跑不和全量数据混在一起避免每次都为几条脏数据跑全量。5. 常见问题与排查技巧实录5.1 权限报错的真实场景第一次跑 Batch 时最容易遇到的就是权限报错而且报错信息往往比较模糊。我那次看到的是任务进入运行状态后立刻失败日志里提到某个存储桶路径没有访问权限。乍一看路径是对的、文件也存在后来才发现问题出在执行任务的服务账号上。排查思路是这样的先确认创建任务时用的是哪个身份再确认这个身份对输入存储桶有读取权限、对输出存储桶有写入权限。如果任务创建时指定了服务账号那就是这个服务账号要去配权限如果没指定用的通常是账号本身的权限。最简单的方法是在控制台手动进入输入存储桶看一眼能不能看到文件列表如果连手动都看不到说明权限确实没配上。配权限的时候遵循最小授权原则只给读输入桶、写输出桶这两项不要图省事直接给一个全权限角色。这样即使别人拿到你的服务账号信息影响范围也有限。5.2 JSONL 格式导致任务失败JSONL 格式问题非常隐蔽因为大多数编辑器打开文件看起来都正常但任务一到执行阶段就报错。常见的有三种情况第一种是文件末尾多了一个空行。空行会被解析成一个空对象模型处理时可能直接报错或者返回空结果。第二种是一行里面写了两个 JSON 对象中间用逗号隔开这是从 JSON 数组直接改后缀名导致的典型错误。JSONL 严格要求每行一个对象逗号分隔符不允许出现。第三种是中文字符编码问题。如果输入文件是在 Windows 上手工编辑保存的默认编码可能不是 UTF-8模型在解析中文提示词时可能出现乱码生成结果完全不对。我的做法是在创建任务前用脚本对输入文件做一次校验逐行读取并用 JSON 解析器验证。只要有一行解析失败就自动定位到行号并打印出来。这一步虽然简单,但能省掉很多排查时间。写校验脚本的时候注意用 UTF-8 编码读取文件碰到解析失败不要只报错停掉把行号记录下来一次性把所有问题行都列出来。5.3 任务排队太久怎么处理任务提交成功但一直处于排队状态这个现象我也遇到过。首先要分清是正常排队还是出了问题。平台在资源紧张时排队是常态尤其是批量任务高峰时段等个十几分钟都很正常。如果超过预期时间还没开始运行我会按三个方面排查配额是否耗尽。去配额页面看 Batch 相关指标是不是已经满了满了就申请提升配额或者换一个区域。输入数据规模是否异常。单行数据是否特别大比如图片 URI 指向的图片对象本身几百兆处理起来很慢影响调度判断。是不是区域资源拥挤。预览版模型在某些区域用量高峰期资源很紧张换一个模型可用且负载较低的区域排队时间会明显缩短。另外排队时间长不代表任务出了问题不要草率取消任务。取消之后重新提交等于又排到队尾反而更慢。5.4 输出结果为空或缺少内容任务显示成功结果文件也生成了但里面有些行的prediction是空的或者只有部分内容。这种情况最可能是模型批次输出触发了内容过滤或者提示词语义不明确导致模型没有生成有效结果。先说内容过滤。图像模型对输入图片和输出内容都有安全过滤机制一旦判断提示词或生成结果触碰边界会返回空结果或者失败标记。排查方法是先单独用在线接口测试同样的提示词和图片如果在在线接口也被过滤那就是提示词本身的问题需要改写提示词再跑。再说提示词本身。图像生成任务里提示词越具体结果越稳定。笼统地说“改一下风格”模型可能不知道具体改到什么程度说清楚“改成赛博朋克风霓虹灯色调保留人物轮廓”结果明显可控得多。还有一类情况是输出 token 上限设得太小。模型还没来得及生成完整内容就被截断了结果文件里会有截断标识。把maxOutputTokens调大一些可以改善。5.5 成本控制与资源浪费Batch 任务跑起来之后成本主要来自三块模型推理计算、输入输出存储读写、数据转移。虽然批量任务在资源利用上比逐条在线请求高效但量一旦大了账单还是会让人肉痛。我控制成本的经验是这样先拿 20 条数据跑一个小规模任务验证提示词效果和参数配置确认输出符合预期再跑全量。很多人急着出结果直接全量提交等结果出来发现提示词写得不好、风格不是想要的又要重跑一遍等于白跑一次账单。其次是合理设置maxOutputTokens。图像模型如果输出内容较长token 消耗很快。给这个参数设一个合理的上限既能控制单条成本也能避免模型跑偏生成一堆没有用的长文本。再就是输出结果的存储生命周期。临时验证用的结果文件确认没问题之后就删掉不要一直堆在存储桶里。存储费用虽然单价不高但千万个文件累积起来也不是小数目。注意Batch 任务的输出文件一定要在确认结果无误后再清理。我建议先保留最新一轮的结果用于对比等下一轮结果确认没问题后再清掉上一轮的临时目录。6. 一点实操中的体会创建 Batch 任务本身不难真正的难度在于把输入数据整理干净、把权限配好、把参数调合适。我前面几次跑得不顺利基本都是这三块出了问题而不是平台本身不稳定。尤其是输出前缀加时间戳这个习惯帮我避免了好几次覆盖旧结果的麻烦。最后分享一个实用小技巧第一次跑不熟悉的模型时先用最小数据集把整个流程走通从任务创建到结果解析全跑一遍哪怕只有 3 条数据。这个动作能让你提前发现格式问题、权限问题、参数问题避免把错误放大到全量任务里。等小流程确认没问题再按真实数据量拆分文件、提交正式任务这样看起来多花了一点时间实际上是最省成本的路径。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑