AI 应用多租户隔离与配额管理实战:SaaS 场景下如何公平分配 API 预算
2026-09-04 · 约 12 分钟阅读
---
title: "AI 应用多租户隔离与配额管理实战:SaaS 场景下如何公平分配 API 预算"
description: "AI应用安全与多环境管理:覆盖配置隔离、密钥管理、数据脱敏、多租户隔离五大场景。附安全配置清单、审计方案与合规要点,帮你构建安全合规的企业级AI应用,适合安全工程师与架构师,含中转站实测数据,附2026年最新API价格,含可直接复用的代码片段,覆盖中转站稳定性对比,是开发者必读的实战指南。"
date: "2026-09-04"
tags: ["多租户", "配额管理", "SaaS", "计费"]
---
# AI 应用多租户隔离与配额管理实战:SaaS 场景下如何公平分配 API 预算
把 AI 能力做成产品时,最容易踩的坑是租户 A 用光了租户 B 的额度,或者一个大客户把整个供应商账号打爆。本文是一篇方法论性的多租户架构指南,从租户隔离、配额分配、限速策略到计量计费,逐层拆解 SaaS 化 AI 应用的设计要点。
一、为什么 AI 应用的多租户比传统 SaaS 更难
传统 SaaS 多租户隔离的重点是数据库行级隔离和RBAC。AI 应用多了两层难题:
1. 供应商侧限速:上游 API Key 的 RPM/TPM 是共享的,一个租户的"突刺流量"会影响所有租户
2. 成本不可预测:一次推理成本随 prompt/output 长度变化,单次调用可能从 ¥0.01 到 ¥1,恶意租户能在 1 小时内烧光你的预算
所以 AI SaaS 的多租户隔离不只是"租户之间数据隔离",还包括"租户之间的资源(API 额度)和成本隔离"。
二、租户级 API Key 体系
最基础的设计是每个租户一个独立的供应商 API Key:
```
租户A (Acme) 租户B (Beta) 租户C (Gamma)
│ │ │
▼ ▼ ▼
供应商Key-A 供应商Key-B 供应商Key-C
│ │ │
└─────────────────────┴─────────────────────┘
│
中转站 / 自建网关
```
好处:
- 一个租户出问题不影响其他租户
- 可以给大客户独立 Key,单独谈 RPM/TPM 配额
- 计费清晰——查 Key 用量 = 查租户用量
缺点:
- 供应商 Key 有数量上限和最小充值
- 多 Key 管理复杂(key rotation、余额监控)
实际工程上更常见的折中:少量"共享 Key" + 配额隔离:
```
所有租户 ───▶ 中转站/网关 ───▶ 共享 Key 池 (3-5 个 Key)
│
├── 租户A: 100万 TPM 配额
├── 租户B: 50万 TPM 配额
└── 租户C: 200万 TPM 配额
```
三、配额池(Quota Pool)设计
配额池把"上游额度"和"租户可用额度"解耦:
```python
class QuotaPool:
def __init__(self):
self.tenant_quotas = {} # tenant_id -> {rpm, tpm, monthly_tokens}
self.tenant_usage = {} # tenant_id -> 当前窗口用量
self.token_buckets = {} # tenant_id -> TokenBucket
def try_consume(self, tenant_id: str, estimated_tokens: int) -> bool:
quota = self.tenant_quotas.get(tenant_id)
if not quota:
return False
# 检查令牌桶(突发限速)
bucket = self.token_buckets.setdefault(
tenant_id,
TokenBucket(rate=quota["tpm"] / 60, capacity=quota["rpm"]),
)
if not bucket.consume(estimated_tokens):
return False
# 检查月度上限
monthly = self.tenant_usage.setdefault(tenant_id, 0)
if monthly + estimated_tokens > quota["monthly_tokens"]:
return False
return True
```
配额维度的常见组合:
| 维度 | 用途 | 典型设置 |
|---|---|---|
| RPM | 每分钟请求数 | 60 / 600 / 6000(按订阅等级) |
| TPM | 每分钟 token 数 | 100K / 500K / 2M |
| 月度 Token 总量 | 包月套餐核心 | 1M / 10M / 100M |
| 并发请求数 | 防止单租户占满 | 5 / 20 / 100 |
四、限速策略:从令牌桶到分级配额
1. 令牌桶(Token Bucket)—— 限速基础
```python
import time
class TokenBucket:
def __init__(self, rate: float, capacity: int):
self.rate = rate # tokens per second
self.capacity = capacity # 最大桶容量
self.tokens = capacity
self.last_refill = time.time()
def consume(self, tokens: int) -> bool:
now = time.time()
elapsed = now - self.last_refill
self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
self.last_refill = now
if self.tokens >= tokens:
self.tokens -= tokens
return True
return False
```
2. 滑动窗口(Sliding Window)—— 月度配额
```python
class SlidingWindowCounter:
def __init__(self, window_seconds: int):
self.window = window_seconds
self.events = [] # [(timestamp, tokens)]
def add(self, tokens: int):
now = time.time()
self.events.append((now, tokens))
cutoff = now - self.window
self.events = [(t, v) for t, v in self.events if t > cutoff]
def total(self) -> int:
return sum(v for _, v in self.events)
```
3. 分级配额
按订阅等级给租户不同 RPM/TPM:
```yaml
plans:
free:
rpm: 10
tpm: 50_000
monthly_tokens: 500_000
pro:
rpm: 60
tpm: 500_000
monthly_tokens: 10_000_000
enterprise:
rpm: 600
tpm: 5_000_000
monthly_tokens: 100_000_000
custom_upstream_key: true # 可绑定自有 Key
```
五、计量(Metering)与计费(Billing)
计量是"用了多少",计费是"按多少收钱"。两者要解耦,因为计费规则会随业务变:
```python
class MeteringService:
def record(self, tenant_id, usage: Usage):
# 计量记录存到 ClickHouse / TimescaleDB
metrics_db.insert({
"tenant_id": tenant_id,
"timestamp": usage.timestamp,
"model": usage.model,
"prompt_tokens": usage.prompt_tokens,
"completion_tokens": usage.completion_tokens,
"latency_ms": usage.latency_ms,
})
class BillingService:
def calculate(self, tenant_id, period_start, period_end) -> Bill:
usage = metrics_db.aggregate(
tenant_id, period_start, period_end
)
plan = plan_service.get_plan(tenant_id)
# 套餐内 + 超出部分按阶梯计费
in_package = min(usage.total_tokens, plan.monthly_tokens)
overage = max(0, usage.total_tokens - plan.monthly_tokens)
cost = (
plan.base_price
+ overage * plan.overage_price_per_1k_tokens / 1000
)
return Bill(tenant_id=tenant_id, usage=usage, cost=cost)
```
六、越权防护:租户隔离的"反例"
最容易出问题的 3 类越权:
1. 数据越权:租户 A 通过修改请求参数读取租户 B 的对话历史 → 用中间件做 tenant_id 强制注入
2. 配额越权:租户 A 调高自己的 plan 字段绕过限额 → 套餐信息服务端查库,不接受客户端参数
3. Key 越权:租户 A 直接用供应商 Key 调用,绕开你的计量 → 强制所有请求走网关
```python
@app.middleware("http")
async def tenant_isolation(request, call_next):
token = decode_jwt(request.headers["Authorization"])
request.state.tenant_id = token["tenant_id"]
# 强制使用请求中的 tenant_id 与 token 中的一致
body = await request.body()
if b'"tenant_id"' in body and not is_admin(token):
raise HTTP403("禁止指定 tenant_id")
return await call_next(request)
```
七、租户用量可视化与告警
租户需要"看到"自己的用量,建议提供:
1. 实时用量面板:当前 TPM、RPM、本月累计 tokens
2. 预算告警:用量达 80%/95%/100% 时邮件 / Webhook 通知
3. API 查询接口:让租户自助集成到自己的 dashboard
```python
@app.get("/v1/usage/current")
async def current_usage(request):
tenant_id = request.state.tenant_id
return {
"rpm_used": quota_pool.tenant_usage[tenant_id]["rpm"],
"tpm_used": quota_pool.tenant_usage[tenant_id]["tpm"],
"month_tokens": metrics_db.month_to_date(tenant_id),
"month_limit": plan_service.get_limit(tenant_id),
}
```
八、中转站在多租户场景的优势
对 SaaS 提供方来说,专业的中转站比"每租户独立供应商 Key"更划算:
| 方案 | 优势 | 劣势 |
|---|---|---|
| 每租户独立 Key | 隔离彻底 | Key 管理复杂,最低充值门槛高 |
| 共享 Key + 中转站配额 | 集中计费,统一供应商协议 | 中转站本身可能成为单点 |
| 自建网关(One API / New API) | 完全可控,可二次开发 | 需要运维投入 |
如果选第三方中转站,建议在 [openairouter.net](https://openairouter.net) 上对比各家平台的多租户支持能力(是否提供租户级 API Key、用量计量、计费回调等)。
九、3 个常见反模式
1. "所有租户用一个 Key" —— 一个大客户的突刺流量让所有租户一起被限速
2. "客户端传 plan 等级" —— 客户端永远不可信,plan 服务端查
3. "用量数据不可见" —— 租户看不到自己用了多少,月底账单惊讶就跑了
总结
AI SaaS 的多租户隔离核心是资源隔离 + 成本隔离:用配额池+令牌桶做限速,用滑动窗口做包月计量,用服务端鉴权做越权防护。这套架构搭好之后,剩下的就是让租户能"看见"自己的用量,这本身就是减少客诉的最有效手段。
如果你正在评估不同的中转站 / 聚合平台来承载 SaaS 业务,可以参考 [openairouter.net](https://openairouter.net) 上的平台横向对比,关注它们的限速策略、配额粒度、用量回调接口支持情况。
---
相关阅读
- [AI API 速率限制与配额管理指南](/blog/ai-api-rate-limiting-quota-management)
- [AI API 中转站计费方式全解析](/blog/ai-api-billing-methods-explained)
- [AI API 多供应商容错架构设计](/blog/ai-api-multi-provider-fault-tolerance-architecture)