我写了一个轻量 AI 网关库,多模型路由 + 自动降级 + 预算控制,一个包全搞定

我写了一个轻量 AI 网关库,多模型路由 + 自动降级 + 预算控制,一个包全搞定

路由、降级、限流、成本控制------调多个 LLM 必须解决的四个问题,一个零依赖 TypeScript 库搞定。

背景:调 AI 接口为什么越来越像运维

你的项目一开始只用 OpenAI,一个 fetch 搞定。后来产品说"Claude 写文案更好",加一个 Provider。再后来"GPT-4 太贵了,简单任务用 mini",加路由逻辑。然后有天 OpenAI 429 了------整个服务挂了。

于是你的代码变成了这样:

typescript 复制代码
async function callAI(messages, taskType) {
  if (taskType === 'copywriting') {
    try {
      return await callAnthropic(messages);
    } catch (e) {
      return await callOpenAI(messages); // 降级
    }
  } else if (taskType === 'chat' && user.tier === 'free') {
    return await callOpenAI(messages, 'gpt-4o-mini'); // 省钱
  } else {
    return await callOpenAI(messages, 'gpt-4o');
  }
  // 还要加预算检查、重试、日志、超时......
}

这段代码有几个问题:

  1. 路由逻辑硬编码------加个 Provider 要改代码、重新部署
  2. 降级是 try-catch 嵌套------三层降级链写出来想吐
  3. 没有预算控制------凌晨跑了个 bug 循环,早上起来账单 $200
  4. 没有统一日志------出了问题翻三个 Provider 的日志找原因

这些不是"高级需求",是每个调多模型的项目必须解决的基础设施

所以我做了 ai-gateway-lite------一个轻量级 AI 网关库,用 JSON 配置替代硬编码,一个包解决路由、降级、预算、日志四个问题。

bash 复制代码
npm install ai-gateway-lite

它能做什么

多模型路由

用 JSON 配置路由规则,按 taskTypefeatureuserTier 灵活分发请求:

json 复制代码
{
  "rules": [
    {
      "name": "premium-complex",
      "priority": 100,
      "match": { "taskType": "complex", "userTier": "premium" },
      "target": { "provider": "anthropic-main", "model": "claude-sonnet-4-20250514" }
    },
    {
      "name": "default-chat",
      "priority": 10,
      "match": {},
      "target": { "provider": "openai-main", "model": "gpt-4o-mini" }
    }
  ]
}

优先级匹配------VIP 用户走 Claude,普通用户走 Mini,一行代码不用改。

自动降级

Provider 挂了?自动切换到下一个:

json 复制代码
{
  "name": "complex-fallback",
  "steps": [
    { "provider": "anthropic-main" },
    { "provider": "openai-main", "model": "gpt-4o", "when": ["timeout", "provider_error"] },
    { "provider": "openrouter-fallback", "when": ["timeout", "rate_limit", "provider_error"] }
  ]
}

降级触发条件可以精确控制------只有 timeoutprovider_error 才降级,budget_exceeded 不降级(钱不够就别换个更贵的)。

预算控制

怕跑飞?设个每日上限:

json 复制代码
{
  "name": "global-daily",
  "scope": { "type": "global" },
  "window": "day",
  "limits": { "maxTotalTokens": 1000000, "maxCostUsd": 10.0, "warnAt": 0.8 },
  "enforcement": "hard"
}
  • hard 模式:超了直接拒绝
  • soft 模式:超了告警,但还是放行
  • warnAt: 0.8:用到 80% 时就开始告警

流式输出

SSE 流式响应,所有 Provider 统一接口:

typescript 复制代码
const stream = await gateway.chatStream({
  messages: [{ role: "user", content: "写一首关于 TypeScript 的诗" }],
});

for await (const chunk of stream.stream) {
  process.stdout.write(chunk.delta);
}

const summary = await stream.getUsageSummary();
console.log(`Tokens: ${summary.totalTokens}, Cost: $${summary.estimatedCostUsd.toFixed(4)}`);

成本估算

