GLM Batch 批量接口什么时候值得用
数据截至 2026-08,价格与限额以各官网为准。本文只讲计费与接入机制,不列具体价格数字。
判断标准其实只有一句话:你的任务能不能接受”提交完先去干别的”。 GLM 的 Batch API 按官方文档的说法是”专为处理大规模数据请求而设计,适用于无需即时反馈的任务”,它给你两样东西——按低于标准价计费(具体比例见官方定价页),以及一套和常规接口并发限制相互独立的排队额度。代价是你拿不到同步返回值:请求要先写成 jsonl 文件上传,再创建任务、轮询状态、下载结果文件。所以给用户看的实时对话、需要马上决定下一步动作的 Agent 循环,都不该往这条路上塞;而文章打标签、评论情感分类、存量数据字段抽取、批量向量化这类”跑完一次能用很久”的活儿,几乎没有理由继续用同步接口一条条打。
先确认你的任务过不过得了这几道门槛
在写任何代码之前,有四件事决定了这个方案对你成不成立,其中任何一条不满足,后面的工作都白做。
第一,必须完成实名认证。 官方 FAQ 写得很直白:调用 Batch API 必须实名认证,要先去开放平台的实名认证页面完成个人认证或企业认证。这是硬前置,不是”建议”。团队里常见的翻车姿势是开发同学拿自己的测试账号写完了整套流程,上线时才发现账号主体不对,又得重走一遍认证。
第二,一个 Batch 文件只能打一个模型。 官方在文件限制里明确写了”每个 batch 文件只能包含对单个模型的请求”。如果你的流水线里既要跑文本分类又要跑向量化,那就是两个文件、两个任务,不能图省事塞在一起。
第三,每个请求必须有唯一的 custom_id。 官方在文件限制里对它的定义是”每个请求必须包含 custom_id 且是唯一的,用来将结果和输入进行匹配”。换句话说,官方指定的对齐凭据就是这个字段本身,回填数据库时应该按 custom_id 去 join,而不是按结果文件的行序去对——官方文档里没有找到任何关于结果文件行序的说明,别把它当成可以依赖的约定。既然要靠这个字段对齐,就别用 request-1、request-2 这种在多次任务之间会重复的临时编号,直接把你自己业务表的主键写进去,回填时一条 SQL 就完事,也不怕两批任务的结果文件混在一起。
第四,你得能接受”结果不是马上就有”。 官方文档里 completion_window 这个参数已经标注为废弃,说明写的是”原有的时间参数已不再适用,新的任务调度策略将根据系统负载情况自动调整”,并给出了预计完成时间与超期自动取消的规则(具体时限以官方文档当前版本为准)。也就是说完成时间不由你指定,你只能等。要是你的业务对交付时刻有硬承诺,这条就是否决项。
五个步骤,每一步的坑都不一样
官方教程用商品评价情感分析当例子,把流程拆成了五步,我按同样的顺序过一遍,重点标出容易理解错的地方。
步骤一:把请求写成 jsonl
格式要求是 .jsonl,每个请求占一行,是一个完整的 JSON 对象。每一行的骨架长这样:
{
"custom_id": "request-1",
"method": "POST",
"url": "/v4/chat/completions",
"body": {
"model": "glm-4-plus",
"messages": [
{"role": "system", "content": "你是一个意图分类器."},
{"role": "user", "content": "对以下用户评论进行情感分类,只输出结果"}
],
"temperature": 0.1
}
}
注意 body 就是你平时调对话补全时发的那个请求体,原样搬进来即可,temperature 这类采样参数照常生效。这里有个容易绕晕的地方:url 写在 jsonl 的每一行里,而创建任务时还要单独传一个 endpoint 参数,两者是两处不同的写法。官方对 endpoint 的说明是”Batch 中所有请求将使用的端点。目前支持 /v4/chat/completions”,接口定义里这个字段的可选值当前也只列出 /v4/chat/completions 一个(以官方文档为准)。至于行内 url 与 endpoint 参数填得不一样时接口会怎么处理,官方文档里没有找到相关说明,所以照着官方示例的写法走最稳妥,别自己发挥。
Batch 不是只能跑对话。官方示例里还给了视觉模型(body.messages 里带 image_url)、图像生成(url 走 /v4/images/generations)和向量化(url 走 /v4/embeddings、body 里是 input)三种形态。要提醒的是,这几种形态官方只给了 jsonl 行怎么写,并没有配上对应的创建任务参数示例——教程里所有 client.batches.create 的示例传的都是 /v4/chat/completions。真要跑图像生成或向量化的 Batch,建议先拿几条数据试着创建一次任务,确认能不能通过验证,再决定要不要把整条流水线改过去。另外,官方对向量模型的 Batch 文件请求数量有单独的、比通用限制更严的上限,做大规模向量化之前先去文档里核一眼这个数。
步骤二:上传文件,purpose 必须写对
上传走文件 API,SDK 里是 client.files.create(file=..., purpose="batch")。这个 purpose 是个枚举,官方 OpenAPI 里列出的取值有 batch、code-interpreter、agent、voice-clone-input(以官方文档为准)。只有 batch 这个取值对应批量任务,写成别的,文件传上去了也不能用来创建 Batch。官方对 batch 用途的文件同时规定了单文件体积上限和账号下文件数上限,具体数值见官方文档。
步骤三:创建任务
batch = client.batches.create(
input_file_id=file_object.id,
endpoint="/v4/chat/completions",
auto_delete_input_file=True,
metadata={"description": "商品评价情感分析", "project": "sentiment_analysis"}
)
auto_delete_input_file 值得单独说一句。官方说明它控制”是否自动删除 batch 原始文件”,True 执行自动删除、False 保留(默认行为以官方文档当前版本为准)。为什么这个开关重要?因为账号下能存的文件数是有上限的,官方在”删除文件”一节里专门提醒:“若任务量巨大,请及时删除已处理完毕的文件,以便继续上传新文件。“如果你是天天跑批的场景,又把这个开关关掉且没做清理,迟早会撞上文件数上限,表现出来就是新任务传不上去——这种报错第一眼很难联想到是几个月前的历史文件占了位置。
metadata 是给你自己用的键值对,官方描述是”用于存储与 Batch 相关的数据,如客户 ID、描述或其他任务管理和跟踪所需的额外信息”,键值对数量以及键、值的长度都有上限(数值见官方文档)。建议把你这边的批次号、数据版本写进去,后面在控制台一排任务里找特定批次时会省很多事。
步骤四:轮询状态,别把 finalizing 当完成
官方给出的状态取值一共八个(以官方文档为准):validating 是文件正在验证、任务未开始;failed 是文件未通过验证;in_progress 是验证通过、任务执行中;finalizing 是任务已完成但结果还在准备;completed 是结果已就绪;expired 是任务未能完成;cancelling 与 cancelled 对应取消中和已取消。
这里最容易写错的是终止条件。finalizing 从字面看像是”收尾了”,很容易被当成完成信号,但官方把它和 completed 的措辞分得很清楚:前者是”Batch 任务已完成,结果正在准备中”,后者才是”Batch 任务已完成,结果已准备好”。官方在下载结果这一步的说法也是”Batch 任务完成后,您可以使用 Batch 对象中的 output_file_id 字段下载结果”,示例代码同样把下载动作放在 status == "completed" 的分支里。所以终止条件就卡在 completed 上,别自作主张提前一步。官方示例里的循环写法是:只有 completed 才算成功跳出,failed、expired、cancelled 三种一起当失败跳出,其余状态继续等待。另外提醒一句,failed 在这套语义里指的是文件没通过验证,也就是你 jsonl 写坏了,而不是”模型没答上来”——单条请求级别的失败不体现在任务状态上,得去错误文件里看。
步骤五:结果分两个文件下载
任务完成后系统生成的是两个文件,不是一个:output_file_id 存成功执行请求的输出,error_file_id 存出错请求的输出。官方在这一步专门加粗提示要”分别进行下载”。
只下载 output_file_id 是新手最常见的漏项。你以为跑完了,结果数据库里少了一批记录,回头去查才发现有一部分请求进了错误文件而你从来没打开过。稳妥的做法是在下载逻辑里判断 error_file_id 是否存在,存在就一并落盘,并且把行数和你提交的条数对一遍——request_counts 对象里的 total、completed、failed 三个计数正好用来做这个校验。
结果文件里每一行的结构是 {"response": {...}, "custom_id": ..., "id": ...},模型的实际输出在 response.body.choices 里,token 消耗在 response.body.usage 里。想核对这批任务到底花了多少,把每行的 usage 累加起来就是最准的口径,比事后看账单聚合值更容易定位到具体是哪批数据吃掉了预算。这套按 usage 回算的思路和API 成本监控怎么做里讲的是同一个方法论,只是 Batch 场景下你手里正好有一份完整的逐条明细,做起来更省力。
便宜是有条件的,这几种情况省不下来
Batch 的低价不是无条件生效的,有几个地方会让实际收益缩水。
任务过期时,已完成的部分照样付费。 官方 FAQ 写得很清楚:批次未能及时完成会被标记为过期状态,未完成的请求会被取消,“对于批次中已完成的请求,用户可以通过文件获取,并且需要支付这些请求消耗的费用”。所以把一个超大文件一次性怼进去、指望它要么全成要么全免,是行不通的。切成多个中等规模的文件,过期时的损失面更可控,重投也更快。
排队上限意味着你不能无限提交。 官方说明 Batch 的并发限制与常规接口的每模型并发限制是分开的,同时”每个模型的 Batch 有最大排队限制。当达到请求队列上限时,请等待当前任务完成后再提交新任务”。注意这个上限是按模型算的,不同模型的额度也不一样。做调度的时候要按模型分别记账,别写成一个全局计数器。想搞清楚常规接口那边的额度口径怎么读,可以对照RPM 与 TPM 到底限的是什么一起看,两套限制不是一回事,别互相套用。
结果文件不会一直给你留着。 官方明确系统只保留文件有限期限,过期后自动删除且无法恢复(具体天数见官方文档)。跑完就下载落盘,别把平台当存储用。
省钱优先级上,Batch 未必是第一顺位。 如果你的请求之间共享大段相同前缀(比如同一套长 system prompt 或同一份文档),先去看GLM 上下文缓存怎么才能命中,缓存和 Batch 是两个独立的优化维度,能叠的时候一起用收益更大。计费口径上的整体分类,GLM API 计费方式那篇讲得更全。
最后:什么时候不该用它
反过来列一遍否决项,比列适用场景更实用。需要毫秒级返回的、需要流式输出给用户看的、请求内容依赖上一条请求结果的(Batch 是一次性提交,没法做链式依赖)、单次只有几条数据的(走一遍上传—创建—轮询—下载的开销比省下来的钱贵)、以及对完成时刻有对外承诺的,这五类都别改。
真要动手,建议第一次先拿一小撮真实数据走通全流程:确认 jsonl 能过验证、状态机能正常流转到 completed、错误文件能拿到、custom_id 能对齐回你的业务表。这套骨架跑通之后再放大数据量,比一上来就提交几万条、结果卡在 failed 上不知道哪一行写坏了要省心得多。