我让大模型“查书”再回答:RAG 是怎么把幻觉降下来的
让大模型先查书再开口:我把 RAG 完整落地了一遍
这两年做大模型应用,最常被业务方追问的一句话就是:“它会不会乱说?”确实,大模型什么都能聊,但一到企业内部的规章制度、产品参数、项目流程,它就经常一本正经地给你编一套答案。我在实际项目里见过太多次这种“自信满满的错误回答”了,说实话,这已经不是模型够不够聪明的问题,而是技术方案本身有没有把“事实依据”这条链路做扎实。
后来我把 RAG(Retrieval-Augmented Generation,检索增强生成)完整落地到企业知识库问答场景里,幻觉率肉眼可见地降了下来。RAG 的思路其实一句话就能讲明白:先让模型去你自己的资料库里“查书”,把相关文档片段捞出来,再基于这些片段组织回答,而不是让它凭记忆硬答。这篇文章我就围绕这个思路,把我在真实项目里怎么一步步把幻觉压下来、中间踩过哪些坑、参数怎么调,全部拆开讲一遍。如果你正准备做企业内部问答、文档助手、智能客服这类应用,这篇文章应该能帮你少走不少弯路。
1. 先想明白:幻觉到底是怎么来的,RAG 又是怎么对症下药的
1.1 大模型的“一本正经胡说八道”不是偶然
要想让 RAG 发挥作用,得先理解大模型为什么会“编”。本质上,大模型是一个超大的文本接龙器。它看到你输入的一句话,会基于训练阶段从海量语料里学到的统计规律,逐字猜下一个最可能出现的词。它并不是先去数据库里查到“正确答案”再回答,而是直接根据概率分布生成一段最像样的话。
问题就出在这里。模型训练数据是有截止时间的,训练语料也不可能覆盖企业内部那些琐碎、冷门、甚至根本没公开过的内容。当用户问到一个超出模型知识覆盖的问题时,它没有事实依据可引用,就只能靠概率和联想“补全”一段看起来合理的内容。这就是我们常说的幻觉。最麻烦的是,这种幻觉往往语气笃定、逻辑自洽,用户如果不专门去核对,根本不知道它是错的。
我在项目里遇到过最典型的翻车现场:员工问公司某套冷门系统的操作流程,模型居然给出了一段格式规范、步骤完整、但内容完全不存在的 SOP,连责任部门的名称都给改了。这种错误比“回答不出来”危险得多——回答不出来,用户知道要去翻文档;一本正经地答错,用户就照着错了。
1.2 RAG 解决的其实是“有依据地回答”这件事
RAG 的思路,说简单点就是“开卷考试”。它不修改模型的参数,也不重新训练模型,而是在用户提问之后,先从一个预先构建好的知识库里检索出与问题最相关的文档片段,再把这些片段拼接到 Prompt 里,最后让模型“看着材料回答”。
这个转变很关键。原来的模型是闭卷考试,全靠脑子里那些模糊的参数记忆,遇到不会的只能编;RAG 之后变成开卷考试,正确答案就在手边的材料里,模型只要具备基本的阅读理解能力,就能把材料里的信息整理成回答。你问它公司报销流程,它不再凭训练数据里的通用常识乱答,而是先去知识库里捞到那份真实的报销制度文档,然后照着制度内容回答。
我落地之后的体会是,RAG 对幻觉的抑制不是靠单一环节发力,而是靠整条链路共同作用。检索结果准不准、文档片段切得好不好、Prompt 组装规不规范,任何一个环节偷懒,最终效果都会大打折扣。很多人搭完 RAG 发现“还不如直接问模型”,大概率不是 RAG 路线错了,而是某个环节做得太糙了。
1.3 为什么企业场景里 RAG 比微调更合适
技术圈里讨论 RAG 时,总会有人问:“我是不是应该直接微调模型?”这个问题值得花点篇幅说清楚。
微调是改变模型本身的参数,相当于给学生开小灶补课,把特定知识“塞进脑子里”。这种方式适合模型输出风格、固定话术、特定格式需要长期稳定的场景。但它有个致命的短板:知识一旦更新,微调要重新做。企业制度文件、产品手册、FAQ 是经常变更的,如果每次改个条款都要重新训练一次模型,那成本谁也扛不住。
RAG 则是把知识外置了。模型不需要记住你的知识,只需要在回答的时候去外部知识库“查一下”。知识库更新了,替换掉对应文档,几分钟就能生效。单就这一点,RAG 在企业动态知识场景里的优势就已经很明显了。我见过一些项目一上来就想微调,模型训练还没跑完,制度文档已经改了三版,最后只能推倒重来。
当然,两者不是完全互斥的,个别项目会把微调和 RAG 结合使用,用微调固定输出风格,用 RAG 提供事实内容。但如果你预算和人力都有限,我的建议是先把 RAG 跑通。它能解决 80% 以上的业务问题,而且迭代成本低,效果反馈快。
2. 拆解 RAG 核心链路:从文档入库到答案生成的每一个关键环节
2.1 整体架构:离线建库 + 在线问答
一个标准的 RAG 系统,我习惯把它拆成两半看:离线建库和在线问答。
离线建库阶段,核心是把原始文档变成可检索的向量数据。原始格式通常是 PDF、Word、Markdown 甚至扫描件,先要做清洗,把页眉页脚、目录、水印、乱码这些噪声去掉,再按一定策略切分成文本块。然后调用嵌入模型,把每个文本块变成一组数字向量,连同原文和来源信息一起存入向量数据库。
在线问答阶段,用户输入问题后,系统先调用同一个嵌入模型把问题也变成向量,去向量数据库里做相似度检索,找出最相关的 TopK 个文档片段。这些片段经过重排、过滤等处理之后,连同用户问题一起组装成 Prompt,交给大模型生成最终答案。
整个流程看起来不复杂,但每一环都有讲究。我把核心环节一个个拆开讲,尤其是我实际踩过坑、调过参的地方。
2.2 文档切分:最容易被忽略,却直接决定检索质量的上限
文档切分是 RAG 链路里最“不起眼”但又最影响效果的一环。切分策略,直接决定了检索回来的片段是不是一个语义相对完整、能独立支撑回答的单元。
切太粗会出现什么问题呢?把整本几十页的产品手册当成一块存入知识库,向量化之后,这一块的语义信息过于混杂,做相似度计算时会被稀释掉;而且就算检索到了,把这么大一块全部塞进 Prompt,既浪费 token,也容易干扰模型关注重点。切太细呢?如果按每个句子单独切,虽然单个句子在向量空间里可能得分高,但句子脱离上下文之后,主语、场景、前提条件全丢了,模型拿到一个孤零零的句子根本没法给出完整回答。
我实际项目里,对于一份常规技术规范文档,用的方案是优先按标题层级和段落边界做语义切分,块大小控制在 256 到 512 个 token 之间,块与块之间设置 64 个 token 的重叠。重叠的意义在于:相邻两块之间保留一部分交叉内容,这样即使某条信息被切分边界卡在上一块的末尾,下一块里仍然能通过重叠部分看到它的上下文,避免信息被拦腰斩断。
为什么不能只按字符数硬切?因为硬切完全不看语义,极容易把一句话从中间劈开,产生大量内容破碎、无法独立阅读的文本块。这些碎片进入知识库之后,检索出来的结果质量必然很差,后面的 Prompt 组装和生成环节再努力也没用。
还有一个特别容易被忽视的场景:表格和代码块。纯文本切分很容易把一张表格按行切开,导致模型只检索到某一行的数字,完全不知道这个数字对应哪一列。我在切分规则里专门加了逻辑:遇到 Markdown 表格、HTML 表格、代码块,整体保留为一个独立文本块,不做内部切分。实测下来,这个调整对含表格的文档检索准确率提升非常明显。
注意:文档切分的核心目标是“让每个文档块成为一个语义相对完整、可以独立支撑回答的单元”,而不是单纯追求块大小一致。刻板地按固定 token 数切块,是本末倒置。
2.3 嵌入模型选型:不要迷信榜单,要拿自己的数据测
嵌入模型就是那个把文本变成向量、把向量变成坐标的工具。它决定了“语义相似”这件事在向量空间里到底怎么衡量。这一步如果选不好,后面检索效果再优化都是空中楼阁。
市面上的嵌入模型非常多,通用型模型在日常生活、新闻、百科类语料上表现尚可,但一进入专业领域,比如法律条款、医疗术语、工业参数、代码片段,通用模型的向量表示经常抓不住要点。原因也简单,训练语料里专业内容的占比不够多,模型对专有名词的语义理解不够敏感。
我在这里给一个非常务实的建议:不要只听别人说某个模型体验震撼,也不要盲目追求公开榜单的高分,一定要拿自己的真实文档去测。具体做法很傻瓜但有效:从你的知识库里挑出 20 到 30 个最典型的问题,每个问题手工标注出应该在哪个文档块里能查到答案,然后用不同嵌入模型分别跑一遍检索,看 Top1 命中率和 Top5 命中率。这个方法虽然原始,但比任何公开评测都更贴近你的业务场景。
除了模型选型,还有两个细节值得留意。一是嵌入模型的输入长度限制,必须和你的切分块大小匹配。如果块太大、超出模型输入上限,长文本会被截断,后面那部分信息等于白算了。二是查询和文档最好使用同一个嵌入模型。如果查询用一个模型、文档用另一个模型,向量维度和分布可能不一致,检索结果会非常飘。
2.4 向量数据库与召回策略:相似度不等于相关性
向量数据库用来存储和检索向量,市面上的选择很多,有的开源免费、有的商业化收费。我先说一个容易被人误解的点:底层逻辑其实大同小异,决定检索质量上限的并不是数据库本身,而是你的查询向量质量、相似度计算方式、索引参数和数据分布适配程度。数据库本身的差异更多体现在并发性能、存储扩展、运维成本和生态支持上。
向量相似度计算方式,常见的有三种:欧氏距离、曼哈顿距离、余弦相似度。RAG 里最常用的是余弦相似度,它衡量的是两个向量的方向一致性,对向量长度不敏感,很适合文本嵌入模型生成的向量分布。但我不建议你完全按默认配置就跑,最好入库后先拿几个真实问题跑一遍检索,看打分排序是否符合你的直觉。如果发现某些该排前面的结果排到后面去了,就要考虑是不是相似度计算方式或者向量归一化处理有问题。
召回数量 TopK 也是一个需要实际测试的参数,不能随便设。设得太大,比如 20,会把大量无关片段混进上下文,模型反而容易被噪声干扰;设得太小,比如 2,正确答案可能压根没被召回来。我通常以 5 为起点,然后根据实际测试结果在 3 到 10 之间调整。值得注意的是,最适合的 TopK 和你的文档切分粒度、知识库文档风格是强相关的。如果文档切得碎,TopK 可以适当调大一点;如果文档切得整,TopK 可以调小一点。
2.5 上下文组装:Prompt 里那句“只依据资料回答”是定海神针
检索完成之后,怎么把材料组装成 Prompt,很多人做得太随意。直接拿十几段检索片段一股脑拼起来丢给模型,这不是 RAG,这只是给模型塞了一堆可能相关的文本。我实际用的 Prompt 结构大致是四段式:
第一段,角色和任务定义。明确告诉模型:“你是一个企业知识库问答助手,必须严格依据给定的参考资料回答用户问题。”这一步非常关键,它把模型从“通用闲聊助手”切换成“闭卷变开卷”的工作模式。
第二段,参考资料区块。把检索到的文档片段,按相关度得分从高到低排列,用清晰的分隔符标记出来。如果有来源信息,比如“文档名称、章节标题、页码”,也一并附上,方便后续引用。
第三段,用户问题。把用户的原始提问放在显眼的位置。
第四段,回答约束。这是整段 Prompt 的灵魂。通常我会写清楚几条规则:只依据参考资料回答;如果参考资料中没有相关信息,直接说明“知识库中未找到相关信息”,不要推测;不要写入参考资料之外的背景知识。
我做过一个小实验验证最后一段约束的效果。同样一套检索结果,去掉“允许说不知道”这句授权之后,模型在一部分问题上会开始自行发挥,而加上之后,它更倾向于老老实实复述材料里的内容。我当时的感觉就是:模型其实是“怕”说不知道的,你给它明确的许可,它才会放下心理负担,承认知识盲区,不硬编。
提示:在 Prompt 中明确授权模型“可以承认不知道”,是降幻觉性价比最高的一个动作。它比任何提示工程技巧都管用。
3. 实操过程:一个内部知识库系统把幻觉率降下来的完整记录
3.1 项目背景和数据准备
这个项目我用于企业内部知识库问答场景。业务方提的需求很直白:员工以后查制度、走流程、看规范,直接问一个对话框,系统自动给出答案。知识库的原始材料,是历史上遗留下来的一堆 Word 文档、PDF 手册、零散聊天记录里沉淀的 FAQ,信息新旧混杂。
第一步就是文档清洗。这一步我没有图省事,老老实实把页眉页脚、文档目录、水印全部清掉。这里面有个常见的坑:扫描版 PDF。如果直接拿扫描件去切分向量化,能索引的其实是空的,因为根本没有文本层。我专门走了一道 OCR 流程,把扫描件里的内容识别成文本之后再做后续处理。虽然 OCR 偶尔会有字符识别错误,但总比完全搜不到强。
清洗完之后,我统计了文档结构,发现多数制度文件和产品手册都有明确的标题层级,部分文档里还夹着大量表格。所以最终切分策略定为:按文档原有章节结构切,块大小尽量控制在 512 个 token 以内,遇到表格单独提取为大块,块之间保留 64 个 token 重叠。这套方案属于行业内常见实践,并不算特别激进,但已经比无脑按固定长度切块好太多了。
说明:以上文档预处理、切分、数据库选型等具体步骤,是基于常见 RAG 落地实践做的合理化补充。不同项目的数据形态不一样,切分策略和清洗规则需要结合自己手里的文档情况调整。
3.2 切分、向量化入库与检索测试
切分和向量化入库,本质上是一个批处理流程。每个切分好的文本块,喂给嵌入模型,生成一个向量,连同来源文档名、章节标题等元数据一起写入向量数据库。这里我强调一句:元数据一定要存。如果大数据都库丢了来源信息,后面你检索到一条结果,根本不知道它出自哪份文档,排查问题和做引用溯源会非常痛苦。
入库完成后,我做的第一件事不是急着联模型,而是先测检索质量。我从员工真实提问里整理了 20 个典型问题,覆盖“制度流程、技术参数、联系方式、入口位置”等类型,然后逐个去检索,人工判断 Top5 返回结果里有没有包含正确答案。第一轮测试结果,检索命中率只有大概六七成。不少问题返回的根本不是最相关的文档片段,偶尔甚至跑偏到完全不相关的内容。
我逐条分析失败样本,发现主要问题出在两类。第一类是切分粒度不合理。答案本来是长段落里的一部分,但切分后被分成了两半,导致检索时命中的只是包含部分关键词的半截内容。第二类是嵌入模型对专有名词不够敏感,比如部门全称和简称、产品型号的不同写法,在向量空间里的相似度没有得到合理体现。
针对这两类问题,我做了两个调整。第一,优化切分规则,把“从标题开始到下一个同级标题结束”作为一个基本切分单元,段落中间不断句,尽量保持一个语义完整的知识模块。第二,针对专有名词和同义表述,在知识库里维护了一份同义词映射表,检索时同时查询原词和同义词,扩大召回。改完之后,Top5 命中率基本达到 85% 以上,这时候我才放心进入下一步。
3.3 生成阶段的两个关键设置:TopK 与 Prompt 结构
生成阶段,我主要调两个东西:召回数量和 Prompt 结构。
召回数量,我做了一个专门的对比测试。同一组问题,TopK 分别设为 2、5、10,人工评估答案质量。结果很有意思:TopK=2 时,很多问题根本没有召回正确答案,模型只能硬着头皮答,幻觉风险重新抬头;TopK=10 时,正确答案倒是大概率能召回来,但混入的无关片段也变多了,模型偶尔会被无关内容带跑偏,反而增加了不稳定性;TopK=5 的时候效果最好,既能保证正确答案大概率被召回,又不至于加入太多噪声。这个测试再次印证了前面说的:TopK 必须实测,不能拍脑袋。
Prompt 结构,我按照前面说的四段式来搭,角色、资料、问题、约束四段分开。其中最核心的一条约束是:如果参考资料中未包含答案,请直接回复“未在知识库中检索到相关信息”,不要尝试猜测。就是这么一句话,让最终语料的幻觉比例有了肉眼可见的下降。
3.4 效果对比测试:有 RAG 和没 RAG 的差距有多大
项目上线前,我专门做了一个对照测试:用同一批问题,分别跑“裸模型直接回答”和“加上完整 RAG 链路回答”,然后人工打分。
裸模型的表现很有代表性:通用常识类问题回答得还行,但一涉及企业内部独有知识,就开始明显“编”。有一道题问“项目验收需要提交哪些材料”,裸模型列出了一份看起来非常规范的材料清单,但对照公司真实制度文档,错漏超过一半。这种回答放在内部知识库场景里,性质很严重,因为员工会直接照着执行。
加了 RAG 之后,同一批问题的答案基本都能在知识库里找到出处。模型不再天马行空,每个结论都有相关文档片段作为依据,人工判定错误率从无 RAG 时的接近 40%,降到了 10% 以内。虽然不完美,但在真实业务场景里,这已经是质变了。这次对比让我确信,RAG 的价值不需要复杂指标来背书,最简单的“答案是否正确、是否有编造内容”就能说明问题。
4. 常见问题与排查技巧实录:RAG 效果不好时的急救手册
4.1 材料都对,答案还是错的:问题多半出在 Prompt 和模型侧
这是我在实践里遇到最多的情况之一:检索出来的文档片段看起来是对的,相关资料也进了 Prompt,但模型最终回答依然不对。这种时候,不要急着去改检索参数,先按三步排查。
第一步,人工检查检索片段本身。把返回的 Top5 片段单独读一遍,判断这些片段里到底有没有能支撑问题答案的信息。如果片段里根本没有答案,那是检索召回的问题;如果片段里有准确答案但模型答错,那是生成环节的问题。这一步能快速切分排查方向。
第二步,检查 Prompt 结构。看参考材料有没有正确插入,看四个关键段落是否清晰分隔,看模型有没有被系统层的通用角色设定覆盖掉。这里有个常见坑:很多框架默认带的系统 Prompt 是“你是一个 AI 助手”,如果你在这个系统角色之外拼接了自定义角色,模型可能会优先听系统层的设定,把它当成通用问题来回答。
第三步,检查模型对指令的服从性。不同模型在简单指令下表现都很好,但一旦上下文变长、约束变多,服从性就会下降。解决方法是把指令精简,把最重要的“只依据参考资料回答”放在最靠前的位置,并尽量缩短中间与核心指令无关的冗余内容。
我印象最深的一次排查经历是:检索结果完全正确,重要信息就在片段里,但模型每次回答都倾向于用自己的训练知识生成一个“更完整”的答案。后来发现就是角色定义写得太弱。我把角色描述从“你是一个 AI 助手”改成“你是某企业内部知识库问答助手,必须严格依据给定资料回答”,效果立刻改善。别看只是几个字的差别,对模型的行为影响却非常大。
4.2 检索结果完全不相关:优先检查切分、嵌入模型和文档版本
如果检索引擎返回的 Top 片段里面压根没有正确答案,那问题就基本确定在召回环节。这时候我按顺序排查:切分是否合理、嵌入模型是否适应业务数据、知识库里是否混入了旧版本文档。
切分问题最常见。有些正确答案是一个比较长的小节,但由于切分粒度太大,整体向量里关键词占比被稀释了,导致检索时得分不如一个只提到某个相关词但不含实质内容的短块。解决办法一个是针对大段落单独设置切分规则,另一个是为这个段落额外生成一段摘要,用摘要参与检索、让正文参与生成。第二种方法我在一个技术文档场景里实测有效,属于一个比较实用的补救技巧。
嵌入模型的问题,通常表现为相似度打分完全不符合业务直觉。比如两个明显语义相关的句子,向量相似度得分反而很低。这时候就需要考虑是不是当下这个嵌入模型不适合你的领域,换个更专业的模型再测一轮。切换模型之前,务必把知识库向量全部重新生成一遍,否则新旧向量混用会让检索结果更混乱。
文档版本问题在长期维护的知识库里特别常见。同一份制度文件可能同时存在旧版和新版,两版内容差异很大,同时被检索到后,模型容易在冲突的片段中选择错误信息。解决方案是入库的时候做版本管理,只保留当前有效版本参与检索,历史版本归档但不参与在线问答。
4.3 新增知识检索不到:先查入库管道,再查索引刷新
知识库更新后,新增文档搜不到,是动态场景下的高频问题。我排查时先看两处:入库管道是否成功执行、向量库索引是否完成刷新。
第一件事是确认新增文档有没有真的走完“清洗、切分、向量化、写入”的全流程。很多时候问题出在中间某一环断了。比如新增文档是图片型 PDF,没有触发 OCR,虽然文件进了库,但可检索的文本是空的。这种情况就需要在入库流程里加一个“入库后自动抽查”机制,每新增一批文档,自动跑几个检索测试,确认新增内容能被召回。
第二件事是确认向量数据库的索引没有过期。有些向量数据库在追加新数据后不会自动重建索引,需要手动触发或者任务调度。如果索引一直没刷新,新增向量就不会参与检索,旧内容倒是好好的。我一共有两次排查到最后都是这个问题,确认索引刷新运行正常后,新文档立刻就能被检索到。
4.4 系统响应慢、成本高:从缓存、模型和降级策略三个方向优化
RAG 系统上线一段时间后,新的问题会冒出来:变慢了,成本变高了。每个问题都要经过“查询嵌入、向量检索、LLM 生成”三步,用户量大了之后,延迟很难看。
性能优化,我有几个验证过比较有效的手段。第一是加缓存,把高频问题的检索结果缓存起来,命中缓存时直接跳过检索环节。这个在内部知识库场景里尤其管用,因为员工的提问往往高度集中在少数几个话题上。第二是做一些问题归一化,把相似问题合并成同一个缓存键,提升缓存命中率。第三是考虑换一个小一点的基础生成模型。企业知识库问答很多时候不需要最强模型,一个中等参数的模型配上靠谱的 RAG 链路,效果完全可以接受,但延迟和成本能降不少。
还有一个实用的降级策略:给检索和生成单独设置超时和兜底逻辑。如果检索超时,就直接把问题抛给模型裸答,同时标注回答置信度较低;如果生成超时,就把检索到的资料摘要返回给用户。这种降级方案在个别情况下会牺牲质量,但总比整个系统偶发超时错误让用户空等要好。
4.5 常见问题排查速查表
| 症状 | 可能原因 | 优先排查方向 |
|---|---|---|
| 检索结果完全不相关 | 文档切分不合理、嵌入模型不匹配、知识库中混有旧版本 | 检查切分结果,换嵌入模型测试,清理旧版本 |
| 检索正确但回答错误 | Prompt 指令模糊、模型服从性不足、角色定义不清晰 | 精简指令、强化角色定义、调整 Prompt 结构 |
| 回答过于笼统、缺少细节 | 召回片段太短、上下文丢失、原文档本身信息不全 | 调整块大小、增大重叠、补充原始文档质量 |
| 新增知识检索不到 | 入库管道中断、索引未刷新、扫描件未走 OCR | 检查入库日志、触发索引重建、补 OCR 环节 |
| 系统响应慢 | TopK 偏大、模型过大、无缓存 | 缩小 TopK、换轻量模型、加检索缓存 |
| 知识库更新后答案未变 | Prompt 缓存未失效、文档版本错乱 | 清理 Prompt 缓存、统一版本管理 |
这张表基本就是我平时排查问题时脑子里过的那遍流程。遇到问题先归类、再定位,效率会高很多。没有它,我一遇到异常就容易在切分、检索、生成几个环节里来回乱试,做了很多无用功。
4.6 幻觉评测:怎么衡量 RAG 到底降了多少幻觉
最后再讲一个容易被忽视的问题:怎么量化“幻觉降下来了”。如果只是感觉“好像准确了一点”,项目汇报的时候是站不住脚的。我在实际项目里使用了一套不算复杂但足够实用的评测流程。
首先准备一套覆盖常见业务场景的测试问题集,规模不需要太大,50 到 80 题足够。然后为每个问题准备标准答案,答案以知识库中的权威文档片段为依据。评测时让系统逐一回答,并人工给每个回答打“正确、部分正确、错误、编造”四类标签。其中“编造”是最严重的,代表回答内容在知识库中找不到任何依据。
跑完一轮之后,重点关注两个指标:整体正确率,以及“编造率”——也就是幻觉比例。我做 RAG 前后对比测试时,重点看的就是“编造率”从多少降到多少。这个指标非常直观,业务方也能看懂。如果团队想做得更精细,还可以针对不同问题类型分别统计,看看是流程类问题容易出错还是参数类问题容易出错,再做定向优化。
这套评测流程最忌讳的就是用一组固定问题反复跑,然后观察模型是否“背答案”。RAG 链路里检索结果每次会有细微差异,如果同一道题两次回答不一致,本身也是需要留意的信号。说明检索或生成阶段存在不稳定性,需要进一步排查原因。
5. 进阶优化:当基础 RAG 不够用之后我做的几件事
5.1 混合检索:向量检索的盲区比想象中大
基础 RAG 上线后,业务效果虽然可用,但在某些特殊场景下还是不够好。最典型的是用户输入了精确的产品型号、合同编号、人员工号这类信息。这类查询的本质是精确匹配,而不是语义相似。向量检索把它转成语义向量后,可能把相似的干扰项也排上来,精确的那一条反而排名不高。
遇到这种情况,我引入了混合检索。混合检索的核心是同时跑两路召回:一路是传统的 BM25 关键词匹配,擅长精确匹配;一路是向量语义检索,擅长理解含义和近义表达。然后把两路结果合并,统一送给重排环节做精排。这样既照顾到语义理解,又保证精确词条不会被淹没。
实战效果非常直接。我之前在另一个项目里测试过用户问“查一下合同编号 X-2024-013 的付款条款”,如果只用向量检索,经常会把相似编号合同的内容混进来;加 BM25 这一路之后,精确编号直接命中目标合同,效果判若云泥。如果你要做企业级 RAG,混合检索不是锦上添花,在特定场景里它就是必需品。
5.2 重排模型:让精排从经验判断变成稳定技术
粗排通常是双塔模型算出的向量相似度,计算高效但精度有限。混合检索把候选集扩大到比如 20 个片段之后,Prompt 里只能放 5 个左右的时候,就需要一个重排环节来决定到底哪 5 个片段最相关。
重排模型通常采用交叉编码器(Cross-Encoder)结构。它把用户问题和候选文档片段一起输入模型,逐字逐句地计算它们之间的关联度。这种精排方式的精度远高于简单的向量相似度,当然计算成本也更高,所以只适合在候选集缩小之后使用。
稳定性的价值在于,纯靠向量相似度排出来的结果,有时会让人捉摸不透;而重排模型出来之后,Top1 到 Top5 的顺序基本符合业务直觉。在一次测试里,用户问“离职交接需要哪些手续”,向量检索返回的 Top 结果里混进了入职流程的内容,经过重排之后,正确答案稳定排到了最前面。现在我做 RAG 项目,基础链路跑通后第二步基本就是加重排。并且如果对响应速度有要求,可以用较小的重排模型或者只在候选集偏大时启用重排来平衡成本。
5.3 上下文裁剪与引用溯源管理
最后一个优化,也属于我所有项目里都会坚持的:上下文裁剪和引用溯源。
即使经过了混合检索和重排,最终进入 Prompt 的几个片段里,仍然有可能混入个别关联度低的噪声信息。虽然这些噪声不多,但大模型是“有闻必录”的,偶尔会被带偏。我在组装 Prompt 前会多做一步:按重排后的得分,只保留超过一定阈值的片段;低于阈值的即使排在 TopK 内,也直接丢弃。这个阈值不需要很严格,主要目的是把明显不相关的尾巴切掉。
引用溯源管理就更简单了,给每个最终进入 Prompt 的片段都带上来源元数据——来自哪份文档、哪个章节、大致页码。生成的回答里,在关键结论后面附带对应的资料来源。这一步表面上是为了用户体验,让提问员工能点进去核对原文;实际上对我排查问题也极其重要。只要看一眼回答对应的引用来源,就能快速判断到底是检索错了、生成错了还是知识库本身错了。
我现在的习惯是,每个 RAG 项目都要强制加上引用溯源和可解释性展示。这不仅是业务需求,更是给自己留一条快速定位问题的路径。越到后来我越觉得,RAG 不只是“给模型塞资料”,更是一套需要精密协作的过程工程,每个环节都必须对结果负责。
6. 最后再分享一点实际体感
如果你正在准备做一个 RAG 项目,我这几个月的经验可以浓缩成三句话。
第一句:先跑通,再优化。不要试图第一次就把切分、混合检索、重排、缓存、引用溯源全部配满。RAG 链路环节太多,先把一条最简单的链路跑通,拿到一个“能用”的版本,再逐步迭代。我第一版只用了简单的固定长度切分和 TopK 检索,效果虽然一般,但从零到一的通路打通了,后面每次优化都有基线可对比。
第二句:优化要有数据意识。每次改动一个参数,就固定其他变量跑同一套测试题。哪怕只是调整一下重叠 token 数,都记录下来前后的检索准确率和回答正确率。我见过太多团队今天改切分、明天换模型、后天调 Prompt,最后效果变好了却不知道是哪一步的功劳。用数据管理优化过程,比依赖“感觉”可靠得多。
第三句:故意准备一些“陷阱问题”去测试系统。我会在上线前准备几个知识库里没有答案的问题去问系统,如果模型老老实实说“未在知识库中检索到相关信息”,说明 Prompt 约束和检索兜底逻辑是可靠的;如果模型硬着头皮编出答案,说明还有幻觉漏洞需要补。这个习惯帮我拦住了至少两轮会让业务方崩溃的灾难性幻觉,建议你也试一下。
个人体感最深的一句话是:RAG 降幻觉的本质,就是给模型足够的事实依据,并明确约束它只依据这些事实回答。把所有优化动作都围绕这个核心来展开,方向就不会出错。
免责说明:文中涉及的项目背景和参数均为虚构演示场景下的通用实践经验,具体项目的参数设置需要根据你自己手里的文档形态、业务场景、模型选择另行测试调优。