每次请求自动计算费用,内置 OpenAI / Anthropic 主流模型定价表:

typescript 复制代码
const res = await gateway.chat({
  messages: [{ role: "user", content: "Hello!" }],
});

console.log(res.estimatedCostUsd); // 0.0001

自定义模型?注册一下就行:

typescript 复制代码
import { registerModelPricing } from "ai-gateway-lite";

registerModelPricing("my-model", {
  inputPer1kTokens: 0.001,
  outputPer1kTokens: 0.002,
});

30 秒上手

bash 复制代码
# 1. 安装
npm install ai-gateway-lite

# 2. 配 Key
export OPENAI_API_KEY=sk-xxx
typescript 复制代码
import { Gateway, loadConfigFromObjects } from "ai-gateway-lite";

const config = loadConfigFromObjects({
  providers: [
    {
      name: "openai",
      provider: "openai",
      models: ["gpt-4o-mini"],
      auth: { type: "apiKey", envVar: "OPENAI_API_KEY" },
    },
  ],
  routes: {
    rules: [{ name: "default", priority: 0, match: {}, target: { provider: "openai" } }],
  },
  budgets: [],
});

const gateway = new Gateway({ config });

const res = await gateway.chat({
  messages: [{ role: "user", content: "Hello!" }],
});

console.log(res.content);
console.log(`Cost: $${res.estimatedCostUsd.toFixed(4)}`);

不想写代码先试试?clone 下来跑 demo:

bash 复制代码
git clone https://github.com/hyxnj666-creator/ai-gateway-lite.git
cd ai-gateway-lite && npm install
cp .env.example .env   # 填上你的 API Key
npm run demo

访问 http://localhost:3170,三个接口直接能用:

方法 路径 说明
POST /v1/chat 非流式对话
POST /v1/chat/stream SSE 流式对话
GET /health 健康检查 + Provider 列表

核心设计决策

为什么用 JSON 配置而不是代码

路由规则、降级链、预算策略------这些应该是运维配置,不是代码逻辑

用 JSON 配置意味着:

  • 不改代码就能调整路由------"Claude 涨价了,简单任务切到 Mini",改 JSON 重启就行
  • 配置可以版本管理------谁改了什么一目了然
  • 可以动态加载------未来支持从远程配置中心读取

当然,如果你嫌建配置文件麻烦,loadConfigFromObjects() 直接传对象也行。

为什么零运行时依赖

Node.js 18+ 自带 fetchReadableStreamTextDecoder------调 HTTP API 需要的东西全有了。

不依赖 openai@anthropic-ai/sdk 等官方 SDK 意味着:

  • 体积小------整个包 47KB(minified)
  • 不会被 SDK 更新 break------直接对接 REST API,接口稳定
  • 支持任何 OpenAI 兼容的 Provider------DeepSeek、Groq、Together 都能通过 OpenRouter 或自定义 Provider 接入

为什么只重试特定状态码

重试逻辑只对 429(限流)、502、503、504(后端故障)和网络超时进行重试,其他错误直接报错。

原因是:

  • 400(参数错误)------重试也没用
  • 401/403(鉴权失败)------重试也没用
  • 500(内部错误)------可能重试有用,但 500 通常意味着逻辑 bug,盲目重试可能加重问题

指数退避 + 可配置重试次数:

json 复制代码
{
  "retry": { "maxAttempts": 3, "backoffMs": 1000 }
}

首次等 1s,第二次 2s,第三次 4s。避免雪崩。


架构一览

bash 复制代码
请求进来
  │
  ├── 路由匹配(taskType / feature / userTier → 最高优先级规则)
  │
  ├── 预算检查(超限?hard → 拒绝 / soft → 告警放行)
  │
  ├── 执行请求
  │    ├── 成功 → 返回
  │    └── 失败 → 分类错误(timeout / rate_limit / provider_error)
  │              └── 触发降级链 → 下一个 Provider
  │
  ├── 记录用量(token / 费用 / 延迟)
  │
  └── 返回 GatewayResponse(含 estimatedCostUsd)

