多租户 AI SaaS 架构:3 种生产就绪模式
- 作者

- 姓名
- Nino
- 职业
- Senior Tech Editor
构建多租户 AI 应用与传统的 SaaS 开发有着本质的区别。在标准的 B2B 应用中,多租户通常只是在关系型数据库中添加一个 tenant_id 列。然而,当你引入大语言模型 (LLM) 和向量数据库时,数据泄露的风险面会呈指数级扩大。我们曾目睹过医疗行业的案例,由于共享向量索引,一名患者的查询竟然检索到了另一家医院的内部协议;在 B2B 支持领域,也曾发生过因 RAG(检索增强生成)管道缺少过滤而导致机器人泄露竞争对手定价信息的事件。
在扩展 AI 基础设施时,使用像 n1n.ai 这样可靠的 API 聚合器可以确保你的后端能够处理跨不同模型的高速请求,但底层架构必须针对严格的隔离进行设计。本指南概述了我们在金融科技、医疗保健和监管合规领域部署的 3 种生产就绪模式。
多租户 AI 的核心挑战
传统的 SaaS 隔离数据库行、文件存储和 API 访问。AI 额外增加了三个需要隔离的关键层:
- 向量嵌入隔离 (Vector Embedding Isolation):高维向量本身不携带身份信息。如果多个租户共享一个索引,相似性搜索很容易跨越边界,除非实施了极其严格的预过滤。
- 模型上下文隔离 (Model Context Isolation):LLM 的上下文窗口和对话历史必须限定范围。没有命名空间的共享缓存会导致“幻觉式”泄露,即一个租户的历史记录出现在另一个租户的会话中。
- 推理成本隔离 (Inference Cost Isolation):AI 查询具有很高的边际成本。如果没有针对每个租户的预算控制,一个重度用户可能会耗尽你的所有利润。使用 n1n.ai 可以让你跨不同供应商跟踪和管理这些成本,但你的架构必须强制执行这些限制。
模式 1:物理隔离(每租户一个集合)
最佳适用场景:租户数量少于 100 个、高合规性行业(医疗、金融)。
在这种模式下,每个租户都拥有自己专用的向量集合 (Collection)。在应用层,查询被路由到属于该租户的特定索引。这使得跨租户的数据泄露在物理上成为不可能,因为数据驻留在完全不同的逻辑结构中。
import { QdrantClient } from '@qdrant/js-client-rest'
const qdrant = new QdrantClient({ url: 'http://localhost:6333' })
async function createTenantCollection(tenantId: string) {
// 为每个租户创建独立的集合
await qdrant.createCollection(`tenant_${tenantId}`, {
vectors: { size: 1536, distance: 'Cosine' },
})
}
async function queryTenantDocuments(tenantId: string, queryVector: number[], limit = 5) {
// 路由查询到租户专属的集合
return qdrant.search(`tenant_${tenantId}`, {
vector: queryVector,
limit,
with_payload: true,
})
}
权衡取舍:操作复杂性。如果你有 1,000 个租户,你就需要管理 1,000 个集合。与共享索引相比,这会增加约 3 到 4 倍的基础设施开销(内存、备份和索引时间)。然而,对于 PHI(受保护健康信息)边界不可逾越的临床产品来说,这是行业金标准。
模式 2:元数据过滤的共享集合
最佳适用场景:100 到 10,000+ 租户、对成本敏感的 B2B 工具。
此模式使用单个向量集合,其中的每个文档块都标记有 tenant_id。你依靠元数据过滤器来限制搜索范围。
专业提示:过滤器必须是“预过滤 (Pre-filter)”。如果你在搜索之后才进行过滤(后过滤),你会得到不一致的结果和潜在的泄露风险。预过滤确保向量数据库在进行最近邻计算时,仅考虑该租户的数据。
async function queryDocuments(tenantId: string, queryVector: number[], limit = 5) {
return qdrant.search('shared_documents', {
vector: queryVector,
limit,
filter: {
// 关键:在相似性计算前进行预过滤
must: [{ key: 'tenant_id', match: { value: tenantId } }],
},
with_payload: true,
})
}
为了防止开发人员失误,建议将 SDK 封装在租户作用域的客户端中。这可以确保任何查询在执行时,tenant_id 都会被自动注入到过滤块中,无法被遗忘。
function createTenantScopedClient(qdrant: QdrantClient, tenantId: string) {
return {
search: (collection: string, params: any) => {
const tenantFilter = { key: 'tenant_id', match: { value: tenantId } }
const existing = params.filter?.must || []
return qdrant.search(collection, {
...params,
filter: { must: [...existing, tenantFilter] },
})
},
}
}
将 n1n.ai 提供的统一 API 与此模式结合使用,可以让你在保持单一、易于管理的基础设施足迹的同时,实现业务的快速扩展。
模式 3:域分区(共享参考语料库)
最佳适用场景:监管类产品、法律科技和科研平台。
有时,数据并非由租户所有。例如,一个税务法律平台可能拥有一个所有用户都可以访问的联邦法规共享语料库,但每个用户对这些数据的 分析 必须是私有的。在这种情况下,我们按管辖区或领域(而不是按客户)进行分区。
const JURISDICTIONS = {
federal: 'regulations_fed',
eu_gdpr: 'regulations_eu',
}
async function assessImpact(clientProfile: any, queryVector: number[], jurisdiction: string) {
const chunks = await qdrant.search(JURISDICTIONS[jurisdiction], {
vector: queryVector,
limit: 10,
})
// 客户画像保存在应用层,绝不与全局向量混合
return evaluateImpact(chunks, clientProfile)
}
强化关系层:Postgres RLS
虽然向量处理嵌入,但你的元数据(日志、对话、用户数据)仍存储在 PostgreSQL 中。使用 行级安全性 (RLS) 在数据库引擎级别确保隔离。这比在应用代码中依赖 WHERE 子句要安全得多。
-- 启用行级安全
ALTER TABLE ai_usage_logs ENABLE ROW LEVEL SECURITY;
-- 创建策略:只允许访问当前租户的数据
CREATE POLICY tenant_isolation ON ai_usage_logs
FOR ALL
USING (tenant_id = current_setting('app.current_tenant')::UUID);
在你的中间件中,为事务持续期间设置租户 ID:
// 第三个参数 true 确保设置仅限于当前事务
await client.query("SELECT set_config('app.current_tenant', $1, true)", [tenantId])
管理 AI 成本和预算
AI 支出是一项变动成本,很容易失控。实现一个中间件,在调用 LLM API 之前检查租户的预算:
- 基于层级的路由:将标准用户路由到较便宜的模型(如 GPT-4o-mini),将企业用户路由到 GPT-4o。
- Token 计量:记录每次请求的 Token 使用量和成本。
通过利用 n1n.ai,你可以轻松地在不同模型和供应商之间切换以优化成本,同时为你的多租户逻辑保持一致的接口。
缓存隔离:不容忽视的细节
如果将一个租户的 AI 响应缓存并提供给另一个租户,这同样属于严重的数据泄露。解决方案是:租户 ID 必须进入缓存键。
function buildCacheKey(tenantId: string, queryHash: string) {
return `ai_cache:${tenantId}:${queryHash}`
}
总结
多租户 AI 需要“纵深防御”策略。在基础设施层隔离(向量数据库集合或 RLS),在 SDK 层强制执行(作用域客户端),并在 API 层进行监控。不要等到发生第一次数据泄露后才去重新思考你的架构。
通过 n1n.ai 接入最先进的模型,结合上述架构模式,你将能够构建出既安全又具备成本效益的 AI SaaS 产品。
立即在 n1n.ai 获取免费 API 密钥。