一个 API Key,调用 Claude、GPT、Gemini、DeepSeek 所有主流大模型。听起来简单,但背后的工程细节远不止换个 endpoint 那么简单。

为什么需要 AI API 网关

如果你的业务只用一个模型提供商,直接调用官方 API 没什么问题。但现实中大多数团队会遇到以下场景:

  • 多模型并存:不同功能模块用不同模型,有的用 Claude 做代码审查,有的用 Gemini 做文档摘要,有的用 DeepSeek 跑批量任务
  • 单点故障风险:OpenAI 在 2024 年多次出现 API 中断,Anthropic 也会有限流。没有 fallback 就意味着你的业务直接挂掉
  • 计费混乱:每个提供商有独立账单,token 单价不同,月底对账是噩梦
  • 合规与审计:企业客户要求记录所有 AI 调用,方便审计、排查问题

AI API 网关就是解决这些问题的基础设施层。它站在你的应用和各个模型提供商之间,统一入口、统一协议、统一计费、统一监控。

核心架构:四层设计

我们在设计 TheRouter 时把整个请求链路分成四层,每层职责明确:

客户端请求
    │
    ▼
┌─────────────────────────────────┐
│  1. 请求解析层(Ingress Layer)   │  ← 协议适配、鉴权、参数校验
└─────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────┐
│  2. 模型路由层(Router Layer)   │  ← 模型映射、路由选择、健康过滤
└─────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────┐
│  3. Provider 适配层              │  ← 协议转换、错误归一化、重试
└─────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────┐
│  4. 计费层(Billing Layer)      │  ← Token 计量、费用记录、余额扣减
└─────────────────────────────────┘
    │
    ▼
上游 Provider(OpenAI / Anthropic / Bedrock / Vertex AI / ...)

第一层:请求解析层

所有入站请求首先到达这里。主要职责:

  1. 协议适配:支持 OpenAI Chat Completions 格式(messages 数组)、OpenAI Responses API(input 字段)、Anthropic Messages API 等多种请求格式,统一转换为内部标准格式
  2. 鉴权:验证 API Key 合法性,加载租户配置(路由策略、允许使用的模型、消费上限)
  3. 参数校验:检查 model 字段是否存在、请求体格式是否合法,在路由前快速返回错误

这一层的关键设计原则是快速失败——所有能在路由前拒绝的请求,不要带进下游。

第二层:模型路由层

这是整个网关最核心的部分。

两层模型抽象

我们设计了两层模型命名体系:

  • Standard Model(标准模型):对外暴露的模型 ID,格式为 品牌/模型名,比如 anthropic/claude-sonnet-4.6openai/gpt-5google/gemini-2.5-pro。这是客户看到的,也是 /v1/models 接口返回的。
  • Upstream Model(上游模型):实际调用时使用的提供商内部模型 ID,比如通过 Bedrock 调用 Claude 时,上游模型是 us.anthropic.claude-sonnet-4-5-20251001-v1:0

两层抽象的好处是:客户代码里只出现标准模型 ID,内部路由切换对外完全透明。 我们把一个 Anthropic 直连路由切换成 Bedrock 路由,客户完全无感知。

配置文件结构:

src/config/
├── standard-models.yaml          ← 标准模型定义 + 售价
└── provider-models/              ← 每个 provider 一个文件
    ├── anthropic-api.yaml        ← Anthropic 直连
    ├── bedrock-us-east-2.yaml    ← AWS Bedrock us-east-2
    ├── openai-api.yaml           ← OpenAI 直连
    └── vertex-ai-us-central1.yaml← Google Vertex AI

每个 provider 文件里,通过 standard_model 字段把上游模型挂载到标准模型上:

# bedrock-us-east-2.yaml (示意)
upstream_models:
  us.anthropic.claude-sonnet-4-5-20251001-v1:0:
    standard_model: anthropic/claude-sonnet-4.6
    priority: 20           # 优先级,越小越优先
    cost:
      input: 3.00          # $/MTok,成本价
      output: 15.00
路由选择算法

路由层根据以下因素决定用哪个 provider:

  1. 优先级(Priority):每条路由有一个 priority 值,数字越小越优先。同一个标准模型可以挂多条路由,形成有序的 fallback 链
  2. 能力过滤(Capability Filter):如果请求用了 tools(函数调用)或 vision(图片输入),过滤掉不支持这些能力的 provider
  3. 健康状态(Health Filter):过滤掉当前不健康的 provider(下文详述)
  4. 客户偏好(Customer Preference):租户可以通过请求头或 API 参数指定 only(只用某些 provider)、ignore(排除某些 provider)、order(自定义排序)

支持两种路由算法,可以按租户或按请求切换:

  • priority:按优先级排序,优先选最高优先级的健康路由
  • lowest_cost:在健康路由中选当前成本最低的

第三层:Provider 适配层

每个 provider 是独立的微服务,负责:

  1. 协议转换:把网关内部格式翻译成 provider 原生 API 格式(Anthropic 的 Messages API、OpenAI 的 Chat Completions、Bedrock 的 InvokeModel 等)
  2. 错误归一化:把各家的错误码统一映射到网关内部错误类型(error_5xxerror_4xxtimeoutrate_limit),让上层路由决策逻辑不需要感知具体 provider
  3. 内部重试:provider 层做短暂的内部重试(只针对 transient 5xx),与路由层的跨 provider failover 分离

