资讯详情

拆解六款开源RAG后,我总结出自研检索增强生成系统的架构蓝图

📅 2026/10/28 0:54:28 | 华诺云谱 👁 阅读
拆解六款开源RAG后,我总结出自研检索增强生成系统的架构蓝图
1. 为什么我要花两周时间拆解六款开源RAG过去大半年我一直在带团队做一套面向企业内部的检索增强生成系统。最开始我们的思路很直接找一个star数高的开源RAG框架改改prompt、换换向量库就能上线。结果第一版跑通之后问题一个接一个冒出来——召回率忽高忽低、多轮对话里上下文被截断、知识库更新之后旧索引还在生效、图片和表格类文档解析出来全是乱码。那段时间我几乎每天都在翻issue区和源码越翻越觉得光靠拿来主义根本撑不住一个真正要落地的自研RAG。于是我做了一个决定不再盲目集成而是把当时市面上口碑比较好的六款开源RAG项目逐个拆开从数据摄入、切分策略、索引结构、检索链路、重排、生成编排到评估体系一层一层逆向它们的架构设计。这两周下来我最大的收获不是抄到了什么代码而是看清了这些项目在关键节点上做的取舍以及这些取舍背后的工程逻辑。这篇内容就是把这套逆向工程的方法论和结论整理出来给同样在自研RAG路上摸索的人一份可复用的蓝图参考。需要先说明一点我这里说的逆向工程不是破解、不是绕过授权而是以学习架构为目的对开源项目的模块划分、接口设计、数据流走向做系统性拆解。这跟游戏逆向那种改内存、破协议完全是两码事本质上是读源码加画架构图只不过带着明确的问题意识去读效率会高很多。这篇文章适合三类人一是正在选型、纠结用开源还是自研的团队负责人二是已经上手某个RAG框架、但遇到瓶颈想深入理解的工程师三是想从零搭一套可控RAG系统、不想被框架绑死的技术人。我会尽量把每个设计决策的为什么讲透而不是只丢结论。2. 拆解之前先想清楚RAG到底难在哪2.1 从能跑到能用之间隔着三道坎很多人对RAG的第一印象是不就是向量检索加个大模型吗demo阶段确实如此文档切一切、embedding一算、相似度一搜、拼进prompt就完事。但真正上线之后你会发现RAG的难点从来不在检索这个动作本身而在检索之前的准备和检索之后的编排。我把这中间的鸿沟归纳成三道坎。第一道是数据摄入的脏活PDF里的双栏排版、扫描件的OCR噪声、Excel里的合并单元格、PPT里的图文混排这些非结构化内容怎么变成干净的文本块直接决定了后面检索的天花板。第二道是检索的精准度纯向量检索对语义相似但事实不同的内容区分度很差比如2023年的营收和2024年的营收在向量空间里可能挨得很近但答案完全相反。第三道是上下文编排检索回来一堆片段怎么排序、怎么去重、怎么控制token预算、怎么在多轮对话里保持一致性这些都是框架层面要解决的问题。六款开源项目在这三道坎上的处理方式差异非常大有的把重心放在摄入管道的健壮性上有的在检索链路上做了多层融合有的干脆把编排抽象成可插拔的组件。理解这些差异比记住某个API怎么调用重要得多。2.2 开源RAG和自研RAG的真实边界在拆解过程中我反复问自己一个问题什么情况下该用开源什么情况下必须自研后来我总结出一条比较实用的判断标准——看你的核心竞争力和数据形态是否落在框架的舒适区内。开源RAG框架的舒适区是通用文档标准问答你的知识库是常规的PDF、Word、网页你的查询是自然语言问题你的答案可以从原文片段里直接找到或简单归纳。这种情况下开源框架能帮你省掉80%的重复劳动直接改配置就能跑。但一旦你的场景出现下面任何一种情况自研的必要性就上来了知识库里有大量结构化数据需要和文本混合检索业务要求答案必须可溯源到具体条款或字段查询涉及多跳推理需要跨多个文档片段组合或者你对延迟、成本、数据合规有硬性约束。这些场景下开源框架要么不支持要么支持得很别扭改起来比自己写还费劲。我拆的这六款项目里有三款明显偏向通用场景开箱即用程度高另外三款则更像半成品工具箱提供了大量底层抽象适合拿来当自研的起点。这个分类本身就很有参考价值——它告诉你选开源不是选最好的而是选最接近你终点的。2.3 逆向工程六款产品的统一方法论拆解不能瞎拆得有统一的框架否则每个项目看的东西不一样最后没法横向对比。我给自己定了一套四层拆解法从下往上依次是数据层、索引层、检索层、编排层。数据层看的是文档加载器、解析器、切分器的设计重点观察它怎么处理异构格式、怎么定义chunk的边界、有没有做元数据抽取。索引层看的是向量库选型、索引结构是纯向量还是向量加关键词混合、增量更新机制。检索层看的是召回策略、重排模型、多路融合逻辑。编排层看的是prompt组装、上下文压缩、多轮状态管理、以及有没有内置评估。每拆一层我都会问三个问题它解决了什么问题它为此付出了什么代价如果换成我的场景这个取舍还成立吗正是这三个问题让我从看热闹变成了看门道。下面几章我会按这个框架把六款产品的共性设计和关键分歧点逐一展开。3. 数据摄入层六款产品在切分策略上的分歧3.1 固定长度切分为什么在真实文档上会翻车几乎所有RAG教程都会从固定长度切分讲起按500个字符切一块重叠50个字符防止语义断裂。这个方法在demo里很好用但在真实文档上经常翻车。我拿一份技术白皮书测试过固定切分把一张参数表格从中间劈开前半块是表头后半块是数据行检索时两块都召回了但拼进prompt之后模型完全看不懂对应关系。六款产品里只有一款还在默认使用纯固定长度切分其余五款都做了不同程度的改进。改进方向主要有三个按语义边界切比如按段落、按标题层级、按结构切识别表格、代码块、列表并整体保留、按递归规则切先按大标题切超长再按段落切还超长才按字符切。这三种思路各有适用场景没有绝对优劣但有一个共识——切分的粒度应该由内容结构决定而不是由字符数决定。我自己的经验是对于技术文档和法律合同这类结构清晰的文本按标题层级递归切分效果最好对于聊天记录、访谈稿这类没有明显结构的文本反而需要结合语义相似度做动态切分。这一点在拆解时给了我很大启发好的框架不会只提供一种切分器而是提供一套可组合的切分策略。3.2 表格、图片与多模态内容的处理差异热词里有人问rag知识库能存储图片嘛这个问题在拆解过程中正好有答案。六款产品对多模态内容的处理可以分成三个梯队。第一梯队是只处理纯文本遇到图片直接跳过或OCR成文字表格转成Markdown或CSV文本。这是大多数项目的默认做法实现简单但丢失了视觉信息。第二梯队是文本加图片描述用多模态模型给图片生成一段文字描述把描述和原图一起存进知识库检索时命中描述再返回原图。这种做法在图文混排的产品手册场景下效果不错。第三梯队是原生多模态索引直接把图片的向量和文本的向量放在同一个空间里检索技术上最优雅但工程复杂度也最高六款里只有一款做了初步尝试。表格处理上我特别关注了一款项目的做法它不把表格当普通文本切而是先解析成结构化数据存一份原始Markdown用于展示再存一份字段名加字段值的扁平化文本用于检索。这样检索时能精准命中某个单元格的内容展示时又能还原成完整表格。这个双存储的思路我觉得非常值得借鉴后面在自研蓝图里我会展开讲。3.3 元数据抽取被低估的检索加速器拆解过程中我发现一个规律越是成熟的项目越重视元数据。新手做RAG往往只存文本和向量而成熟项目会给每个chunk打上一堆标签——来源文件、页码、章节标题、创建时间、文档类型、甚至权限等级。这些元数据在检索阶段的价值巨大。举个例子用户问最新的差旅报销标准是多少如果chunk里带了生效日期元数据就可以在检索时加一个时间过滤直接排除掉旧版本避免模型拿着过期信息胡编。再比如多租户场景权限元数据能在检索前就把无权访问的chunk过滤掉既安全又省算力。六款产品里元数据抽取做得最细的一款甚至会在切分时自动识别文档里的日期、金额、人名等实体作为结构化字段存下来。这其实已经有点知识图谱的味道了和热词里提到的kg知识库、rag知识库和结构知识库区分正好呼应。我的看法是纯RAG适合处理答案在原文里的问题知识图谱适合处理答案需要跨实体推理的问题而结构知识库适合处理答案在数据库字段里的问题。三者不是替代关系而是互补关系成熟的自研RAG应该具备按问题类型路由到不同知识源的能力。4. 索引与检索层向量、关键词与混合检索的取舍4.1 纯向量检索的天花板在哪里纯向量检索的核心假设是语义相近的文本向量距离也近。这个假设在大多数情况下成立但有几类查询它会明显失效。第一类是精确匹配类比如查一个特定的订单号、错误码、产品型号向量检索经常召回一堆语义相似但编号不同的内容。第二类是否定和对比类比如哪些产品不支持退款向量检索容易召回支持退款的段落。第三类是长尾专有名词embedding模型没见过的新词向量表示质量很差。我在测试中做过一个对比同一批文档同一批问题纯向量检索的召回率在语义类问题上能到85%以上但在精确匹配类问题上掉到60%以下。这个差距在demo里看不出来因为demo的问题都是精心设计的语义问题但真实用户的提问五花八门什么都有。六款产品里有两款默认就是纯向量另外四款都引入了关键词检索作为补充。这个比例本身就说明问题——纯向量检索在工程上是不够用的。4.2 混合检索的融合策略RRF还是加权打分混合检索的思路是把向量检索和关键词检索通常是BM25的结果融合起来。融合策略主要有两种一种是加权打分把两路得分归一化之后按权重相加另一种是RRF倒数排名融合不看具体得分只看排名把各路的排名倒数相加。我拆的这几款产品里用RRF的占多数。原因很实际向量相似度和BM25分值的量纲完全不同归一化本身就是个麻烦事而且不同查询的分数分布差异很大固定权重很难调。RRF绕开了这个问题只依赖排名鲁棒性强得多。代价是丢失了分数信息无法区分第一名遥遥领先和第一名险胜这两种情况。我的建议是如果你的检索链路后面还有重排模型用RRF就够了因为重排会重新打分如果没有重排那可能需要加权打分来保留更多信息。这个取舍在自研时一定要想清楚因为它直接决定了你后面要不要上重排。4.3 重排模型性价比最高的一环如果说混合检索是广撒网那重排就是精挑选。做法是先召回一个较大的候选集比如50条再用一个交叉编码器模型对每个候选和查询做精细打分选出最相关的几条比如5条送给大模型。重排是整条链路里性价比最高的一环。我实测下来加了重排之后最终答案的准确率能提升15到25个百分点而增加的延迟只有几百毫秒。六款产品里有四款把重排做成了可插拔组件你可以换不同的重排模型也可以关掉。另外两款没有内置重排需要自己接。这里有个坑要提醒重排模型和embedding模型最好来自同一家族或者经过联合训练否则打分尺度可能不匹配。我试过用A家的embedding配B家的重排效果反而不如不加重排。这个细节很少有文档会写但实际踩过就知道有多坑。4.4 增量更新与索引一致性知识库不是静态的文档会新增、修改、删除。怎么让索引和源文档保持一致是自研RAG必须解决的问题。六款产品在这方面的成熟度差异很大。最简单的做法是全量重建每次更新都把整个知识库重新切分、重新embedding。这种做法实现简单但文档一多就慢得没法用而且embedding是要花钱的。稍微好一点的是按文档增量只重新处理变化的文档但需要维护文档到chunk的映射关系。最成熟的是按chunk增量能识别出文档里具体哪个段落变了只更新对应的chunk但这需要文档解析阶段就做好内容指纹。我拆的一款项目用了内容哈希加版本号的方式每个chunk算一个哈希文档更新时对比哈希只处理变化的chunk同时保留旧版本一段时间用于回滚。这个设计我觉得很实用自研时可以直接借鉴。另外要注意的是删除操作往往比新增更容易出问题——如果只删了源文档没删索引检索时就会召回已经不存在的内容这种幽灵召回在测试阶段很难发现上线后却会严重损害用户信任。5. 编排层从检索结果到最终答案的最后一公里5.1 上下文压缩token预算的精细管理检索回来五条片段每条500字加起来2500字再加上系统提示和对话历史很容易就逼近模型的上下文上限。上下文压缩要解决的就是这个问题在保留关键信息的前提下把送进模型的token降下来。六款产品用的压缩策略主要有三种。第一种是抽取式压缩用一个小模型判断每个句子和查询的相关性只保留高分句子。第二种是摘要式压缩用模型把长片段改写成短摘要。第三种是去重合并把多条片段里重复的内容去掉只保留差异部分。抽取式压缩速度快、成本低但可能丢掉句子之间的逻辑连接摘要式压缩保留的信息更完整但多了一次模型调用延迟和成本都上去了。我个人的偏好是先用去重合并做粗筛再用抽取式压缩做精筛摘要式只在片段特别长的时候才用。这个组合在实测中能把token量压到原来的40%左右而答案质量基本不掉。5.2 多轮对话中的检索状态管理单轮问答好做多轮对话就麻烦了。用户第二轮的提问往往是省略式的比如第一轮问你们有哪些产品第二轮问那个最贵的多少钱这里的那个指代什么检索系统必须搞清楚。六款产品里处理多轮的方式差别很大。简单的是查询改写用模型把省略式问题补全成完整问题再检索。复杂一点的是对话状态跟踪维护一个结构化的状态对象记录用户已经提到的实体、意图、约束条件每轮更新。最复杂的是检索历史融合把前几轮检索到的内容也纳入当前轮的候选集做统一重排。我实测下来查询改写能解决80%的多轮问题成本也低是性价比最高的方案。但它有个前提——改写模型要能准确理解指代关系如果第一轮提到的实体有多个改写就容易出错。这时候就需要对话状态跟踪来兜底。我的建议是如果对话轮次普遍在3轮以内查询改写足够如果经常出现长对话那状态跟踪是必须的。5.3 引用溯源让答案可验证企业场景下用户不只要答案还要知道答案是从哪来的。引用溯源就是给生成的每句话标注来源片段用户点一下就能看到原文。这个功能看起来简单做起来坑不少。第一个坑是生成内容和引用片段对不上。模型可能会把两个片段的信息糅合在一起然后只引用其中一个或者干脆编一个不存在的引用。解决办法是让模型在生成时输出结构化的引用标记而不是事后用相似度去匹配。第二个坑是引用粒度太粗。如果只标到文档级别用户还得自己找体验很差标到句子级别又太碎。我拆的一款项目标到了chunk级别并且在展示时高亮命中的句子这个粒度我觉得比较合适。第三个坑是多跳问题的引用。有些答案需要综合多个片段才能得出这时候引用哪个我的做法是把所有支撑片段都列出来按贡献度排序让用户自己判断。这比强行选一个最佳引用要诚实得多。6. 六款产品逆向后的自研蓝图设计6.1 模块划分哪些必须自研哪些可以复用拆完六款产品我对自研RAG的模块划分有了清晰的判断。核心原则是与业务强相关的自研与业务无关的复用。必须自研的部分包括数据摄入管道因为你的文档格式和业务规则是独特的、切分策略因为你的内容结构是独特的、元数据体系因为你的权限和过滤需求是独特的、以及编排逻辑因为你的prompt和对话流程是独特的。这些部分直接决定了系统的效果上限交给通用框架反而会限制你。可以复用的部分包括embedding模型、重排模型、向量库、关键词检索库、以及大模型本身。这些是基础设施开源方案已经很成熟自己造轮子没有意义。六款产品里做得好的都是在这条边界上把握得很准——该自研的地方做得很深该复用的地方直接拿来。我建议的自研蓝图是四层架构最底层是存储层向量库加文档库加元数据库往上是索引层负责切分、embedding、索引构建和更新再往上是检索层负责多路召回、融合、重排最上层是编排层负责查询理解、上下文组装、生成和引用。层与层之间用清晰的接口隔开任何一层都可以独立替换和测试。6.2 关键接口设计让每一层可插拔可插拔的关键在于接口设计。我在拆解时特别留意了各项目的接口抽象发现做得好的项目都有一个共同点接口只定义输入输出不定义实现细节。比如切分器的接口输入是原始文档对象输出是chunk列表至于怎么切、用什么规则切接口不管。这样你可以随时换一个切分器上层代码完全不用改。再比如检索器的接口输入是查询字符串和过滤条件输出是带分数的候选列表至于用向量还是关键词还是混合接口也不管。这种设计的好处是你可以在早期用简单实现快速跑通后期再逐步替换成更复杂的实现而不用推倒重来。六款产品里接口抽象做得最好的那款甚至允许你在运行时动态切换检索策略这对做A/B测试非常友好。自研时我强烈建议把接口设计放在实现之前哪怕多花两天时间后面能省两周。6.3 评估体系没有度量就没有优化这是我在拆解中最大的收获也是很多自研团队最容易忽略的一环。六款产品里只有两款内置了评估功能其余四款都需要自己搭。但没有评估你根本不知道改动是变好了还是变坏了。评估体系要分两层。第一层是检索评估用标注好的查询-片段对算召回率、精确率、MRR这些指标。第二层是生成评估用查询-答案对算答案准确率、引用准确率、以及用模型打分做相关性评估。两层要分开测因为检索好不代表生成好生成差也不一定是检索的锅。我建议在项目一开始就建一个小的评估集哪怕只有50条数据也比没有强。每次改动之后跑一遍看指标是涨是跌。这个习惯能帮你避免很多感觉变好了其实变差了的误判。评估集的构建也有技巧要覆盖不同类型的查询语义类、精确类、多跳类要包含边界情况空结果、冲突信息还要定期更新防止过拟合。7. 落地过程中我踩过的几个真实坑7.1 embedding模型换了索引没重建这个坑说起来很蠢但确实发生过。我们中途换了一个效果更好的embedding模型代码里改了模型名称但忘了重建索引。结果查询用的是新模型的向量索引里存的是旧模型的向量两者根本不在一个空间里检索结果完全是随机的。更坑的是系统没有报错只是效果变差了我们排查了两天才定位到原因。教训是embedding模型和索引必须绑定版本。我在后来的自研系统里加了一个校验机制索引元数据里记录生成它用的模型名称和版本查询时先校验不一致就直接报错而不是默默返回垃圾结果。这个机制看起来多余但能帮你省下大量排查时间。7.2 切分重叠导致的重复召回切分时设置重叠是为了防止语义断裂但重叠设置不当会导致同一个内容被多个chunk包含检索时全部召回送进模型后模型看到重复内容要么重复回答要么被搞糊涂。我遇到过最严重的一次一个关键段落被五个chunk覆盖检索时五条全回来了占了上下文的一大半把真正有用的其他片段挤掉了。解决办法有两个一是在检索后做去重用内容哈希或者相似度判断把高度重叠的chunk合并二是优化切分策略用语义边界切分代替固定重叠从源头减少重复。我现在倾向于两者结合切分时尽量按语义边界检索后再做一层去重兜底。7.3 大模型一本正经地胡说的抑制即使检索到了正确内容模型也可能不按检索内容回答而是根据自己的参数知识胡编。这种情况在检索内容与模型固有认知冲突时特别容易出现。抑制方法有几个。最直接的是强化prompt约束明确告诉模型只根据提供的资料回答资料里没有就说不知道。但光靠prompt不够模型有时候会阳奉阴违。更有效的是引用强制要求模型每句话都标注来源没有来源的话不许说。这样模型在胡编时会因为找不到引用而收敛。还有一个技巧是降低温度参数让生成更保守减少自由发挥。我实测下来prompt约束加引用强制能解决大部分问题但仍有少量漏网之鱼。最后的兜底是答案校验用另一个模型或者规则检查生成的答案是否能在检索内容里找到支撑找不到就标记为低置信度提示用户谨慎参考。这个校验会增加延迟但对于高准确性要求的场景是值得的。7.4 知识库更新后的幽灵召回前面提过删除操作的问题这里展开讲。我们有一次下线了一批过期文档源文件删了但索引没同步删除。结果用户提问时系统召回了已经下线的文档内容给出了过期的答案。用户投诉之后我们才发现问题。根本原因是索引更新和文档管理是两套系统没有强一致性保证。解决办法是建立文档生命周期和索引生命周期的绑定文档创建时同步创建索引任务文档删除时同步创建删除任务用消息队列保证最终一致。同时加一个定期对账任务扫描源文档和索引的差异发现孤儿索引就清理。这个对账任务看起来笨但它是最后一道防线能兜住各种意外情况。8. 关于自研RAG节奏的一点个人建议如果你现在正准备启动自研RAG我的建议是不要一上来就追求大而全。先用最简单的方案跑通端到端——固定切分、纯向量检索、直接拼prompt把链路打通让业务方看到效果。然后在这个基础上哪里效果差就优化哪里召回不准就加混合检索和重排上下文超了就加压缩多轮混乱就加查询改写答案不可信就加引用溯源。这个渐进式的节奏比一开始就设计完美架构要务实得多因为RAG的效果瓶颈往往不在你预想的地方只有跑起来才知道真正的问题在哪。六款开源产品也都是从简单版本迭代出来的它们的架构复杂度是随着场景需求逐步长出来的不是一开始就设计好的。另外评估集一定要早建。我见过太多团队埋头优化了两个月最后发现优化的方向从一开始就错了因为没有度量全靠感觉。哪怕只有几十条标注数据也能帮你把方向校准。这个投入的回报率比任何单点技术优化都高。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