
在SaaS软件即服务模式中,多租户指的是:一套大模型服务集群,同时为多个独立的租户(企业、用户、团队)提供服务,租户之间逻辑上完全独立、物理上共享基础设施;而多租户隔离,就是通过技术手段,让不同租户的请求、数据、资源、权限、性能完全互不干扰,实现共享一套服务,独享专属体验。
放到大模型场景中,传统单租户大模型服务是一个企业买一套模型、一套服务器,自己用,成本极高、资源利用率极低;而大模型多租户隔离,是让金融、教育、电商等多个行业租户,共用同一套大模型、向量库、推理集群,但金融租户看不到教育租户的数据,电商租户不会占用金融租户的计算资源,一个租户请求拥堵不会影响其他租户。

大模型多租户隔离的三大核心目标,也是SaaS场景的刚需:
简单来说,大模型多租户隔离就是“一套房子住多户人家,每户有独立房间、独立水电、独立门锁,互不打扰”,是大模型SaaS化的核心基石。
大模型的训练和推理高度依赖GPU、显存等稀缺资源,单租户部署成本动辄百万级,中小企业无法承担;而SaaS模式的核心是“规模化、低成本、易运维”,没有多租户隔离,大模型SaaS根本无法落地。
从业务和技术两个维度,其核心价值如下:
2.1 业务价值
2.2 技术价值
3.1 资源隔离:底层基础
资源隔离是多租户的物理、逻辑底层屏障,针对大模型的稀缺资源做精细化划分:

3.2 权限管控:安全防线
权限管控是多租户的访问安全锁,基于“身份认证 + 细粒度授权”实现:
3.3 性能隔离:稳定性保障
性能隔离是多租户的服务质量护城河,解决租户间相互干扰问题:

这三大维度层层递进,构成了大模型多租户隔离的完整技术体系,缺一不可。
多租户隔离有三种经典架构,从浅到深、隔离强度逐级提升,大模型SaaS场景需根据业务需求选择:

1.1 共享数据库、共享Schema
1.2 共享数据库、独立Schema
1.3 独立数据库、独立部署

大模型的核心流程分为请求接入→身份校验→资源分配→推理执行→结果返回,多租户隔离就是在这个流程的每一步植入”租户识别 + 隔离控制“逻辑,原理如下:
2.1 租户唯一标识原理
每个租户在平台注册时,通过UUID或雪花算法生成全局唯一的TenantID,所有与租户相关的数据、资源、权限,都绑定TenantID。
2.2 请求拦截与校验原理
所有大模型API请求,必须在请求头参数中携带TenantID和认证令牌Token,服务端通过拦截器统一校验:
2.3 资源配额与隔离原理
基于令牌桶、漏桶算法实现资源配额管控,为每个租户分配固定的资源令牌:
2.4 性能隔离原理
通过线程池隔离、队列隔离、优先级调度实现性能互不干扰:
在没有深入理解前,我们通常都会把大模型多租户和传统Web服务多租户混淆,两者核心差异源于大模型的资源特性:
这也是为什么大模型多租户隔离不能直接复用传统方案,需要针对性设计隔离机制。
先理解单租户流程,才能快速掌握多租户隔离逻辑:

缺陷:仅支持一个租户,资源闲置,无法SaaS化。
这是大模型SaaS平台的标准隔离流程,覆盖权限、资源、性能三大维度:

