通过聚合站发起长任务:超时、重试与去哪儿查进度
本文讨论在聚合站发起长时间 LLM 调用时,如何应对超时、断连与重试风险,并设计一个既能自动恢复又避免重复计费的任务包装层。重点包括不同后端的超时行为差异、幂等请求键的设计、轮询状态与日志的查询方式,以及超时与重试策略的取舍。
长任务的特点与难点
聚合站的一个 API key 背后可能路由到不同模型厂商。单次调用跑几分钟时,各后端对长连接的处理方式并不一致:有的会在网关层先断开,有的能维持较长时间但响应体很大,有的在生成中途因负载被中止。客户端看到的表现可能是连接重置、网关超时、流式响应突然结束,而不是一个干净的 4xx/5xx。
长任务的第二个难点是重试的代价。一次几分钟的调用如果因为读超时重发,可能同时有两份任务在后端执行,既浪费额度也容易在结果合并时出错。因此任务包装层的核心不是“重试得更多”,而是“让重试可被安全识别”。
先看清各后端会怎么失败
你无法凭聚合站文档精确知道每个上游的超时阈值,正确做法是实测并分类:
- 连接建立阶段失败:通常是网络或鉴权问题,重试一般安全。
- 首字节前超时:请求可能已进入队列,重发有重复执行风险。
- 流式传输中断:已收到的部分内容可用,但完整结果未知,需要状态查询或重新生成。
- 非流式长响应读超时:客户端主动断开,但后端可能仍在生成。
建议为每类失败打标签,并记录耗时、是否收到部分响应、HTTP 状态。这些数据决定后续重试策略,而不是凭直觉统一重试三次。
设计任务包装层:幂等键优先
包装层最关键的设计是客户端生成一个幂等键(例如业务 ID + 请求指纹),随请求发给你的中间层,而不是直接发给聚合站。中间层负责:
- 收到请求后先查该键是否已有进行中的任务;
- 有则返回任务 ID 和当前状态,不重复发起;
- 无则创建任务记录,再调用聚合站;
- 调用结果(成功/失败/部分内容)落库。
这样客户端断连后重试,只是再次询问任务状态,不会触发第二次上游调用。
超时与重试策略
超时不应只有一个总时长,而应分层:
- 连接超时:较短,用于快速失败。
- 首字节超时:适中,超过后按“请求可能已入队”处理,转为状态查询而非直接重发。
- 整体任务超时:由业务允许多长决定,到达后主动取消或标记为超时。
- 流式空闲超时:两个数据块之间超过阈值才判定卡死,避免正常的长思考被误杀。
重试只对明确安全的失败类型自动执行,比如连接建立失败。对首字节后失败或读超时,先查询任务状态,确认后端已终止或未接受后再决定是否重发。指数退避加随机抖动依然是合适的,但要设置上限,避免任务无限排队。
进度去哪儿查
聚合站通常不提供任务级进度查询,进度需要你的包装层自己维护:
- 任务记录表保存状态、开始时间、最后更新时间、已接收字节数或 token 计数;
- 流式场景下定期把已收内容或摘要写回,客户端可通过任务 ID 拉取;
- 日志中保留请求 ID 和上游返回的追踪字段,便于对账;
- 若上游返回可查询的调用标识,一并保存,用于判断任务是否仍在执行。
这样客户端无论是否断连,都能通过任务 ID 轮询到一个明确状态,而不是靠反复重发碰运气。
计费与对账注意事项
聚合站按官方价乘以固定系数计费,长任务失败时是否计费取决于上游实际执行情况。包装层应记录每次实际发起的上游调用次数,并与最终任务状态对齐。对于“客户端超时但后端可能已生成”的情况,优先完成状态确认再决定是否重发,这比任何重试次数配置都更能减少重复计费。
小结
长任务的关键不在调用本身,而在调用之外的状态管理。用幂等键防止重复发起,用分层超时区分失败类型,用任务记录支持断连后查询,把重试限制在安全边界内,就能在聚合站这种多后端场景下稳定运行几分钟级的调用。