API 中转站错误码统一封装:上游十几种报错口径,客户端只接一套结构
上游模型服务各写各的报错,客户端被迫为每家写一套异常分支。本文梳理中转站错误码统一封装的落地路径:错误分类、对外结构与状态码分工、限流与额度的区分、流式场景下的错误事件、重试与熔断策略,以及 trace 定位与监控。快米兔 API 以 OpenAI 兼容方式收拢错误口径,注册赠送 5 元测试金,按量计费。
做过大模型接入的团队大多经历过这样的场景:同一条业务代码,背后接了两三家模型服务,日志里却躺着四五种形状完全不同的报错。有的把错误塞在 HTTP 200 的响应体里,有的用 4xx 配一段英文说明,还有的在中途断流时只给一个空响应。客户端开发不得不为每个上游写一套 if-else,重试逻辑越写越乱。中转层如果只做转发、不做错误归一化,这份复杂度就会原封不动地传导给业务方。
错误归一化的第一步是把来源盘清楚。上游报错通常集中在几类:鉴权失败(Key 无效、过期、权限不足)、配额问题(余额耗尽、套餐额度用尽)、限流(QPS 或并发超限)、参数错误(模型名不存在、消息格式不符、字段超长)、内容合规拦截、上游自身故障或超时,以及网关侧的问题(Key 被禁用、路由不到可用上游)。每一类在中转站内部都应有稳定的内部码,再统一映射成对外的错误结构,而不是把上游原文照搬出去。
对外结构建议沿用主流协议里已被广泛识别的形态:一个 error 对象,包含 message、type、param、code 四个字段。message 给人看,type 做粗分类,param 指出出错的参数字段,code 则是机器可判断的稳定标识。中转站再叠加自己的错误码表,把「上游 A 的额度不足」和「上游 B 的并发超限」归到同一个 code 家族里。这样客户端只认一套码,换上游时业务代码基本不用动,异常分支也能收敛到十几个以内。
HTTP 状态码与业务码要分工明确。状态码负责让通用的 HTTP 中间件、重试库、监控系统识别大类,业务码负责精确说明原因。常见约定是:鉴权类 401,额度类 402,限流类 429,参数或模型不存在 400 或 404,上游故障 502 或 503,超时 504,内容合规类 400 加特定 code。最忌讳的是上游返回 200 却带着错误内容,中转层要把这类响应改写成对应的错误状态码,否则客户端的自动重试和告警规则都会失灵,运维只能靠人肉盯日志。
模型名不存在和路由失败容易被混为一谈,但处理方式完全不同。前者是客户端请求里写了不支持的模型,属于参数错误,应该直接返回 400 并提示可用模型列表;后者是中转站内部选不出可用上游,属于服务侧问题,应返回 503 并附带建议的重试时间。两种情况用同一个码返回,业务方既不知道该改参数还是该重试,也看不到真实原因。映射时最好保留一个不含敏感信息的上游标识字段,方便排查又不泄露内部结构。
限流和额度耗尽的区分尤其重要。限流是短时的,响应里通常带 Retry-After 或重置时间,客户端延迟重试就能恢复;额度耗尽在多数平台上属于需要人工处理的状态,重试多少次都没有意义。两者如果都返回 429,客户端会陷入无意义的循环重试,白白消耗请求配额。比较稳妥的做法是限流用 429 并给出建议等待秒数,额度问题用独立业务码,同时在错误信息里区分「账号额度」和「单 Key 额度」,方便子账号体系快速定位。
流式响应把错误处理难度又抬高一层。SSE 在开始输出之后才发生上游中断,此时 HTTP 状态码早已是 200,没法再改。可行的办法是在数据流中下发一个结构化的 error 事件,字段与普通错误保持一致,并明确标注这是流内错误。客户端收到后应保留已经渲染的部分内容,同时按错误类型决定是否重新发起请求。中转站还要处理已产生的 token 如何结算,建议在错误事件里带上用量字段,避免账单对不上而产生纠纷。
归一化之后,重试策略才有条件做得干净。可按错误码配置:限流和上游 5xx 允许有限次数的指数退避重试,参数错误、鉴权错误、内容合规直接失败不再重试,避免浪费额度。多上游路由的场景下,还可以把「换一个上游重试」和「等待后重试同一个上游」区分开——前者适合上游故障,后者适合限流,混在一起会放大故障面。需要注意的是流式请求一旦开始输出,重试要非常慎重,防止同一段内容被重复计费和重复渲染。
可观测性是把错误码真正用起来的关键。每个请求应生成一个 trace id,错误响应里带上它,日志侧记录内部码、上游码、上游标识、耗时和是否重试。按上游维度统计错误率、限流触发次数、超时比例,就能判断某条线路是不是该降权甚至临时摘除。不少团队做错误封装时只关心客户端看不看得懂,忽略了运营侧看不看得见,结果线上故障排查仍然靠翻原始日志。统一封装的另一半价值,恰恰是让错误数据可聚合、可告警、可回溯。
落地顺序上,建议先把各上游的错误样例收集齐,整理成映射表;再定义对外错误结构和内部码体系;然后接入路由与重试策略;最后补上流式错误事件和监控看板。这个过程不必一次做完,但映射表必须有人维护,上游接口改版时第一反应应该是检查错误返回有没有变化。错误码是接口契约的一部分,一旦对外发布就要尽量保持语义稳定,否则客户端刚写好的重试分支又得重写一遍。把这层做扎实,后面的多模型接入和成本优化才有稳定的地基。
快米兔 API 在这条链路上的思路,是把归一化尽量放在中转层完成:对外保持 OpenAI 兼容的调用方式与错误结构,多模型路由、限流与计费都在服务侧处理,业务方按一套码写判断逻辑即可。新用户注册赠送 5 元测试金,采用按量计费,适合先把错误处理分支跑通再逐步扩量;具体可用模型、额度规则与错误码清单以官方说明为准。对同时接多家模型、又不想在业务代码里堆一堆异常分支的团队来说,把报错口径收拢在一处的接入方式,通常更省事一些。
