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

RAG 怎样按文档版本过滤检索候选

来源:17golang原创

时间:2026-10-24 20:29:40 346浏览 收藏

RAG 同时保留 v1、v2、v3 时,不能指望向量距离自动理解“只回答 v2”。更稳的做法是:入库时把版本写进每个 chunk 的元数据,请求进入检索链路后先解析允许版本,再把版本条件和租户、文档条件一起放进向量库过滤器。这样候选集从源头就不会混入不应使用的旧内容。

要点速览
  • 版本字段是检索约束,不是提示词里的软要求。
  • 优先在向量检索阶段预过滤,避免 top-k 被旧版本占满后再丢弃。
  • 用有效候选率、版本命中率、p95 延迟和空结果率同时评估,别只看向量相似度。

先把版本语义从向量相似度里拿出来

建议每个切片至少保存 tenant_id、doc_id、version、version_rank、effective_from 和 superseded_at。其中 version 用于精确选择,时间字段用于“回答某个历史时点”的查询,version_rank 只适合排序或回退,不应单独充当访问边界。

字段检索用途常见边界
doc_id限定同一份文档文档拆分后所有 chunk 必须一致
version精确匹配 v2不要混用字符串和数字格式
effective_from按生效时间筛选时区和闭区间必须固定
superseded_at排除已被替代的内容回滚时不能直接物理删除旧版本

例如知识库允许用户指定“产品手册 v2”,检索请求应先得到 allowed_version = "v2"。如果请求没有版本,才按产品的默认发布策略解析出一个明确版本;不要把“最新”留给生成模型猜。

RAG 文档版本过滤说明图,展示 doc_id、version、有效时间元数据进入检索约束的关系
图1:RAG 文档版本元数据与检索约束的静态说明图,不是截图或运行证据。

把版本条件放进检索过滤器

以 Qdrant 为例,payload 过滤器的 must 表示条件全部满足。官方资料也建议为经常过滤的 payload 字段建立索引。下面的代码只演示“先锁定版本,再做相似检索”的关键关系,向量生成和客户端初始化省略。

官方地址:https://qdrant.tech/documentation/search/filtering/

from qdrant_client import models

def build_version_filter(tenant_id: str, doc_id: str, allowed_version: str):
    # 租户、文档和版本必须同时满足,防止旧版本或其他租户混入候选。
    return models.Filter(must=[
        models.FieldCondition(
            key="tenant_id",
            match=models.MatchValue(value=tenant_id),  # 先隔离租户
        ),
        models.FieldCondition(
            key="doc_id",
            match=models.MatchValue(value=doc_id),  # 再限定文档
        ),
        models.FieldCondition(
            key="version",
            match=models.MatchValue(value=allowed_version),  # 精确版本约束
        ),
    ])

query_filter = build_version_filter("tenant-a", "pricing", "v2")
result = client.query_points(
    collection_name="knowledge_chunks",
    query=query_vector,
    query_filter=query_filter,  # 过滤发生在候选检索阶段
    limit=8,
    with_payload=True,
)

如果版本不是离散标签,而是按时间回放,可以把 version 换成 effective_from 与 superseded_at > query_time 的范围条件。两种语义不要混在一个字段里,否则回滚和审计时很难解释“为什么这段内容被选中”。

多版本系统还要处理索引和写入的一致性:先写入带完整元数据的 chunk,再把该版本标记为可检索;删除或替代旧版本时保留可追溯标记。Qdrant 的分支检索示例也采用 payload 条件和覆盖标记来解析某个分支可见的版本。

RAG 版本过滤检索链路说明图,展示请求版本、must 过滤、向量召回和答案上下文的关系
图2:版本过滤检索链路的静态结构图,展示候选先过滤再排序的边界。

用基线和压测指标判断是否真的改善

不要只比较平均耗时。先记录“混合版本召回后再过滤”的基线,再记录“带版本条件的预过滤”结果。下面是一个用于设计压测报表的示例,数字是说明格式的原创假设,不是某个向量库的固定承诺。

方案有效候选率p95 延迟空结果率
先召回 20 个再丢旧版本84%310 ms8.6%
版本字段预过滤后召回 8 个96%190 ms3.1%

这里的有效候选率指 top-k 中真正满足版本约束的比例,版本命中率则要单独核对最终上下文。生产压测至少固定:同一批问题、同一 embedding 模型、同一 top-k、版本分布、索引状态和冷/热缓存。否则一次换模型或换缓存状态,就无法判断收益来自过滤还是来自别的变化。

如果版本过滤后空结果率反而升高,不要立刻放宽到所有版本。先确认请求解析出的版本是否存在、过滤字段类型是否一致、索引是否覆盖该字段,以及当前版本是否完成了“可检索”发布。只有业务明确允许回退时,才按 v2 → v1 的顺序做第二次查询,并在答案中记录实际命中的版本。

版本过滤失效时按这张清单排查

  • 结果混入旧版本:检查过滤器是否真的传给 query 接口,而不是只写进提示词;再抽样打印返回 payload 的 doc_id 和 version。
  • 过滤后没有结果:检查版本值的大小写、类型、租户字段和索引构建状态;不要用“版本不存在”掩盖写入延迟。
  • 回滚难以解释:保留版本和替代关系,用明确的发布状态控制可检索性,不要覆盖原 chunk。
  • 性能忽高忽低:同时记录过滤命中数量、索引命中情况、top-k 和 p95,避免只看平均耗时。

常见问题

只在生成提示词里写“使用最新版本”可以吗?

不建议。提示词约束是软规则,无法阻止旧版本进入上下文;版本字段应在检索阶段过滤,提示词只负责解释已选上下文。

文档版本和 chunk 版本必须都保存吗?

至少要让每个 chunk 能追溯到文档版本。通常保存 doc_id 与 version 最清楚,必要时再加生效时间和替代关系。

过滤后候选太少怎么办?

先提高该版本的切片覆盖率或调整切片策略,再考虑有审计记录的版本回退;不要直接取消版本过滤来换取表面上的召回数量。

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