大模型多租户隔离:资源隔离、权限管控、性能互不干扰,SaaS落地场景实战.156

简介: 大模型多租户隔离是SaaS化核心,通过租户ID实现资源、权限与性能三重隔离:共享GPU/模型降低成本,逻辑隔离确保数据不交叉、请求不干扰、权限不越界,满足金融级安全与高并发稳定性要求。

一、大模型多租户隔离

1. 基础概念

       在SaaS软件即服务模式中,多租户指的是:一套大模型服务集群,同时为多个独立的租户(企业、用户、团队)提供服务,租户之间逻辑上完全独立、物理上共享基础设施;而多租户隔离,就是通过技术手段,让不同租户的请求、数据、资源、权限、性能完全互不干扰,实现共享一套服务,独享专属体验。

       放到大模型场景中,传统单租户大模型服务是一个企业买一套模型、一套服务器,自己用,成本极高、资源利用率极低;而大模型多租户隔离,是让金融、教育、电商等多个行业租户,共用同一套大模型、向量库、推理集群,但金融租户看不到教育租户的数据,电商租户不会占用金融租户的计算资源,一个租户请求拥堵不会影响其他租户。

156.2-ScreenShot_2026-04-21_184907_798.png

大模型多租户隔离的三大核心目标,也是SaaS场景的刚需:

  • 资源隔离:计算资源(GPU、CPU)、存储资源(模型缓存、向量数据)、网络资源,按租户分配,不越界占用;
  • 权限管控:租户只能访问自己的模型接口、私有数据、配置参数,杜绝越权访问;
  • 性能互不干扰:单个租户的高并发、大流量请求,不会导致其他租户响应延迟、推理失败,实现性能隔离。

       简单来说,大模型多租户隔离就是“一套房子住多户人家,每户有独立房间、独立水电、独立门锁,互不打扰”,是大模型SaaS化的核心基石。

2. 核心价值

       大模型的训练和推理高度依赖GPU、显存等稀缺资源,单租户部署成本动辄百万级,中小企业无法承担;而SaaS模式的核心是“规模化、低成本、易运维”,没有多租户隔离,大模型SaaS根本无法落地。

从业务和技术两个维度,其核心价值如下:

2.1 业务价值

  • 降本增效:共享基础设施,资源利用率从单租户的10%-20%提升至70%-90%,大幅降低单租户服务成本;
  • 快速规模化:无需为每个新租户单独部署模型、服务器,一键开通服务,SaaS平台可快速拓展海量租户;
  • 统一运维:一次升级、一次漏洞修复,全租户生效,运维成本降低90%以上。

2.2 技术价值

  • 数据安全合规:大模型处理的是租户核心数据,包括合同、客户信息、业务文档,隔离机制确保数据不泄露、不交叉,满足等保、GDPR等合规要求;
  • 服务稳定性保障:SaaS 平台服务海量租户,若没有性能隔离,一个租户的突发高并发(如电商大促、金融批量报表生成)会拖垮整个集群,导致全平台故障;
  • 精细化运营:支持按租户配置不同的模型版本、调用额度、推理参数,实现“基础版、企业版、旗舰版”的差异化SaaS服务。

3. 隔离维度

3.1 资源隔离:底层基础

资源隔离是多租户的物理、逻辑底层屏障,针对大模型的稀缺资源做精细化划分:

  • 计算资源:GPU显存、CPU核心、推理线程,按租户配额分配,禁止超额占用;
  • 存储资源:租户的私有向量库、对话历史、微调数据,独立存储,不与其他租户混存;
  • 中间件资源:消息队列、Redis缓存,按租户命名空间隔离,避免数据污染。

156.3-多租户资源配额对比.png

3.2 权限管控:安全防线

权限管控是多租户的访问安全锁,基于“身份认证 + 细粒度授权”实现:

  • 身份层:租户唯一标识TenantID,所有请求必须携带合法TenantID;
  • 权限层:接口权限(哪些模型接口可调用)、数据权限(哪些私有数据可访问)、操作权限(是否可微调模型、是否可导出数据);
  • 审计层:全量记录租户调用日志,追溯越权行为。

3.3 性能隔离:稳定性保障

性能隔离是多租户的服务质量护城河,解决租户间相互干扰问题:

  • 限流隔离:按租户设置每秒请求数QPS、并发数上限,超出直接拒绝,不占用公共资源;
  • 优先级隔离:企业版租户优先级高于基础版,高优请求优先分配资源;
  • 排队隔离:租户请求独立队列,避免一个租户的长耗时请求阻塞其他租户。

156.4-高并发场景:隔离机制对服务性能影响对比 llm_tenant_performance.png

这三大维度层层递进,构成了大模型多租户隔离的完整技术体系,缺一不可。

二、基础知识与原理

1. 多租户隔离的三种架构模式    

       多租户隔离有三种经典架构,从浅到深、隔离强度逐级提升,大模型SaaS场景需根据业务需求选择:

156.5-大模型多租户隔离架构图 llm_multi_tenant_architecture.png

1.1 共享数据库、共享Schema

  • 特点:最低隔离,低成本
  • 架构:所有租户共用同一数据库、同一数据表,通过TenantID字段区分数据;
  • 大模型适配:适合轻量级SaaS,如个人用户、小型团队,共享模型推理实例,仅通过TenantID区分对话历史;
  • 优缺点:成本最低、部署最简单,但隔离性最差,数据和性能易相互干扰。

1.2 共享数据库、独立Schema

  • 特点:中等隔离,平衡型
  • 架构:所有租户共用同一数据库,但每个租户拥有独立的数据表集合Schema;
  • 大模型适配:适合中小企业租户,共享模型集群,每个租户有独立的向量库、缓存空间;
  • 优缺点:隔离性中等,成本较低,满足大部分 SaaS 场景的安全和性能需求。

1.3 独立数据库、独立部署

  • 特点:最高隔离,高安全
  • 架构:每个租户拥有独立的数据库、独立的推理实例,物理层面完全隔离;
  • 大模型适配:适合金融、政府等对数据安全要求极高的租户,独享GPU资源;
  • 优缺点:隔离性拉满,性能完全独立,但成本最高、运维复杂。
  • 大模型SaaS主流选择:核心租户用独立数据库,普通租户用共享数据库 + 独立 Schema,平衡成本与隔离性。

156.6-大模型多租户三种架构:隔离强度与成本对比 llm_tenant_arch_compare.png

2. 大模型多租户隔离的基础原理

       大模型的核心流程分为请求接入→身份校验→资源分配→推理执行→结果返回,多租户隔离就是在这个流程的每一步植入”租户识别 + 隔离控制“逻辑,原理如下:

2.1 租户唯一标识原理

       每个租户在平台注册时,通过UUID或雪花算法生成全局唯一的TenantID,所有与租户相关的数据、资源、权限,都绑定TenantID。

  • 示例:租户A的TenantID=1001,其对话历史存储key为tenant:1001:chat:xxx,向量库集合为tenant_1001_collection。

2.2 请求拦截与校验原理

       所有大模型API请求,必须在请求头参数中携带TenantID和认证令牌Token,服务端通过拦截器统一校验:

  • 校验Token合法性,确认租户身份;
  • 校验TenantID是否存在,是否有权限访问请求的模型接口;
  • 校验租户调用额度是否耗尽,实现基础限流。

2.3 资源配额与隔离原理

基于令牌桶、漏桶算法实现资源配额管控,为每个租户分配固定的资源令牌:

  • 推理请求消耗令牌,令牌耗尽则拒绝请求;
  • GPU显存、缓存资源按TenantID划分空间,租户数据仅能写入自己的空间。

2.4 性能隔离原理

通过线程池隔离、队列隔离、优先级调度实现性能互不干扰:

  • 为每个租户创建独立的请求队列,高并发请求仅阻塞自身队列;
  • 按租户优先级分配GPU推理线程,高优租户优先执行。

3. 大模型多租户隔离与传统服务多租户的差异

       在没有深入理解前,我们通常都会把大模型多租户和传统Web服务多租户混淆,两者核心差异源于大模型的资源特性:

  • 1. 资源稀缺性不同:传统服务依赖CPU、内存,成本低;大模型依赖GPU、显存,稀缺且昂贵,必须极致共享 + 严格隔离;
  • 2. 请求耗时不同:传统接口请求毫秒级;大模型推理秒级,长耗时请求更容易阻塞集群,性能隔离要求更高;
  • 3. 数据特性不同:传统服务数据结构化;大模型包含非结构化文本、向量数据,数据隔离和存储复杂度更高;
  • 4. 状态性不同:传统服务无状态;大模型有对话上下文、微调状态,状态数据的隔离要求更严格。

这也是为什么大模型多租户隔离不能直接复用传统方案,需要针对性设计隔离机制。

三、多租户隔离的流程

1. 单租户大模型请求流程

先理解单租户流程,才能快速掌握多租户隔离逻辑:

156.7-单租户大模型请求流程 deepseek_mermaid_20260421_a45f9c.png

  • 1. 用户发起请求:调用大模型对话接口,传入问题;
  • 2. 服务接收请求:无身份校验,直接分配GPU资源;
  • 3. 模型推理:GPU执行推理,生成回答;
  • 4. 结果返回:返回给用户,流程结束。

缺陷:仅支持一个租户,资源闲置,无法SaaS化。

2. 多租户隔离完整执行流程

