跳到主要内容

Node.js 接 AI 服务时,为什么网关层比业务层更先复杂

· 阅读需 5 分钟
一介布衣
全栈开发者 / 技术写作者

补档说明:本文属于「AI 工程落地周记」系列,计划发布时间为 2025-05-06 20:15。当前先保留为草稿,后续补充真实案例、代码片段和复盘细节后再发布。

如果只用一个真实链路来解释这个标题,我会选“内部知识问答 API”。

这套服务最开始的目标很简单:前端把用户问题丢给后端,后端转发给模型,再把答案返回。最早大家以为复杂度会集中在业务逻辑上,比如:

  • 检索怎么做
  • 答案怎么组织
  • 是否需要引用来源

但上线后很快发现,真正最先失控的不是这些,而是业务层外面那一圈:谁能调用、该走哪个模型、超时怎么退、缓存怎么命中、配额怎么算、错误怎么统一。

也就是说,业务逻辑还没来得及长大,网关层已经先膨胀了。

这个 API 为什么会先在网关层炸开

上线后没多久,大家就开始问:

  • 这个请求该走便宜模型还是强模型?
  • 同一个用户为什么今天能用、明天超额?
  • 相同问题为什么命中不到缓存?
  • 这个错误到底是供应商返回的,还是我们自己包装的?

你会发现,这些问题几乎都和“具体业务答案是什么”没关系,而和网关边界高度相关。

在这个知识问答服务里,我们后来把请求流拆成这样:

Client
-> Auth / Quota
-> Request normalization
-> Cache lookup
-> Model routing
-> Provider adapter
-> Output normalization
-> Trace / billing record

这条链路里,真正属于业务逻辑的其实只是一小段。剩下的大部分复杂度,天然都堆在网关。

传统 API 网关为什么不够用

AI 网关和普通 API 网关最大的差别,不是“多了一个转发目标”,而是多了 3 类普通接口不那么突出的约束:

1. 成本是实时变量

普通接口多打一遍,更多是资源浪费;AI 接口多打一遍,常常会直接体现在账单上。于是网关不仅要管吞吐,还要管预算。

2. 路由不是静态规则

同一个业务接口,不同请求可能要走:

  • 小模型
  • 强模型
  • 带检索路径
  • 带工具调用路径

这让路由本身就变成了一层业务策略。

3. 结果不天然可信

普通接口返回结构一般稳定,而 AI 返回结果往往还要经过:

  • 结构化校验
  • 安全过滤
  • 引用补全
  • 风险标记

这意味着网关常常不只是转发层,而是“协议整形层”。

一个更真实的 Node.js AI 网关长什么样

后来我们把这层拆成了几块:

1. 入口层

负责:

  • 鉴权
  • 配额
  • requestId
  • 基础限流

2. 路由层

负责:

  • 任务识别
  • 模型选择
  • 是否走检索
  • 是否允许流式

3. 供应商适配层

负责:

  • 不同 SDK 差异
  • 错误语义统一
  • 响应结构统一

4. 结果治理层

负责:

  • Schema 校验
  • fallback
  • trace 落盘
  • 成本记录

只有拆成这样,业务层才能继续只关心“知识问答到底答了什么”。

一段更接近生产的代码

后来我们的 Node.js 网关入口大致会长成这样:

async function handleAiRequest(req, res) {
const requestId = createRequestId()
const budget = await quotaService.check(req.user.id)
if (!budget.allowed) {
return res.status(429).json({error: 'quota_exceeded'})
}

const normalized = normalizeRequest(req.body)
const cached = await cacheService.get(normalized.cacheKey)
if (cached) {
return res.json({...cached, source: 'cache'})
}

const route = modelRouter.pick(normalized)
const result = await providerAdapters[route.provider].run({
model: route.model,
payload: normalized,
requestId,
})

const checked = validateAiResponse(result)
await traceStore.save({requestId, route, checked})

return res.json(checked)
}

这段代码看起来不像“业务代码”,但这正说明了问题:真正先复杂起来的,是业务外面的边界层。

我现在会优先放进网关层的 6 件事

只要是 Node.js 接 AI 服务,我现在会默认把下面这些放进网关层,而不是散在业务控制器里:

  1. 鉴权与配额
  2. 请求归一化
  3. 缓存
  4. 模型与供应商路由
  5. 超时 / 重试 / 降级
  6. trace 与成本记录

如果这些能力散落在业务层,系统后面一定会越来越难解释。

总结

Node.js 接 AI 服务时,网关层比业务层更先复杂,不是偶然现象,而是 AI 接入天然会把路由、预算、缓存、超时、供应商差异和结果治理全部压到边界层。

谁越早把这层当成独立基础设施来设计,谁后面的业务演进就越轻。反过来,如果一开始把这些东西都临时塞进业务接口里,复杂度只会越来越像一团解不开的毛线。

  • 读者:关注 AI 应用落地、全栈工程化、工作流自动化和技术内容系统的开发者。
  • 场景:补充 2025 年到 2026 年初这段时间里缺失的技术观察和工程复盘。
  • 目标:不写成新闻转述,而是写成可以复用到项目里的判断框架。