
半年前我帮某团队搭过一套内部规章问答系统PDF、制度文档、会议纪要全灌进了向量库当时觉得自己已经把这个叫RAG系统的东西玩明白了。直到对方随手问了一句上个月报销流程改了没系统返回的三段参考里有两段是去年的旧政策生成模型为了圆场还一本正经地告诉你报销流程没有变动。那时我才真正意识到RAGRetrieval-Augmented Generation知识检索增强不是简单地把文档塞进数据库、查一下丢给大模型就完事它是一条完整链路每一环都会把误差放大到最终答案上。这篇文章我想把从能跑通的Demo到勉强能上线这段路上最关键的东西写透。包括离线索引怎么做、Chunk怎么切、向量库怎么选、检索召回和重排序怎么配合、多轮对话下怎么改写查询、最后怎么定量评估效果。不绕弯子都是实际操作中验证过的思路适合正在从0到1搭建RAG系统、或者在已有原型上反复调优效果不佳的开发者参考。1. 为什么裸用大模型会翻车RAG系统的定位与价值1.1 一个真实翻车现场当时为了让演示效果好看我先用纯Prompt方式跑了一遍。把几十份制度文档直接塞进上下文窗口让大模型只依据这些内容回答。结果有三种典型失败上下文超长直接被截断模型记住的是前半部分内容而对后面真正关键的流程细节视而不见多个文档相互有冲突新旧制度并存模型倾向于选择更常见、说得更顺畅的内容而不保证是最新、最准确的用户问的问题很口语化与文档中的正式表述不一致模型就只能靠自己的知识来补幻觉就从这里冒出来。这个翻车现场不是巧合而是所有LLM应用绕不开的三道坎知识陈旧、领域知识缺失、生成幻觉。RAG恰好对应解决这三个问题它的核心思路也很直白先根据用户问题去文档库里检索出最相关的片段再把问题相关片段一起交给大模型生成答案。模型不再是裸答而是带着参考资料答题。1.2 RAG和微调、长上下文之间是什么关系很多人会问既然大模型支持200K上下文了为什么还要RAG我做过一个对比测试把同样30页的合同文档用三种方式喂给模型直接塞全文、用RAG只塞最相关的8个片段、以及微调后再回答。结果很有意思。直接塞全文时模型对合同中的违约金比例这类细节问题回答准确率只有六成左右而且经常出错——因为长上下文里有大量无关信息在稀释注意力。RAG模式下同样的问题准确率明显更高响应速度也更快因为输入给模型的Token数只有直接塞全文的零头。至于微调它能改变模型的说话风格和知识倾向但无法低成本地频繁更新知识不可能每周微调一次来应对制度变更。所以RAG的关键价值不仅仅是把文档塞进去就算完而是让系统具备按需取用、频繁更新、可追溯引用的能力。在实际项目里RAG不需要训练模型文档更新后重新走一遍索引流程即可成本优势非常明显。1.3 RAG系统到底长什么样一句话概括RAG系统的骨架离线把文档切块、向量化、建索引在线把用户问题改写、向量化、召回候选片段、重排序、拼Prompt、生成答案。整个系统里大家最容易低估的是切块Chunking和召回质量。很多团队把重点放在调大模型Prompt上但上线后发现问题往往出在根子上——召回回来的片段压根就不对。比如用户问离职手续怎么办检索引擎召回的是入职手续怎么办的段落因为两者在向量空间里离得很近这就是典型的召回错误。所以后面几节我会先讲离线索引阶段怎么把文档处理成高质量的基础单元再讲在线阶段的检索与生成配合。2. 离线索引阶段从PDF到可检索片段的全过程2.1 文档加载与清洗脏数据决定了效果上限很多人以为文档加载就是读个PDF文件实际上这一步决定RAG系统效果的上限。我们当时遇到过一个很典型的案例某部门提供的年度总结PDF是扫描件直接读出来全是乱码和空白检索几乎完全失效。最后补了OCR环节才把文本提取出来。我建议在加载环节至少要做三件事按文件类型走不同解析通道PDF用文本提取和OCR并行Office文档用对应解析库网页内容则要清洗掉导航栏、广告和页脚统一编码格式表格尽量转换成Markdown格式因为大模型对Markdown格式的表格理解准确率明显优于纯文本排版做一次内容去重和版本筛选保留当前生效版本历史版本单独打标。元数据发布日期、部门、适用范围要保留下来这些都是后续做时间过滤和权限过滤的关键字段。2.2 Chunk切分检索的基本单位不是随便砍一刀做过RAG的人都知道Chunk是检索的基本单位。切得太小语义破碎模型得不到完整上下文切得太大向量里混入太多无关信息相似度被稀释。我们的经验是不同类型文档定不同的切分策略而不是全局统一。比如制度类文档按章节和条款边界切一个条款尽量放在同一个Chunk里技术方案类文档按标题层级切每个小节作为一个独立Chunk关联表格图例尽量跟着正文会议纪要这类非结构化文本则需要按语义段落切。实际测试过的三种切分策略固定窗口切分按固定字符数或Token数硬切实现最简单但很容易把一句话、一个表格从中间断开递归字符切分设定分隔符优先级段落、句号、逗号优先在语义边界断开是所有策略里性价比最高的语义切分用Embedding模型识别语义转折点再切分效果最好但计算开销也最大。我目前生产环境用得最多的是递归切分设置区块大小为500-800字符重叠率10%-20%。重叠部分的作用是避免出现在边界处的关键信息被截断尤其当用户的问题恰好覆盖到两块交界处时重叠区能保证两块都能检索到相似的内容。2.3 元数据与环境隔离很多人忽略的治理问题这个要单独拿出来提醒一下。如果你们公司有多个产品线、多个文档库千万不要把所有文档都灌进同一个向量集合里。回收站里删除残留的旧版本、其他部门的内部资料、不同权限级别的文件一旦混在一起检索时就会出现权限泄露和内容错乱的问题。正确做法是每个独立业务域建一个独立的索引集合或者用元数据字段做硬隔离。比如某公司的知识库里既有研发文档又有销售话术当用户问这个产品怎么卖时研发文档里的技术细节混进来会严重干扰生成质量。通过索引分区和元数据过滤系统只会检索销售域的内容效果提升可以说是立竿见影的。3. 向量化与Embedding选型检索精度的第一道命门3.1 Embedding模型怎么选语种、领域、维度一个都不能少Embedding模型选择直接影响向量召回质量。我试过不少模型这里不推荐最好只说我踩过坑之后留下的经验。先看语种匹配度。如果你处理的是纯中文文档建议优先找一个中文语料充分训练的Embedding模型例如BGE系列的中文模型它们的语料覆盖度比通用模型要高不少。如果你是纯粹英文文档或者中英混合再考虑多语种通用模型。再看领域匹配度。法律、医疗这类专业术语密集的文本通用Embedding常常识别不好要约和承诺、绿脓杆菌和铜绿假单胞菌这样的同义表达。如果条件允许可以用领域语料对Embedding模型做增量训练或者干脆在检索链路里加入词典扩展把同义词、缩写、上下位概念都展开查询。最后看向量维度。维度决定了存储成本和计算开销也和模型能力相关。768维和1536维对短文本检索来说差异没有想象中大但向量库的规模上去之后维度带来的磁盘占用、内存占用差异就很可观了。我的建议是先跑一批小规模评测用实验结果选型不要盲目追大模型。3.2 向量化之前先想清楚是查原文还是查改写后的内容这里有一个很反直觉的细节到底应不应该把用户问题原封不动地拿去向量化检索答案是不一定。用户普遍倾向于口语化表达比如离职要办啥但制度文档里写的是员工离职手续办理流程。原问题向量化之后跟文档片段的相似度往往偏低由此召回的内容就会偏。解决思路有两种一是做查询改写把口语问题改写成书面语和关键词组合二是做HyDE让大模型先生成一个假设答案再用这个答案去检索。后者在部分场景里效果惊人但也有代价我后面会专门讲。3.3 向量索引的核心参数HNSW里藏着召回率和延迟的平衡把向量处理好之后你会面临索引库的选择。小型Demo用内存型向量库就够了生产环境我更倾向独立向量数据库。几乎所有主流向量库都支持HNSW图索引其中有三个参数是必须调过的M每个节点的最大连接数M越大召回效果略好但内存消耗和构建时间也越大efConstruction构建时的候选集大小构建质量越高索引越大efSearch查询时的候选集大小查询时越大召回越准但延迟越高。我们的经验值是M设16-32之间efConstruction设200左右efSearch设100-500之间。如果检索结果明显滞后优先调低efSearch如果召回质量不够优先调高M和efSearch但每次调整后要做一次评测防止肉眼感觉而不是数据驱动。4. 检索召回与重排序从大概相关到精准有用4.1 混合检索向量召回和关键词召回是互补的我刚开始只用向量检索很快发现两个问题一是精确的专有名词、编号代码匹配效果差比如GB/T 12345-2023向量检索经常找不到二是新传入的文档还没被模型充分理解时Vector相似度可能不如简单字符串精确匹配可靠。于是切到混合检索方案同时用稀疏检索BM25和稠密向量检索两者结果融合后统一输出。BM25对精确词项、专业编号、短文本特别敏感向量检索对同义改写、语义相关表达更擅长。融合方式我推荐最简单的RRFReciprocal Rank Fusion把多个检索结果按排名取倒数并加权求和排名越靠前权重越大。没有复杂的调参效果通常很稳定适合作为基线。4.2 重排序Rerank召回只是海选重排才是精选混合检索召回出来的是候选集可能Top50都是粗略相关的。但大模型的上下文有限且对信息密度有要求直接把这50段塞进Prompt既浪费Token又干扰注意力。所以必须在中间加一道重排序环节。最常用的是Cross-Encoder重排序模型把查询和候选文本成对地送进模型输出一个0-1或0-5的相关性分数然后按分数从高到低取Top5-10。这个方案比Embedding相似度计算更准因为它做了真正的细粒度语义交互但缺点是延迟明显更高。所以线上通常的做法是先用粗排向量检索BM25召回50-100条用重排序筛选到Top5-8条这样既有精度又控制住了成本。我自己跑过的数据是纯向量召回Top5准确率大概在65%左右加了混合检索和重排序之后Top5准确率可以提升到85%以上。效果最明显的是那些用户问法跟文档写法完全不同的场景比如我干了三个月想走和试用期离职办理流程粗排可能排在30名开外重排序却能把它捞回前3名。4.3 还要记得把引用来源一起传给大模型这一步很多人会忽略但它是RAG落地到业务场景的硬要求。检索命中的片段需要把对应的文档名、章节、原文一并传给生成模型并明确要求模型在答案中标记引用源。这样做的意义不仅是让模型能自证更是给用户信任感。我们在测试中发现带上引用自《员工手册》第三章这类句子后用户对答案的信任度明显更高也更容易在人工复核时快速定位问题。5. 查询改写与多轮对话检索质量提升的隐藏杠杆5.1 为什么要改写用户问题用户的问题天然发散。有人问一句工资怎么算有人问我去年入职时说的底薪跟年终奖跟合同里不一样这个怎么处理如果直接把原句丢进检索器症状很明显要么召回出一堆泛泛的内容要么只召回其中的一小段。正确做法是先做查询理解拆解出实体工资、合同、入职时间、意图差异处理、约束条件去年、合同约定再生成多个检索子查询。多查询并行召回之后汇总重排的时候再合并去重。5.2 维护会话历史把指代和省略问题补全RAG系统一定会有多轮对话场景。用户第一轮问报销流程怎么走第二轮问那发票有什么要求如果系统不维护上下文第二轮检索到的可能是发票丢失如何作废这种完全不相干的内容。这里就需要做多轮对话改写在进入检索流程之前先让大模型结合历史上下文把当前问题改写成一个独立完整的问题。比如用户我想报销差旅费要走什么流程用户那发票呢改写后的问题报销差旅费时发票有什么要求这个改写步骤通常选用更便宜更快的轻量模型就能完成尽量不要占用主模型的复杂推理能力因为它的目标不是生成答案而是生成一个更好的检索条件。5.3 HyDE让答案先飞一会儿反而检索更准HyDEHypothetical Document Embeddings的思路很特别先让大模型根据用户问题生成一个假设的答案文档再把这个假设答案拿去向量化检索用命中的真实文档片段作为最终生成的参考资料。为什么这招有效因为用户问题和文档之间往往存在语言鸿沟但LLM生成的假设答案通常已经包含了答案的语言风格和术语体系更接近目标文档的表述习惯从而缩小鸿沟。比如问湿气大对设备有什么影响假设答案里会出现凝露绝缘性能下降密封圈老化这些术语而文档里恰恰用这些词来写。但HyDE有明确的代价它增加了一次大模型的完整生成调用延迟多出几百毫秒甚至数秒且成本上升。因此我的建议是只在语义鸿沟明显的场景里使用比如用户习惯口语化提问、文档专业性强、或者现有召回效果不佳时。如果检索质量已经很好了不要为了炫技牺牲延迟。6. 效果评测与线上调优别靠感觉用数据说话6.1 RAG系统的评测指标做RAG系统最忌讳的是看着差不多就不管了。我建议至少建立以下三类量化指标检索质量上下文准确率Context Precision、上下文召回率Context Recall核心衡量检索出的片段是否真的包含答案生成质量忠实度Faithfulness、答案相关性Answer Relevancy核心衡量生成答案是否基于检索内容而非幻觉以及是否有价值业务指标答案可接受率、引用有效率和二次查询率这些需要人工评或线上反馈埋点。RAGAS是业界常用的开源评测框架核心思路是用大模型当评委通过构造测试集批量评估。但我必须提醒大模型评委会带来误差最稳妥的方法还是抽样做人工复核两者结合。6.2 实测中最常出现的三类问题和排查链路第一类回答与检索内容冲突答非所问或幻觉明显。排查链路是先看检索结果里到底有没有正确内容。如果没有问题在检索侧如果有但模型没答对问题在生成侧。最常见的还是检索侧召回不够精准。第二类回答正确但关键细节缺失。比如用户问报销额度系统回答需要按标准报销但没说具体数字。这种往往是TopK太少正确片段被重排序压到了后面或者Prompt里没有强制要求若参考内容中存在具体数字必须引用。第三类响应太慢用户不可接受。排查链路是先测纯检索耗时再测重排序耗时最后测大模型生成耗时。实际项目里重排序往往是大头可以把候选集从Top50缩减到Top20或者重排序模型换成更轻量的版本这样一般能省下不少时间。6.3 先调检索还是先调生成我的答案很明确很多团队一上来就让大模型的Prompt答得更好这其实是在错误的方向上猛踩油门。我先调检索因为检索是RAG系统的基石检不到正确答案后面生成端再怎么调模型也只能发挥想象力。调检索的顺序也有讲究先调Chunk切分策略再调Embedding模型再调召回候选数扩到Top50-100再加重排序环节最后回归测试集看各项指标的变化。一轮不行就再来一轮每次只动一个变量避免混淆因素。6.4 成本与延迟优化缓存和索引精简线上系统还有一个绕不开的话题成本。我做的优化有三板斧第一给高频问题加缓存。相同或相似的问题直接命中历史答案不再走完整链路。命中率能到20%-30%时整体成本下降很可观。第二限制重排序的候选量。多数场景Top20的粗排结果经过重排序后已经把好料都捞回来了扩大候选集的边际收益很低。第三对上下文做摘要片段两档处理。长文档命中后如果片段太长先用小模型压缩摘要再拼进Prompt能显著减少Token消耗。注意绝不能在检索前对所有文档做摘要那会丢失细节只对命中的片段做摘要即可。6.5 流程闭环小步快跑迭代最后说一个个人体会比较深的管理问题。RAG系统的调试不是一次性的。文档每周更新、用户提问方式也在变必须把评测集持续维护起来每次文档库变化就跑到评测集上回归一遍防止旧的调优成果被新数据冲掉。我们后来把评测流程做成了定时任务每天晚上在测试集上自动跑一遍出报告。有了数据兜底做任何改动都不心虚了。如果你正在搭建RAG系统我的最核心建议就是一条先把基础链路的每一步分别用评估指标打通再去做花式优化。Chunk、Embedding、检索、重排序、生成的调试顺序不能乱每一环都需要独立可量化的验证方法。踩过坑之后回头看RAG系统最难的不是某一个深度学习模型调参而是把一堆相对简单的环节串成一条可靠的工程链路这本身就是一件很有价值的事。