☰
RAG检索重排与引用溯源:怎么找到真正有用的资料?面试加分项
2026/10/10 6:14:12 网站建设 项目流程

检索、重排与引用溯源:怎么找到真正有用的资料

作者:利威尔xu | CSDN 专栏《RAG 保姆级实战:从原理到落地》


前言

在第四篇《向量数据库》里,咱把向量和向量数据库拆开了讲。向量是文字在高维空间里的坐标,Embedding 把语义相近的文字映射到相近的位置,向量数据库解决的是海量向量怎么快速找到最相似的几条。

这个专栏一共 6 篇,从 RAG 概念、降幻觉武器库、流程与切分、向量与向量库,到检索重排与引用溯源、落地坑与评估,一路走下来你能完整搞懂 RAG。

那检索出来的东西怎么用?为什么光靠向量检索还不够?为什么要重排?引用溯源到底解决什么问题?

这篇,咱把 RAG 的第五步和它周边的配合环节拆开来讲——检索结果怎么用,比检索本身更重要。


一、混合召回:光靠向量不够

你可能觉得,向量检索已经很强大了,语义相近就能找到,还有什么不够的?

讲真,光靠向量还真有盲区。

向量检索擅长的是语义匹配,但有些东西它不敏感。专有名词、订单号、人名、数字编码——这些精确的信息,向量检索搞不定。你问"订单号 A12345 的状态是什么",系统拿到的是一批语义相关的文档块,里面可能根本没有 A12345 这个号码,因为向量相似度跟精确字符匹配是两码事。

反过来,关键词检索(BM25)擅长精确匹配。你搜"A12345",它就找包含这串字符的记录,但搜"怎么查订单",它找不到"订单状态查询"——因为字面对不上,同义词它不懂。

那怎么办?答案是混合召回。

你可以把它想象成秘书整理材料。秘书收到你一个指令,不会只翻一本档案,他会把几本档案同时翻,然后综合判断。向量检索翻的是"语义档案",关键词检索翻的是"文字档案",两路结果合并起来,比单独用哪一路都全面。

混合召回的基本思路是这样:用户问一个问题,同时跑向量检索和关键词检索,得到两组候选结果。这两组结果的评分体系不一样,向量是相似度分数,关键词是词频分数,不能直接比。通常的做法是给两路结果分别归一化,然后按某个权重(比如 7:3 或者 6:4)加权合并,再按最终分数排序,取 top-k。

权重怎么定?没有标准答案,跟你的数据特点有关。如果你的文档专有名词多、编码多,关键词那路权重可以高一点;如果文档偏自然语言、语义复杂,向量那路权重可以高一点。调一调,看效果。

为什么放这段代码?展示混合召回的基本形态,理解向量检索和关键词检索怎么合并。

// 混合召回:向量检索 + 关键词检索合并funchybridSearch(querystring,topKint)[]SearchResult{// 向量检索:先查向量库queryVec:=embedText(query)// 问题转向量vectorResults:=vectorDB.Search(queryVec,topK*2)// 关键词检索:BM25 查原始文本bm25Results:=bm25Index.Search(query,topK*2)// 归一化 + 加权合并scored:=mergeAndScore(vectorResults,bm25Results,0.7,0.3)sort.Slice(scored,func(i,jint)bool{returnscored[i].score>scored[j].score})returnscored[:topK]// 取 top-k 精排候选}

这段代码在干嘛?混合召回的简化流程:先并行跑向量检索和关键词检索,各取两倍 top-k 的候选;然后归一化两路分数,按 7:3 的权重加权合并;最后排序取 top-k 作为精排候选。实际代码里归一化逻辑要处理分数分布差异、权重要可配置,这里只展示最基本的数据流。为了代码清晰,这里省略了常规的错误处理和相关逻辑,实际生产代码中务必加if err != nil判断。

面试官可能追问:混合召回为什么比纯向量检索更好?

答:向量检索和关键词检索各有盲区。向量检索对精确词不敏感,搜"订单 A12345"可能找到一批语义相关但不包含这个订单号的文档;关键词检索不懂同义词,搜"退款流程"找不到"退货步骤"。混合召回把两路结果合并,取长补短——语义相关性和精确匹配同时考虑,召回质量更高。实际业务里,纯向量检索往往不够用,混合是常见做法。


