Agent 多租户设计:租户隔离、资源配额与成本分区

· 系列: Agent Governance and Permissions · 阅读时间: 18 分钟

30 秒核心要点

  • 三区架构:控制平面共享、编排层按租户隔离、数据平面严格分区,是 Agent 多租户的骨架。
  • 配额必须双层实施:Kubernetes 层限制 CPU/内存,Agent 编排层限制并发、Token 与工具调用频率。
  • 成本分区靠网关:在 LLM 网关注入 tenant_id 元数据,实现精确到单次调用的成本归集与回摊。
  • 超量执行机制:预分配额度耗尽后,新发布被阻断或执行失败,避免“吵闹邻居”拖垮全局。

背景与挑战

当企业级 SaaS 平台从单租户 Agent 走向多租户,核心挑战不再是“如何运行一个 Agent”,而是“如何安全、公平、可计量地运行数百个租户的 Agent”。传统的 Web 多租户方案(如共享数据库加 row-level security)在 Agent 场景下显得力不从心——因为 Agent 不仅仅是数据读写,它还涉及 LLM 调用、工具执行、上下文窗口、记忆存储等全新资源维度。

一个典型的 Agent 请求会触发多次 LLM 调用、数次工具执行、可能读写租户专属的向量数据库,并在短期内存中维护状态。这种调用链的复杂性意味着:如果租户隔离只停留在数据层,那么一个租户的 Agent 可以轻易通过工具调用或共享模型配额影响其他租户。更关键的是,成本不再是一笔固定的服务器账单,而是高度动态的 Token 消耗——没有精细的配额和分区,财务上根本无法向租户收费。

因此,Agent 多租户设计必须回答三个问题:如何隔离?(数据、执行、网络、身份)如何配额?(资源、调用、成本)如何分区?(成本归集、计费、回摊)。本文将从这三方面展开,提供一套可落地的架构与实践。

核心架构设计

参考 Google Cloud Architecture Center 与 Zylos Research 的实践,多租户 Agent 平台应采用三区架构

  • 控制平面(共享):租户注册、认证、配额策略执行、审计日志收集。此平面完全共享,但所有操作都携带 tenant_id。
  • 编排层(租户级隔离):Agent 实例、工作流引擎、工具注册表。每个租户拥有独立的命名空间或 Kubernetes Namespace,运行各自的 Agent 编排器。
  • 数据平面(按租户分区):向量数据库、对象存储、缓存、会话历史。数据严格按 tenant_id 分区,可采用 schema-per-tenant 或 bucket-per-tenant。

租户标识(tenant_id)必须贯穿架构的每一层——从认证 Token 到 LLM 调用的 metadata,再到存储分区键。共享基础设施(如 LLM 网关、监控系统)通过 tenant_id 实现多租户复用,而隔离边界则确保一个租户的故障或恶意行为不会波及他人。

平衡共享与隔离是关键:完全隔离(每租户独立集群)成本过高,完全共享则失去安全边界。推荐的做法是共享控制平面 + 隔离编排与数据平面,这也是大多数企业级平台的选择。

租户隔离策略

隔离是多租户的基石,需要从四个维度实施:

数据隔离

向量数据库(如 Pinecone、Milvus)使用 collection-per-tenant 或 partition key。对象存储使用 bucket-per-tenant。关系数据库可采用 schema-per-tenant,但要注意连接数限制。

执行隔离

每个租户的 Agent 运行在独立的沙箱中。根据安全等级,可选择容器(Docker)、gVisor(用户态内核隔离)、或 MicroVM(Firecracker,强隔离)。沙箱同时限制 CPU、内存与网络。

网络隔离

在 Kubernetes 中使用 NetworkPolicy 限制租户命名空间之间的流量。默认拒绝跨租户通信,仅允许通过 API 网关的受控访问。

身份与权限隔离

使用 OIDC 或 SAML 实现租户级认证。RBAC 权限模型绑定 tenant_id,确保一个租户的 API Key 无法访问另一租户的资源。

沙箱选型需权衡隔离强度与启动时间:Firecracker MicroVM 提供硬件级隔离但启动约 125ms;gVisor 启动更快(~50ms)但隔离略弱;容器最快但共享内核。对于多租户 Agent,建议至少使用 gVisor,金融级场景使用 MicroVM。

资源配额管理

配额管理必须双层实施:基础设施层与 Agent 编排层。

基础设施层(Kubernetes):利用 ResourceQuota 和 LimitRange 为每个租户命名空间设置硬性限制。以下是一个租户命名空间的配额示例:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-acme
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 16Gi
    limits.cpu: "20"
    limits.memory: 32Gi
    persistentvolumeclaims: "5"
---
apiVersion: v1
kind: LimitRange
metadata:
  name: tenant-limit-range
  namespace: tenant-acme
spec:
  limits:
  - default:
      cpu: "500m"
      memory: 512Mi
    defaultRequest:
      cpu: "100m"
      memory: 128Mi
    max:
      cpu: "2"
      memory: 4Gi
    type: Container
        

Agent 编排层:在应用层限制并发 Agent 实例数、每分钟 LLM 调用次数、单次会话 Token 上限。这通常通过 API 网关或 Agent 编排器实现。例如,使用 Redis 计数器实现滑动窗口限流:

# Python 伪代码:租户级 LLM 调用限流
import redis
import time

r = redis.Redis(host='redis', port=6379)

def check_quota(tenant_id: str, limit_per_min: int = 100) -> bool:
    key = f"quota:{tenant_id}:{int(time.time() // 60)}"
    current = r.incr(key)
    if current == 1:
        r.expire(key, 60)
    return current <= limit_per_min
        

