Skip to content

召回、重排与上下文预算 ​

召回要尽可能找全候选,重排在候选中辨别相关性,上下文组装决定模型最终看到的证据。三个步骤不能共享一个“相似度足够高”的口号:重排找不回没召回的文档,增加 top-k 也不能无限扩大模型窗口。

词法检索擅长型号与精确编号,向量检索擅长相近语义;用 Reciprocal Rank Fusion(倒数排名融合)合并名次可以避开两个分数尺度不同的问题。Cross-Encoder 把问题与候选一起编码,能比较更细的交互,但每一对都要计算,通常在少量候选上使用。这里先手工给定排序,单独检验预算算法。

python
ranked = [
    {'id': 'a', 'parent': 'p1', 'tokens': 7, 'text': '适用对象与规则'},
    {'id': 'b', 'parent': 'p1', 'tokens': 5, 'text': '重复规则'},
    {'id': 'c', 'parent': 'p2', 'tokens': 4, 'text': '例外条件'},
]
def pack(items, budget):
    selected, parents, used = [], set(), 0
    for item in items:
        if item['parent'] in parents or used + item['tokens'] > budget:
            continue
        selected.append(item)
        parents.add(item['parent'])
        used += item['tokens']
    return selected, used
chosen, used = pack(ranked, 11)
assert [x['id'] for x in chosen] == ['a', 'c']
assert used == 11
assert pack(ranked, 3) == ([], 0)
print([x['id'] for x in chosen], used)

本例按父文档去重是刻意简化:同一父文档可能有两个互补证据,不能生产照抄“一父一片”。改用片段重复率、MMR 多样性或按问题所需字段选证据时,要检查例外条款仍保留。贪心装箱也不保证预算下整体信息量最优。tokens 是已知测试值;在线应使用真实 tokenizer,并计入标签、问题、系统说明和预留输出。

对话、改写与拒答 ​

“那它能退吗?”需要先从已知对话恢复“它”的对象,再检索;改写不得增加用户未说过的型号。多查询让不同措辞各自召回后合并,但会扩大费用。HyDE 先生成假想答案用于检索:假想内容只是查询信号,不是事实证据。自检式或 Agentic RAG 可以在证据不足时再次查找,但需要最大轮数、预算、稳定停止条件。

生成时把用户问题、证据和历史区分开,证据附文档名、版本、片段 ID。摘要压缩后仍要保留能回溯到原文的映射;摘要既可能遗漏,也可能产生新错。证据冲突时报告冲突和日期,不把多篇投票当作真相。超预算时先保留支持主张的完整片段,不截断否定词或例外条件。

若查询只需结构化值,直接抽取并校验比要求模型自由发挥更容易审计。SQL RAG 要用只读账户、参数化和行级授权;知识图谱适合沿关系追问,详细推导见图检索。这些分支仍需回到原始证据验证。

练习 ​

在候选最前面加入一个需要20 token的片段,预算仍为11。要求后面的a和c仍能入选,说明为何使用continue而不是break。

完成后查看本章答案。

下一篇:继续本章完整实验。

用心记录每一步成长