二、重排:给检索结果再排一次序

混合召回拿到了候选结果,但这些候选直接交给大模型还不够。

你想想餐厅上菜的场景。厨师做完一桌菜,端上来的顺序是有讲究的——冷菜先上、热菜后上、主菜压轴。如果你把一桌菜一股脑全堆到客人面前,体验就很差。

检索也是一样。第一轮召回追求的是快,可能一口气拉回来几十条、上百条候选,质量参差不齐,有的相关度高,有的相关度低。如果直接把这几十条全部塞进 Prompt,模型看着一堆资料反而容易挑花眼。

重排就是第二轮精排——给检索结果再排一次序。

重排用的是比向量模型更重的打分模型,比如 Cross-Encoder。Cross-Encoder 把查询和候选文档一起喂进模型,输出一个相关度分数。因为它看到了查询和文档的完整上下文,打分比向量检索那种"隔空比相似度"的方式精准得多。

重排和召回的区别,咱打个"初筛和面试"的比方。HR 收简历,一天可能看几百份,靠的是关键词过滤——学历、工作年限、技术栈,这是初筛,快但粗糙。通过初筛的几十份进入面试,面试官一页一页细读,问技术细节,评判更准确。重排就是面试,初筛就是召回。

当然,重排有代价。Cross-Encoder 比向量模型慢很多、贵很多,不可能对几千条候选全部重排。所以通常是先召回 50 条、100 条候选,再重排取 top-5、top-10。这是一个速度和精度的权衡。

面试官可能追问:召回和重排有什么区别?

答:召回追求速度,重排追求精度。召回在海量文档里快速拉回一批候选,可以用向量检索、关键词检索、混合召回,延迟要低;重排对候选逐一精打细算,用 Cross-Encoder 等重型模型重新打分排序,结果更准但更慢。实际链路通常是先召回再重排——先用快的过滤大批量,再用准的选出精华。一个比喻:召回是初筛简历,重排是细读面试。


三、Prompt 编排:把检索结果塞给大模型

好,检索结果排好序了,接下来要把它们塞进 Prompt 交给大模型。

但这里有个问题——不能一股脑全塞进去。

塞给厨师做菜的食材是要讲究搭配的。主料配料要配比,摆盘顺序有讲究,量太大客人吃不完,量太小不够吃。Prompt 编排也是这个道理。

给大模型塞检索结果,有几个要点要注意。

第一,文档块要排序。模型对 Prompt 开头和结尾的内容最敏感,中间的内容容易被忽略——这叫"位置偏见"。所以最相关的文档块要么放最前面,要么放最后面,不要塞在中间吃灰。

第二,控制总长度。大模型上下文窗口有限,Prompt 塞太满,有用的信息反而放不下。一般建议检索结果加上问题和其他指令,不要超过上下文窗口的 70%,留点余量给模型发挥。

第三,加分隔符和标记。让模型清楚知道哪些是用户问题、哪些是参考资料、哪些是要求它输出的格式。常见做法是用 XML 标签或者 Markdown 格式区分,比如## 参考资料、## 用户问题,结构清晰了模型不容易混淆。

第四,要求引用来源。Prompt 里要明确告诉模型"根据文档 [1]、文档 [2] 回答",并在输出里标注每段答案对应哪个文档。这个要求要写进系统 Prompt 里,不然模型可能自己发挥,不引用资料。

为什么放这段代码?展示 Prompt 拼接和引用标注的基本形态。

// Prompt 编排:拼接检索结果 + 引用要求funcbuildPrompt(querystring,chunks[]Chunk)string{// 构造参考资料部分refs:=""fori,chunk:=rangechunks{refs+=fmt.Sprintf("[%d] %s\n\n",i+1,chunk.Text)}// 组装完整 Promptprompt:=fmt.Sprintf(`你是问答助手。请根据以下参考资料回答用户问题。 如果答案在资料中,引用来源编号,例如"根据 [1]"。 用户问题:%s 参考资料: %s`,query,refs)returnprompt}

