第 15 / 15 章 约 6 分钟
LLM Gateway
统一模型调用、用量、限流和降级。
内容同步:2026年10月25日 · 文档版本 8
这个模块在 Agent 里的位置
LLM Gateway 是业务代码和模型供应商之间的统一入口。它决定:
- 业务代码调用哪个模型抽象。
- 供应商协议如何适配。
- 请求是否超时、重试或降级。
- usage 和成本如何归因。
- 租户和模型如何限流。
- 供应商错误如何保留。
如果没有 LLM Gateway,业务代码会逐渐和某个供应商强耦合。
先记住几个概念
| 概念 | 含义 | 为什么重要 |
|---|---|---|
| ModelKind | fast / main / visual 等抽象模型 | 业务不绑定供应商 |
| Provider adapter | 供应商协议适配 | 换模型不改业务 |
| Usage | 输入、输出、缓存 token | 成本归因 |
| Quota | 租户或模型级配额 | 控制资源 |
| Rate limit | 请求频率限制 | 保护下游 |
| Fallback | 降级模型 | 降低故障影响 |
| Provider error | 供应商原始错误 | 保留排障信息 |
从一个真实问题开始:换一个模型,业务代码改了 40 处
一个系统最初直接调用某个模型供应商:
await provider.chat({
model: 'vendor-main-model',
messages,
});
后来要做三件事:
- 换供应商。
- 增加便宜模型处理简单任务。
- 支持图片理解。
结果:
- 40 处业务代码写死了模型名。
- 20 处处理了供应商特有错误。
- 10 处自己估算 token。
- 5 处无法知道真实成本。
根因是业务层直接理解了供应商细节。
网关应该提供的接口
业务层只关心:
type ModelRequest = {
modelKind: 'fast' | 'main' | 'visual';
messages: Message[];
tools?: ToolDefinition[];
timeoutMs: number;
runId: string;
};
网关负责:
- 将 modelKind 映射到具体供应商模型。
- 处理认证和 endpoint。
- 适配请求格式。
- 统一超时和重试。
- 归一 usage。
- 记录 provider error。
模型路由
| 任务 | 模型 | 原因 |
|---|---|---|
| 检索规划 | fast | 简单、低延迟 |
| 综合分析 | main | 强推理 |
| 图片理解 | visual | 多模态 |
| 引用校验 | fast | 结构化检查 |
模型路由不能写死在业务代码里,应该由网关配置:
{
"fast": {
"provider": "a",
"model": "model-a"
},
"main": {
"provider": "b",
"model": "model-b"
},
"visual": {
"provider": "c",
"model": "model-c"
}
}
这样换供应商只改配置,不改业务。
usage 和 cost
真实 token 和 cost 只能来自模型响应。
不能由工具层或前端自行估算。
一个 usage 记录:
{
"runId": "run-9f27",
"turnId": "turn-103",
"modelKind": "main",
"provider": "provider-b",
"usage": {
"inputTokens": 48200,
"outputTokens": 1800,
"cacheReadTokens": 12000,
"cacheWriteTokens": 3000
},
"cost": {
"input": 0.048,
"output": 0.018,
"cacheRead": 0.002,
"cacheWrite": 0.003,
"total": 0.071
},
"latencyMs": 4200,
"usageMissing": false
}
如果 provider 没返回 usage:
{
"usageMissing": true
}
不要伪造成 0。
数据库设计
create table agent_model_usage (
id bigint primary key,
run_id bigint not null,
turn_id bigint not null,
model_kind text not null,
provider text not null,
input_tokens bigint,
output_tokens bigint,
cache_read_tokens bigint,
cache_write_tokens bigint,
total_cost numeric,
usage_missing boolean not null,
latency_ms int not null,
created_at timestamptz not null
);
create index agent_model_usage_run_idx
on agent_model_usage (run_id, created_at);
用途:
- 按 run 归因成本。
- 比较模型质量、延迟和成本。
- 发现异常调用。
- 支撑租户计费。
限流和降级
在峰值 500 QPS、10 万 session / 天的规模下,网关至少要有:
- 租户级限流。
- 模型级配额。
- 熔断。
- 降级策略。
- 超时控制。
降级要谨慎:
| 任务 | 是否可降级 | 原因 |
|---|---|---|
| 简单检索规划 | 可以 | 低风险 |
| 报告综合 | 谨慎 | 质量影响大 |
| 引用校验 | 不建议 | 影响可信度 |
| 视觉分析 | 视情况 | 需要多模态能力 |
不要为了省钱把关键校验任务降级到弱模型。
常见工程错误
| 错误 | 实际后果 | 正确做法 |
|---|---|---|
| 业务直连供应商 | 难替换、难观测 | 统一网关 |
| 业务写死模型名 | 换模型要改代码 | modelKind 抽象 |
| usage 丢失不标记 | 成本失真 | usageMissing |
| 所有任务用 main | 成本高 | 模型路由 |
| 供应商错误被吞 | 排障困难 | 保留 provider error |
| 没有租户限流 | 单租户拖垮系统 | per-tenant quota |
上线前检查
- 密钥不出网关。
- 模型路由显式。
- usage 可归因到 run。
- usage missing 显式标记。
- 有租户级限流。
- 有超时和熔断。
- 模型变更有质量、延迟和成本对比。