AI API 网关实践:模型路由和降级做好以后,线上会稳很多
前面几篇一直在聊 AI API Key、Token 统计、用户用量、缓存、幂等和异常排查。
这篇继续聊一个更偏线上稳定性的问题:
当一个系统接入多个 AI 模型以后,应该怎么做模型路由和降级?
一开始我接 AI API 的时候,通常只会配置一个模型。
比如:
```env
AI_MODEL=chat-model
AI_BASE_URL=https://api.example.com/v1
AI_API_KEY=sk_xxxxxxxxx
```
然后业务代码里直接调用。
短期看没什么问题。
但项目跑久了以后,就会遇到这些情况:
模型接口偶尔超时
某个模型价格突然变高
某个模型效果不稳定
某个上游服务临时不可用
不同任务其实适合不同模型
高价值用户和普通用户应该用不同策略
这时候如果所有请求都写死一个模型,系统就会很被动。
所以我后来觉得,AI API 网关不应该只是转发请求,还应该负责模型路由和降级。
一、为什么不要把模型写死在业务代码里?
很多项目刚开始会这样写:
```js
async function callAI(message) {
const response = await fetch("https://api.example.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.AI_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "chat-model",
messages: [
{
role: "user",
content: message
}
]
})
});
return await response.json();
}
```
这个写法能跑。
但问题是,模型名称直接写死在业务代码里。
后面如果要换模型,就要改代码。
如果多个项目都这样写,改起来会更麻烦。
比如:
聊天项目里写了一遍
知识库问答里写了一遍
批量摘要脚本里写了一遍
后台运营工具里写了一遍
测试环境里又写了一遍
当你想统一切换模型时,就会发现到处都是配置。
更好的方式是:
业务系统只告诉网关“我要做什么任务”。
至于用哪个模型,由网关决定。
比如:
```js
const result = await aiGateway.call({
task_type: "summary",
user_id: "user_123",
input: articleContent
});
```
业务方不直接关心具体模型。
网关根据任务类型、用户等级、预算、模型状态来选择模型。
二、模型路由可以按任务类型区分
不同 AI 任务对模型的要求不一样。
比如:
短文本分类
标题生成
文章摘要
知识库问答
代码生成
客服回复
内容审核
这些任务没有必要全部使用同一个模型。
可以先做一个简单的路由表:
```js
const modelRoutes = {
chat: {
primary: "model-chat-large",
fallback: "model-chat-small"
},
summary: {
primary: "model-summary-large",
fallback: "model-summary-small"
},
classify: {
primary: "model-fast-small",
fallback: "model-chat-small"
},
code: {
primary: "model-code-large",
fallback: "model-chat-large"
}
};
```
调用时根据 task_type 选择模型:
```js
function selectModel(taskType) {
const route = modelRoutes[taskType];
if (!route) {
return "model-chat-small";
}
return route.primary;
}
const model = selectModel("summary");
```
这样做以后,模型选择就不再散落在业务代码里。
后面要调整,只改路由配置就行。
三、不要所有任务都用最贵的模型
很多人刚开始接 AI API 时,会倾向于都用效果最好的模型。
这很正常。
但长期运行后,成本会变得很高。
其实很多任务不需要最强模型。
比如文本分类:
```txt
判断下面评论是正面、负面还是中性。
```
这种任务通常用轻量模型就够了。
再比如关键词提取:
```txt
从下面内容里提取 5 个关键词。
```
也不一定需要很大的模型。
更合理的策略是:
简单任务用便宜模型
复杂任务用强模型
失败后再升级模型
高价值用户优先使用强模型
普通批量任务优先控制成本
可以写成这样:
```js
function selectModelByTask(taskType) {
if (taskType === "classify") {
return "model-fast-small";
}
if (taskType === "keyword") {
return "model-fast-small";
}
if (taskType === "summary") {
return "model-summary-medium";
}
if (taskType === "code") {
return "model-code-large";
}
return "model-chat-medium";
}
```
先不用做得很复杂。
只要能按任务拆开,就已经比所有请求共用一个模型好很多。
四、中间说一下我现在用的 API 网站
我自己后来整理这些 AI API 调用问题时,也做了一个统一 API 管理网站:
斑马API - AI API 中转站 - AI API Gateway
它主要就是想把 AI API 调用统一收口。
比如:
多个 API Key 统一管理
不同项目分配不同 Key
统计每个 Key 的 Token 消耗
查看用户、项目、模型的调用情况
支持预算、限流、异常排查
后续也可以继续做模型路由、缓存、降级和失败重试记录
如果你的项目现在还是每个业务自己写 Key、自己写模型名、自己处理失败逻辑,后面会越来越难管。
我的感受是:
AI API 接入越多,越需要一个统一入口。
不是为了把架构做复杂,而是为了以后模型切换、成本统计和异常排查更清楚。
五、降级是什么意思?
降级就是:
主模型不可用或者不合适时,自动切到备用模型。
比如主模型超时了:
```txt
model-chat-large 请求超时
```
系统不要直接失败。
可以尝试切到备用模型:
```txt
model-chat-small
```
一个简单的降级逻辑可以这样写:
```js
async function callWithFallback(payload) {
const route = modelRoutes[payload.task_type];
const models = [
route.primary,
route.fallback
];
for (const model of models) {
try {
return await callModel({
...payload,
model
});
} catch (error) {
console.log("model failed:", model, error.message);
}
}
throw new Error("all models failed");
}
```
这样主模型出问题时,系统还有机会继续返回结果。
当然,降级不是所有场景都适合。
比如代码生成、复杂推理、严肃内容审核,降级后效果可能明显变差。
所以最好按任务类型配置。
六、哪些情况应该触发降级?
我一般会考虑这些情况:
模型请求超时
上游返回 5xx
错误率持续升高
当前模型达到预算上限
当前模型达到限流阈值
某个 Key 额度不足
响应时间超过阈值
比如可以写一个判断:
```js
function shouldFallback(error) {
if (!error) {
return false;
}
const fallbackErrorCodes = [
"timeout",
"rate_limit_exceeded",
"server_error",
"insufficient_quota"
];
return fallbackErrorCodes.includes(error.code);
}
```
调用时:
```js
async function callModelWithFallback(payload) {
const route = modelRoutes[payload.task_type];
try {
return await callModel({
...payload,
model: route.primary
});
} catch (error) {
if (!shouldFallback(error)) {
throw error;
}
return await callModel({
...payload,
model: route.fallback
});
}
}
```
这样不是所有错误都降级。
只有适合降级的错误才降级。
七、降级也要记录日志
降级不是偷偷切换一下就完了。
一定要记录日志。
否则后面你只会发现:
为什么今天模型效果变差了?
为什么成本突然下降了?
为什么某些回答质量不稳定?
但不知道是不是发生过降级。
日志里最好记录这些字段:
```json
{
"request_id": "req_1001",
"task_type": "summary",
"primary_model": "model-summary-large",
"final_model": "model-summary-small",
"fallback_used": true,
"fallback_reason": "timeout",
"user_id": "user_123",
"total_tokens": 3200
}
```
这样后面就能统计:
今天降级了多少次
哪个模型最容易失败
哪个任务最常触发降级
降级后 Token 是否变少
降级后用户反馈是否变差
这些数据很重要。
八、模型路由也可以按用户等级区分
如果系统有不同用户等级,也可以按用户等级路由。
比如:
普通用户用中等模型
高级用户用更强模型
企业用户用稳定性更高的模型
内部测试用户用便宜模型
示例:
```js
function selectModelByUserLevel(taskType, userLevel) {
if (userLevel === "enterprise") {
return "model-chat-large";
}
if (userLevel === "pro") {
return "model-chat-medium";
}
if (userLevel === "free") {
return "model-chat-small";
}
return selectModelByTask(taskType);
}
```
这样可以把成本和用户价值对应起来。
普通用户不一定每次都要用最贵模型。
企业用户可以优先使用更稳定、更强的模型。
内部测试用户则可以默认走低成本模型,避免测试环境消耗太多。
九、路由配置最好不要写死
模型路由如果写死在代码里,后面还是不方便。
更好的方式是把它做成配置。
比如:
```json
{
"routes": {
"chat": {
"primary": "model-chat-large",
"fallback": "model-chat-small",
"timeout_ms": 10000
},
"summary": {
"primary": "model-summary-medium",
"fallback": "model-summary-small",
"timeout_ms": 15000
},
"classify": {
"primary": "model-fast-small",
"fallback": "model-chat-small",
"timeout_ms": 5000
}
}
}
```
后端加载配置:
```js
function getRouteConfig(taskType) {
return routeConfig.routes[taskType] || routeConfig.routes.chat;
}
```
这样后面想调整模型,不一定要重新发版。
尤其是模型经常变化的时候,配置化会省很多事。
十、模型切换前后要对比数据
模型路由不是配完就结束。
每次切换模型后,最好对比几个数据:
请求成功率
平均响应时间
平均 Token 消耗
用户反馈
错误率
降级次数
单位成本
比如:
```txt
切换前:
模型:model-chat-large
平均耗时:4.8 秒
平均 Token:3200
失败率:2.1%
切换后:
模型:model-chat-medium
平均耗时:2.9 秒
平均 Token:2800
失败率:2.4%
```
如果效果差不多,成本更低,速度更快,那就可以考虑继续使用。
如果失败率升高,或者用户反馈变差,就要谨慎。
AI API 管理不是只看价格。
还要看效果、速度和稳定性。
十一、最后总结
AI API 项目刚开始时,一个模型就能跑。
但项目多了、用户多了、任务多了以后,模型管理就会变成一个很现实的问题。
我现在更推荐尽早把这些事情放到网关里处理:
模型路由
任务类型映射
用户等级策略
主模型和备用模型
超时降级
限流降级
预算降级
模型调用日志
降级原因记录
模型效果对比
这样业务代码就不用到处写模型名,也不用每个项目单独处理失败逻辑。
AI API 网关的价值,不只是把请求转发出去。
更重要的是:
该用哪个模型
失败了怎么办
成本怎么控制
效果怎么比较
异常怎么排查
这些问题越早统一管理,后面越不容易乱。
接口调通只是开始。
真正长期运行时,模型路由和降级才是稳定性的关键。
````
更多推荐

所有评论(0)