这段代码在干嘛?Prompt 拼接的简化示例:把检索到的文档块编号排列,构造参考资料段落;然后把用户问题、引用要求和参考资料组装进系统 Prompt,返回完整 Prompt 字符串。实际代码里要处理长度截断(如果 chunks 太多太长)、角色设定(system/user 分离)、引用格式规范化,这里只展示最基本的数据流。代码块里用了多行字符串,实际使用时要注意去掉行首缩进,避免多余空格进到 Prompt 里。为了代码清晰,这里省略了常规的错误处理和相关逻辑,实际生产代码中务必加if err != nil判断。


四、引用溯源:RAG 相对微调最能打的优势

讲到这儿,RAG 的检索链路基本串起来了。但还有一个环节值得单独拎出来讲——引用溯源。

你可能觉得,检索结果都塞给模型了,模型回答了,问题不就解决了吗?为什么要溯源?

咱用论文的脚注来打比方。

你看一篇学术论文,引用了别人的研究,会在页脚标上出处。读者觉得这个结论可疑,可以翻到脚注看原始文献。脚注是学术诚信的基础,也是读者信任的来源。

大模型生成回答也一样。你告诉用户"根据参考资料,退款需要在 30 天内申请",用户凭什么信你?用户得能查:哪篇文档哪一段说的?什么时间发布的?出自哪个部门?

引用溯源解决的就是这个问题——让模型的回答可查证、可审计。

这在金融、医疗、法律、客服等场景是硬需求。你做金融问答,用户问"这家公司的负债率是多少",模型给出一个数字,用户要能查这个数字来自哪份财报。你做医疗问答,模型说"这种情况建议用某药物",用户要能查这句话出自哪篇临床指南。答错了要能追责,答对了要能溯源。

微调为什么做不到?微调把知识揉进模型权重里,说不清哪条知识来自哪里。模型能回答,但它回答的依据是什么,没人知道——连模型自己也不知道。这在需要对答案负责的场景,是硬伤。

RAG 天然支持引用溯源,因为答案的来源是检索出来的文档块,文档块有 ID、有内容、有元数据。实现思路很简单:检索的时候保留文档 ID 和元数据(比如文档标题、发布时间);Prompt 里要求模型引用来源;返回答案的时候同时返回引用列表,关联到原文。

举个好操作的例子。用户问"退货政策是什么",检索结果里有一块来自文档 ID 为 “policy-v2.3” 的文档,标题是"2024 年售后服务条款",内容是"退货需在签收后 30 天内申请"。Prompt 里告诉模型"如果答案来自参考资料,请标注来源,例如 [policy-v2.3]"。模型回答:"根据 [policy-v2.3],退货需在签收后 30 天内申请。"返回结果里附上这块文档的完整内容,用户点开就能看到。

面试官可能追问:引用溯源为什么是 RAG 相对微调的优势?

答:微调把知识编码进模型权重,说不清来源。模型能回答,但为什么这么答、依据哪条知识,没人知道,连模型自己也不知道。RAG 的答案是从检索到的文档里生成的,文档有 ID、有内容、有元数据,可以标注来源、可以追溯、可以审计。在金融、医疗、法律、客服等需要对答案负责的场景,这是硬需求,微调满足不了。


五、完整检索链路收拢

把之前的内容串一下,咱看看完整检索链路是怎么走的。

用户提问 → 同时跑向量检索和关键词检索(混合召回),拿到候选 → 用重排模型对候选逐一打分排序(重排)→ 取 top-5 或者 top-10(精筛)→ 把这几块文档编排进 Prompt,标好引用(Prompt 编排)→ 交给大模型生成回答 → 返回答案和引用,引用关联到原文(引用溯源)。

这就是 RAG 检索侧的全流程。

回顾一下 RAG 六步的位置:加载和切分咱在第三篇讲了,向量化和存储在第四篇讲了,检索和生成就是这一篇的内容。但检索不是孤立的——它依赖前面的切分质量(切分不对,检索再好也白搭)、依赖向量化模型的语义表达能力(Embedding 不准,向量库再快也是垃圾进垃圾出)。六步是一个整体,每一步都影响最终效果。


