☰
RAG进阶实战:混合检索、分块与引用溯源如何提升LLM回答质量
2026/10/23 5:18:26 网站建设 项目流程

做过几个 LLM 问答项目后你会发现,单靠模型本身的知识去回答垂直领域问题,上下文稍微具体一点就答非所问,或者一本正经地编。RAG(检索增强生成)就是当前落地成本最低、见效最快的一剂补药,而这篇要聊的是 ACP-LLM 项目里 RAG 部分的第二个阶段。第一篇我们搭完了从文档解析、向量化到检索生成的基础链路,这一篇会把决定线上效果好坏的进阶环节逐个拆开,不只讲怎么选,更要讲清楚为什么选它,以及那些文档里根本不会写的坑。

1. 进阶 RAG 的整体设计与一条链路上的取舍

1.1 基础 RAG 跑通之后,下一步瓶颈出在哪

先快速对齐一下基础链路的形态。文档进来后做解析、清洗、分块、向量化,然后把向量写入向量数据库;回答问题时,拿到用户 query 向量化,在库里做 ANN 近似最近邻检索,取回 Top-K 个片段作为上下文,连同问题一起交给 LLM 生成答案。这个流程初版不难,但一旦放入真实业务场景,问题立刻暴露。

我在实际项目里遇到最多的三类瓶颈,基本代表了 RAG 进阶要解决的核心矛盾。

第一类是召回精度。向量检索对这种语义匹配场景很友好,但它本质上是将“相关性”压成一个向量距离,两个语义相似但表述结构差异很大的句子,向量距离未必近。更多时候,用户 query 里包含精确关键词、编号、型号,这类信息靠纯向量检索往往丢分严重,Top-K 里真正可用的片段经常不足一半。

第二类是上下文质量。检索回来的片段数量是有限的,如果分块大小不合适、块内混入大量噪声,或者多轮对话中用户意图本身模糊,那么拼给模型的上下文既浪费 token,又干扰最终答案。这里的问题通常不是模型能力,而是输入的信息密度太低。

第三类是生成可靠性。模型拿到相关片段之后仍然可能偷懒不引用原文,或者把多个片段的信息串在一起编出新内容。这类问题靠调 prompt 能压一部分,但根源在于检索端有没有提供足够忠实、清晰的证据结构。

基础 RAG 能回答“能跑吗”,但回答不了“跑得好不好”。进阶阶段的核心工作,是把这条链路从可用推到好用。

1.2 进阶阶段的路线图:每一环都在解决一个失真问题

在 ACP-LLM 的第二阶段,我的设计主线是围绕信息失真去做补偿。数据从原始文档到最终答案,中间要经历语义保持、位置保持和相关性保持,任何一个环节失真都会直接体现为答案质量下降。

所以整体拆成这样几条工作线。文档层做清洗与结构化提取,解决原始信息颗粒度不一致的问题;分块层做递归与结构化分块,解决语义撕裂的问题;索引层做向量与关键词的混合检索,解决单一检索策略各有盲区的问题;生成层做引用回溯与精简上下文,解决模型不信不忠实利用证据的问题。

这条路线和做索引的思路很像:先保证数据被正确写入,再保证查询能精准命中,最后保证命中的结果能以高质量格式输出。每一条线之间是递进关系,前面做不好,后面优化的空间非常有限。这篇的实际操作顺序也建议从文档处理开始,而不是先想着微调模型或者换更大的模型。

2. 文档预处理与分块策略,这是最容易被低估的一层

2.1 文档清洗和结构化提取的实操要点

经常有人把 PDF 扔进解析器,拿出来的文本又乱又碎,就直接丢进切分器。这样后面的向量化基本是在垃圾堆里找黄金。文档级预处理的核心目标只有一个:把“给人看”的排版信息还原成“给模型看”的语义单元。

我的标准流程是三步。第一步做解析,把 PDF、Word、HTML 各自转成纯文本或 Markdown;第二步做规则清洗,去除页眉页脚、多余换行、表格错位、OCR 噪声;第三步做结构识别,尽量把标题层级、段落边界、表格结构标记出来。第三步的产出直接影响分块质量,因为后续分块要依据标题和段落边界做切分。

