大模型的批量任务一跑几分钟,让用户干等并不现实,异步调用把提交和拿结果拆成两步,通知完成的方式主要就是回调与轮询两条路。两条路各有脾气,选错会白费功夫。
提交之后发生了什么
提交请求后服务端立刻返回一个任务标识,任务进入队列排队执行。进来的是任务请求,发生的是入队与受理确认,出去的是任务号加受理回执。此刻任务多半还没开始算,用户拿到的只是已登记的凭证。
任务号背后是状态机:排队中、执行中、已完成、失败,每一步都有记录,查询接口读的就是这份状态。凭证是后面一切通知的锚点,丢了它就得靠别的途径找回。队列还有优先级:紧急任务可以插队,但插队要有配额,人人都紧急等于没有紧急,插队额度按账号分配。
受理和执行分离是异步的精髓:服务端先确认能接,再慢慢消化,用户拿到凭证就可以去干别的。任务号的生成有讲究:随机串加前缀,既不含内部结构信息,又能在日志里快速归类,格式定了就别改。
回调是怎么敲门的
回调是服务端主动上门:任务完成时,服务端按提交时登记的地址发一条通知,带上任务号和结果位置。进来的是完成事件,发生的是主动推送,出去的是一条回调消息。
回调省心但有两个前提:调用方要有能被访问到的接收端,通知丢了要有补救。接收端收到通知后要尽快确认,没确认的通知会被视为丢失。所以正式实现里回调通常带重发与签名校验,收不到就按退避节奏再发几次。回调的内容也有规范:通常只带任务号和状态,结果正文放对象存储,通知里给地址,避免大包压垮通知通道。接收端还要做幂等,同一条通知重复送达时不能重复处理。通知的时序也要注意:回调先到、任务状态还显示执行中,是缓存延迟,以回调为准即可。
轮询是怎么盯进度的
轮询是调用方自己盯:每隔一段时间拿任务号去问一次状态,完成了就取结果。进来的是查询请求,发生的是状态读取,出去的是进行中或已完成。间隔起点短、倍数增长、设上限,和退避重试是同一套思路,问得勤浪费请求,问得疏拿到结果晚。
轮询简单可靠、不依赖接收端,代价是请求次数多。两者并用的架构不少见:回调负责快,轮询负责稳,一条路堵了另一条还在。你在秘塔AI搜索、扣子(Coze)里提交长任务后看到进度条自己动,多半是轮询在幕后跑。轮询的节奏可以更聪明:按任务的历史耗时估计完成点,在估计值附近加密询问,其余时间放宽间隔,请求次数能省一半以上。轮询查询本身也有限流:问得太勤会被当成异常流量,按文档建议的间隔来,别拿查询接口刷出新的超限。
两条路的前提、代价和补救方式,并排看更清楚。
| 对比项 | 回调 | 轮询 | 并用的分工 |
|---|---|---|---|
| 通知方向 | 服务端按登记的地址主动推送 | 调用方拿任务号定时去问 | 回调负责快,轮询负责稳 |
| 成立前提 | 调用方要有能被访问到的接收端 | 不依赖接收端 | 一条路堵了另一条还在 |
| 丢了怎么补 | 没确认视为丢失,按退避节奏重发并带签名校验 | 下一轮查询读到状态机里的最新状态 | 通知丢了轮询还能捞回来 |
| 重复与顺序 | 同一条通知重复送达要做幂等 | 读的是状态记录,不会重复处理 | 回调先到而状态仍显示执行中,以回调为准 |
| 成本与限制 | 只带任务号和结果地址,避免大包压垮通道 | 请求次数多,问太勤会被当异常流量 | 按文档建议的间隔查 |
- 速查:提交即拿任务号;状态机记录全程;回调主动上门带重发;轮询自己盯间隔渐长;两者并用互为备份。
异步只是拆开了等待,后续环节各有文章:降级时的小模型是怎么顶上的?机制细节全梳理应对执行中的故障,上下文超限的报错是怎么触发的?拦住塞不下的任务,推理结果的日志怎么记?排查的第一手资料记录执行轨迹,一次请求的显存峰值出现在哪?内部门道在这决定一条任务占多少资源。
聊聊异步调用的常见疑问
- 任务号丢了还能找回结果吗?:登记过的标识一般可凭账号在任务列表里查回,匿名提交就难说了。
- 回调和轮询能同时用吗?:可以,回调为主轮询兜底是稳妥做法,通知丢了轮询还能捞回来。
- 任务排队多久算正常?:取决于队列长度和任务大小,产品一般会给预估时长或排队位置,超时太久的任务先查状态再决定要不要重新提交。


