为什么大多数 AI 应用比想象中更早需要 AI Gateway

5 min read

为什么大多数 AI 应用比想象中更早需要 AI Gateway

每个 AI 应用都从一次直接 API 调用开始

PYTHON
from openai import OpenAI
 
client = OpenAI(api_key="sk-...")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize this document"}]
)

五行代码。完美运行。一个下午就能上线。

每个 AI 应用都是这样开始的,这没问题。对原型来说,直接调用 SDK 是正确的架构。问题在于,大多数团队在这个架构早已不够用之后,还继续用它太久,而他们每多等一周,迁移成本都会更高。

我见过这个模式在几十个团队里反复出现,也包括我们自己。你从一次直接调用开始。它能跑。你又加了几个功能。它还是能跑。然后某天早上,你的 Provider 对你限速了,或者因为有人发布了一次 prompt 变更,成本突然翻了三倍,或者某个 Agent 工作流无声失败,而你完全查不出原因。那时你才意识到,问题不在你的 AI 逻辑,而在围绕它的一切。

这篇文章讲的就是:如何在这个时刻变成危机之前识别它。


两种架构

把你的应用连接到 LLM Provider,本质上只有两种方式。理解它们的区别,是理解为什么第二种最终会变得必要的第一步。

架构 1:直接调用 SDK

TEXT
你的应用 → OpenAI SDK → OpenAI API → 响应

你的应用代码引入某个 Provider 的 SDK,传入凭证,然后直接发起 API 调用。响应以内联方式返回。你的业务逻辑负责处理一切:重试、错误场景、解析、日志。

这种架构适合以下情况:

  • 你只调用一个 Provider 的一个模型
  • 流量足够低,短暂故障可以接受
  • 你不需要跨请求的可观测性
  • 成本追踪暂时还不是优先级
  • 整个集成由一个开发者负责

大多数原型、黑客松项目和早期 MVP 都处在这里。也应该如此。在真正需要之前就加基础设施,是过早优化。

架构 2:Gateway

TEXT
你的应用 → AI Gateway → Provider A(主)
→ Provider B(备用)
→ Provider C(备用)
→ 缓存层
→ 可观测性
→ Schema 校验
→ 用量计量

Gateway 位于你的应用和 Provider 之间。你的应用调用 Gateway。Gateway 负责路由、故障转移、缓存、日志和响应校验。你的应用代码保持简单,只负责发送请求并拿到响应,不需要知道到底是哪个 Provider 处理了请求,也不需要知道中途发生了什么。

当“发送请求”和“拿到响应”之间发生的事情,已经多到不应该由应用代码合理承担时,这种架构就变成正确选择。

问题不在于你最终会不会需要第二种架构。问题在于,你会主动采用它,还是被动补救它。而被动补救的路径总是更贵。


直接 SDK 架构会在哪里失效

我想把失败模式讲具体,因为它们足够可预测,你可以提前观察到。这些不是可能发生的边界情况,而是直接集成规模变大后的正常结果。

Provider 故障会跨功能叠加

你的应用有三个 AI 功能:聊天机器人、内容摘要器和内部分类器。三个功能都直接调用 OpenAI。OpenAI 出现了一次影响 GPT-4o 的局部故障。

在直接 SDK 架构里,三个功能会同时不可用。没有自动备用。最好的情况是你的重试逻辑捕获了 5xx 错误,然后给用户展示“请重试”的提示。最糟糕、也更常见的情况是,Provider 返回了 200,但响应质量退化或内容为空,而你的应用依然把它当作一切正常来处理。

TEXT
功能 A(聊天机器人) → OpenAI(退化) → ❌ 变慢、空响应
功能 B(摘要器) → OpenAI(退化) → ❌ 15 秒后超时
功能 C(分类器) → OpenAI(退化) → ❌ 无声错误答案

带故障转移链的 Gateway 会把它变成:

TEXT
功能 A(聊天机器人) → Gateway → OpenAI(失败) → Claude ✓
功能 B(摘要器) → Gateway → OpenAI(失败) → Gemini ✓
功能 C(分类器) → Gateway → OpenAI(失败) → Mistral ✓

三个功能都继续可用。用户不会察觉。你第二天早上从请求日志里看到这件事,而不是从客户投诉里知道。

可观测性会变得不可能

直接调用 SDK 时,你对 AI 请求的可见性取决于你手动记录了什么。大多数团队从 print(response) 开始,后来逐渐加上结构化日志。但即使是好的日志,也会漏掉关键细节:

  • 到底是哪个 Provider 服务了这个请求?
  • 每一次尝试在重试前花了多久?
  • 响应来自缓存,还是一次实时调用?
  • 实际发送的 prompt 和实际返回的响应是什么?
  • 这个请求的延迟和昨天同一个工作流相比如何?

你可以自己把这些都做出来。大多数团队也确实会尝试。他们写日志中间件,搭 dashboard 查询,用电子表格追踪 token 用量。三个月后,有人问“上周二那个 Agent 为什么给了一个错误答案?”没人能找到那条请求。

你可能也会喜欢:AI Agent 做 Demo 很容易,在生产环境里调试才是真正的难题

成本追踪总是事后才想起来

每个 AI 创业公司到第四个月左右,都会出现这样一段对话:

“我们在 AI 上花了多少钱?” “大概每月 2000 美元。” “花在哪些功能上?” “……我得查一下。” “它在上涨吗?” “……我觉得是?”

直接 SDK 架构给你的只有一个数字:总 token 用量。这就像只知道 AWS 总账单,却不知道具体是哪些服务在花钱。你无法优化那些无法按功能、按用户、按工作流衡量的东西。

用直接 SDK 解决这个问题的团队,最后都会搭一套自己的计量系统:按请求统计 token、按模型计算成本、按功能聚合。它能工作,但要做对的基础设施量出乎意料地大,尤其是当缓存 token、失败尝试和多模型故障转移都会改变成本公式时。

Provider 锁定会悄悄发生

没人一开始就计划被锁定在单一 Provider 上。它只是自然而然地发生了。

你从 OpenAI 开始,因为它的文档最好。你在十二个地方硬编码了 gpt-4o。你写的 prompt 模板依赖 OpenAI 特定的 system message 处理方式。你的结构化输出解析假设了 OpenAI 的 JSON mode 格式。你的错误处理检查的是 OpenAI 特定的错误码。

六个月后,Anthropic 发布了一个对你的场景便宜 40% 的模型。切换本该只需要一天。结果它花了三周,因为所有关于 Provider 的假设都散落在代码库各处。

Gateway 引入了一层间接性。你的应用调用的是工作流名称,比如 summarizeclassifydraft_reply。Gateway 把它映射到某个 Provider 和模型。当你想切换 Provider 时,改映射就行。你的应用代码不变。你的 prompt 不变。迁移时间从几周变成几分钟。

你可能也会喜欢:可靠 AI Agent 背后那些看不见的架构决策

响应契约很脆弱

不同 Provider 返回的响应形态不同。即使是同一个 Provider,不同模型版本之间也可能改变响应格式。如果你的解析逻辑假设了某个特定结构,它就会出问题,而且往往是缓慢、无声地出问题。

最糟糕的版本是:你的代码在开发环境里配合 gpt-4o 能正常工作,但生产环境中一次故障转移把请求路由到了 Claude,响应结构略有不同,于是你的解析器无声地丢掉了一个字段。没有报错。没有崩溃。只是产品里出现了错误数据。

Gateway 会规范化响应,并在它们到达应用之前用 schema 校验。无论是哪个 Provider 生成的响应,你的应用始终收到同一种形态。


该引入 Gateway 的五个信号