步骤 1:租户接入,携带唯一标识
租户调用大模型API,请求头必须携带:
headers = { "TenantID": "tenant_2024001", "Authorization": "Bearer xxxxxxx" }
步骤 2:全局拦截器:权限管控(第一道隔离)
服务端启动租户拦截器,统一校验:
步骤 3:限流校验:性能隔离(第二道隔离)
基于租户配额,执行限流控制:
步骤 4:资源分配:资源隔离(第三道隔离)
按租户分配专属资源:
步骤 5:独立队列调度:性能深度隔离
租户请求进入独立队列,调度器按优先级处理:
步骤 6:模型推理与数据隔离
推理过程中严格数据隔离:
步骤 7:结果返回与资源释放
通过TenantID 拦截、限流、独立缓存、权限校验实现隔离核心,用简单的文本生成模拟大模型,突出核心业务,提高代码的可读性;
from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
import time
import uuid
from collections import defaultdict
# 初始化FastAPI应用
app = FastAPI(title="大模型多租户隔离实战Demo")
# ===================== 1. 多租户核心配置:权限、资源、限流 =====================
# 租户配置库:存储TenantID、权限、限流配额、资源配额
# 格式:{租户ID: {"name": "租户名称", "model_perm": ["模型接口列表"], "qps": 每秒请求数, "quota": 剩余调用额度}}
TENANT_CONFIG = {
"tenant_001": {
"name": "电商企业租户",
"model_perm": ["llm_chat", "llm_summary"],
"qps": 5,
"quota": 1000,
"gpu_quota": 2 # 分配2GB显存资源
},
"tenant_002": {
"name": "教育小型租户",
"model_perm": ["llm_chat"],
"qps": 2,
"quota": 500,
"gpu_quota": 1 # 分配1GB显存资源
}
}
# 租户独立缓存:模拟Redis命名空间隔离,存储对话历史
TENANT_CACHE = defaultdict(dict)
# 租户请求计数器:用于限流(性能隔离)
TENANT_REQUEST_COUNTER = defaultdict(int)
# ===================== 2. 模拟大模型推理函数 =====================
def mock_llm_infer(tenant_id: str, prompt: str) -> str:
"""模拟大模型推理,仅使用租户自身缓存/资源"""
# 数据隔离:仅读取当前租户的对话历史
chat_history = TENANT_CACHE[tenant_id].get("chat_history", [])
chat_history.append(prompt)
TENANT_CACHE[tenant_id]["chat_history"] = chat_history[-5:] # 保留最近5轮对话
# 模拟推理耗时
time.sleep(0.5)
return f"【租户{tenant_id}】模型回答:已处理你的问题「{prompt}」,对话历史:{len(chat_history)}轮"
# ===================== 3. 多租户隔离核心中间件 =====================
def check_tenant_isolation(tenant_id: str, token: str, model_name: str):
"""
多租户三合一校验:
1. 权限管控(身份+接口权限)
2. 性能隔离(限流)
3. 资源隔离(调用额度)
"""
# -------------- 权限管控:身份校验 --------------
if tenant_id not in TENANT_CONFIG:
raise HTTPException(status_code=403, detail=f"租户[{tenant_id}]不存在,无访问权限")
tenant_name = TENANT_CONFIG[tenant_id]["name"]
# 权限管控:接口访问权限校验
if model_name not in TENANT_CONFIG[tenant_id]["model_perm"]:
raise HTTPException(status_code=403, detail=f"租户[{tenant_name}]无权限访问{model_name}接口")
# -------------- 性能隔离:限流管控 --------------
if TENANT_REQUEST_COUNTER[tenant_id] >= TENANT_CONFIG[tenant_id]["qps"]:
raise HTTPException(status_code=429, detail=f"租户[{tenant_name}]请求超限,性能隔离触发")
TENANT_REQUEST_COUNTER[tenant_id] += 1
# -------------- 资源隔离:调用额度管控 --------------
if TENANT_CONFIG[tenant_id]["quota"] <= 0:
raise HTTPException(status_code=402, detail=f"租户[{tenant_name}]资源额度耗尽,资源隔离触发")
TENANT_CONFIG[tenant_id]["quota"] -= 1
# ===================== 4. 多租户大模型API =====================
class LLMRequest(BaseModel):
prompt: str
model_name: str = "llm_chat"
@app.post("/llm/chat")
def llm_chat(request: LLMRequest, TenantID: str = Header(...), Authorization: str = Header(...)):
"""
多租户隔离大模型对话接口
必须携带请求头:TenantID、Authorization
"""
# 执行三合一隔离校验
check_tenant_isolation(TenantID, Authorization, request.model_name)
# 执行模型推理(数据隔离)
response = mock_llm_infer(TenantID, request.prompt)
# 释放计数器
TENANT_REQUEST_COUNTER[TenantID] -= 1
return {
"code": 200,
"tenant_id": TenantID,
"response": response,
"remaining_quota": TENANT_CONFIG[TenantID]["quota"]
}
# ===================== 5. 直接启动(无需命令行)=====================
if __name__ == "__main__":
import uvicorn
print("🚀 启动多租户大模型服务...")
print("📍 服务地址: http://0.0.0.0:8010")
print("📖 API文档: http://0.0.0.0:8010/docs")
uvicorn.run(app, host="0.0.0.0", port=8010)1.1.1 权限管控实现
1.1.2 性能隔离实现
1.1.3 资源隔离实现
1.1.4 测试方法


