你的 RAG 系统部署给银行,普通员工能搜到领导的薪资文件?不同分行的数据怎么隔离?向量数据库有权限控制吗
P1 · rag · 🏢 蚂蚁
🏷 标签:rag, permission, vector-database, milvus, security
1️⃣ 考察意图
这道题是典型的系统设计 + 安全审计类问题,面试官真正想看的是:你是否意识到RAG系统在金融场景下,权限管理不是事后补丁,而是从数据摄入到检索返回的贯穿性约束。刁钻点在于:向量数据库(如Milvus、Pinecone)默认只提供集合级权限,没有行级或文档级ACL,而面试官直接抛出“分行隔离”这种多租户场景,就是逼你给出分层架构方案。答好了能展示你对企业级RAG的工程落地深度,包括元数据过滤、分区策略、二次验证等硬核能力。
2️⃣ 标准答
核心认知:向量数据库的权限盲区
- 主流向量库(Milvus、Qdrant、Weaviate)只支持集合/索引级别的CRUD权限,没有行级ACL。例如Milvus的RBAC只能控制“谁可以建索引”,无法控制“谁可以搜到某条向量”。
- 这意味着:如果直接把文档向量化后一股脑塞进一个集合,任何用户查询都会返回所有匹配结果,包括领导的薪资文件。
三层隔离架构(银行场景)
- 接入层:JWT携带权限上下文 - 用户登录后,Token中嵌入
org_id(分行ID)、role(岗位)、clearance_level(密级)。 - 每次搜索请求,API网关解析Token,将权限字段注入请求头(如X-User-Org: SH_Branch)。 - 为什么这么做:避免在检索层硬编码权限逻辑,保持无状态,方便审计。 - 检索层:元数据过滤 + 分区隔离 - 元数据过滤(推荐):在Milvus中,为每条向量附加
org_id、doc_level等标量字段。查询时用expr参数过滤:坑:标量字段必须建索引(如Milvus的bitmap索引),否则全表扫描导致延迟飙升。实测不加索引时,100万条数据过滤耗时从2ms涨到200ms。 - 分区隔离(备选):按分行建独立分区(collection.partition("SH_Branch")),查询时指定分区名。取舍:分区隔离物理隔离更彻底,但跨分行查询(如总行审计)需要合并结果,复杂度高;元数据过滤更灵活,但依赖索引性能。 - 返回层:二次验证 - 即使检索层过滤了,也要在应用层做白名单校验:对返回的每条文档,检查其
allowed_roles字段是否包含当前用户角色。 - 为什么需要:防止向量库的expr过滤因bug或配置错误漏掉权限(例如Milvus的expr对空值处理不一致,doc_level <= 3可能漏掉doc_level为NULL的记录)。二次验证是安全底线。
实际落地的坑 + 解法
- 坑1:元数据过滤导致召回率下降。例如用户搜“薪资”,但领导文档的
doc_level是5(最高密级),普通员工clearance_level是2,过滤后直接丢掉。解法:采用渐进式权限——先按用户权限过滤,再对低权限用户做结果脱敏(如薪资数字替换为“***”),而不是直接丢弃。 - 坑2:多租户下向量库的索引膨胀。每个分行独立集合?不行,Milvus单集群最多支持65536个集合,银行有2000个分行,每个分行还有子部门,集合数爆炸。解法:用单集合+元数据过滤,配合
partition_key(Milvus 2.3+)自动路由到子索引,减少扫描范围。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从三个层面回答:第一,向量数据库的权限盲区——主流产品没有行级ACL,必须靠应用层补;第二,三层隔离架构——接入层用JWT带权限上下文,检索层用Milvus的元数据过滤或分区隔离,返回层做二次验证;第三,实际坑点——元数据过滤要建索引否则性能崩,低权限用户用结果脱敏代替直接丢弃。总结一句:RAG权限不是向量库的事,是数据摄入、检索、返回整条链路的系统工程。”
4️⃣ 高频追问 & 应对
追问 1:如果领导薪资文件被误标为低密级,普通员工搜到了,怎么追溯?
应对策略:审计日志 + 数据血缘。在接入层记录每次搜索的
user_id、query、返回文档ID列表到Elasticsearch。同时,文档摄入时生成doc_id和version,并记录谁在何时修改了密级。一旦发生泄露,通过日志反查:① 哪个用户搜了什么关键词;② 该文档的密级变更历史;③ 是否是元数据过滤配置错误(如expr写成了doc_level <= 5)。关键:审计日志不能存在向量库里,要独立存储,防止被篡改。
追问 2:Milvus的元数据过滤性能瓶颈在哪?怎么优化?
应对策略:瓶颈在标量字段的索引类型。Milvus支持
inverted(倒排)、bitmap(位图)、marisa_trie三种标量索引。对于银行场景(org_id基数低,约2000个值),用bitmap索引最合适,过滤延迟<5ms。如果doc_level是连续值(1-10),用inverted索引。优化技巧:把高频过滤字段(如org_id)设为partition_key,Milvus会自动按该字段值分片,查询时只扫描相关分片,减少IO。实测1000万条数据,partition_key+bitmap索引,过滤延迟从150ms降到3ms。
追问 3:如果用户跨分行查询(比如总行审计),怎么处理?
应对策略:特权用户 + 动态权限提升。在JWT中增加
is_auditor: true字段,检索层检测到该标志后,跳过expr中的org_id过滤,但保留doc_level过滤(审计员也不能看绝密文件)。同时,在返回层记录审计日志,标记为“跨分行查询”。取舍:特权用户会绕过分区隔离,所以必须用二次验证兜底,且审计日志要额外标注“特权操作”,方便事后审查。
5️⃣ 避坑 · 常见错误答法
- ❌ 答:“用向量数据库的RBAC功能控制权限。”→ ✅ 正确切入:向量数据库的RBAC只到集合级别,没有行级权限。必须用应用层元数据过滤+二次验证。
- ❌ 答:“把所有文档放一个集合,查询时用
expr过滤就行。”→ ✅ 正确切入:expr过滤依赖标量索引,不建索引性能崩;且过滤逻辑可能漏掉权限(如NULL值)。必须配合返回层二次验证。 - ❌ 答:“按分行建独立集合,每个集合一个索引。”→ ✅ 正确切入:银行分行数量多(2000+),集合数会爆炸,Milvus单集群有限制。用单集合+
partition_key更合理。
6️⃣ 简历呼应
- 如果你有RAG项目:从“我在项目中用Milvus的
expr实现了文档级权限过滤,但发现标量索引没建导致延迟高,后来改用bitmap索引并配合二次验证”切入,突出踩坑和优化。 - 如果你只做过传统NLP:用“传统NLP的权限管理在应用层做,RAG的向量库引入了新维度——检索层过滤。类比MySQL的行级权限,向量库需要自己实现类似功能”来迁移经验。
- 如果你是校招无项目:聚焦“我复现过Milvus的权限控制demo,用元数据过滤模拟了多租户场景,并对比了分区隔离和元数据过滤的性能差异”,展示动手能力。
- Milvus 官方文档:
partition_key与标量索引配置 - 论文:
Fine-Grained Access Control for Vector Databases(VLDB 2024) - 博客:
Building Multi-Tenant RAG Systems with Milvus(Zilliz Blog) - 工具:
Apache Ranger集成向量数据库的权限方案 - 论文:
RAG Security: A Survey of Threats and Mitigations(arXiv 2024)