不是每个团队都需要 Gateway。如果你读到这里觉得“我们还没到这个阶段”,那你大概是对的。下面这些具体信号说明你正在接近临界点:

信号 1:你正在应用代码里写重试逻辑

第一个重试 wrapper 没问题。第二个出现在另一个服务里,而且逻辑略有不同,就是警告信号。等你有三个不同的重试实现,使用不同的超时值和不同的错误处理策略时,你实际上已经在应用层里搭了一个糟糕且不一致的 Gateway。

PYTHON
# 出现在应用代码里的这段逻辑就是一个信号
try:
response = client.chat.completions.create(...)
except openai.RateLimitError:
time.sleep(2)
response = client.chat.completions.create(...) # 同一个 provider
except openai.APIError:
# 切到 anthropic?怎么切?不同 SDK,不同格式
response = anthropic_client.messages.create(...) # 完全不同的 API

如果这看起来很熟悉,你已经越过临界点了。

信号 2:你回答不了“这个请求是哪个模型服务的?”

当用户反馈某个 AI 响应很糟糕时,你能追溯到确切的模型、Provider、prompt 和响应吗?如果答案涉及在应用日志里 grep、检查多个 dashboard、再交叉比对时间戳,那你需要集中式的请求级可观测性。

信号 3:你的 AI 成本只是一个总数

如果你的成本追踪是“这个月我们在 OpenAI 上花了 X 美元”,那你是在盲飞。生产环境的 AI 成本管理需要按工作流、按功能、按客户细分。你需要知道聊天机器人每月花 800 美元,摘要器每月花 200 美元,以及某个用户的 Agent 循环因为一个 prompt bug 每天烧掉 50 美元。

信号 4:你害怕切换模型

一个新模型发布了。它对你的场景更好、更便宜。但切换它需要修改多个服务的代码、调整 prompt、更新响应解析器,再做一轮完整回归测试。如果模型迁移是一个多 sprint 项目,而不是一次配置变更,那你已经积累了太多 Provider 耦合。

信号 5:你有不止一个 AI 功能

这是最简单的启发式判断。一个 AI 功能加一个 Provider,用直接调用还能管理。两个功能意味着两套重试逻辑、两套成本追踪、两套错误处理。到了三个功能,你维护的就是一层分布式、不一致、没人设计也没人拥有的 AI 基础设施。


Gateway 实际上做什么

“转发请求的代理”和“管理 AI 生命周期的 Gateway”之间有实质区别。代理只会增加延迟,却没有收益。Gateway 之所以值得存在,是因为它承担了本来会散落在应用代码里的运维复杂性。

下面是一个生产级 AI Gateway 会处理的事情:

智能路由和故障转移

不只是重试同一个 Provider。而是在主 Provider 失败时,真正路由到另一个 Provider 的另一个模型。透明处理不同 Provider API 之间的转换。知道哪些错误可以重试(限速、超时),哪些不能重试(认证失败、请求格式错误)。

TEXT
请求到达
→ 路由到 GPT-4o(主)
→ 200ms 后被 429 限速
→ 路由到 Claude 3.5 Sonnet(备用 1)
→ 1.8s 成功
→ 规范化响应为标准格式
→ 返回给应用

你的应用只发送了一次请求,也只拿到了一次响应。它不需要知道失败尝试、Provider 切换或响应规范化。

响应校验和结构化输出

定义一次 JSON schema。来自每个 Provider 的每个响应都会用它校验。如果模型返回了格式错误的数据,Gateway 会处理它:重试、换一个模型,或者返回结构化错误。你的应用代码永远不会看到无法解析的响应。

请求级可观测性

每个请求都会记录完整生命周期:尝试了哪个 Provider、每次尝试花了多久、是否触发故障转移、token 用量、成本,以及可选的完整请求和响应正文。出问题时,你打开的是一条时间线,而不是从五个不同日志来源里重建故事。

工作流抽象