这是大模型SaaS平台的标准隔离流程,覆盖权限、资源、性能三大维度:

156.8-多租户隔离执行流程图.png

步骤 1:租户接入,携带唯一标识

租户调用大模型API,请求头必须携带:

  • TenantID:租户唯一标识;
  • Authorization:租户认证令牌;
  • 示例请求头:

headers = {

   "TenantID": "tenant_2024001",

   "Authorization": "Bearer xxxxxxx"

}

步骤 2:全局拦截器:权限管控(第一道隔离)

服务端启动租户拦截器,统一校验:

  • 1. 校验Token是否合法,拒绝无效请求;
  • 2. 校验TenantID是否在白名单,封禁未开通租户;
  • 3. 校验租户是否有权限访问当前模型接口,如禁止基础版租户访问指定参数量级别模型;
  • 4. 记录租户请求日志,用于审计。

步骤 3:限流校验:性能隔离(第二道隔离)

基于租户配额,执行限流控制:

  • 1. 读取租户配置:QPS上限=10,并发上限=5;
  • 2. 检查当前租户请求数是否超出配额,超出直接返回”请求超限“,不进入后续流程;
  • 3. 作用:避免单个租户高并发拖垮集群,实现性能互不干扰。

步骤 4:资源分配:资源隔离(第三道隔离)

按租户分配专属资源:

  • 1. 从租户资源池分配GPU显存或CPU 线程,禁止占用其他租户资源;
  • 2. 加载租户私有配置:模型温度、最大生成长度、私有向量库;
  • 3. 初始化租户独立缓存空间,存储对话上下文。

步骤 5:独立队列调度:性能深度隔离

租户请求进入独立队列,调度器按优先级处理:

  • 1. 企业版租户队列优先调度;
  • 2. 基础版租户队列排队执行,不影响高优租户;
  • 3. 长耗时推理请求仅阻塞自身队列,不干扰其他租户。

步骤 6:模型推理与数据隔离

推理过程中严格数据隔离:

  • 1. 仅读取租户私有数据,如私有文档、对话历史;
  • 2. 推理结果仅写入租户独立存储;
  • 3. 绝不跨租户读取、写入数据。

步骤 7:结果返回与资源释放

  • 1. 返回推理结果给租户;
  • 2. 释放租户占用的GPU、缓存资源,回归资源池;
  • 3. 更新租户调用额度,完成全流程。

四、应用实践

1. 大模型多租户隔离实现

       通过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)

image.gif

1.1 代码说明

1.1.1 权限管控实现

  • 通过TENANT_CONFIG存储租户权限,仅允许访问配置内的模型接口;
  • 校验TenantID合法性,拒绝未授权租户,实现身份隔离。

1.1.2 性能隔离实现

  • 基于TENANT_REQUEST_COUNTER实现租户级限流,超出QPS直接拒绝;
  • 每个租户请求独立计数,互不干扰,解决性能拥堵问题。

1.1.3 资源隔离实现

  • 租户拥有独立的调用额度,耗尽后无法使用服务;
  • TENANT_CACHE按TenantID划分独立空间,对话历史完全隔离,不交叉污染。

1.1.4 测试方法

  • 1. 运行代码,打开http://127.0.0.1:8010/docs;
  • 2. 携带TenantID: tenant_001调用接口,正常返回;
  • 3. 使用tenant_001调用llm_summary,有权限;使用tenant_002调用,无权限;
  • 4. 快速多次调用,触发限流,验证性能隔离。

1.2 启动服务

156.9-启动服务 ScreenShot_2026-04-21_153857_812.png

1.3 接口入参说明

156.10-接口参考文档 ScreenShot_2026-04-21_161957_091.png

1.3.1 请求头 (Headers)

  • TenantID,必填,租户ID,如 tenant_001、tenant_002
  • Authorization,授权令牌,以Bearer xxx开头的任意字符

1.3.2 请求体 (Body)

  • prompt,必填,表示用户输入的问题
  • model_name,模型接口名,默认值为llm_chat,可选llm_chat、llm_summary

{

 "prompt": "你的问题内容",

 "model_name": "llm_chat"

}

1.4 curl语法简单测试

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\"}"

image.gif

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\"}"

image.gif

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\"}"

image.gif

156.11-简单curl测试 ScreenShot_2026-04-21_160546_931.png

1.5 简单测试脚本

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())

image.gif

测试输出:

{'code': 200, 'tenant_id': 'tenant_001', 'response': '【租户tenant_001】模型回答:已处理你的问题「你好,请介绍一下自己」,对话历史:6轮', 'remaining_quota': 986}

2. 完整的测试细节

       测试覆盖的隔离维度包括: 权限隔离(身份校验、接口权限)、性能隔离(滑动窗口限流 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}")

