Node.js 接 AI 服务时,为什么网关层比业务层更先复杂
补档说明:本文属于「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 服务,我现在会默认把下面这些放进网关层,而不是散在业务控制器里:
- 鉴权与配额
- 请求归一化
- 缓存
- 模型与供应商路由
- 超时 / 重试 / 降级
- trace 与成本记录
如果这些能力散落在业务层,系统后面一定会越来越难解释。
总结
Node.js 接 AI 服务时,网关层比业务层更先复杂,不是偶然现象,而是 AI 接入天然会把路由、预算、缓存、超时、供应商差异和结果治理全部压到边界层。
谁越早把这层当成独立基础设施来设计,谁后面的业务演进就越轻。反过来,如果一开始把这些东西都临时塞进业务接口里,复杂度只会越来越像一团解不开的毛线。
- 读者:关注 AI 应用落地、全栈工程化、工作流自动化和技术内容系统的开发者。
- 场景:补充 2025 年到 2026 年初这段时间里缺失的技术观察和工程复盘。
- 目标:不写成新闻转述,而是写成可以复用到项目里的判断框架。