清洗这一步有几个容易忽略的细节。PDF 解析出的文本经常会在表格和双栏布局上乱序,常见的正则没法处理,建议优先看解析器输出的坐标信息,按坐标排序后再拼接,收益很大。另外,段落中如果出现箭头、项目符号等冗余字符,要设计黑名单替换,避免这些符号混进向量特征里。

表格数据是一个特殊项。直接把表格拍平成一行文字,会让细胞之间的语义关系丢失。我的做法是保留 Markdown 表格结构,并在分块时把表格作为一个整体块处理,而不是和上下文混切。这样检索到表格时,模型看到的是完整行列关系,而不是被切碎的单元格。

2.2 固定分块、递归分块与结构化分块怎么选

分块大小和重叠率是一个流传很广的经验参数,网上说法从 256 到 1024 不等,实际上没有一个万能值。分块太小,语义上下文不完整;分块太大,向量平均化之后精度下降,且浪费上下文窗口。

我用的基准策略是递归字符分块,核心是层级回退:先用段落标记切分,如果块太小,向上升级到章节;如果块太大,向下递归到句子级别。这个策略能让块的大小尽量跟随语义边界,而不是被硬切。

结构化分块是在递归分块之上叠加元信息。切分时把当前块所属的标题路径、文档名、页码记录下来,组成类似这样的块结构:

{ "content": "块正文内容...", "metadata": { "doc_id": "manual_v3_12", "chapter": "3.2 故障诊断", "section": "3.2.1 电源指示灯异常", "page": 8 } }

这个 metadata 后面有两个用处。一是检索时可以做过滤,用户只查某个章节时直接在库层先过滤再检索;二是生成时可以把标题路径回填进 prompt,模型能明白这段内容的上下文位置,回答会可靠很多。

分块重叠率我一般控制在 10% 到 15%。重叠的目的是防止检索时句子被从中间截断,但重叠太多会让库里出现大量近似重复的向量,既占空间,又容易在召回时出现同一段话的多个变形体挤占 Top-K 名额。

2.3 分块中的常见错误:硬切句子和过度切分

犯过最多次的错误是硬按固定字数切分,比如 char_split 一下按 500 字符切。这种切法会让句子、表格、列表项被拦腰截断,检索时虽然也能命中,但召回片段往往缺失结论或前提,模型只能靠猜。后期评估时会发现这类块贡献了相当比例的幻觉样本。

另一个坑是过度追求块粒度小,以为块越小匹配越精确。试过 200 字左右的小块,匹配率确实看起来高,但生成时模型缺乏上下文来理解指代关系,比如块里出现“该方法”却不知道方法主体在上一块。小块方案必须搭配强大的重排序和上下文归并机制,否则不如稳妥用 400~600 字的中块。

3. 向量化、混合检索与重排序,召回质量的关键引擎

3.1 Embedding 模型选型:按语言和领域综合判断

向量化是对语义的一次投影,embedding 模型的能力直接决定了后续检索的上限。选模型时我主要看三点:语言覆盖度、检索能力、以及句长支持。

中文场景下,建议优先找在中文语料上有充分训练的开源模型,而不是直接用英语模型。通用域模型跑垂直领域文本时也需要验证,因为领域术语的语义表示差异很大。选型时必须做一件事:自己构建一个几十条的领域测试集,把模型逐个跑一遍,计算 Recall@K。

有一个容易被忽略的点是 query 和 document 的表示不对称问题。很多模型在训练时对 query 和 document 采用了不同的编码方式,比如一个模型输出维度为 1024,但内部对短 query 和长文本各有独立优化。实际使用时要按模型建议的规范拼接输入,不要随手把 query 直接塞进文档编码接口。

另外,embedding 模型不是越新越好,而是越匹配越好。评估指标上,我会重点看中等召回数量下的命中率,比如 Recall@10 是否够硬,而不是只盯着单一分数。同时要看模型对长文档的编码稳定性,有些模型超过 512 token 之后向量质量急剧下降,这决定了分块大小上限。

3.2 向量索引参数:关于 ANN 的误区

向量数据库的检索性能靠索引实现,常见的是基于图的近似索引。这里的参数选择存在很多想当然。很多教程会告诉你调 M 和 efConstruction,但没人解释这两个参数的控制范围。

M 控制每个节点的连接数,影响索引的稠密程度。M 越大,查询精度越高,但索引体积和内存占用也越大。efConstruction 是构建图时的动态候选集大小,影响索引质量,构建完成后不再参与查询。查询时还有一个 ef_search,决定检索时的探索范围,这才是线上可动态调的精度开关。

