跳到主要内容

元数据的过滤场景

前面讲了怎么给文本块"上户口"(元数据设计),这篇来聊聊检索的时候怎么用这些户口信息——也就是元数据过滤。

向量检索的核心能力是语义匹配——找到意思最接近的文档。但有些场景下,语义相似不等于答案正确。

举个实际遇到的例子:一个智能客服系统,知识库里存了三个版本的产品手册(V1.0、V2.0、V3.0)。用户问"怎么连接蓝牙设备",三个版本的手册里都有蓝牙连接的说明,语义上几乎一模一样。但V1.0是"设置→蓝牙→搜索设备",V2.0改成了"下拉通知栏→长按蓝牙图标",V3.0又变成了"设置→连接→蓝牙"。

向量检索返回了什么?三个版本的内容混在一起,因为它们的语义相似度几乎相同。大模型拿到这三段内容,可能会把不同版本的步骤混着说,给出一个根本不存在的操作流程。

问题出在哪?向量检索只看语义,不看版本号。

这就是元数据过滤要解决的问题:在语义匹配的同时,用结构化条件把不相关的文档排除掉。

三个典型的过滤场景

场景一:版本/分类精确过滤

这是最常用的场景。当知识库中存在同一主题的多个版本或多个分类时,必须用元数据过滤来限定范围。

回到刚才的例子,如果用户明确说了"V3.0的蓝牙怎么连",我们就应该只在V3.0的文档中检索:

SearchRequest request = SearchRequest.builder()
.query("怎么连接蓝牙设备")
.topK(5)
.similarityThreshold(0.5)
.filterExpression("version == '3.0'")
.build();

List<Document> results = vectorStore.similaritySearch(request);

类似的场景还有很多:

  • 多语言文档:filterExpression("language == 'zh'")
  • 多产品线:filterExpression("product == 'ProMax'")
  • 时间范围:filterExpression("createTime >= '2026-01-01'")

场景二:提供引用来源

在RAG的回答中附上引用来源,能大幅提升用户信任度。元数据就是引用信息的载体。

List<Document> docs = vectorStore.similaritySearch(request);

for (Document doc : docs) {
String fileName = (String) doc.getMetadata().get("fileName");
Integer page = (Integer) doc.getMetadata().get("pageNumber");
String version = (String) doc.getMetadata().get("version");

log.info("引用来源: {} 第{}页 (版本{})", fileName, page, version);
}

// 在Prompt中加入引用要求
String systemPrompt = """
根据参考资料回答问题。回答末尾请标注引用来源,格式:
[来源:文件名, 页码]
""";

用户看到的回答效果:

连接蓝牙设备的步骤:打开设置 → 点击"连接" → 选择"蓝牙" → 打开蓝牙开关 → 等待搜索到目标设备后点击配对。

[来源:产品手册V3.0.pdf, 第23页]

场景三:访问权限控制

企业级RAG系统中,不同用户能看到的文档范围不同。财务部的薪资文档不能被其他部门检索到,机密级文档不能被普通员工看到。

@GetMapping("/chat")
public String chat(@RequestParam String question,
@RequestParam String userId) {
UserInfo user = userService.getUser(userId);
String department = user.getDepartment();
String accessLevel = user.getAccessLevel();

// 构建权限过滤表达式
String filter = String.format(
"department == '%s' && accessLevel <= '%s'",
department, accessLevel);

SearchRequest request = SearchRequest.builder()
.query(question)
.topK(5)
.similarityThreshold(0.5)
.filterExpression(filter)
.build();

List<Document> docs = vectorStore.similaritySearch(request);
// ... 后续RAG流程
}
权限过滤是安全底线

权限过滤必须在检索层做,不能依赖大模型"不要回答敏感内容"这种Prompt约束。Prompt约束是可以被绕过的(Prompt注入),但元数据过滤是在数据库层面执行的,用户根本看不到被过滤掉的文档。

付费内容提示

该文档的全部内容仅对「JavaUp项目实战&技术讲解」知识星球用户开放

加入星球后,你可以获得:

  • 超级八股文:100万+字的全栈技术知识库,涵盖技术核心、数据库、中间件、分布式等深度剖析的讲解
  • 讲解文档:超级AI智能体、黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的从0到1的详细文档
  • 讲解视频:超级AI智能体、黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的核心业务详细讲解
  • 1 对 1 解答:可以对我进行1对1的问题提问,而不仅仅只限于项目
  • 针对性服务:有没理解的地方,文档或者视频还没有讲到可以提出,本人会补充
  • 面试与简历指导:提供面试回答技巧,项目怎样写才能在简历中具有独特的亮点
  • 中间件环境:对于项目中需要使用的中间件,可直接替换成我提供的云环境
  • 面试后复盘:小伙伴去面试后,如果哪里被面试官问住了,可以再找我解答
  • 远程的解决:如果在启动项目遇到问题,本人可以帮你远程解决
进入星球后,即可享受上述所有服务,保证不会再有其他隐藏费用。
知识星球二维码

1. 打开微信 -> 扫描左侧二维码 -> 加入「JavaUp项目实战&技术讲解」知识星球

2. 查看星球使用指导,获取完整项目讲解资料索引

👉 点击解锁全部付费内容
🎁优惠