返回
统一 AI 模型网关:一个入口接多家模型
4 分钟

统一 AI 模型网关:一个入口接多家模型

“从 Python 框架 bida 到网关加接入台:用一层统一入口隔离各家模型的差异。”


用的模型一多,麻烦也跟着来:每家的 SDK 不一样,鉴权方式不一样,模型列表也在不停变。我的做法是在中间放一层统一入口:上层只认一种调用方式,下层再去对接各家模型。

为什么需要统一入口

  • 换模型不改代码:业务代码只写一次,切换模型只改配置;
  • 密钥集中管理:每个应用一把独立的 Key,出问题可以单独停用;
  • 能力差异透明化:哪家支持流式、哪家能拉模型列表,在一个地方说清楚。

早期尝试:bida

最早我用 Python 写过一个开源框架 bida,目标是「简单、易用、稳定、高效,便于扩展和集成」:用同一个 ChatLLM 接口调用不同厂商的模型。

from bida import ChatLLM

llm = ChatLLM(model_type="openai", model_name="gpt-4")
print(llm.chat("从 1 加到 100 等于多少?"))

切换厂商时,只需要改 model_type。

现在的做法:网关 + 接入台

现在我更倾向于把统一入口做成服务,而不是库:

  1. 网关:对外提供 OpenAI 兼容的接口,所有应用都调用它;
  2. 接入台:一个本地小服务,负责登录各家模型、保存凭证、拉取实时模型列表、做一次测试调用。

各家的能力用一份配置描述,比如「用哪种方式拉模型列表、能不能做测试调用」:

{
  "providers": {
    "anthropic": { "list": "anthropic-models", "test": "pi-stream" },
    "google":    { "list": "google-models",    "test": "pi-stream" },
    "amazon-bedrock": { "list": "unsupported", "test": "unsupported" }
  }
}

拉模型列表时,不同的 Base URL 写法要处理好,避免出现 /v1/v1/models 这种拼接错误:

export function versionedEndpoint(baseUrl, leaf) {
  const base = baseUrl.trim().replace(/\/+$/, "");
  const pathname = new URL(base).pathname.replace(/\/+$/, "") || "/";
  const rel = String(leaf).replace(/^\/+/, "");
  if (/\/v\d+(?:beta|alpha)?$/i.test(pathname)) return `${base}/${rel}`;
  return `${base}/v1/${rel}`;
}

几条经验

  • 每个应用一把 Key:用量和费用一目了然,泄露了也只影响一个应用;
  • 模型列表要实时拉:写死的列表很快就会过时;
  • 测试要有离线版:单元测试不依赖真实网络和密钥,联网测试单独标记;
  • 测试里别写死个人信息:比如邮箱,我专门加了一个测试来防止它混进代码。

小结

统一入口的本质是把「变化」隔离在一层里:模型怎么变,上层都不用动。从 bida 这样的库,到现在的网关加接入台,思路一直没变,只是形态从代码变成了服务。