先说明本文的前提:本次可引用的官方资料部分为空,没有提供 DeepSeek API 的超时默认值、限流阈值、错误码表或重试相关响应字段。因此下文不写“官方默认 X 秒”“遇到某状态码就重试”这类断言,只讨论客户端集成层的工程方法,所有具体数值和字段名都需要回到官方文档确认。以下内容属于工程分析,与官方事实分开看待。
一、超时不是单一参数
很多超时问题源于只设了一个“超时时间”。更可控的做法是拆成三层:连接超时、读超时、总超时。连接超时管建连阶段,应该设得比较短,因为建连失败极少会因为多等而成功;读超时管等待响应,非流式请求下它是“从发出到收完”的窗口,流式请求下更合理的定义是“两个数据块之间的最大间隔”,否则一个正常生成但耗时较长的请求会被误杀;总超时是兜底,用来防止连接正常但传输极慢的请求长期占用连接与并发额度。三者需要满足不等式:连接超时加读超时不超过总超时,总超时不超过上层调用方愿意等待的时间。
二、先分类失败,再决定是否重试
不要在所有异常分支里无差别重试。判断一个失败是否可重试,可以问三个问题。第一,失败发生在哪一层:建连前失败、请求已发出但无响应,通常可重试;响应中途断开要谨慎,服务端可能已经完成了部分工作。第二,错误语义是什么:参数或格式错误、鉴权失败、额度或权限不足、内容被拒绝,这类失败重试多少次结果都一样,属于不可重试,应立即上抛并记录,而不是用重试掩盖。第三,请求是否幂等:纯生成类调用一般没有副作用,重试相对安全;但若该请求会触发外部写操作或回调,就必须靠业务侧幂等键去重,否则重试会放大副作用。对于语义不明的失败,建议只做有限次重试,并把原始响应保留下来,便于后续定位。
三、重试参数要带预算
重试的三个关键参数是最大次数、退避基数和退避上限,并且退避必须加抖动,否则同一时刻失败的请求会同步重试,形成重试风暴。更重要的是重试预算:单次超时乘以重试次数加一,必须小于端到端预算。否则重试序列还没跑完,上层调用方已经超时返回,重试不仅无效,还白白占用连接和并发额度。如果响应中带有服务端给出的等待提示,应当优先尊重该提示;没有提示时,对限流类失败应采用比网络抖动更保守的退避。
四、并发与队列是第二道闸
并发上限(信号量或连接池大小)是保护自己和下游的第一道闸。队列必须设上限,无上限的队列等于把内存当缓冲。排队超时要独立于请求超时设置,否则会出现“请求还没发出去就已超时”的情况。队列满时快速失败并返回可识别的错误,通常比让所有请求一起变慢更好。需要提醒的是,提高并发并不能解决限流,只会更快撞上限;吞吐由并发数与单请求耗时共同决定,连接池过小还会让并发额度形同虚设。
五、把参数串成一套自洽配置
推荐的落地顺序是:连接超时、读超时、总超时、重试次数与退避与重试预算、并发上限、队列上限与排队超时、熔断与降级、最后是观测埋点。这些参数之间存在明确的不等式关系,应当以代码常量或配置注释的方式显式写出来,避免后续有人单独调大某一项而破坏整体约束。
六、没有观测就调不好参
每次调用至少记录:排队时长、建连时长、首字节时长、总时长、重试次数、最终错误分类。只有拿到耗时分位数,才能判断该调超时还是该调并发;把重试率作为独立指标暴露出来也很有价值,重试率上升往往是上游开始限流或自身并发过高的早期信号。
七、落地检查清单
不可重试类错误默认不重试;所有重试都带抖动;端到端预算显式分配并向下切分;队列有上限且有排队超时;并发上限可配置且可观测;错误分类逻辑集中在一处实现,而不是每个调用点各写一套。最后,由于缺少官方参数,第一步应当是到官方文档确认限额、错误码与重试约定,再用上述框架填入具体数值,不要从任何二手文章里抄数字当默认值。