AI 网关离线批量接口与异步任务回调落地

日期:2026-07-30

一、项目背景

这个项目的起因是一场"重试风暴"事故。客户是一家企业服务公司,内部多个业务系统通过 AI 网关调用大模型。某天晚上,文档中心的开发同学要给存量的四万多份文档打分类标签,写了个脚本循环调网关的同步接口,并发开到 200。同步接口的连接一直挂着等模型生成,网关的连接池很快耗尽;更糟的是脚本设了 30 秒超时加三次重试,超时的请求不断重发,后端还在算的旧请求叠加新来的重试请求,队列雪崩,连带在线业务全部超时。运维凌晨两点被叫起来,最后靠封禁那个调用方的 API Key 才止血。

复盘的结论很清楚:不能怪业务同学,网关根本没有给大批量场景提供合法的通道——只有同步接口,逼着所有人硬扛。我们采用的 AI 网关此前主要覆盖在线同步调用,这个项目为它补上异步批量能力:任务落库、限速下发、进度查询、完成回调、失败重跑。项目周期约两个月。

二、落地场景

改造后,大批量调用走专门的批量接口:调用方一次性提交任务包——一个包含全部条目的文件(或对象存储地址)、模型与参数模板、回调地址。网关校验后立即返回任务 ID,连接就此断开,不再长挂。任务进入持久化队列,调度器把任务拆成分片(默认每片 200 条),按当前系统水位限速下发到后端,充分利用闲时算力而不冲击在线流量。

调用方获取结果有两条路:主动轮询任务进度接口(返回总数、成功、失败、隔离计数与预计完成时间),或者等回调——任务完成(或每完成 10% 进度)时网关向登记的回调地址推送通知,调用方拿到通知后到结果地址下载。回调本身做了可靠性保障:推送失败按指数退避重试最多六次,超过后进入死信列表,控制台可以人工触发重放;每条回调带唯一事件 ID 和签名,调用方按事件 ID 幂等消费。

失败处理是分片粒度的:某个分片因为后端抖动整体失败,调度器自动重跑该分片;分片内单条失败(超长输入、内容触发安全拦截)记入隔离区,不阻塞其他条目。任务完成报告里明确列出三类计数和隔离原因分布,调用方可以修正后对隔离条目发起补跑,补跑按条目 ID 幂等覆盖结果。

同步接口同时加了防护:单 Key 并发上限、请求体大小上限,检测到疑似批量行为(高并发同质请求)时返回明确的错误码引导走批量接口,而不是默默排队。

三、关键技术挑战与解决思路

第一个挑战是任务状态的持久化设计。批量任务生命周期长达数小时,网关节点随时可能发布重启,状态不能放内存。我们把任务与分片状态落到数据库,调度器无状态化——任何节点重启后从数据库恢复现场继续调度。这里有个细节坑:分片状态更新频率很高(每条完成都想更新进度),直接写库会把数据库打爆。最终方案是分片内进度在内存与轻量缓存中累积,按"每 30 秒或每完成 50 条"批量刷库,分片终态(成功/失败)才实时落库。崩溃恢复时最多重算半个刷库窗口的条目,靠条目级幂等保证不产生重复结果。

第二个挑战是回调的可靠性与安全。回调是网关主动请求业务系统,网络问题、对方服务重启、地址配错都很常见。除了退避重试和死信重放,我们还要求回调地址在任务提交时做一次挑战校验(网关发一个随机串,对方原样返回),把"配错地址导致回调打到别人家服务"这类低级但危险的错误挡在提交阶段。签名用租户级密钥,防止伪造回调诱导业务系统下载恶意结果。

第三个挑战是限速下发与在线流量的协同。批量任务的下发速率不能是固定值——在线流量低谷时应该加速,高峰时要让路。调度器每 15 秒读一次网关在线队列的水位指标,按水位分档调整批量下发的并发数,水位红线之上完全暂停。这套联动上线后,批量任务从"在线业务的威胁"变成了"闲时算力的消化者",同一套集群的日均有效产出明显上升。

案例片段(已脱敏):批量任务与回调的核心配置——yaml batch_api:  shard_size: 200  dispatch:    probe_interval_s: 15    concurrency_by_water: { low: 64, mid: 24, high: 4, red: 0 }  retry:    shard_max_retry: 2    item_isolate_on: [input_too_long, safety_blocked, parse_error] callback:  challenge_on_submit: true  sign: hmac_sha256(tenant_key)  backoff: [1m, 5m, 15m, 1h, 3h, 6h]  dead_letter: console_replay sync_guard:  per_key_concurrency: 20  burst_detect: same_template > 100/min -> ERR_USE_BATCH_API事故复盘对比:改造前那次四万条打标(同步硬扛)跑了一夜未完成还拖垮在线;改造后同量级任务作为标准批量包提交,在线零感知,任务在当晚闲时窗口约三小时跑完,隔离条目 117 条(全部是超长文档),补跑一次全部消化。

四、效果数据

上线三个月后的数据(脱敏示意值):批量任务完成率约 99.4%,无一次因批量作业引发在线服务劣化;同步接口超时率从事故月的峰值回落并稳定在 0.5% 以下,超时引发的重试放大流量下降约 80%;回调到达率约 99.9%(含重试),死信月均个位数且全部人工重放成功;重跑幂等机制运行至今零重复结果事故;批量通道承接的调用量已占网关总调用量的约四成,等效算力利用率提升约 25%——原来这些需求要么硬扛同步要么干脆不做,现在有了合法且安全的出口。

五、可复用经验总结

第一,网关必须给大批量场景提供合法通道,没有批量接口,业务就会用并发脚本自己造一个危险的。第二,异步任务的状态要持久化、调度器要无状态,进度更新用批量刷库平衡实时性与数据库压力。第三,回调要按"必然会失败"来设计:退避重试、死信重放、事件幂等、提交时挑战校验,一样都不能省。第四,失败要分片局部化、坏条目进隔离区,全或无的批量任务在真实数据面前必然全军覆没。第五,批量下发速率要与在线水位联动,让批量成为闲时算力的消化者而不是在线业务的竞争者。