超量执行(Overage Enforcement):当租户预分配额度耗尽时,新的 Agent 发布应被阻止,正在执行的 Agent 可允许完成但拒绝新任务。这需要配额系统与 CI/CD 门禁集成。

成本分区与计费

成本分区是财务可持续的关键。核心思路是在 LLM 网关层注入租户上下文,实现精确到单次调用的成本归集。

以 Portkey 或自研网关为例,每次 LLM 请求携带 metadata 中的 tenant_id:

# LLM 网关调用示例(伪代码)
import requests

def call_llm(tenant_id: str, prompt: str, model: str):
    response = requests.post(
        "https://llm-gateway.internal/v1/chat/completions",
        headers={"Authorization": "Bearer sk-..."},
        json={
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            "metadata": {
                "tenant_id": tenant_id,
                "agent_id": "customer-support-v2"
            }
        }
    )
    return response.json()
        

网关记录每次调用的 token 数、模型单价,并按 tenant_id 聚合。成本追踪工具链可选用:

  • Langfuse:开源 LLM 可观测性,支持按租户标签追踪成本。
  • Portkey:网关内置成本分析与预算告警。
  • Amberflo:实时计量与计费平台,适合复杂回摊模型。

对于 Chargeback 模型,推荐组合计费:按 Token 消耗(基础)+ 按 Agent 实例数(固定)+ 按工具调用次数(附加)。每个租户应能自助查看成本仪表板,按日/周/月粒度分析。

性能与安全

性能隔离:避免“吵闹邻居”是配额管理的直接目标。Kubernetes ResourceQuota 保证 CPU/内存上限,但还需注意 LLM API 的速率限制——如果多个租户共享同一个 OpenAI 部署,一个租户的突发流量可能触发 429 错误影响他人。解决方案是使用 Azure OpenAI 的预置吞吐量(Provisioned Throughput)或为高优先级租户配置独立部署。

安全加固:沙箱逃逸是最大风险。分层缓解措施包括:

  • 沙箱内禁用宿主机 IPC、PID 命名空间共享。
  • 只读根文件系统,/tmp 使用 tmpfs。
  • 网络出口白名单,仅允许访问必要 API。
  • 定期扫描沙箱镜像漏洞,使用 distroless 基础镜像。

可观测性:所有监控指标、日志必须携带 tenant_id。Prometheus 指标按租户标签分区,日志索引使用租户字段,审计日志记录每次跨租户访问尝试。这不仅是安全要求,也是成本争议仲裁的依据。

企业级落地

从单租户迁移到多租户的路径:第一步,在现有系统中引入 tenant_id 字段,所有数据表和调用链带上租户标识。第二步,将 Agent 执行环境容器化,并迁移到按租户命名空间的 Kubernetes 集群。第三步,在 LLM 网关层实现成本归集。第四步,与现有 IAM、计费系统集成。

企业内部多业务单元的成本回摊实践:建议采用“固定费用 + 可变费用”模式。固定费用覆盖基础设施共享成本(如控制平面),可变费用按实际 Token 消耗和 Agent 实例数计算。财务部门需要每月导出分租户账单,并与云服务商账单对账。

与现有系统集成时,重点关注:SSO 集成(企业 IdP 映射到租户)、审计日志导出(SIEM 系统)、成本异常告警(例如某租户单日成本突增 500% 时自动冻结)。

常见陷阱

陷阱 1:共享助手导致跨租户数据泄露

如果多个租户共享同一个 Agent 助手(Assistant),且助手内部使用了共享的向量存储,那么租户 A 的上下文可能被租户 B 检索到。解决:每个租户必须拥有独立的助手实例或明确的 collection 分区。

陷阱 2:配额只配 CPU/内存,忽略 Token 配额

Kubernetes 配额无法限制 LLM Token 消耗。一个失控的 Agent 可能耗尽租户的月度预算。必须在上层实施 Token 配额,并与网关联动。

陷阱 3:成本归集粒度不足

如果只在月末汇总一次成本,无法定位是哪个 Agent、哪个功能导致超支。需要精确到单次调用、按 agent_id 和 function 标签聚合。

陷阱 4:忽略冷启动延迟

使用 Firecracker 沙箱时,如果租户流量突增,冷启动延迟可能导致超时。需要预热池或使用更轻量的隔离技术。

常见问题(FAQ)

如何选择隔离级别?

根据合规要求和成本预算。金融/医疗建议使用 MicroVM 或独立集群;一般企业级使用 gVisor + Kubernetes 命名空间即可。数据层至少使用 schema-per-tenant 或 row-level security。

配额应该在哪一层实施?

双层:基础设施层(Kubernetes ResourceQuota)控制 CPU/内存;编排层(网关/Agent 运行时)控制并发数、Token 消耗、工具调用频率。缺一不可。

如何实现精确到单次调用的成本追踪?

在 LLM 网关层注入 tenant_id 和 agent_id 到 metadata,网关记录每次调用的 token 数与单价,写入时序数据库。使用 Portkey、Langfuse 或自研中间件。

如何处理租户超量执行?

预付费租户:超额后阻断新任务,允许当前任务完成。后付费租户:可以超额但需告警。关键是在配额耗尽时,Agent 发布门禁应阻止新的部署。

多租户下如何设计审计日志?

所有日志必须包含 tenant_id,并集中存储。审计日志需记录:谁(用户/Agent)、何时、对哪个租户资源做了什么操作。参考我们的 Agent 审计日志设计

共享模型部署如何避免租户间影响?

使用 Azure OpenAI 的预置吞吐量或 AWS Bedrock 的 provisioned throughput。如果使用标准部署,必须在上层网关实施严格的速率限制,并为高优先级租户预留容量。

下一步阅读

多租户设计是 Agent 治理体系的一部分。建议继续阅读以下专题: