一句话结论:如果你的调用是可延迟、可批处理、可回放,就该把在线请求下沉到 Batch API;省钱最明显,但前提是你把拆批、失败分流和回放链路先做好。
很多团队把 Batch API 当“便宜版同步接口”来用,结果不是省钱,而是把失败样本堆成事故池。真正的保守做法是:先定义成本边界和SLO,再做离线拆批与失败回放。
先给落地框架(保守目标版)
按这个顺序走,最稳:
- 把任务分成「可离线」与「必须实时」两类。
- 为离线任务定义批次窗口和最大批量。
- 每条任务加
custom_id,保证可追踪、可幂等回放。 - 结果处理做三路分流:成功、可重试失败、不可重试失败。
- 先小流量灰度,再全量切换。
一、先画成本边界,不要先写代码
先回答三个问题:
- 延迟容忍度:业务能接受多晚拿到结果(例如 1h / 6h / 24h)?
- 失败容忍度:允许多少比例进入重放队列?
- 预算上限:每天最多允许花多少钱?
最小可执行预算看板(本地日志聚合也行):
# 每天汇总批任务输入条数、成功条数、失败条数
jq -r '.date + "\t" + (.input|tostring) + "\t" + (.ok|tostring) + "\t" + (.fail|tostring)' /Users/wow/dev/book/mengboy/tmp/batch-metrics/*.json
# 失败率超过阈值时告警(示例阈值 3%)
python3 - <<'PY'
import json,glob
for f in glob.glob('/Users/wow/dev/book/mengboy/tmp/batch-metrics/*.json'):
d=json.load(open(f))
rate=d['fail']/max(d['input'],1)
if rate>0.03:
print('ALERT', f, f'{rate:.2%}')
PY
二、离线拆批:按“稳定吞吐”切,不按“最大极限”切
推荐一个保守策略:
- 单批条数先从小批量起步(比如 200~500)
- 批次窗口固定(例如每 15 分钟聚合一次)
- 触发阈值二选一:到窗口时间或到条数上限即提交
Go 侧核心是:任务规范化 + custom_id 唯一。
type BatchTask struct {
CustomID string `json:"custom_id"`
Method string `json:"method"`
URL string `json:"url"`
Body json.RawMessage `json:"body"`
}
func buildCustomID(bizKey string, ts int64) string {
return fmt.Sprintf("%s-%d", bizKey, ts)
}
把 JSONL 输入落盘(方便审计与回放):
mkdir -p /Users/wow/dev/book/mengboy/tmp/batch-input
# 生成的 JSONL 放这里,命名带批次号
ls -lh /Users/wow/dev/book/mengboy/tmp/batch-input
三、失败重放:只重放“可重试失败”
失败不要一锅端重提。至少分三类:
- SUCCESS:直接入库并关闭任务
- RETRYABLE_FAIL:限次重放(例如最多 3 次)
- FINAL_FAIL:进入人工池,避免死循环
建议把重放条件写死在策略函数里,别散落在业务代码:
func retryable(code string) bool {
switch code {
case "rate_limit", "timeout", "server_error":
return true
default:
return false
}
}
重放命令建议单独可执行:
# 根据失败清单重建重放JSONL
python3 /Users/wow/dev/book/mengboy/scripts/rebuild_batch_replay.py \
--failed /Users/wow/dev/book/mengboy/tmp/batch-failed/failed-2026-03-13.jsonl \
--out /Users/wow/dev/book/mengboy/tmp/batch-replay/replay-2026-03-13.jsonl
四、回放幂等:先做幂等键,再谈自动化
重复回放最常见事故是“结果重复入库”。
最低要求:
- 业务表有唯一键(如
custom_id) - 写入操作使用 upsert
- 每次重放都记录 replay_count
-- 示例:保证 custom_id 唯一
ALTER TABLE ai_batch_result
ADD CONSTRAINT uk_custom_id UNIQUE (custom_id);
五、部署前后的验收指标
上线验收别只看“请求成功”。至少看这四个:
- 单日成本是否下降到目标区间
- 总体失败率是否可控
- 重放后最终成功率是否稳定
- 人工兜底量是否在可处理范围
如果你做的是“保守目标推进”,宁可多留一点实时链路,也不要把关键路径一次性全迁到离线批处理。
最小可行方案(MVP)
如果你时间有限,就先做到这 5 件事:
- 只迁移非实时任务到 Batch API。
- 所有任务强制
custom_id。 - 失败分成可重试/不可重试。
- 重放最多 3 次,超限转人工。
- 每天固定出一份成本与失败率报表。
这套做完,通常就能在不牺牲稳定性的前提下,把成本明显压下来。