1.3.1 请求头 (Headers)
1.3.2 请求体 (Body)
{ "prompt": "你的问题内容", "model_name": "llm_chat" }
1.4.1 tenant_001正常调用ll_chat返回
curl -X POST "http://localhost:8010/llm/chat" -H "TenantID: tenant_001" -H "Authorization: Bearer xxx" -H "Content-Type: application/json" -d "{\"prompt\": \"你好,请介绍一下自己\", \"model_name\": \"llm_chat\"}"1.4.2 传入不存在的tenant_005租户
curl -X POST "http://localhost:8010/llm/chat" -H "TenantID: tenant_005" -H "Authorization: Bearer xxx" -H "Content-Type: application/json" -d "{\"prompt\": \"你好,请介绍一下自己\", \"model_name\": \"llm_chat\"}"1.4.3 tenant_002没有llm_summary权限
curl -X POST "http://localhost:8010/llm/chat" -H "TenantID: tenant_002" -H "Authorization: Bearer xxx" -H "Content-Type: application/json" -d "{\"prompt\": \"你好,请介绍一下自己\", \"model_name\": \"llm_summary\"}"
import requests
response = requests.post(
"http://localhost:8010/llm/chat",
headers={
"TenantID": "tenant_001",
"Authorization": "Bearer xxx",
"Content-Type": "application/json"
},
json={
"prompt": "你好,请介绍一下自己",
"model_name": "llm_chat"
}
)
print(response.json())测试输出:
{'code': 200, 'tenant_id': 'tenant_001', 'response': '【租户tenant_001】模型回答:已处理你的问题「你好,请介绍一下自己」,对话历史:6轮', 'remaining_quota': 986}
测试覆盖的隔离维度包括: 权限隔离(身份校验、接口权限)、性能隔离(滑动窗口限流 QPS)、资源隔离(调用额度配额)、数据隔离(租户独立缓存)
测试脚本包含以下8个测试场景:
序号 | 测试函数 | 测试场景 | 说明 |
|---|---|---|---|
1 | test_normal_request() | 正常请求测试 | 验证基本功能是否正常,使用 tenant_001 发送标准对话请求 |
2 | test_tenant_isolation() | 多租户数据隔离测试 | 验证 tenant_001 和 tenant_002 的数据相互隔离 |
3 | test_rate_limit() | 限流测试(并发) | 5 个线程并发请求,tenant_002 QPS=2,验证超限时返回 429 |
4 | test_concurrent_rate_limit() | 并发限流测试 | 10 个线程同时请求,tenant_001 QPS=5,统计成功/限流数量 |
5 | test_invalid_tenant() | 非法租户测试 | 使用不存在的 tenant_999,验证返回 403 |
6 | test_no_permission() | 无接口权限测试 | tenant_002 调用未授权的 llm_summary 接口,验证返回 403 |
7 | test_quota_exhausted() | 额度耗尽测试 | 连续发送请求消耗额度,演示额度扣减机制 |
8 | test_stress() | 压力测试 | 10 秒内持续发送请求,统计成功率和平均 QPS |
"""
多租户大模型服务 - 测试脚本合集
包含:正常请求、限流测试、权限测试、额度耗尽测试
"""
import requests
import threading
import time
import json
BASE_URL = "http://localhost:8010"
# ===================== 测试配置 =====================
TENANT_001 = {"id": "tenant_001", "name": "电商企业租户", "auth": "Bearer token001"}
TENANT_002 = {"id": "tenant_002", "name": "教育小型租户", "auth": "Bearer token002"}
INVALID_TENANT = {"id": "tenant_999", "name": "非法租户", "auth": "Bearer xxx"}
def print_result(test_name, response):
"""打印测试结果"""
print(f"\n{'='*60}")
print(f"【{test_name}】")
print(f"{'='*60}")
print(f"状态码: {response.status_code}")
try:
print(f"响应内容: {json.dumps(response.json(), ensure_ascii=False, indent=2)}")
except:
print(f"响应内容: {response.text}")
# ===================== 1. 正常请求测试 =====================
def test_normal_request():
"""正常对话请求测试"""
url = f"{BASE_URL}/llm/chat"
headers = {
"TenantID": TENANT_001["id"],
"Authorization": TENANT_001["auth"],
"Content-Type": "application/json"
}
data = {
"prompt": "你好,请介绍一下自己",
"model_name": "llm_chat"
}
response = requests.post(url, headers=headers, json=data)
print_result("正常请求测试", response)
return response
# ===================== 2. 限流测试(高频请求)=====================
def test_rate_limit():
"""限流测试 - 并发发送多个请求触发限流"""
url = f"{BASE_URL}/llm/chat"
headers = {
"TenantID": TENANT_002["id"], # 教育租户 QPS=2
"Authorization": TENANT_002["auth"],
"Content-Type": "application/json"
}
data = {"prompt": "测试限流", "model_name": "llm_chat"}
print(f"\n{'='*60}")
print("【限流测试】并发发送5个请求(租户QPS限制为2)")
print(f"{'='*60}")
results = [None] * 5
def send_request(idx):
response = requests.post(url, headers=headers, json=data)
results[idx] = (idx, response)
# 创建线程
threads = []
for i in range(5):
t = threading.Thread(target=send_request, args=(i,))
threads.append(t)
# 几乎同时启动所有线程
for t in threads:
t.start()
for t in threads:
t.join()
# 打印结果
for idx, response in sorted(results, key=lambda x: x[0]):
status = "✓ 成功" if response.status_code == 200 else f"✗ 被限流"
detail = ""
if response.status_code == 429:
detail = f" - {response.json().get('detail', '')[:40]}"
print(f" 请求{idx+1}: {status} (HTTP {response.status_code}){detail}")
return [r[1] for r in results]
# ===================== 3. 并发限流测试 =====================
def test_concurrent_rate_limit():
"""并发请求测试"""
url = f"{BASE_URL}/llm/chat"
headers = {
"TenantID": TENANT_001["id"], # 电商租户 QPS=5
"Authorization": TENANT_001["auth"],
"Content-Type": "application/json"
}
data = {"prompt": "并发测试", "model_name": "llm_chat"}
print(f"\n{'='*60}")
print("【并发限流测试】同时启动10个线程请求(租户QPS限制为5)")
print(f"{'='*60}")
results = {"success": 0, "rate_limited": 0}
def make_request():
try:
response = requests.post(url, headers=headers, json=data, timeout=5)
if response.status_code == 200:
results["success"] += 1
elif response.status_code == 429:
results["rate_limited"] += 1
except Exception as e:
print(f" 请求异常: {e}")
threads = []
for i in range(10):
t = threading.Thread(target=make_request)
threads.append(t)
# 同时启动所有线程
for t in threads:
t.start()
for t in threads:
t.join()
print(f" 成功: {results['success']} 个")
print(f" 被限流: {results['rate_limited']} 个")
# ===================== 4. 权限测试(非法租户)=====================
def test_invalid_tenant():
"""非法租户测试"""
url = f"{BASE_URL}/llm/chat"
headers = {
"TenantID": INVALID_TENANT["id"],
"Authorization": INVALID_TENANT["auth"],
"Content-Type": "application/json"
}
data = {"prompt": "测试", "model_name": "llm_chat"}
response = requests.post(url, headers=headers, json=data)
print_result("非法租户测试", response)
return response
# ===================== 5. 权限测试(无接口权限)=====================
def test_no_permission():
"""无接口权限测试 - tenant_002 没有 llm_summary 权限"""
url = f"{BASE_URL}/llm/chat"
headers = {
"TenantID": TENANT_002["id"],
"Authorization": TENANT_002["auth"],
"Content-Type": "application/json"
}
data = {"prompt": "总结这段文本", "model_name": "llm_summary"}
response = requests.post(url, headers=headers, json=data)
print_result("无接口权限测试", response)
return response
# ===================== 6. 额度耗尽测试 =====================
def test_quota_exhausted():
"""额度耗尽测试 - 快速消耗完租户额度"""
url = f"{BASE_URL}/llm/chat"
headers = {
"TenantID": TENANT_002["id"], # 教育租户 quota=500
"Authorization": TENANT_002["auth"],
"Content-Type": "application/json"
}
data = {"prompt": "消耗额度", "model_name": "llm_chat"}
print(f"\n{'='*60}")
print("【额度耗尽测试】快速发送请求消耗额度")
print(f"{'='*60}")
# 先发送几个正常请求
for i in range(3):
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
remaining = response.json().get("remaining_quota", "未知")
print(f" 请求{i+1}: 成功,剩余额度: {remaining}")
# 模拟额度耗尽(直接修改配置,实际测试用)
print(" ...模拟额度耗尽...")
# 这里只是演示,实际需要通过大量请求或修改服务端配置
# ===================== 7. 多租户隔离测试 =====================
def test_tenant_isolation():
"""多租户数据隔离测试"""
url = f"{BASE_URL}/llm/chat"
print(f"\n{'='*60}")
print("【多租户隔离测试】两个租户分别发送请求")
print(f"{'='*60}")
for tenant in [TENANT_001, TENANT_002]:
headers = {
"TenantID": tenant["id"],
"Authorization": tenant["auth"],
"Content-Type": "application/json"
}
data = {"prompt": "这是第一条消息", "model_name": "llm_chat"}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
resp_data = response.json()
print(f" {tenant['name']}: {resp_data.get('response', '')}")
else:
print(f" {tenant['name']}: 请求失败 {response.status_code}")
# ===================== 8. 压力测试 =====================
def test_stress():
"""压力测试 - 持续发送请求"""
url = f"{BASE_URL}/llm/chat"
headers = {
"TenantID": TENANT_001["id"],
"Authorization": TENANT_001["auth"],
"Content-Type": "application/json"
}
data = {"prompt": "压力测试", "model_name": "llm_chat"}
print(f"\n{'='*60}")
print("【压力测试】10秒内持续发送请求")
print(f"{'='*60}")
success = 0
failed = 0
start_time = time.time()
while time.time() - start_time < 10:
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
success += 1
else:
failed += 1
time.sleep(0.2) # 200ms间隔
print(f" 10秒内成功: {success} 个")
print(f" 被限流/失败: {failed} 个")
print(f" 平均每秒: {(success+failed)/10:.1f} 请求")
# ===================== 主程序 =====================
if __name__ == "__main__":
print("🚀 多租户大模型服务测试脚本")
print(f"服务端地址: {BASE_URL}")
print("="*60)
# 检查服务是否可用
try:
requests.get(f"{BASE_URL}/docs", timeout=3)
print("✅ 服务连接正常\n")
except:
print("❌ 无法连接到服务,请确保服务端已启动")
print(f" 启动命令: python 260421.(156)1-main.py")
exit(1)
# 执行测试
test_normal_request()
test_tenant_isolation()
test_rate_limit()
test_concurrent_rate_limit()
test_invalid_tenant()
test_no_permission()
test_quota_exhausted()
test_stress()
print(f"\n{'='*60}")
print("✅ 所有测试执行完成")
print(f"{'='*60}")输出结果:
🚀 多租户大模型服务测试脚本 服务端地址: http://localhost:8010 ============================================================ ✅ 服务连接正常 ============================================================ 【正常请求测试】 ============================================================ 状态码: 200 响应内容: { "code": 200, "tenant_id": "tenant_001", "response": "【租户tenant_001】模型回答:已处理你的问题「你好,请介绍一下自己」,对话历史:1轮", "remaining_quota": 999 } ============================================================ 【多租户隔离测试】两个租户分别发送请求 ============================================================ 电商企业租户: 【租户tenant_001】模型回答:已处理你的问题「这是第一条消息」,对话历史:2轮 教育小型租户: 【租户tenant_002】模型回答:已处理你的问题「这是第一条消息」,对话历史:1轮 ============================================================ 【限流测试】并发发送5个请求(租户QPS限制为2) ============================================================ 请求1: ✓ 成功 (HTTP 200) 请求2: ✓ 成功 (HTTP 200) 请求3: ✗ 被限流 (HTTP 429) - 租户[教育小型租户]请求超限(QPS:2),性能隔离触发 请求4: ✗ 被限流 (HTTP 429) - 租户[教育小型租户]请求超限(QPS:2),性能隔离触发 请求5: ✗ 被限流 (HTTP 429) - 租户[教育小型租户]请求超限(QPS:2),性能隔离触发 ============================================================ 【并发限流测试】同时启动10个线程请求(租户QPS限制为5) ============================================================ 成功: 5 个 被限流: 5 个 ============================================================ 【非法租户测试】 ============================================================ 状态码: 403 响应内容: { "detail": "租户[tenant_999]不存在,无访问权限" } ============================================================ 【无接口权限测试】 ============================================================ 状态码: 403 响应内容: { "detail": "租户[教育小型租户]无权限访问llm_summary接口" } ============================================================ 【额度耗尽测试】快速发送请求消耗额度 ============================================================ 请求1: 成功,剩余额度: 496 请求2: 成功,剩余额度: 495 请求3: 成功,剩余额度: 494 ...模拟额度耗尽... ============================================================ 【压力测试】10秒内持续发送请求 ============================================================ 10秒内成功: 4 个 被限流/失败: 0 个 平均每秒: 0.4 请求 ============================================================ ✅ 所有测试执行完成 ============================================================
简单来说,大模型多租户隔离的核心逻辑,就是共用一套底层GPU、模型、存储资源,通过租户唯一标识做逻辑切割,既解决了大模型部署成本高、资源浪费的问题,又能守住数据安全、访问权限与服务稳定的底线。区别于传统业务多租户,大模型推理耗时久、硬件资源稀缺,因此限流队列、显存配额、独立数据空间这类隔离设计,都是保障平台平稳运行的关键。
多租户隔离不只是单纯的技术配置,更是大模型从单点部署走向商业化SaaS服务的必经门槛。很多时候大模型功能落地不难,难的是多用户并发下的平衡与风控。所以我们首先要理解租户拦截、限流、数据隔离的运行逻辑;后续可以逐步延伸到显存隔离、向量库租户拆分、灰度资源调度等进阶内容,循序渐进积累应用落地能力,才能逐步吃透大模型线上服务的核心技术。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。