我的建议是,索引构建阶段 M 值可以设大一点确保质量,比如 16 到 32,efConstruction 设 200 到 400。线上查询把 ef_search 设为一个中间档位,如果召回率不够再往上加,而不是一开始就把索引建得很粗。做索引耗时是个一次性成本,但查询延迟是每个请求都要付出的,精度与延迟的平衡点在更新 ef_search 时找。

3.3 混合检索:让精确匹配和语义检索互补

纯向量检索在长尾专有名词上表现不稳定,最典型的例子是用户搜索一个设备型号,比如“ABC-200 电源故障”,向量召回的结果可能全是泛泛的电源知识,而真正包含这个型号的文档片段排在后面。这种问题用混合检索几乎是必解:向量检索负责语义相关,关键词检索负责精确命中。

关键词侧我常用 BM25 算法,核心思想是词频和稀有度加权,对精确匹配非常友好。混合检索要做的是把两个结果列表按同一标准融合。直接用分数加权容易出问题,因为向量分数和 BM25 分数分布不一致。我更倾向于先做倒序归一化,把位置信息转成分数,再按权重融合。

权重设定需要动态观察。预设词命中密集的 query 上,比如用户粘贴了一段报错日志,关键词权重应加大;纯语义表述的 query,比如“如何判断设备过热风险”,向量权重应加大。线上实现可以做一个简单的 query 分析,按包含的专有名词数量、引号比例、文本长度来选择权重,实测比固定权重稳定很多。

3.4 重排序:最后一道精排关卡

检索阶段为了召回率,往往会取回较多片段,比如 Top-20。直接把这 20 个片段全部塞给模型非常浪费且有害。重排序环节用更强的模型,对 query 和每个片段做精细相关性打分,再用分数挑出 Top-5。这个思路和经典搜索里的粗排、精排两段式完全一致。

重排序模型普遍对中文有专门优化,使用体验上最大的区别在于输入形式。有些重排序模型支持交叉编码器,把 query 和文档拼接后打分,精度高但计算量随文档数线性增长。好在 Top-20 这个量级完全扛得住。重排之后的效果提升通常非常明显,我见过不少项目不加重排时答案质量差得明显,加上之后肉眼可见改善。

这里有一个细节:重排分数的绝对值不能跨请求比较,它只用于本请求内部的片段排序。所以不要试图设置一个全局限定阈值去过滤,而是宁可保留固定数量,比如始终取 Top-5,让后续生成策略去兜底。

4. 生成侧优化:上下文编排、引用溯源和多轮对话

4.1 Prompt 模板怎样才让模型愿意用上下文

生成阶段最常见的误区是 prompt 里堆满指令,什么“你必须严格根据上下文回答”“不要编造”,但上下文本身一团乱。模型不是不愿遵循,而是不知道该信谁。

我的模板设计原则很简单:上下文放在前,问题放在中,约束放最后。上下文用清晰的标记区分每一条来源,并带上 metadata 里的标题路径。这样模型能知道每段文字的出处语境。

一个可复用的模板结构大致是:

【背景资料】 来源1(标题:xxx 章节:yyy) 内容... 来源2(标题:xxx 章节:yyy) 内容... 【用户问题】 问题... 【要求】 1. 优先依据背景资料回答,若资料不足,请明确说明缺失信息。 2. 引用资料中的关键依据时,请标注对应来源编号。 3. 不要将不同来源的信息拼接成不存在的事实。

实测里,把来源编号和标题路径写清楚之后,模型的“幻觉”明显减少,而且回答更结构化。这不全靠 prompt 技巧,本质上是你给模型提供了足够的证据链。

4.2 引用溯源:给每个答案装上定位锚点

RAG 落地到企业内部,用户不只是要一个答案,还要能核验。引用溯源的核心是让生成结果和检索片段建立对应关系。实现上可以在 prompt 要求模型在引用依据后输出编号,后在解析层把模型输出的编号映射回 metadata 的文档标题和页码。

做引用映射的时候要注意一个细节:模型生成的编号不一定对应 prompt 里的原始编号,偶尔会自己乱写。所以解析之后要做一次校验,检查引用的片段编号是否真实存在于本次检索结果中,不存在就把引用标记为无效。校验不通过时宁可显示“AI 生成,无直接引用”,也不要让用户被错误引用误导。