内置 Provider

Provider 流式 认证方式
OpenAI Bearer token(OPENAI_API_KEY
Anthropic x-api-key(ANTHROPIC_API_KEY
OpenRouter Bearer token(OPENROUTER_API_KEY

需要接其他 Provider?实现 Provider 接口即可:

typescript 复制代码
class MyProvider implements Provider {
  readonly name = "my-provider";
  readonly family = "custom";

  async chat(options: ProviderRequestOptions): Promise<ProviderResult> {
    // 你的实现
  }
}

const gateway = new Gateway({
  config,
  customProviders: {
    custom: (config) => new MyProvider(),
  },
});

错误处理

所有错误统一为 GatewayError,带结构化字段:

typescript 复制代码
import { GatewayError } from "ai-gateway-lite";

try {
  await gateway.chat(request);
} catch (err) {
  if (err instanceof GatewayError) {
    console.log(err.kind);       // "provider_timeout" | "provider_rate_limit" | "budget_exceeded" | ...
    console.log(err.httpStatus);  // 504, 429, etc.
    console.log(err.retryable);   // true / false
  }
}

HTTP 状态码自动分类:

状态码 分类 可重试
401/403 provider_auth
429 provider_rate_limit
408/504 provider_timeout
500 provider_error
400 provider_response

和同类方案的对比

维度 ai-gateway-lite LiteLLM Portkey
形态 npm 包,嵌入应用 Python 服务 SaaS + SDK
语言 TypeScript Python 多语言
运行时依赖 0 大量 SDK 依赖
路由配置 JSON 声明式 代码/YAML Dashboard
降级链 ✅ 多步骤 + 条件触发
预算控制 ✅ 内置 有限
流式 ✅ SSE
成本追踪 ✅ 内置定价表
部署 无需部署,库引用 需部署服务 第三方 SaaS
开源 MIT MIT 部分开源
包大小 47KB - -

核心差异ai-gateway-lite 是嵌入式的------不需要额外部署一个网关服务,npm install 进项目直接用。适合中小团队或个人项目,不想多维护一个服务的场景。


适用场景

  • SaaS 产品------按用户等级分配不同模型,VIP 走 GPT-4,免费用户走 Mini
  • AI 应用后端 ------统一网关层,不管接几个 Provider 都是一个 gateway.chat()
  • 成本敏感项目------设好每日预算,再也不怕凌晨跑飞
  • 高可用场景------主 Provider 挂了自动切备用,用户无感知

开源地址

bash 复制代码
npm install ai-gateway-lite

84 个测试,TypeScript strict 模式,Node.js 18/20/22 全版本 CI 通过。


如果对你有帮助,给个 ⭐ 或者掘金点个赞,是我继续迭代的动力。

有问题或建议欢迎提 issue 或评论区交流。

相关推荐
用户69371750013842 小时前
AI来了,同事们的效率为什么差这么多?
android·前端·ai编程
殷紫川2 小时前
Spring AI 整合火山引擎豆包向量库搭建企业知识库:我踩过的 10 个致命坑与终极解决方案
java·ai编程
NikoAI编程3 小时前
用 ultraplan 做了一次大重构规划,我再也不想回终端里写 plan 了
人工智能·ai编程·claude
Pkmer3 小时前
Agent的ReAct(推理+行动)模式
llm·agent
李广坤3 小时前
大模型底层逻辑(四):RAG 检索增强生成
ai编程
chaors3 小时前
LangGraph 入门到精通0x02:Graph 其他基础能力
llm·agent·ai编程
colinCao3 小时前
SDD 规范驱动开发:用自然语言重塑全栈开发流程 从需求描述到前后端交付,AI 仅用 60 分钟完成全栈开发。这不是科幻,这是 SDD(Specificatio
ai编程·全栈
chaors3 小时前
LangGraph 入门到精通0x01:Graph 通讯机制
langchain·llm·agent
阿荻在肝了3 小时前
Agent实践三:基于Chroma的RAG检索
python·学习·agent