Skip to content

第 7 课:重排与上下文组装

RAG 课程 · 07 |目标:把“召回候选”变成“模型能有效使用的证据”|用时:25 分钟

初始召回追求覆盖率,结果往往包含重复、相似但不关键、缺少上下文或顺序混乱的 chunk。重排和上下文组装负责把候选集合变成高质量 prompt。

召回和重排不是一回事

text
召回:快速从大库找出可能相关的 20~100 个候选
重排:用更精细的模型重新判断候选与 query 的相关性

常见实现是双编码器负责第一阶段,交叉编码器负责第二阶段:

  • **Bi-encoder:**query 和 chunk 分别编码,向量可以提前建立索引,速度快。
  • **Cross-encoder:**把 query 和 chunk 一起输入模型,判断更细,但需要逐候选计算,速度慢。

因此 reranker 通常只处理初始召回的几十个候选,而不是扫描整个向量库。

重排应该看什么

相关性不只是“主题相似”,还包括:

  • 是否直接回答 query 的问题。
  • 是否包含完整条件、时间、例外和限制。
  • 是否来自当前租户和有权限的文档。
  • 是否是最新的有效版本。
  • 是否与已经选中的 chunk 重复。

一个重排结果至少应保留:

json
{
  "chunk_id": "leave-policy-annual-001",
  "retrieval_score": 0.82,
  "rerank_score": 0.94,
  "rank": 1,
  "source": "员工请假制度 / 年假"
}

不要覆盖初始分数。保留两阶段分数,才能判断问题发生在初始召回还是重排。

避免上下文重复

向量检索很容易返回相邻窗口或同一段落的重复版本。可以使用:

  1. chunk_id 去重。
  2. 按文本 hash 去重。
  3. 对同一 document_id + section 限制数量。
  4. 使用 MMR,在相关性和多样性之间做平衡。

MMR 的直觉是:候选既要和 query 相关,也要和已经选择的内容不同:

text
MMR(d) = λ × relevance(d, query)
        - (1 - λ) × similarity(d, selected)

λ 越大越重视相关性,越小越重视多样性。具体参数必须通过评测确定。

上下文组装的六个步骤

推荐把上下文组装做成显式函数,而不是简单的 "\n".join()

  1. **过滤:**执行权限、租户、版本和状态过滤。
  2. **重排:**按 reranker 分数排序。
  3. **去重:**删除完全重复或高度重叠的 chunk。
  4. **扩展:**必要时根据 parent_id 取回标题、邻居或父章节。
  5. **排序:**按相关性或原文档顺序组织,保留来源边界。
  6. **预算:**在 token 上限内选择最终上下文。

最终上下文最好显式标识来源:

text
[证据 1]
来源:员工请假制度 > 年假,页码:2
年假申请应至少提前 3 个工作日提交。

[证据 2]
来源:员工请假制度 > 病假,页码:3
病假超过 2 天时,需要上传医院证明。

这样既帮助模型区分证据,也方便用户检查引用。

不要把所有候选塞进 prompt

上下文越多不一定越好:

  • 无关内容会稀释关键信息。
  • 重复内容会增加模型误判概率。
  • 长上下文会增加延迟和成本。
  • 超过模型有效注意力范围后,答案可能反而变差。

一个可用的初始方案是:初始召回 20 个,重排后选择 3~5 个,再根据父章节扩展和 token 预算调整。这个数字只是起点,不是通用答案。

失败时如何判断是哪一层

现象优先检查
正确 chunk 不在候选中embedding、召回策略、metadata filter
正确 chunk 在候选中但排名低reranker、query 改写、候选数量
前几名都相关但信息重复去重、MMR、parent/neighbor 扩展
上下文相关但回答漏条件chunk 完整性、上下文顺序、prompt 约束
上下文过长且回答变差context_k、token 预算和文档扩展策略

本课练习

给定以下 5 个候选:

text
A:年假申请流程,提前 3 个工作日。
B:年假申请流程,提前三个工作日。(A 的重复版本)
C:病假超过 2 天需要医院证明。
D:员工考勤打卡异常处理。
E:年假余额查询方法。

query 是“请假需要提前几天申请”。请写出:

  1. 你会保留哪些候选?
  2. 哪些候选需要去重?
  3. 最终 prompt 中证据的顺序是什么?
  4. 如何保留来源和引用?

主读材料

Passage Re-ranking with BERT。重点理解为什么“快速初筛”和“精细重排”需要不同模型和不同计算预算。

下一步

有任何不清楚的地方,直接向老师提问。