Batch 结果别按行贴回去:用 custom_id 把成功、错误和缺项对齐
输入第一行是 ticket-001,Batch 结果第一行却是 ticket-002。这时按行把结果贴回表格,就会把 002 的记录贴到 001 身上;文件能读、程序没报错,也可能已经对错了对象。
OpenAI 当前 Batch 指南明确说,输出顺序可能与输入不同,需要用 custom_id 对应。还要一起看 output_file_id 和 error_file_id:只对成功结果建表,会漏掉另一份文件中的请求错误。
下面这套小工具只做单批次的本地对账:输入清单、结果文件、错误文件一起核对,按原输入顺序输出。用 Bash 和 jq 1.6+,不需要 API key;本地用 jq 1.7 验证。
这四条记录应该怎样对上
附件里全部是人工构造的离线样例,不是真实 API 返回。requests.jsonl 是本地输入清单,也不能直接拿去提交 Batch。
输入清单按 001、002、003、004 排列;results.jsonl 故意先放 002,再放 001;errors.jsonl 里另放 003。正确对齐后是:
| 输入 ID | 输入内容 | 对应结果 | 本工具的 state |
|---|---|---|---|
| ticket-001 | 导出失败,点重试没反应 | 这条 ID 的返回状态码是 400 | http_error |
| ticket-002 | 怎么修改通知频率? | 这条 ID 的返回状态码是 200,示例标签为“使用问题” | http_ok |
| ticket-003 | 请把这条反馈归类 | 在错误文件中找到请求错误 | request_error |
| ticket-004 | 尚无返回记录的教学样例 | 两份本地文件都没找到它 | missing |
http_ok 只标记 HTTP 这一层。拒绝回答、截断、空内容、标签是否合理,还得检查具体端点的响应体,不能把 200 直接计成业务完成。
解压后,在目录里运行
bash run.sh requests.jsonl results.jsonl errors.jsonl aligned.jsonl
jq -r '[.custom_id, .state, (.source // "-")] | @tsv' aligned.jsonl 预期按输入顺序看到:
ticket-001 http_error output
ticket-002 http_ok output
ticket-003 request_error error
ticket-004 missing - aligned.jsonl 每行都保留了原始 input、对应的完整 returned 记录和来源 source,不是只留下一个状态。比如查看 003 的具体错误:
jq 'select(.custom_id == "ticket-003") | .returned.error' aligned.jsonl 工具会先检查所有 ID,再输出:输入清单的 ID 必须是非空字符串且不重复,返回记录合并后也不能重复,返回了输入清单没有的 ID 则停止。相同 ID 同时出现在结果和错误文件中,也会报错,不采用“后一条覆盖前一条”。
可以直接跑随包的检查:
bash verify.sh 最终 ZIP 已实际解压重跑,9 组检查通过,包括乱序对齐、跨文件重复 ID、未知 ID、空 ID,以及报错时保留旧结果和清理临时文件。这些是本地固定样例验证,没有提交真实 Batch 请求。
run.sh 先写同目录临时文件,全部检查通过后再替换目标文件;检查失败保留原目标,不把半份结果当成完成的对账表。
换成自己的文件时
从同一个 Batch 对象核对实际批次状态、输入版本和两个文件 ID,再使用实际下载的结果。文件 ID 可能为空;确认某一项为空时,本地传一份空文件,例如 : > errors.jsonl,不要猜一个远端文件 ID,也不要为了跑通把真正有错误的文件省掉。
missing 仅表示当前给定的文件中未找到,不证明服务端从未执行。先查批次状态、两份文件是否齐全、是不是拿错输入清单,再决定怎么处理。本工具不会提交或补发请求。
custom_id 的唯一性范围是同一个批次。把多批数据放进数据库时,保留 batch_id,按 (batch_id, custom_id) 区分;这套脚本每次只处理一批。另外它会将文件读入内存,大文件要评估内存占用,不是流式处理工具。
来源:OpenAI《Batch API》当前指南,2026-10-22 核对;官方《Batch processing with the Batch API》,原文日期 2024-04-24,其中说明了每批 ID 唯一和结果对齐方法。