登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

AI RAG 元数据过滤 怎样处理

来源:17golang原创

时间:2026-10-22 07:04:03 223浏览 收藏

AI RAG 元数据过滤 怎样处理

RAG 里遇到“只查某个租户、只看已发布文档、时间不能超过范围”时,不要把这些条件交给 embedding 猜。更稳妥的做法是把它们定义成结构化 metadata,在向量召回时作为硬过滤;语义相似度只负责在合法候选中排序。

官方地址:https://qdrant.tech/

要点速览
  • 租户、权限、状态属于硬边界,必须进入过滤表达式。
  • 分类、标签用精确匹配;时间、数值用 range;长文本不要冒充 keyword。
  • 空结果先查字段类型、默认值和过滤命中率,再决定是否放宽条件。

先把元数据过滤和语义检索分开

一条文档通常同时拥有向量和 payload。向量回答“语义上像不像”,metadata 回答“业务上能不能看”。例如 tenant_id、visibility、status 是权限或生命周期字段,published_at 是范围字段,tags 可以是多值标签。它们的判断结果应该先限制候选域,再交给向量相似度排序。

RAG 元数据过滤边界说明图,展示用户条件、字段白名单、元数据过滤器与向量检索的关系
图1:RAG 元数据过滤边界说明图,硬约束先缩小候选域,语义相似度负责排序。

工程上建议维护一个字段白名单:查询解析器只能生成允许的字段、操作符和值类型,不能让用户输入直接拼成过滤 JSON。这样既能避免越权,也能让日志记录“过滤了什么”,便于解释召回结果。

把用户条件转换成可审计的过滤表达式

下面用 Qdrant Python 客户端展示一个最小写法。这里的字段名只是示例,关键是把租户条件和文档状态放在 must,把时间范围用 range 表达;如果业务需要排除草稿,再用 must_not。

from qdrant_client import models

def build_filter(tenant_id: str, start_ts: int, end_ts: int) -> models.Filter:
    # 只允许服务端定义的字段,租户条件不能由模型自由改写
    return models.Filter(
        must=[
            models.FieldCondition(
                key="tenant_id",
                match=models.MatchValue(value=tenant_id),
            ),
            models.FieldCondition(
                key="status",
                match=models.MatchValue(value="published"),
            ),
            models.FieldCondition(
                key="published_at",
                range=models.Range(gte=start_ts, lt=end_ts),
            ),
        ],
        must_not=[
            models.FieldCondition(
                # 排除明确标记为内部资料的文档
                key="visibility",
                match=models.MatchValue(value="internal"),
            )
        ],
    )

如果一个字段是数组,先确认向量库对数组的匹配语义;不要假设“包含任一标签”和“包含全部标签”是一回事。字段缺失也应有明确策略:权限字段缺失通常拒绝,非关键展示字段缺失才允许继续。

过滤字段要和索引类型一致

过滤失败经常不是语法问题,而是写入类型和查询类型不一致。分类、租户 ID、标签值适合精确匹配;数值和时间要统一为数字或规范化时间;需要按词匹配的长文本应使用 text 类型,而不是把整段文本当作一个 keyword。

字段场景建议类型常见条件排查重点
tenant_id、statuskeyword等于、排除大小写与缺省值
published_at、scoreinteger/float/datetimegte、lt、lte单位和时区
tagskeyword 数组包含某标签数组是任一匹配还是全部匹配
title、body 摘要text词或短语匹配分词、停用词和大小写
RAG 过滤字段与索引类型关系图,展示 metadata schema、keyword、range、text 索引与逻辑过滤组合
图2:过滤字段与索引类型关系图,字段类型决定匹配语义和可用索引。

高频过滤字段应建立对应的 payload index,但不要把所有字段都索引。索引会增加内存和维护成本,优先选择真正参与过滤、且能明显缩小候选集合的字段。过滤条件放在向量查询里,才能避免先召回一堆无权访问的文档再在应用层删除。

空结果和过滤过窄怎样排查

先用一条已知存在的文档做基准查询,只保留 tenant_id,确认租户边界能命中;再逐个加入 status、时间和标签条件。每一步记录候选数、过滤命中数和最终 top-k,不要直接把过滤失败归咎于 embedding。

  • 命中数为零:检查字段路径、值类型、大小写和时间单位。
  • 命中数异常多:检查是否漏了租户条件,或把数组条件写成了宽松的 should。
  • 召回相关但答案不完整:确认过滤是否过窄,并提高候选数量,而不是立刻放弃硬约束。
  • 权限字段缺失:默认拒绝,修复入库流程后再补数据;不要用“不过滤”作为兜底。

相关问题

元数据过滤能替代向量相似度吗?

不能。过滤只判断候选是否满足业务条件,向量相似度仍负责语义排序;两者解决的是不同问题。

为什么过滤字段有值仍然查不到?

优先检查实际存储类型、字段路径、时区和操作符。字符串数字与真正的数值字段不能混用。

所有 metadata 都要建索引吗?

不需要。为高频过滤字段建立匹配类型正确的索引,并根据过滤选择性和资源成本逐步增加。

可以在应用层过滤召回结果吗?

普通标签可以做补充过滤,但租户、权限、删除状态等硬约束必须在检索层生效,避免越权文档先进入上下文。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>