你的应用不引用 gpt-4oclaude-3-5-sonnet。它引用的是 classify_ticketgenerate_summary 这样的工作流名称。工作流到 Provider/模型的映射位于配置里,并通过 dashboard 管理。不部署代码就能修改它。不用 feature flag 就能在模型之间做 A/B 测试。

基于 token 的成本计量

按工作流、按项目、按请求追踪用量。区分缓存和未缓存 token。根据实际服务请求的模型计算成本,而不只是根据你请求的模型计算。拿到足够细的数据来回答“哪个功能最费钱,为什么?”

缓存

对重复请求做精确匹配缓存。同一个 prompt、同一组参数、同一个响应,直接从缓存返回,而不是再次打到 Provider。在有重复流量模式的工作流上,规模化后这可以在不改应用代码的情况下把成本降低 30-50%。


“但我不想再加一次网络跳转”

对 Gateway 最常见的反对意见是延迟。你确实在应用和 Provider 之间增加了一次网络跳转。这是真实成本,值得直接回答。

一个构建良好的 Gateway 会增加 20-50ms 延迟。一次典型的 LLM 调用需要 1000-8000ms。Gateway 的开销占总请求时间的 0.5-5%。作为交换,你得到的故障转移可以避免一次 30 秒超时,缓存可以把响应时间从 3 秒降到 50ms,可观测性可以把调试时间从几小时缩短到几分钟。

延迟这个反对意见,通常来自那些还没有经历过生产故障的团队。等到一次故障发生时,Gateway 跳转的替代选项就是所有 AI 功能 100% 失败。

还有一个更重要的架构点:Gateway 不是把你的 SDK 调用替换成更慢的东西。它替换的是你的 SDK 调用,加上你本来需要自己编写和维护的所有重试逻辑、错误处理、日志、成本追踪和 Provider 管理代码。那些代码也有延迟,只是藏在你的应用里,而且更难衡量。


ModelRiver 的位置

我们构建 ModelRiver,是因为我们经历过这篇文章里描述的每一种失败模式。

在构建 Hyperzoned 时,我们撞上了直接 SDK 的墙:Provider 故障、分散的重试逻辑、零可观测性、没有成本追踪,以及需要代码部署才能完成的模型切换。我们先写了 50 行自定义备用逻辑。然后是 200 行计量代码。然后是日志。然后是缓存。到了某个时刻,我们看着彼此问:“为什么我们在构建 AI 基础设施,而不是我们的产品?”

ModelRiver 就是我们当时希望已经存在的 Gateway。它会做这些事:

OpenAI 兼容 API。 修改你的 base_urlapi_key。你现有的 OpenAI SDK 代码、LangChainLlamaIndexVercel AI SDK 代码都能继续工作。如果你正在比较这些选择,我们的 LLM 框架指南 会拆解它们各自适合的场景。不需要迁移 SDK,也不需要学习新的抽象。

PYTHON
# Before
client = OpenAI(api_key="sk-...")
 
# After
client = OpenAI(
base_url="https://api.modelriver.com/v1",
api_key="mr_live_YOUR_KEY"
)

基于工作流的路由。 每个 AI 功能都映射到一个工作流,工作流拥有自己的 Provider、模型、故障转移链、结构化输出 schema 和缓存配置。你的应用引用 model="support_classifier",而不是 model="gpt-4o"。从 dashboard 切换 Provider,不需要改代码。

跨 Provider 自动故障转移。 定义故障转移链:GPT-4o → Claude 3.5 Sonnet → Gemini 1.5 Pro。如果主模型失败,请求会自动路由到下一个健康 Provider。你的应用会拿到响应。失败的尝试会出现在请求时间线里,方便调试,但用户永远不会看到它。

单请求可观测性。 每个请求都会记录完整时间线:Provider 尝试、每次尝试的延迟、token 用量、成本,以及可选的完整请求和响应正文。按工作流、Provider、时间范围或状态筛选。当一个 Agent 生成错误答案时,打开请求日志就能看到到底发生了什么:哪一步失败了、使用了哪个备用模型、模型实际收到了什么并返回了什么。

