去年双十一大促当天,我负责的电商平台 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 网关?

我最后选定的架构是: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 的真实账单:

合计 $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 个坑,列三个最典型的:

  1. 401 Invalid API Key:业务方把 YOUR_HOLYSHEEP_API_KEY 直接传到了我们网关,网关当然不认。修复:在网关 SDK 强制要求业务方生成自己的 gw_sk_xxx 网关 Key。
  2. 429 Tenant concurrency exceeded:令牌桶 key 没设 TTL,崩溃恢复后计数没清零。修复:r.expire(bucket, 1) 一定要紧跟 incr
  3. Scope denied:财务部想跑 Claude Sonnet 4.5,但 scopes 只配了 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")

如果你的团队也在为"AI 用量失控"头疼,先从这一套 200 行的网关原型开始:RBAC 定边界、配额定上限、统一上游定体验,剩下的就是月度 review 和组织协同了。👉 免费注册 HolySheep AI,获取首月赠额度,把网关跑起来再迭代不迟。