先看现象。自建网关日志显示 200,上游返回的其实是 400 参数错误,框架按成功记账并继续重试,月底账单比实际用量多了 1.8 倍。
真正麻烦的地方在于,几个原因的现象几乎一样。网关只看连接是否建立,没检查上游状态码。还有一种是SDK 把 400 包成异常,但被上层 except 吞掉。
还有一种情况,重试策略对所有异常都生效,包括参数错误。
另外,计费按请求条数记,不区分成功与失败。
第一件事是在网关日志里补上游状态码字段
python -c "print({'upstream_status':400,'client_status':200})"
只对 429 与 5xx 重试
python -c "print([c for c in [400,429,500,503] if c==429 or c>=500])"
然后把异常按类型分开打点
python -c "print(type(ValueError('bad params')).__name__)"
末了用一条故意错的请求验证不重试
curl -s -o /dev/null -w "%{http_code} %{time_total}\n" https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","messages":[]}'
这类问题以前遇到过,但这次的触发条件和上次不一样。
改完先别撤,确认这几项。参数错误的请求只发一次,网关日志里 client_status 与 upstream_status 一致,日账单条数下降 40% 以上。
重试是放大错误的装置,先分清可重试与不可重试,再谈退避和次数。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