带校验的结构化输出。 定义一个 JSON schema。把它绑定到工作流。无论哪个 Provider 生成响应,每个响应都会按 schema 校验。你的应用始终收到格式良好的数据。不再需要为 Provider 差异写解析器 workaround。

事件驱动的异步工作流。 面向复杂 Agent 架构:发起一个异步请求,让 ModelRiver 处理它,通过 webhook 接收结果,运行你的后端逻辑,再通过 WebSocket 把最终结果流式传给前端。整个生命周期可观测,每一步都可调试。

开发用 Test Mode。 不消耗 token 也能构建和测试完整 AI 集成。Test Mode 会通过真实 API 返回你预先定义的样例数据:真实认证、真实路由、真实日志,但没有 Provider 调用。你的 CI 可以免费运行数百次。

精确匹配缓存。 相同请求会立即返回缓存响应。应用代码里不需要任何配置。按工作流开启或关闭。在 dashboard 里追踪缓存命中率和节省金额。


采用 Gateway 的正确时间

如果你还在做原型,不是今天。如果你已经在生产环境里服务真实用户,也不是明年。

下面是我们在不同团队里看到的真实时间线:

阶段架构原因
原型 / 黑客松直接 SDK速度最重要。不要加你暂时不需要的层。
有真实用户的 MVP直接 SDK + 手动监控仍然可以。观察那五个信号。
2-3 个生产 AI 功能该上 Gateway 了重试逻辑开始重复。成本不透明。调试很痛苦。
Agent 工作流 / 多步骤链条Gateway 很关键分步骤可观测性和跨 Provider 故障转移变成不可妥协。
扩大的团队或企业Gateway 是基础设施密钥轮换、访问控制、按团队成本分摊、审计日志。

在你还没有写下几百行 Provider 特定基础设施代码时,迁移最容易。早早采用 Gateway 的团队,把工程时间花在产品逻辑上。等太久的团队,则把时间花在维护没人喜欢碰的自研可靠性层上。


底层模式

如果从 AI 细节里退一步看,Gateway 模式其实和每个后端领域经历过的模式一样:

  • 数据库: 连接池、读副本、自动故障转移。几十年前我们就不再让应用直接连接到单个数据库实例。
  • API: API Gateway(Kong、Nginx、AWS API Gateway)负责限速、认证、路由和可观测性,应用代码不需要自己处理。
  • 微服务: Service mesh(Istio、Envoy)管理服务之间的重试、熔断和负载均衡。
  • 支付处理: 没人会从前端直接调用 Stripe。总会有一个后端层处理幂等、重试和对账。

AI 调用属于同一类外部依赖。它们慢、贵、不可靠,而且对用户体验至关重要。解决其他外部依赖问题的基础设施模式,同样能解决 AI 的问题。

早早意识到这一点的团队,会建在更稳固的地基上。把 AI 调用当成和其他基础设施完全不同的团队,最终也会发现它们并没有那么不同,通常是在凌晨 3 点 Provider 故障的时候。


开始使用

如果这篇文章里的信号符合你现在的状态,迁移会比你想象中简单:

  1. 创建 ModelRiver 账号 — 免费,无需信用卡
  2. 添加你的 Provider key — OpenAI、Anthropic、Google、Cohere、Mistral
  3. 创建一个工作流 — 选择模型,添加备用模型,绑定结构化输出
  4. base_url 改成 https://api.modelriver.com/v1,把 api_key 改成你的 ModelRiver key
  5. 第一条请求日志展示的信息,可能会比你当前设置知道的关于 AI 调用的信息更多

代码改动只有两行。架构转变会持续复利。


正在构建需要经受生产环境考验的 AI 功能?我们在 X 上是 @modelriverai — 随时欢迎聊架构。