4.3 多轮对话:query 改写是绕不开的

RAG 里的多轮对话不能直接把用户当前这句话拿去检索。用户说“那它的功率呢”,如果你不知道“它”指代的是什么,检索一定会偏。我的做法是引入 query 改写模块:利用 LLM 把整段对话历史中的指代信息,改写成完整、独立的检索 query,再拿去向量化检索。

这里有更省事但不太可靠的做法是直接把最近几轮对话拼接后检索,试过之后发现拼接的噪声会把语义带偏。改写显然更干净。

改写后的 query 要用好。另一个实用技巧是改写模块返回两种结果:一个用于检索的完整 query,一个用于生成阶段展示的用户原始 query。生成阶段仍然用用户原话来提问,避免模型被改写后的措辞带歪。

5. 评测体系与问题排查实录,让效果可量化

5.1 怎么搭建一套不骗自己的评测集

RAG 改进如果没有评测,基本属于自嗨。要判断某个环节是否真的有效,关键是有一套固定的评测集和标准指标。我建议按场景构建百条级别的评测样本,每一条包含:标准 query、对应的黄金片段列表、可接受答案要点。

离线评测时我会同时看四个维度:检索命中率、上下文精确率、生成忠实度、答案有用率。检索命中率反映检索端能不能找回黄金片段;上下文精确率看找回的 Top-K 里有多少是真正相关的;生成忠实度看答案是否能从上下文中推出;答案有用率则让评测者手工判断最终答案能不能直接用。

线上效果观测也要做。在日志里记录每次问题的检索 Top-K 来源、最终引用来源、用户反馈,每周做一次抽样复核。如果发现线上失效案例大幅增长,通常不是模型出问题,而是新文档入库后分块不合理,或者检索权重需要调整。

5.2 高频问题与排查思路速查

整理一张速查表很有必要,我按实际踩坑频率排过序,大致如下:

现象优先排查方向常见解决方式
问题上千条但答案经常错误分块是否撕裂语义边界换成递归结构分块,观察命中块边界
专有名词、编号检索不到纯向量检索盲区引入 BM25 混合检索
召回了相关片段但答案仍花式编造上下文信息密度低或模板未引导引用精简 Top-K,加来源编号和引用要求
片段内出现截断的解释说明分块固定字数硬切割增加重叠率或按句子边界切分
相似问题反复回答不一致缺乏评测基线构建评测集,锁定参数版本
检索延迟波动大ef_search 参数过大或召回量过大固定召回数量,逐步调低 ef_search
新文档录入后质量明显下降清洗规则未覆盖新格式检查解析坐标、扩展清洗规则

排查思路上有一点值得多讲:出现质量问题时不要把锅都推给 embedding 模型。先用一个已知问题样例,把检索层的 Top-10 打印出来,肉眼判断片段是否相关。如果片段都无关,优先查索引和检索策略;如果片段相关但答案错误,再去查生成 prompt 和模型选择。这个二分定位法效率最高。

5.3 环节级别还是微调,先提升 RAG 管线

总有人问“是不是应该微调一个领域模型”。我的经验是:在 RAG 链路还没调稳之前,做模型微调属于奢侈行为。微调解决的是输出风格和领域格式问题,不能解决知识缺失。先把检索召回和上下文编排做好,如果此时答案质量已经达标,再考虑用少量高质量问答对做输出格式微调,让模型更贴合业务语气。

有个数据点值得记录:在一次实际对比中,仅靠混合检索与重排序,把领域问答的忠实度从 68% 提升到了 81%,而仅换更大参数量的底座模型,提升只有 3%。这说明大部分收益来自信息供给的准确性,而非推理能力的增强。经费有限的情况下,优先把 RAG 管线里的数据链路做好,投入产出比远高于直接升级模型。

根据我的实际操作经验,RAG 项目里见效最快、最少走弯路的一件事,是第一时间建立评测闭环。不要等系统上线后再靠用户反馈来发现问题,离线百条评测样本就能拦住大部分明显 bug。做评测时也别追求自动化到极致,先从半人工开始,边跑边看检索片段和答案可以积累很多一手感觉。等你能准确说出“这种问题大概会挂在分块上”“这种问题多半是检索权重不对”时,这套系统的稳定性就真正立住了。

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

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

立即咨询