六、落地常见坑,先提一嘴

趁这块地盘,先给你们打几剂预防针,后面第六篇会专门展开。

最常见的坑是只靠向量不混合。以为向量检索能包打天下,结果业务里大量专有名词、编码、人名查不准,召回率上不去。

还有个坑是重排模型太重拖慢响应。Cross-Encoder 效果好,但延迟高,成本也高。选型的时候要看业务能不能接受,不能一味追求精度。

第三个坑是 Prompt 太长模型迷失。把一堆检索结果全塞进去,模型搞不清楚重点,回答飘了。Prompt 编排要克制,不是塞得越多越好。

最后一个坑是引用溯源没做元数据关联。检索结果有文档块,但没关联文档 ID、没保留元数据,生成回答的时候想引用但不知道该标哪个来源。引用溯源要从检索的时候就开始规划,不能等生成完了再补。


💡 本章面试要点

  1. 混合召回为什么比纯向量检索更好?
    向量检索擅长语义匹配,但对精确词不敏感——搜"订单 A12345"可能找到一批语义相关但不包含这个订单号的文档;关键词检索(BM25)擅长精确匹配,但不懂同义词——搜"退款流程"找不到"退货步骤"。混合召回把向量检索和关键词检索两路结果合并,归一化分数、加权求和,语义相关性和精确匹配同时考虑,取长补短。实际业务里,纯向量检索往往不够用,混合是常见做法。

  2. 召回和重排有什么区别?
    召回追求速度,重排追求精度。召回在海量文档里快速拉回候选,可以用向量检索、关键词检索或混合召回,延迟要低;重排对候选逐一精打细算,用 Cross-Encoder 等重型模型重新打分排序,结果更准但更慢。实际链路通常是先召回再重排——先用快的过滤大批量,再用准的选出精华。一个比喻:召回是初筛简历,重排是细读面试。

  3. Prompt 编排有哪些要点?
    四个要点:文档块要排序(模型对开头和结尾最敏感,相关度高的放这两头);控制总长度(不超过上下文窗口 70%,留余量给模型发挥);加分隔符和标记(让模型清楚区分问题、资料、输出格式);要求引用来源(Prompt 里明确写,让模型标注每段答案对应哪个文档)。Prompt 编排不是堆料,是克制——不是塞得越多越好。

  4. 引用溯源为什么是 RAG 相对微调的优势?
    微调把知识编码进模型权重,说不清来源,模型能回答但不知道为什么这么答,连模型自己也不知道。RAG 的答案是从检索到的文档里生成的,文档有 ID、有内容、有元数据,可以标注来源、可以追溯、可以审计。在金融、医疗、法律、客服等需要对答案负责的场景,这是硬需求,微调满足不了。引用溯源不是锦上添花,是 RAG 的核心竞争力之一。

  5. 完整检索链路是怎么走的?
    用户提问 → 混合召回(向量检索 + 关键词检索)→ 重排精筛(Cross-Encoder 打分)→ Prompt 编排(排序、分隔、引用标注)→ 大模型生成 → 返回答案和引用。六步环环相扣,向量检索依赖 Embedding 模型和向量库的质量,重排依赖打分模型,Prompt 编排决定模型能不能用好检索结果,引用溯源让答案可查可审计。任何一个环节掉链子,最终效果都好不了。


下篇预告

第六篇《RAG 落地常见坑与评估上线:怎么知道这套东西好不好用》,咱把 RAG 落地的最后一公里讲完——怎么评估 RAG 系统效果、常见坑怎么避、上线之后怎么监控调优。专栏一路从概念、原理、流程、切分、向量、检索走下来,第六篇是收尾,把"怎么知道好不好"这个问题答清楚。


如果这篇文章帮你搞懂了检索、重排和引用溯源,欢迎点赞、收藏、关注利威尔xu,咱们下篇见。

你们项目里检索链路是怎么设计的?重排模型选型踩过什么坑?评论区聊聊。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询