调用链最常见的超时错误是每层都写一个固定值:Web 服务 30 秒、网关 30 秒、模型 SDK 30 秒、工具服务 30 秒。实际上这些时间会叠加,用户已经超时后,后台还可能继续运行,产生无意义的 token、工具请求和队列占用。
区分 timeout 和 deadline
固定 timeout 表示“这一层最多等多久”;deadline 表示“整个业务请求必须在什么时间前结束”。入口生成截止时间后,后续服务只使用剩余预算。剩余预算不足以完成一次安全调用时,应快速失败或降级,而不是重新给每一层发一个完整的 30 秒。
预算应拆成排队、连接、模型生成、工具执行、重试和清理几个部分。流式请求还要定义“首个事件必须何时到达”和“空闲间隔最长多久”,否则连接一直有少量数据也可能拖住资源。
重试要看剩余时间
重试不是默认动作。剩余时间太短时,重试只会制造另一个必然超时的请求。网关应读取上游的 Retry-After、错误类型和副作用状态,结合剩余 deadline 决定重试、切换上游、返回缓存的安全结果,还是直接结束。工具写入类动作还要先查询是否已经成功。
取消也要真的传到下游。客户端断开后,网关应取消模型流和等待中的工具;无法取消的服务至少要停止结果写回,并把后台任务标成可清理状态。否则表面上请求失败,实际成本和并发仍在增长。
使用 top-api.cc 统一多模型调用时,可以在入口生成 request deadline 和预算标签,让不同供应商的超时语义映射到统一内部状态。网关只能负责传播和记录,工具服务仍需尊重 deadline 并及时释放资源。
测试场景
- 队列已等待一半预算后才开始模型调用;
- 模型首字节很快但生成长尾;
- 工具超时后返回未知结果;
- 上游返回 429 和 Retry-After;
- 客户端提前断开;
- 回退模型只剩很短的剩余时间。
报告中应同时给出用户感知延迟、后台残留时间、实际 token、工具调用数和取消成功率。一个好的 deadline 设计会让失败更早、更可解释,也会减少“用户已经放弃但系统还在付费”的情况。
参考资料:HTTP/gRPC deadline 传播实践、各模型 SDK 的 timeout 与取消文档,以及网关的重试策略说明。
如果你要比较不同上游在同一时间预算下的行为,可以让 top-api.cc 统一传递 deadline,再按模型和工具阶段拆分结果。
Leave a Reply