去年双十一大促当天,我负责的电商平台 AI 客服系统遭遇了一次"幸福的烦恼":在 0 点开抢的瞬间,并发量从平时的 80 QPS 直接飙到 1200 QPS,4 个事业部的客服 Bot 抢同一个 LLM 池子的额度。结果两小时内 budget 被刷爆,财务部的对账模型直接 429 停摆,而运营部的智能导购还在源源不断地发请求。复盘会上 CTO 拍板:必须自研一层 Multi-tenant LLM 网关,把"谁能调、调用哪个模型、配额多少、谁先停"这四件事从代码里抽出来统一治理。
这篇文章就是我从零到一搭这套网关的全过程。我把它完整跑在 HolySheep AI 的统一 API 之上——因为它一家就聚合了 GPT-4.1、Claude Sonnet 4.5、Gemini 2.5 Flash、DeepSeek V3.2 等主流模型,省掉了我们自己再接 N 家供应商的脏活。
为什么必须自建 LLM 网关?
- 成本失控:4 个部门共用一个 OpenAI Key,月底对账时谁也说不清钱花在哪。
- 权限混乱:实习生账号能直接调到 GPT-4.1 做实验,财务月末才发现。
- 故障域无隔离:某个事业部写出死循环,把整个集群额度耗光。
- 模型切换成本高:老板一句话"用国产替代",几百处业务代码要改 base_url。
我最后选定的架构是:API Gateway (FastAPI) + Redis (配额/限流) + PostgreSQL (RBAC) + 统一上游 (HolySheep AI)。所有业务方只调一个内网域名 https://llm-gw.internal.company.com/v1/chat/completions,由网关代为转发到 HolySheep 官方 base_url https://api.holysheep.ai/v1。
RBAC 权限模型设计
我们把权限抽象成三层:Tenant(租户/事业部)→ Role(角色)→ Scope(模型范围)。每个 API Key 绑定一个租户,租户下再划分 Admin / Developer / ReadOnly 三种角色,分别对应不同的 Scope。
-- PostgreSQL 表结构
CREATE TABLE tenant (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(64) NOT NULL, -- 事业部/部门名
monthly_budget_usd NUMERIC(12,2) DEFAULT 0, -- 月度预算
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE api_key (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT REFERENCES tenant(id),
key_hash VARCHAR(128) UNIQUE NOT NULL, -- 存储 SHA-256
role VARCHAR(16) CHECK (role IN ('admin','developer','readonly')),
scopes TEXT[] NOT NULL, -- 允许的模型列表
is_active BOOLEAN DEFAULT TRUE
);
CREATE TABLE usage_log (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
model VARCHAR(64) NOT NULL,
prompt_tokens INT, completion_tokens INT,
cost_usd NUMERIC(10,6),
ts TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_usage_tenant_ts ON usage_log(tenant_id, ts);
这套设计的好处是:横向加部门只要插一行 tenant,RBAC 改 scopes 数组即可,零代码变更。
部门级配额:令牌桶 + 滑动窗口双保险
我用了"令牌桶"控制瞬时并发(防 0 点秒杀),用"滑动窗口"控制月度成本(防月底爆账)。两个都跑在 Redis 上,亚毫秒级判断。
import time, redis, hashlib
from fastapi import HTTPException, Header
r = redis.Redis(host='redis.internal', port=6379, decode_responses=True)
价格表(2026 年 4 月 HolySheep 官方报价,output /MTok)
PRICE = {
"gpt-4.1": 8.00,
"claude-sonnet-4.5": 15.00,
"gemini-2.5-flash": 2.50,
"deepseek-v3.2": 0.42,
}
def check_quota(auth_header: str, model: str, est_tokens: int):
key_hash = hashlib.sha256(auth_header.encode()).hexdigest()
info = r.hgetall(f"key:{key_hash}") # {tenant_id, role, scopes}
if not info or info["is_active"] == "0":
raise HTTPException(401, "Invalid API Key")
if model not in info["scopes"].split(","):
raise HTTPException(403, f"Scope denied: {model}")
# 1) 令牌桶:每租户 50 并发
bucket = f"bucket:{info['tenant_id']}"
if r.incr(bucket) > 50:
r.decr(bucket)
raise HTTPException(429, "Tenant concurrency exceeded")
r.expire(bucket, 1)
# 2) 滑动窗口:本月累计花费不得超过月度预算
month_key = f"cost:{info['tenant_id']}:{time.strftime('%Y%m')}"
used = float(r.get(month_key) or 0)
budget = float(r.hget(f"tenant:{info['tenant_id']}", "monthly_budget_usd"))
cost = est_tokens / 1_000_000 * PRICE.get(model, 8.0)
if used + cost > budget:
raise HTTPException(429, f"Monthly budget exhausted: ${used:.2f}/${budget:.2f}")
r.incrbyfloat(month_key, cost)
r.expire(month_key, 35 * 86400)
return info["tenant_id"]
网关核心:透明转发到 HolySheep
鉴权通过后,网关只需要把请求原样转发到 HolySheep 官方 base_url,然后把 token 用量回写 Redis 即可。业务方代码零感知。
import httpx
from fastapi import FastAPI, Request
app = FastAPI()
HOLYSHEEP_BASE = "https://api.holysheep.ai/v1" # 统一上游
@app.post("/v1/chat/completions")
async def chat(req: Request, authorization: str = Header(...)):
body = await req.json()
model = body.get("model", "gpt-4.1")
tenant_id = check_quota(authorization, model, est_tokens=body.get("max_tokens", 1024))
async with httpx.AsyncClient(timeout=60) as client:
resp = await client.post(
f"{HOLYSHEEP_BASE}/chat/completions",
json=body,
headers={"Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY"},
)
data = resp.json()
usage = data.get("usage", {})
cost = usage.get("completion_tokens", 0) / 1_000_000 * PRICE[model]
r.incrbyfloat(f"cost:{tenant_id}:{time.strftime('%Y%m')}", cost)
return data
实测下来整条链路国内直连 P99 延迟 47ms(来源:自建监控 24h 采样,HolySheep 香港→深圳 BGP 专线),比直连 OpenAI 官方 280ms 快了 6 倍,客服 Bot 的首字延迟从 1.4s 降到 0.6s。
价格对比与月度成本测算
我用网关跑了 30 天,4 个事业部加起来 2.1 亿 token 的真实账单:
- GPT-4.1:1.2 亿 output token × $8/MTok = $960
- Claude Sonnet 4.5:0.3 亿 × $15/MTok = $450
- Gemini 2.5 Flash:0.4 亿 × $2.50/MTok = $100
- DeepSeek V3.2:0.2 亿 × $0.42/MTok = $8.4
合计 $1518.4。同样的用量如果走 OpenAI 官方按 ¥7.3=$1 结算,仅 GPT-4.1 一项就要 ¥7008;走 HolySheep 的 ¥1=$1 无损汇率,人民币结算省下 >85%,且支持微信/支付宝充值,财务打款当天到账。客服高峰期 50 并发实测成功率 99.97%(来源:自建压测 wrk 60s),完全扛得住。
社区口碑与选型参考
选型时我参考了 V2EX 和 GitHub 上几个开源网关(Portkey/LiteLLM/OpenRouter)做了横向对比,最终没选它们的根本原因是:国内合规结算、微信支付、增值税专票这三个能力自建成本太高。在 V2EX 的
我自己在落地时最大的感受是:网关核心代码其实只 200 行,真正吃时间的反而是"和 4 个事业部对账、说服他们接受预算上限"这种组织工程——技术方案上,RBAC + 令牌桶 + 滑动窗口的组合拳已经足够稳,剩下的就是业务侧推动力。 上线第一个月我们踩了 6 个坑,列三个最典型的: 如果你的团队也在为"AI 用量失控"头疼,先从这一套 200 行的网关原型开始:RBAC 定边界、配额定上限、统一上游定体验,剩下的就是月度 review 和组织协同了。👉 免费注册 HolySheep AI,获取首月赠额度,把网关跑起来再迭代不迟。常见报错排查
YOUR_HOLYSHEEP_API_KEY 直接传到了我们网关,网关当然不认。修复:在网关 SDK 强制要求业务方生成自己的 gw_sk_xxx 网关 Key。r.expire(bucket, 1) 一定要紧跟 incr。gpt-4.1,gemini-2.5-flash。修复:Admin 角色调 PUT /api/admin/scopes 动态追加,不用发版。常见错误与解决方案(含修复代码)
# 错误 1:滑动窗口 key 跨月未重置,导致新月份沿用上月额度
修复:用 YYYYMM 后缀天然隔离月份
month_key = f"cost:{tenant_id}:{time.strftime('%Y%m')}" # 自动按月分桶
错误 2:令牌桶 incr 后服务崩溃,decr 未执行 → 计数虚高
修复:用 Lua 脚本原子化判断+扣减
LUA = """
local cur = redis.call('INCR', KEYS[1])
if cur > tonumber(ARGV[1]) then
redis.call('DECR', KEYS[1]); return 0
end
redis.call('EXPIRE', KEYS[1], 1)
return 1
"""
r.eval(LUA, 1, bucket, 50)
错误 3:scopes 用 JSON 存,前端传来"gpt-4.1, claude-sonnet-4.5"带空格
修复:标准化 splits + set 去重
scopes = {s.strip() for s in raw_scope_string.split(",") if s.strip()}
if model not in scopes:
raise HTTPException(403, "model not in scope")