image.gif

输出结果:

🚀 多租户大模型服务测试脚本

服务端地址: 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服务的必经门槛。很多时候大模型功能落地不难,难的是多用户并发下的平衡与风控。所以我们首先要理解租户拦截、限流、数据隔离的运行逻辑;后续可以逐步延伸到显存隔离、向量库租户拆分、灰度资源调度等进阶内容,循序渐进积累应用落地能力,才能逐步吃透大模型线上服务的核心技术。

相关文章
|
2月前
|
消息中间件 负载均衡 算法
大模型GPU推理队列排队治理:限流规则+优先级调度+长短拆分+集群负载指南.172
大模型推理队列是承载生成请求的缓冲调度层,用于应对GPU算力稀缺、推理耗时长且不均等特性。通过限流、优先级调度、长短请求拆分、溢出防护和集群负载均衡五大治理手段,实现削峰填谷、保障高可用与资源高效利用。
261 2
|
2月前
|
存储 缓存 NoSQL
大模型上下文风控解析:过载控制、自动裁剪、超长拦截与敏感熔断应用实践.170
本文系统阐述大模型多轮会话中的四大核心挑战:上下文超窗、资源过载、算力浪费与内容风险,并提出完整的会话状态管理与上下文风控体系,涵盖会话生命周期管控、自动裁剪、超长Prompt拦截及敏感内容熔断等关键能力,保障服务稳定、成本可控与合规安全。
362 1
|
10月前
|
NoSQL 关系型数据库 MySQL
一篇文章带你弄懂SAAS云服务模式
本文详解IAAS、PAAS、SAAS、DAAS四大云服务模式,涵盖基础设施、平台、软件到数据服务的演进逻辑,并深入解析SAAS中的多租户与单租户架构差异,助你全面理解云计算核心概念与应用模式。
1479 11
|
3月前
|
SQL JSON Java
【AgentScope Java新手村系列】(15)MCP协议工具
MCP协议工具 — tools.json 一行声明一个 MCP server,支持 stdio/sse/ws 协议,McpMeta 传递调用元数据。
601 1
|
3月前
|
自然语言处理 API 调度
从推理到执行:厘清大模型Skill固有能力与Function Call函数调用的定位与价值差异.148
本文深入解析大模型两大核心能力:Skill(内生技能)与Function Call(函数调用)。Skill是模型预训练获得的固有推理与生成能力,如翻译、编程、逻辑分析,具备内生性、静态性与低延迟;Function Call则通过调用外部API获取实时数据或执行操作,具备外生性、动态性与精准性。二者互补协同——Skill为“大脑”,负责理解与决策;Function Call为“手脚”,负责执行与连接现实世界,共同构建可靠AI智能体。
539 3
|
3月前
|
人工智能 安全 算法
大模型应用:AI 智能体核心引擎:RAG检索增强生成原理与医疗场景深度落地.126
本文详解RAG(检索增强生成)在医疗智能体中的落地实践:针对大模型知识过时、幻觉、专业性不足三大痛点,基于Qwen本地大模型、MiniLM嵌入、FAISS向量库与LangChain框架,实现全流程可追溯、全本地化、无幻觉的精准问答。含环境配置、适配器封装、知识库构建及调试分析。
521 7
|
3月前
|
自然语言处理 监控 数据可视化
大模型应用:MiniLM实战案例:基于MiniLM模型的多语言智能客服问答检索系统.124
本项目构建基于深度语义理解的智能客服原型系统,支持中英日多语言混合输入与跨语言语义对齐;采用Sentence Transformer向量化+余弦相似度检索,实现口语化、同义表述精准匹配;集成PCA/t-SNE可视化、知识库热力图及性能监控,确保毫秒级响应与可解释性。
278 7
|
3月前
|
机器学习/深度学习 缓存 自然语言处理
多语言文本嵌入模型解析:paraphrase-multilingual-MiniLM 与 all-MiniLM深度对比.123
本文深度对比all-MiniLM-L6-v2与paraphrase-multilingual-MiniLM-L12-v2:前者轻快高效,专精英文;后者12层多语言支持,中英文语义区分更优。实践表明,意图识别等任务中,多语言模型显著提升准确率,虽稍慢但泛化更强。
624 3
|
3月前
|
存储 人工智能 自然语言处理
大模型应用:从零构建医疗AI智能体:大模型驱动的医疗辅助系统全流程解析.125
本文系统阐述医疗AI智能体的落地实践:聚焦高敏感、高合规的医疗场景,提出“大模型+专业知识+安全规则”三位一体架构,涵盖需求规划、模型选型、RAG增强、幻觉抑制、五层技术架构及多模态交互设计,强调稳扎稳打、合规优先的工程化路径。
560 2

热门文章

最新文章