RAG 权限过滤:召回结果正确,也不能越权
RAG 权限过滤召回结果正确也不能越权一、RAG 最怕把不该看的资料说出来RAG 系统经常把注意力放在召回率和答案质量上但权限过滤同样关键。一个答案如果引用了用户无权访问的文档即使技术上回答正确也是严重事故。知识库越大、租户越多这个风险越高。权限过滤不能依赖模型自觉。模型不知道每个 chunk 的真实权限也不能保证生成时不泄露上下文。权限必须在检索阶段和证据注入阶段完成硬过滤。我曾经处理过一个险情内部知识库上线两个月后运营同事投诉说能搜到竞争对手的合同信息。排查发现是权限过滤的 SQL 条件有一个 bug——“space_id IS NULL”的文档被当成了公开文档返回给了所有用户。模型在回答时引用了这个文档造成了数据泄露。这个 bug 不是模型造成的而是权限过滤实现有漏洞。教训是权限过滤要像门禁一样什么人都能过和什么人都不让过一样危险必须精确到每一个 chunk。二、权限元数据要跟着 chunk 走flowchart LR A[原始文档] -- B[权限解析] B -- C[切分 Chunk] C -- D[写入向量库] D -- E[检索过滤] E -- F[生成答案]每个 chunk 都要带上 tenant_id、space_id、owner、role_scope、classification 等元数据。检索时先过滤权限再做相似度排序或者使用向量库支持的混合过滤能力。不能先召回再让模型挑。文档切分也要尊重权限边界。如果一个 chunk 混入了公开段落和私密段落后续过滤会非常难做。切分前最好先识别权限域保证最小证据单元本身就是权限一致的。这个原则和加密数据分区类似一条记录只能属于一个安全域跨域混合就意味着信息泄露风险。权限元数据的管理还要考虑权限变更。用户被移出某个空间后向量库里该空间的 chunk 应该对该用户不可见。如果权限变更后没有及时同步到向量库的元数据就会出现权限系统显示无权但 RAG 仍然能查到的不一致。建议在权限变更时发消息到 Outbox由消费者批量更新向量库元数据。三、过滤条件要可测试type QueryScope struct { TenantID string UserID string Roles []string Spaces []string }权限过滤要有单元测试和集成测试。准备几类用户普通成员、空间管理员、跨部门用户、外部访客。每类用户都要验证可见文档和不可见文档。只测管理员账号结果通常过于乐观。func BuildFilter(scope QueryScope) map[string]any { return map[string]any{ tenant_id: scope.TenantID, space_id: map[string]any{$in: scope.Spaces}, role: map[string]any{$overlap: scope.Roles}, } }还要测试空权限。用户没有任何空间权限时系统应该返回空证据而不是退化成全库检索。很多越权问题就来自过滤条件为空时忽略过滤。这条规则要进代码规范任何权限过滤条件都不能以空条件或无权限状态作为放行信号。四、引用展示也要检查权限retrieval_log: user_scope_hash: 8fe2 matched_chunks: 12 filtered_chunks: 38权限过滤不只发生在向量库。答案引用、展开原文、下载附件、追溯来源都要再次校验权限。否则生成阶段安全展示阶段仍可能泄露。这是一个纵深防御原则任何输出用户可见内容的接口都应该重新验证用户对内容的访问权限不能依赖上游的过滤结果。观测日志要记录过滤数量和 scope hash但不要记录完整权限列表。这样既能排查为什么搜不到也能避免日志泄露权限结构。scope hash 是对权限组合的哈希值两个用户 hash 相同说明权限一致不同说明有差异——既能归类排查又不泄露具体权限。还要处理缓存。很多 RAG 服务会缓存检索结果或最终答案如果缓存 key 里没有权限范围就可能把一个用户的证据返回给另一个用户。缓存 key 至少要包含租户、空间范围、角色摘要和知识库版本。权限变更后要么主动失效相关缓存要么把权限版本写入 key。否则权限系统做得再严缓存层也会开后门。权限过滤也需要压测。过滤条件复杂后向量库可能从毫秒级变成百毫秒级。要分别测试公开库、小空间、多角色和大租户场景确认过滤不会把检索延迟拖垮。安全和性能不是二选一关键是提前知道成本。一个经验数值当过滤条件涉及的 IN/NOT IN 子句超过 100 个时部分向量库的查询性能会明显下降此时需要考虑权限分组压缩或使用位图索引替代列表匹配。五、总结RAG 权限过滤要把权限元数据写到 chunk检索阶段强过滤切分时保持权限一致并在引用展示时再次校验。空权限要拦截而不是放行缓存要带权限标识。召回结果正确只是第一步。对生产 RAG 来说答案必须既正确又属于当前用户可以知道的范围。权限是安全底线不是功能后端。