资讯详情

自研RAG难在哪?拆解六款开源项目提炼可复用架构蓝图

📅 2026/10/20 7:34:03 | 华诺云谱 👁 阅读
自研RAG难在哪?拆解六款开源项目提炼可复用架构蓝图
这两年我接了不少RAG相关的活儿发现一个特别有意思的现象很多人一上来就要自研RAG理由是开源的不够灵活、不够贴合业务。可真把系统搭起来之后又怨检索不准、解析太弱、评估没抓手整体体验远不如那些拿开源产品改一改的团队。我自己也走过这个弯路后面索性花了整整三周时间把市面上六款有代表性的开源RAG产品从头到尾拆了一遍——不是看README而是源码、架构、部署配置、异常处理全过一遍。拆完之后最大的感受是自研RAG的很多难题其实早就有人在开源项目里趟过路、给过答案我们真正缺的不是能力而是一套能把别人经验翻译成自研方案的思考框架。所以这篇文章我想把这轮逆向工程的完整思路和最终沉淀下来的自研蓝图分享出来。它不是某个开源项目的使用教程而是从六款产品的设计取舍中提炼出的一套可复用骨架适合正在做自研RAG、或者打算从零搭RAG平台的技术团队参考。如果你也经历过demo跑得通、上线就翻车的尴尬这篇文章应该能给你一些直接能落地的启发。1. 为什么我不再拍脑袋设计自研RAG最开始我做RAG的时候和大多数人一样向量数据库选一个、Embedding模型挑一个、Prompt模板写一个三层拼起来觉得就完事了。但实际投到业务里问题一个接一个——PDF里的表格被拆得七零八落、用户换个说法就召回不到、同样的配置在A数据集表现好到B数据集就崩。折腾了几个月我才意识到自研RAG最难的部分根本不是把流程跑通而是做出一系列经得起推敲的设计决策。这个认知转变是拿开源产品当镜子照出来的。你去看那些社区活跃、被大量公司拿去二次开发的开源RAG项目会发现它们普遍有几个共性它们是被真实场景磨出来的。不是实验室项目而是有一堆真实用户在喂数据、报bug、提需求所以很多边缘case的处理比我们自己从零写要成熟得多。它们在工程化上下了很多功夫。比如文档解析、批量索引、增量更新、任务队列、监控指标这些脏活累活恰恰是自研团队最容易忽略的地方。它们的架构取舍是明确且可讨论的。为什么这里用混合检索而不用纯向量为什么分块要带标题为什么查询要做改写每一条设计背后都有理由逆向工程这些理由比抄代码有价值得多。所以我的目标就变成了不是找一款最好的开源产品然后模仿而是把六款产品当成六个样本分别从索引管道、检索策略、生成增强、评估机制、部署形态几个维度去解剖最后把共性抽出来重新组合成一套适合自己业务的自研蓝图。提示逆向工程的正确姿态是研究为什么这样设计而不是抄一段代码过来跑。前者帮你建立判断力后者只会让你陷入没完没了的适配泥潭。2. 六款开源产品的拆解记录各自的杀手锏和代价为了让拆解不流于表面我给每一款产品都规定了统一的观察维度解决了什么问题、核心架构长什么样、最关键的一个设计决策、以及这个设计给自研带来的启发。下面按产品逐个说。2.1 产品A把流程编排做成核心资产第一款产品给我的印象非常深刻它本质上是一个以工作流编排为核心的RAG框架。你可以在可视化界面里把查询理解→多路召回→重排→生成串成一个流程图每个节点还能设分支条件、并行策略和人工审批环节。拆它的源码时我才发现它真正的野心不是做一个检索工具而是把RAG变成一种可编排的业务流程。这个设计对我冲击很大——大多数自研团队把RAG写成一个固定的Python函数链参数写死在代码里改流程要发版。而产品A把流程本身当作数据流程定义是JSON节点是插件运行时有独立的调度器来管理节点间的状态传递和失败重试。它的代价是学习成本高、系统复杂度大如果业务只是文档问答这种简单场景这套重量级编排反而是负担。但它给我最大的启发是流程的编排能力决定了RAG系统能走多远。你不一定需要可视化界面但至少要能在配置层调整流程而不是改代码。2.2 产品B把文档解析当成一等公民第二款产品是个知名的开源知识库问答平台。它让我认识到很多RAG项目检索不准的问题根源根本不在检索而在文档解析。产品B对文档解析的重视程度在开源项目里非常少见。它跑完PDF解析之后不只输出纯文本还保留标题层级、表格结构、段落坐标、阅读顺序这些信息。更关键的是它允许你在切片时使用文档自带的版式信息——比如表头可以被当作该表格所有chunk的公共前缀这样表格切片后每个分块都仍然带着列名上下文召回效果自然就上去了。这个设计对应到我们自研场景其实非常简单但执行起来很考验决心解析层的输出不能只是字符串数组而应该是一个带有结构化元数据的文档对象。标题、页码、章节路径、表格标记统统要保留。可惜大多数自研系统这部分都做得极其潦草就是一个PDF库抽文本抽完就切切完就喂向量库。2.3 产品C把混合检索作出真正的工程深度第三款产品更偏检索性能取向它把稀疏检索稠密检索重排这条链路打磨得非常扎实。拆它的代码时我注意到几个细节第一它做BM25索引用的是独立引擎而不是Python里临时算这样大规模文档下的关键词召回性能完全可控第二它把向量检索和关键词检索的结果做了基于分数的融合而不是简单粗暴地两类结果各取一半拼接第三它的重排环节支持热切换你可以在线对比不同重排模型的效果。在这个过程中它还暴露了一个很多团队会踩的坑如果向量索引里混入大量元数据差异很大的文档单一的embedding模型效果会非常不稳定。所以它的做法是建立检索配置文件不同文档库绑定不同的检索策略和模型参数。我从它身上提炼的要点是混合检索不是又用向量又用关键词这么简单而是要在召回、融合、重排三个环节分别做设计并且让每个环节的参数都可以被配置和实验。2.4 产品D把RAG做成了标准推理服务第四款产品很轻量它没做花哨的流程编辑而是把RAG整个封装成一个标准服务对外暴露OpenAI兼容的接口。请求进去之后系统内部自动完成检索、拼接上下文、调用LLM、流式返回调用方完全不需要关心RAG内部发生了什么。这种把复杂度留给自己把简单留给调用方的思路对自研非常有参考价值。它的架构里有一个值得学习的组件叫会话态管理——它会在多轮对话中把历史消息压缩成摘要再跟当前问题一起做检索避免每次对话都把完整历史丢进模型。它还内置了一套缓存机制同样的查询在短时间内会被缓存命中后连检索都不用做。它让我重新思考了自研RAG的服务形态RAG不应该只是业务代码里嵌入的一个函数而应该成为一个有独立生命周期、独立运维边界的基础服务这样上层应用可以稳定依赖它底层优化也可以持续迭代而不影响业务。2.5 产品E用多模态向量打破纯文本天花板第五款产品专注多模态RAG它能把图片、表格、版式复杂的PDF一并进行向量化并且支持跨模态检索——你输入一段文字它可以召回相关的图片片段甚至表格结构。拆解时我发现它的思路不是什么模态都塞进同一个向量空间而是区分对象级向量和块级向量图片、表格这种大对象单独建索引而文本碎片块挂在对象下面。检索时先在对象级做召回再定位到对象内部更具体的位置。这种做法既保证了跨模态召回能力又避免了混合模态分块导致语义被切碎的问题。对于自研团队来说如果不做多模态这部分内容可以暂时跳过。但对象级索引块级索引分层的思想其实是通用的即使全是文本不同粒度的文档单元也可以分层建模。比如一篇文章既是章节级对象又是段落级分块检索时先定位章节再定位段落效果往往比一把梭式的全局切片更可控。2.6 产品F把评估做成了内建基础设施最后一款产品最打动我的是它对评估的偏执。它内置了一套评估机制你只需要准备一组问题-标准答案-参考文档三元组系统就能自动跑批量评测输出召回命中率、答案正确率、引用准确率等多个维度的报告。更厉害的是它的评估结果不是一次性看板而是可以做回归对比每次修改检索策略、重排模型或者Prompt之后都跑一遍同一套评估集所有指标变化一目了然。等于说它把RAG系统优化这件事从凭感觉调参变成了指标驱动迭代。这一点恰恰是自研团队最容易偷懒的地方。我见过不少团队上线RAG之后效果好不好全凭几个人的主观感受出了问题也不知道是检索坏了还是模型坏了。产品F给我的启发就是评估应该和检索、生成一样是RAG系统的一级组成部分而不是事后的临时脚本。产品代称核心能力偏向最值得借鉴的设计主要局限性产品A流程编排流程即配置、节点可插拔轻量场景下过于复杂产品B文档解析保留版式信息的分层切片对解析依赖过重产品C检索性能召回-融合-重排三段式优化调参门槛较高产品D服务化封装会话态管理与缓存内部逻辑张力有限产品E多模态检索对象级与块级分层索引实现成本高产品F效果评估内建评估与回归对比需要持续投入标注精力3. 拆完六款之后我提炼到的五个共性设计产品拆完光记录亮点是不够的得做横向对比才能看出哪些设计是个别团队的偏好哪些是所有优秀产品的共识。这一步我花的时间比拆解本身还长最后沉淀下来五个共性。3.1 混合检索已经是默认配置不再是加分项六款产品里没有一款是只靠向量检索的。即便是最轻量的产品D也内置了BM25作为稠密检索的兜底。原因不难理解向量检索擅长语义匹配但存在两个短板——一是对专有名词、精确编号比如合同号、设备型号不敏感二是embedding模型的训练分布很可能和你的业务分布不一致导致相似度分数不可靠。而关键词检索刚好在这两个场景里表现稳定。混合检索的标准做法是三段式多路召回、结果融合、统一重排。召回阶段向量和关键词并行跑各自取top N融合阶段最常用的是RRFReciprocal Rank Fusion算法它不看具体分数只看排名——好处是对不同检索器的分数尺度不敏感重排阶段用一个更强的模型交叉编码器对融合后的候选列表做精排取top K送入生成环节。3.2 查询端处理被严重低估六款产品里有四款在生成之前做了查询端处理形式各不相同有的是简单的同义改写有的是多跳问题的子问题分解有的是把模糊问题拆成意图识别参数提取两步。它们的共同出发点都一样用户真实的问题很少是标准的、适合直接检索的。举一个很常见的例子用户问去年下半年我们跟那家供应商签的合同里付款条款是怎么约定的这句话直接拿去做向量检索很容易被去年那家约定这些词干扰。更合理的做法是先抽取意图查合同条款和约束条件时间范围、供应商范围再组装成检索query。这一层改写做不做对最终效果的影响往往比换一个更强的embedding模型更明显。自研落地时不需要做得很重可以先从基于规则的query改写开始比如识别实体、剥离修饰词、把口语转成书面语跑通之后再考虑是否引入LLM来做复杂改写。3.3 元数据永远是事前的过滤器不是事后的截断器拆解过程中六款产品里有五款支持元数据过滤而且都是把过滤下推到检索阶段。这句话值得展开说很多自研RAG的做法是先把相关文档召回来再在应用层按业务规则过滤这个顺序其实很亏。因为向量检索是在高维空间找近邻如果文档库里混着多种类型的内容相似度排序会被无关文档干扰等召回结果出来再截断正确结果可能已经被挤出topK了。正确的做法是在索引阶段就把文档类型、时间、部门、标签等元数据写入索引检索阶段先按元数据过滤filter再做相似度搜索。这等于把在全局找相似变成了在子集里找相似精度和性能都会提升。这条经验还引出一个操作建议设计文档模型时多想一层未来我会不会想按这个字段过滤提前在元数据层留好位置比后面改索引结构省事得多。3.4 缓存设计决定了系统的成本与延迟上限拆源码的时候凡是有缓存设计的产品都会在架构图里专门画一层。缓存的对象也各不相同有的缓存LLM的生成结果有的缓存向量检索结果有的缓存query改写结果。缓存的价值有两块一是成本二是延迟。RAG场景里完全相同的用户问题其实是很多的尤其是企业内部知识库场景大批员工问的是同一批高频问题。如果每次都从头跑一遍检索生成token开销和GPU压力都很大。加一层语义缓存之后重复问题直接命中历史答案延迟可以从秒级降到毫秒级。自研落地时我的建议是先做精确缓存完全相同的query直接命中跑稳之后再考虑语义缓存用向量相似度判断是否命中同一意图。语义缓存的水比较深阈值调不好会误命中初期没必要贪。3.5 没有评估闭环一切的优化都无从谈起这是六款产品里我最想强调的共性。它们无一例外地都内置了某种评估和观测能力有的做批量评测有的做线上日志分析。因为RAG链路太长、组件太多不确定因素包夹着不确定因素解析可能丢信息、检索可能漏结果、重排可能改错顺序、LLM可能胡编。要是没有一套评估体系把这些环节的指标拆开看出了问题你根本无法定位归因。自研评估体系的MVP做法不需要很复杂准备一条从线上对话中采集的、覆盖各类典型问题的金标评测集哪怕只有三五十条也行每改动一个组件就跑一遍评测把命中率和答案质量两个核心指标记录下来。坚持两三个版本之后你会明显感觉到自己对系统的掌控力完全不一样了。提示自研RAG最忌讳重检索轻评估。没有评估体系你连检索不准和生成不对都分不清。4. 逆向工程的最终产出一套可复用的自研RAG蓝图把六款产品的共性抽出来之后我意识到它们其实是围绕着同一个清晰分层在做文章。于是我把这些共性重新组装成了一套自研RAG蓝图给团队里两个新同事试用之后效果比预期好很多。下面就是这个蓝图的完整结构。4.1 总体架构五大分层加一条横切面这套蓝图分成五层接入层、流程编排层、索引层、检索增强层、模型层。外加一条横切所有层的观测与评估链路。---------------------------------------------------------- | 接入层 / API 网关 | | 支持流式输出、多轮会话管理、权限校验、语义缓存命中判断 | ---------------------------------------------------------- | 流程编排层 | | query改写 - 路由选择 - 多路召回 - 融合 - 重排 - 生成 | | 流程定义可配置化支持跳过/插拔单个节点 | ---------------------------------------------------------- | 索引层 | | 解析器(文本/PDF/表格/扫描件) - 结构化解构 - 分块 | | 元数据抽取 - 向量化 关键词索引(双写) | ---------------------------------------------------------- | 检索增强层 | | 向量检索 BM25检索 元数据过滤 | | RRF融合 - 重排模型精排 - 引用片段回填 | ---------------------------------------------------------- | 模型层 | | embedding模型 | 重排模型 | 生成LLM | 可选小模型做改写/意图 | ---------------------------------------------------------- | 观测与评估横切面 | | 请求日志、检索指标、生成指标、批量回归评测 | ----------------------------------------------------------这套架构最核心的点在于流程编排层。很多自研项目的问题在于流程藏在代码的if-else里想调整链路非常痛苦。把它抽出来之后RAG系统的每一次改造都可以在一个可配置流程里完成比较直观的做法是定义一份JSON描述节点顺序和节点参数。4.2 索引层的关键设计先还原文档结构再谈切分索引层是整套RAG的地基。这里我想分享几个拆解六款产品后总结下来的实操参数和设计建议。文档解析要输出富结构不只是纯文本。拿PDF举例解析结果至少要包含标题路径、段落所属章节、表格结构和阅读顺序。因为后续的检索和引用需要这些信息来定位上下文。实测中好的解析器能把表格里的内容切成带表头的独立chunk而朴素做法会把表格内容按行拆得语义破碎。分块策略不用追求最优参数但要遵循小底层、大语境的思路。很多产品实际采用的方案是基础分块小一些256~512 token同时把所处分块对应的标题层级、摘要、邻近块作为扩展上下文一起注入。这样既可以保证召回单元的语义纯度又能在生成阶段补充上下文完整度。分块overlap一般取10%~20%太高会带来大量冗余chunk推高向量检索的噪音。索引必须双写稠密索引负责语义稀疏索引负责关键词。从产品C的实践来看两者缺一不可。特别是当你的语料里包含大量编号、型号、缩写时稀疏索引往往是兜住召回下限的关键。4.3 检索层的三个参数组召回、融合、重排检索层不是调一个API它是由三组参数协同决定的。我在项目里把它们拆成三个配置组来管理召回组负责确定候选集合。一般配置为向量召回topK50BM25召回topK50。如果你的业务对精度要求高可以取更小如果文档碎片很多可以加大。融合组负责把两路结果合并成一列。RRF是一个稳妥选择它的公式是score(d) sum( 1 / (k rank_i(d)) )k是一个平滑常数常见取值60。RRF的好处是不依赖两个检索器的分数校准——BM25给100分、向量检索给0.7这种尺度差异不会影响融合结果。融合后取前30个候选送到重排环节。重排组负责精排。部署一个交叉编码器cross-encoder模型对30个候选逐一计算相关性分最后返回top5~10作为生成上下文。交叉编码器虽然比双塔模型慢但相关性判断精度高一个档位是重排环节的标配。我还想提供一个很实际的建议千万别试图在召回阶段把精度一步做够。召回的任务是宁可多召回、不可漏召回精确排序是重排的任务。这两个角色的错位是很多RAG效果不好的隐性原因。4.4 生成层的增强链路引用与验证生成层的核心问题有两个怎么让模型基于上下文回答以及怎么让用户信服答案。前者靠Prompt工程就能解决大半后者则要靠引用回填。引用回填的思路是重排阶段选中的参考片段实际上是带有文档路径和片段索引的。拼接Prompt时让模型在答案里标注引用编号如[1][2]生成之后再把编号映射回文档位置展示给用户。这一步对B端知识库问答系统非常重要——没有引用的RAG答案即便对了也缺少说服力有了引用用户可以一键跳转原文做二次确认。更进阶一点的做法是做答案验证把模型生成的结论和参考片段做一致性验证比如用一个小模型判断答案是否忠于引用片段。这套机制可以拦截一部分幻觉但不是银弹因为它只能验证引用片段支撑答案不能验证引用片段覆盖所有正确答案。4.5 评估层的最小方案三条指标覆盖主流程最后是评估层。我的MVP建议是三条指标召回命中率标准答案里提到的关键信息点是否出现在最终送入生成的上下文片段中。引用准确率模型输出中标记的每一个引用编号是否真的对应到回答内容相关的那一段文档。答案忠实度生成答案中的事实性陈述是否都能从引用片段中找得到依据。评测集不用很大先攒50~100条真实场景的问题-标准答案-参考文档即可。每次调整分块、重排、Prompt后跑一遍回归三条指标的走势就是你优化方向的指南针。5. 把这套蓝图落到自己的系统里有五个坑值得提前知道蓝图是理想化的把它落到真实系统里难免会遇到一些不拆个开源项目就永远不知道的坑。这几个坑我在实际落地中基本都踩过一遍提前说出来希望能帮你省点时间。5.1 分块参数看一眼合理不如跑一遍可靠很多团队在分块大小上喜欢拍脑袋觉得512合适就用512。但你跑一遍评测集就会发现不同文档类型对分块的敏感度差异极大合同条款类文档对精确切片要求高运营手册类文档则依赖段落语义的完整性。建议把分块大小做成可配置项然后在评估集上做小范围网格搜索用指标说话而不是用直觉说话。5.2 重排模型救不了召回就已经漏了的局面如果召回阶段top50里压根没有正确答案重排再强也无济于事。遇到重排后效果还是差的情况先检查召回命中率如果召回命中率低于80%问题出在索引或召回环节这时候去调重排完全是浪费精力。5.3 文档解析是所有问题的隐蔽根源我遇到过很多次检索结果一团糟的排查最后定位到的问题竟然是PDF表格解析后行列错乱或者页眉页脚被当成正文索引进去了。解析环节看起来不显眼但它产生的错误会一路传导到召回、融合、生成污染整条链路。如果预算允许尽量选解析能力强的引擎并且在解析阶段就做一轮质量检查——比如检查每页文本量是否异常、表结构是否完整。5.4 别一上来就堆砌新概念ChatPDF、GraphRAG、Agentic RAG、Self-RAG这些概念确实诱人但它们都有特定的适用前提。GraphRAG适合需要跨文档关系推理的场景Self-RAG适合对幻觉容忍度极低的高危场景但这些都要付出额外的复杂度和算力代价。我的原则是先用最简链路跑通再按评测结果显示的短板引入对应的高级机制。5.5 一定要留好实验开关的配置位自研RAG迭代非常频繁模型在换、参数在调、流程在改。如果每次实验都要改代码发版迭代效率会低到让人绝望。建议从一开始就把链条上所有可调项都暴露成配置分块大小、topK、重排模型、缓存开关、query改写级别全部配置化。这样新方案可以随时在灰度环境里验证效果好了再推全量。我在实际项目里还养成一个习惯每轮调整之后都手动记录一份改动-指标变化-结论的简短笔记哪怕只是几行字几个月后回看这份笔记会是整个项目最值钱的资产之一。最后再分享一个小技巧别把逆向工程当成一次性工作。开源项目在持续演进每隔半年去拆一轮最新版本就像定期体检一样总能发现一些新的设计思路然后拿回来补充到自己的蓝图里。技术和业务都在变化这套蓝图不会一直正确但它给了你一个可以持续演化、可讨论、可复盘的自研框架这比任何一个固定的架构图都重要。
📝

华诺云谱内容团队

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

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

你可能需要的服务

订阅华诺云谱资讯周报

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

↑