面向团队的多租户 LLM 网关架构
设计多租户 LLM 网关,用团队作用域、项目密钥、隔离配额、使用日志与媒体所有权避免凭证和数据跨租户泄漏。
多租户 LLM 网关是一层控制面:它让多个团队、项目和应用共享一个 OpenAI 兼容入口,同时隔离凭证、配额、用量与媒体所有权。架构难点不是“加一列 tenant_id”,而是让每个请求始终回答四个问题:谁在调用、谁来付费、允许使用哪些模型,以及之后可以读取哪些产物。本文把这些问题映射到可落地的网关模式,包括团队工作区、项目作用域密钥、限流作用域,以及图片和视频任务的媒体隔离。
为什么多租户通常出现在首次生产成功之后
早期部署往往从一把管理员密钥和一个供应商通道开始。它会一直工作,直到出现以下情况:
- 产品、研究与支持团队共用同一个费用池
- 外包人员需要临时模型访问,但不能看到组织密钥
- 财务需要知道哪个项目产生了上月账单
- 某个生成视频 URL 不能被同级团队下载
- 一个高噪声 agent 耗尽所有人的限流额度
此时租户边界必须落在网关,而不能只存在于应用代码。应用侧软限制有帮助,但无法阻止泄漏的密钥或配置错误的 worker 向错误所有者计费。没有租户隔离的 多供应商 LLM 网关 最终会变成共享爆炸半径的共享基础设施。可将它与 LLM 代理与 AI 网关 中的薄反向代理对比:代理只转发,多租户网关还负责授权和记账。
核心租户模型:所有者、执行者与作用域
每个请求都要分开维护三种身份:
- 执行者——发起调用的人类或服务主体。
- 计费所有者——请求结算时扣减配额的钱包。
- 访问作用域——限定密钥、模型和产物的团队/项目,或个人工作区。
在此类仓库形态的系统中,个人令牌通常向用户所有者计费;团队作用域令牌同时绑定团队与项目,并把计费解析到团队钱包。团队工作区被禁用、项目已停用或执行者缺少项目所需操作权限时,中间件应拒绝团队令牌。该检查必须在通道分发之前进入热路径。
Client / agent
| Bearer sk-...
v
Auth middleware
- resolve token -> user, team_id, project_id, owner_type
- validate membership + project action grants
v
Policy + rate-limit scope
- team:project:user (or personal user scope)
- model allowlists / group grants
v
Relay / task submit
- upstream channel selection
- pre-consume quota against billing owner
v
Usage log + optional media persistence
- store actor, team, project, billing owner
- authorize later content proxy by same scope
如果把执行者和计费所有者压成一个字段,就无法区分“谁花了团队预算”和“谁点击了生成”。如果作用域只是日志标签,那么 /v1/videos/{id}/content 的授权会跨租户泄漏。
必须保持一致的租户表面
1. API 密钥与项目绑定
把密钥作为一等租户对象签发:
- 用于个人沙箱的个人密钥
- 绑定
team_id+project_id的团队密钥 - 可选的分组或模型授权,用于限制密钥可调用哪些稳定网关别名
稳定别名,例如 gpt-image-2 或面向产品的 video-default,应在通道配置中映射到上游模型 ID。客户端保留别名,运维人员可轮换原始上游 ID,而不必重写每个服务。绝不要把上游供应商密钥嵌入客户端环境。客户端只向网关认证,供应商凭证由通道保存。在多团队产品中,应把同样的隔离纪律应用到 AI API 访问的 RBAC。
2. 配额与预扣安全
计费安全也是租户问题。昂贵任务开始前先向计费所有者预扣,待上游完成后结算或退款。对于图片 n、视频时长等媒体乘数,必须在校验阶段设置硬上限,避免恶意或有 bug 的客户端让配额计算溢出为负数费用。本代码库将图片数量限制为 MaxImageN = 128,并用 MaxTaskDurationSeconds 限制视频时长。即使团队策略设置了更严格的项目预算,多租户系统仍应全局保留这些防护。
3. 使用复合作用域键限流
团队流量可使用 team:{id}:project:{id}:user:{id} 形式的作用域键,个人流量则使用仅含用户的键。这样,一个项目的 agent 风暴不会饿死另一个项目的聊天流量。限流决策应独立于通道选择:团队可以获准使用某个模型,同时仍受流量限制。
4. 使用日志是审计表面
每个已结算调用都应保留执行者、计费所有者、团队/项目(若有)、模型别名、请求 ID,以及媒体乘数(n、秒数、尺寸)。财务与安全审阅者都需要这些字段。面向产品的用量视图是经过认证的控制台表面;公开文档应解释审计模型,而不是反复把读者链接到私有控制台路由。
5. 媒体所有权不是可选元数据
图片和视频产物会比 HTTP 请求存活更久。对象键与任务 ID 必须被视为租户资源:
| 表面 | 本仓库中的作用域(声明前请验证) | 所有权规则 |
|---|---|---|
| 图片工作台 UI/API | /api/user/image-workbench 下的个人/session/token 作用域及 API-key 变体;对象键归用户所有 | 当前没有团队/项目图片工作台路由 |
| 视频工作台 UI/API | /api/user/video-workbench 下的个人作用域,以及 /api/teams/:team_id/video-workbench 下的团队/项目作用域 | 团队运行与资产按团队 + 项目授权 |
| OpenAI 兼容图片入口 | POST /v1/images/generations、POST /v1/images/edits | 向令牌的计费所有者计费;除非自行持久化,否则不要虚构团队历史 |
| OpenAI 兼容视频入口 | POST /v1/videos、查询、内容;remix 路由仍已注册 | Content GET 必须重新检查创建任务时的同一所有者/作用域 |
上游供应商 URL 经常会过期。把对象持久化到私有存储并通过授权代理重新提供,可以减少失效链接与意外公开暴露。工作台需要对象存储时,若存储配置错误,应失败关闭,而不是返回一个没有作用域保护的临时 URL。
接入第二个团队前的隔离清单
把它当作发布门禁,而不是演示幻灯片:
| 边界 | 通过标准 |
|---|---|
| 鉴权 | 已移除成员和已禁用项目使用团队令牌时失败 |
| 计费 | 团队任务绝不扣个人钱包,反之亦然 |
| 模型 | 未获授权的项目不能调用受限别名 |
| 日志 | 跨团队日志查询返回空或拒绝,而不是部分行 |
| 媒体 | 视频内容代理对外部团队任务 ID 返回未找到/禁止 |
| 限流 | 项目 A 的负载不消耗项目 B 的 token bucket |
| 管理 | 超级管理员操作与租户管理员操作分开审计 |
自动化测试必须覆盖拒绝路径,而不只是 happy path。多租户 bug 常藏在“软 404”决策中:如果资源是否存在本身就是敏感信息,对外部资源返回 404 往往比 403 更合适。
团队作用域聊天的参考请求路径
curl https://your-gateway.example.com/v1/chat/completions \
-H "Authorization: Bearer $TEAM_PROJECT_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_STABLE_CHAT_ALIAS",
"messages": [
{"role": "user", "content": "Summarize yesterday deploy risk for project alpha."}
],
"max_tokens": 400
}'
网关内部应执行以下步骤:
- 认证密钥并解析
team_id/project_id。 - 确认执行者可以为该项目使用项目令牌。
- 通过允许的分组/通道集合解析模型别名。
- 从团队计费所有者预扣估算配额。
- 中继到上游,并写入同时包含执行者与所有者字段的消费日志。
- 在经过认证的用量视图中暴露相同标识,供财务和支持使用。
同一令牌规则下的媒体与不同工作台作用域
媒体端点不应为计费另造第二套鉴权系统。OpenAI 兼容入口应优先沿用相同的令牌与 session 规则:
# Image generation through OpenAI-compatible ingress (GPT Image returns b64_json)
curl https://your-gateway.example.com/v1/images/generations \
-H "Authorization: Bearer $TEAM_PROJECT_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "Product hero shot on matte black pedestal, studio light",
"size": "1024x1024",
"n": 1,
"output_format": "png"
}'
# Async video job (evaluate Sora 2 only with the official deprecation timeline in mind)
curl https://your-gateway.example.com/v1/videos \
-H "Authorization: Bearer $TEAM_PROJECT_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_STABLE_VIDEO_ALIAS",
"prompt": "Slow orbit around a ceramic mug on a wood table",
"seconds": "4",
"size": "1280x720"
}'
两个工作台的 UI 作用域不同:
- 图片工作台 是个人运维表面:预设、运行记录和资产都按用户划分。除非你已经实现,否则不要宣称存在团队图片历史或
/api/teams/:team_id/image-workbench路由。 - 视频工作台 同时支持个人与团队/项目作用域。把生成和管理资产能力映射到团队操作权限;session 绑定团队时,运行历史必须按项目划分。
重试持久化端点不得把资产重新归属到另一个所有者。对于新的绿地视频工作,考虑到 OpenAI Videos API / Sora 2 将在 2026-09-24 关闭,应优先选择关闭后仍能支持的供应商与网关适配器(参见 OpenAI 弃用公告);如果仍承载 Sora 流量,现在就要规划任务存储和客户端代码路径迁移。
无需重写客户端即可扩展的策略层
策略应从粗到细叠加:
- 平台默认值——最大图片
n、最大视频秒数、禁止模型。 - 团队策略——允许的分组、预算告警、功能开关。
- 项目授权——哪些成员可以生成媒体或管理视频资产。
- 密钥约束——IP allow list、过期时间、模型子集。
- 运行时限制——RPM/TPM 与并发任务上限。
客户端继续调用 /v1/*。运维人员在管理员配置和通道模型映射中调整策略。这正是 OpenAI 兼容 API 网关 的运维收益。
多租户网关特有的失败模式
- 静默回退所有者: 团队解析失败时,不要为了“方便”而向执行者的个人钱包计费,应直接让请求失败。
- 共享通道亲和性缺少隔离标签: 缓存键必须包含租户作用域,否则会混合粘性路由状态。
- 误以为图片工作台支持团队: 用户所有的个人图片资产不同于团队视频项目。
- 日志留存忽略法律边界: 团队移除可能要求选择性删除;留存任务必须按所有者过滤。
- 内容代理混淆: Dashboard session 鉴权和 API token 鉴权都需要相同的所有权检查。
- 预算告警没有操作权限: 如果任何成员仍可创建密钥,只提醒财务没有意义。
OWASP LLM Top 10 的安全指导仍然适用:当一个租户能影响另一个租户时,过度代理、敏感信息泄漏与无界消耗都会变成租户事故。
最小实现顺序
- 建模团队、项目、成员与操作授权。
- 为令牌和消费日志加入所有者字段。
- 在鉴权中间件中强制校验团队令牌。
- 为限流与用量查询添加作用域。
- 将视频任务鉴权和内容代理迁移到同一作用域 helper;除非有意增加团队图片持久化,否则保持图片工作台归用户所有。
- 为聊天、你保存的图片字节与视频内容添加跨租户拒绝的端到端测试。
- 完成这些步骤后,才把真实产品流量迁移到团队密钥。
跳过拒绝路径测试,就可能交付“有多租户 UI、没有多租户安全”的系统。
相关阅读
来源与延伸阅读
- OWASP Top 10 for LLM Applications
- OpenAI 生产最佳实践
- OpenAI 弃用公告(包含 Videos API / Sora 2 于 2026-09-24 关闭)
- Google Cloud 面向企业组织的多租户指导
决策检查
是否必须为每个租户建立独立数据库?
多数 AI 网关不需要。通过严格查询过滤实现行级隔离很常见。独立数据库有助于受监管隔离或存储层的 noisy-neighbor 限制,但会成倍增加迁移与通道配置。应根据合规需求选择,而不是追逐潮流。
每个微服务都应该创建自己的供应商密钥吗?
不应该。应按服务身份创建网关密钥,把供应商密钥留在通道中。这样才能保留轮换、费用可见性与 failover 能力。
个人工作区如何与团队共存?
把个人所有者类型保留为一等路径。用户可先用个人密钥和个人图片工作台做原型,然后切换到团队项目密钥来共享聊天/视频费用,而不改变请求形状;只需更换 Bearer token 与策略。
多租户媒体最严重的错误是什么?
把上游结果 URL 当成持久公开链接,或假设每个工作台都是团队作用域。产品需要持久性时应保存对象,通过授权路由代理访问;无法保存时应说明过期规则,并如实说明个人与团队所有权。
迁移演练
选一个生产应用,把它从共享管理员密钥迁移到团队项目密钥。验证消费日志显示正确的计费所有者,外部视频任务 ID 在 /v1/videos/{id}/content 被拒绝,图片工作台资产仍归用户所有(除非你实现了额外共享),并确认项目限流不再与同级团队的负载测试相互碰撞。