关键设计决策:每个上游 API 必须有独立的 provider 服务。 即使两个 provider 的 API 格式兼容(比如许多第三方都兼容 OpenAI 格式),也要给它们各自的服务。原因:provider 特有的错误处理、reasoning token 格式、Rate Limit 行为各不相同,共用镜像会埋下难以排查的 bug,也让独立升级变得困难。

第四层:计费层

每次请求完成后,计费层负责:

  1. Token 计量:从响应的 usage 字段读取实际消耗的 input/output token 数
  2. 成本计算:根据实际使用的 provider 的成本价计算原始成本,按售价计算向客户收取的费用
  3. 记账:写入计费流水,扣减余额

计费层和路由层共享同一份定价配置——标准模型有"售价",provider 路由有"成本价"——两层价格独立维护,网关统一管理 margin。

故障转移机制

这是 AI 网关区别于普通 API 网关的核心能力之一。

Provider 健康检查

网关维护一个 provider 健康状态缓存,来源有两个:

  • 主动探测:定期向各 provider 发送探测请求,根据响应时间和错误率更新状态(healthy / degraded / unhealthy
  • 被动感知:每次真实请求如果返回 5xx 或超时,记录失败事件,动态调整该 provider 的健康分数

自动 Fallback 流程

请求 → 路由层选出有序候选列表 [A, B, C]
         │
         ▼
      尝试 A
         │
    A 返回 503 ──→ 记录失败,标记 A 健康分下降
         │
         ▼
      尝试 B
         │
    B 成功 ──→ 返回响应,记录 fallback_depth=1

路由层在构建候选列表时已经过滤掉 unhealthy 的 provider,但 degraded 的仍然会保留(排在后面)。这样在所有健康 provider 都不可用时,降级 provider 还能作为最后兜底。

我们在 Prometheus 指标里专门追踪 fallback 深度(gateway_fallback_depth)和 fallback 总次数(gateway_fallback_total),用于告警和 SLA 评估。

流式响应的特殊处理

Fallback 在流式(SSE)请求下有一个关键约束:一旦响应头已经发送(HTTP 200 + Content-Type: text/event-stream),就不能再切换 provider 了。

所以流式请求的 fallback 只能在第一个 token 到达之前触发。具体做法:

  1. 建立 SSE 连接后,先不立即向客户端发送响应头
  2. 等待 provider 开始返回数据流(拿到第一个 chunk)
  3. 第一个 chunk 确认成功后,再向客户端发送响应头 + 开始转发数据
  4. 如果在第一个 chunk 到来前 provider 报错,可以切换到下一个 provider 重试

这个设计增加了首 token 延迟(TTFT),但保证了流式请求的可靠性。

另一个挑战是流式过程中断:数据已经开始传输,中途 provider 连接断掉了怎么办?这种情况我们选择向客户端发送一个特殊的错误 chunk,然后关闭连接——此时重连到新 provider 并续传是不现实的,因为我们无法知道客户端已经收到多少内容。

实践中踩过的坑

1. SSE 连接泄漏

早期版本里,如果客户端提前断开连接(比如用户刷新了页面),网关侧不会立即感知,上游的 SSE 流还在跑,消耗资源还在计费。现在我们监听客户端连接的 close 事件,客户端断开时立即 abort 上游请求。

2. 跨 Provider 的 Token 计数差异

不同 provider 对同一段文本的 token 计数略有差异(因为分词器不同)。如果用预估 token 数做余额预扣,误差会导致少扣或超扣。我们的做法是:预扣时用一个保守估算(留 20% buffer),请求完成后根据实际 usage 做精确结算。

3. Bedrock 的特殊性

AWS Bedrock 不是一个简单的 HTTP API,它需要 AWS SigV4 签名。我们把 Bedrock 做成一个独立的 provider 服务,所有签名逻辑都封装在里面,网关主体不感知 AWS SDK。

4. 响应里的模型名字必须回显标准模型 ID

Claude 官方 API 返回的响应里,model 字段会是类似 claude-sonnet-4-5-20251001 这样的内部版本号。我们必须把它替换成用户请求时用的标准模型 ID(比如 anthropic/claude-sonnet-4.6),否则客户代码里做模型判断的逻辑会出错。

架构总结

一个生产可用的 AI API 网关需要解决的问题远比"转发请求"复杂得多。上面提到的两层模型抽象、能力感知路由、流式 fallback 策略、精确 token 计费,每一块都有相当多的工程细节。

如果你正在构建自己的 AI 基础设施,建议:

  1. 不要直接暴露 provider 名字给业务代码——用抽象层隔离,方便未来迁移
  2. 从第一天就做健康检查和 fallback——AI provider 的稳定性远不如传统 SaaS
  3. 流式请求单独处理——SSE 的错误处理逻辑和普通请求完全不同,不能复用
  4. 双层定价——成本价和售价分开管理,方便调整 margin 和做成本分析

如果不想自己造轮子,TheRouter 提供了一个已经解决以上所有问题的 AI API 网关,一个 API Key 接入所有主流大模型,支持自动故障转移和统一计费。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