migrating-in-house-backend-to-openai-format · ZH · 2026-11-05

把自研的 LLM 后端换成聚合站的 OpenAI 兼容路由:接口对齐与回退思路

面向已围绕自托管模型搭建私有封装的团队,讲解如何把客户端切换到聚合站的 OpenAI 兼容路由,并保留旧后端作为回退。内容涵盖接口对齐要点(路径、鉴权、请求与响应字段)、模型名映射、回退与降级策略、灰度切换步骤,以及用 Base 上 USDC 充值的计费差异。

为什么用兼容路由替换自研后端

很多团队最初围绕自托管模型做了私有封装:自定义路径、自定义鉴权头、固定的模型名,甚至把流式输出再包一层。这套封装在单一后端下工作良好,但当你想接入更多模型(Claude、GPT、DeepSeek、Qwen、GLM、Kimi)时,每加一个都要改一遍适配层。

聚合站的 OpenAI 兼容路由把这件事收敛成一个标准:客户端按 OpenAI 的请求/响应格式发,路由负责分发给不同厂商的模型。你不需要重写业务逻辑,只需要把封装层里的 base URL 和模型名换掉,同时把旧后端保留为回退。

接口对齐要检查的四个点

切换前先确认你的封装层没有依赖 OpenAI 协议之外的行为:

  • 路径:兼容路由通常挂在 /v1/chat/completions 这类标准路径下,自研后端如果是 /api/generate 之类,需要在封装层做一次路径改写。
  • 鉴权:标准做法是 Authorization: Bearer <API key>。如果旧封装用了自定义的 X-Api-Key,改成标准头即可,不要两套同时发。
  • 请求字段:model、messages、stream、max_tokens、temperature 是通用字段。厂商特有的参数(如某些推理控制字段)不是所有模型都接受,封装层应只透传通用字段,其余按模型白名单放行。
  • 响应字段:非流式关注 choices[0].message.content 与 usage;流式关注 data: 行的增量结构,以及结尾的 [DONE] 标记。你的解析器要能容忍 usage 在流式末尾才出现。

建议在封装层写一组契约测试:同一段请求分别打到旧后端和新路由,断言解析出的文本、结束原因、用量字段结构一致。这比人工点几次页面可靠得多。

模型名映射与能力差异

聚合站的一个 key 可以调多个模型,但模型名由路由方定义。做法是在封装层维护一张映射表:

  • 业务侧只认抽象名(如 chat-default、chat-long),由映射表翻译成路由上的具体模型名;
  • 每个抽象名标注能力边界:是否支持流式、是否支持工具调用、上下文上限大致量级;
  • 当某个模型在路由上不可用时,映射表能快速改指向,而不动业务代码。

不要把模型名硬编码在业务逻辑里,也不要在封装层假设所有模型对同一段 prompt 表现一致。切换后先跑一遍你的评测集,对比输出长度、结构化程度和工具调用成功率。

保留旧后端作为回退

回退不是“出错了就重试”,而是分层处理:

  • 连接层回退:新路由超时或返回 5xx 时,切到旧后端。设置较短的首字节超时,避免用户长时间等待。
  • 协议层回退:新路由返回 4xx(如模型名错误、参数不被接受)时,通常说明映射或字段有问题,应先记录并告警,而不是盲目回退到旧后端,否则问题会被掩盖。
  • 质量层回退:业务侧对新路由的输出做轻量校验(如 JSON 可解析、必填字段齐全),不通过时用旧后端重跑一次。

回退要可观测:每次回退记录原因、模型名、耗时和请求 ID,方便判断是路由侧问题还是你的映射问题。同时注意回退会放大成本——旧后端如果是自托管,算力成本另算;新路由按用量计费,用 Base 上的 USDC 充值、无 KYC,按官方价 ×1.3 扣费。回退频率高时,账单会直接反映出来。

灰度切换步骤

  1. 在封装层加一个开关,按百分比或按租户把流量导向新路由,默认仍走旧后端;
  2. 先放小流量跑契约测试和评测集,观察错误率、首字节延迟、回退率;
  3. 逐步提高比例,每次提高后观察一个完整业务周期;
  4. 稳定后把旧后端降级为回退路径,而不是直接删除;
  5. 保留开关和映射表,作为长期的多模型调度入口。

计费与额度的心智模型

切换后计费方式变了:原来自托管是算力成本,现在是按官方价 ×1.3 扣 USDC。封装层最好把每次调用的 usage 聚合成内部指标,按业务线或租户拆分,这样能看出哪些调用该走便宜模型、哪些值得用更强的模型。如果你自己也向聚合站贡献 key,贡献侧按官方价 ×1.1(优质 ×1.2)返 USDC,但这属于另一条链路,不要和消费侧的成本混在一起算。

常见坑

  • 把厂商特有参数原样透传,导致换模型后请求被拒;
  • 流式解析假设 usage 在首块返回,实际可能在末尾;
  • 回退逻辑写成无限重试,路由故障时把旧后端也打满;
  • 模型名散落在代码各处,换一个模型要发一次版。

把这些问题收拢到封装层的映射表和契约测试里,切换就只是一次配置变更。