今年年初做了个内部知识库问答系统,技术栈选了RAG,业务场景是企业内部文档的智能检索。
文案一扔进去跑,效果直接劝退。投喂了一批产品文档和FAQ,问一个「你们产品的日志最大保留多久」,返回的内容里混着安装指南、配置说明、三个不同版本的手册片段。原因很简单,纯向量检索只看语义相似度,不看这个词在当前上下文里的具体价值。高频词会把向量拉偏,长尾的精准信息反而排到了后面。
纯向量检索的问题在哪
向量检索的核心逻辑是,把文本映射到高维语义空间,然后找最近的邻居。这个方法对于大段的主题性查询效果不错,比如「介绍一下你们的部署架构」。但对于精确查找,比如「日志保留时间」「支持的数据库类型」这种确定性知识,它天然不擅长。
原因有两个。
一个是维度灾难。嵌入向量的维度通常是768或者1536,在这么高的维度空间里,距离度量的区分度会下降。所有东西看起来都「差不多近」。你把日志相关的文档全埋在一堆安装配置文档里,向量距离可能只差零点零几。
另一个是缺乏词级别的精确匹配能力。我在产品文档里写的是「日志保留周期为30天」,你问的是「最长保留多久」,语义上确实接近,但如果是「日志存储上限50GB」,跟你的查询也很接近。向量把两段都拉回来,你根本分不清哪个是你真正要的。
混合检索,两套方案解决两类问题
做得好的RAG系统不会只用一种检索方式。基本都采用了混合检索的思路。
标准做法是同时跑两路。一路向量检索,找语义相关的文档块。一路关键词检索,找字面上匹配的文档块。然后把结果合并,重新排权重。
说到关键词检索,很多人第一反应是ES的全文搜索。ES的BM25算法确实是用得最多的关键词检索方案。它的基本原理很简单,一个词在文档里出现得越多,这篇文档越相关。但如果这个词在很多文档里都出现,那它的重要性就降低。
向量检索的优势在于理解意图,关键词检索的优势在于精确命中。各管一摊。
但两路结果怎么合并是个工程问题。
最简单的做法是加权求和。向量得分乘0.7加BM25得分乘0.3。但权重设死了就不好,不同查询对两路检索的需求是不一样的。我们内部的做法是引入一个轻量的排序模型,用一个几层的小网络学习每个检索结果的相关性分数。特征包括向量的相似度、BM25得分、文档长度、查询中的关键词命中率、文档的时效性。这个模型小到什么程度,参数量不到两万,单次推理微秒级。
分块策略比检索算法更关键
整个RAG系统里投入产出比最高的优化,不是检索算法,是分块策略。
同样的文档,你怎么切,切多大,切不切重叠,切完之后怎么保留上下文,这些直接影响检索质量。
我们经历了三版迭代。
第一版,按固定Token数切。每段512个token,前面留32个token的重叠。上线一看,很多问题搜不到答案。原因很简单,一个完整的配置说明可能分布在两个块里,第一个块讲参数,第二个块讲效果。你问参数相关的问题,命中了第一块,但答案在第二块里。
第二版,按语义段落切。把Markdown的标题层级作为分块依据,一个H2或H3下的内容作为一个块。效果好了不少。但又有新问题,有些段落太短,只有两行字,信息不够支撑回答。有些段落太长,一个H2下面放了四五个子主题,混杂在一起。
第三版,递归分块加元数据拼接。先用段落层级做粗切,然后对特别短的段落向上跟父段落合并,对特别长的段落用主题边界再做子切。每个块生成的时候,把它所属的大段落标题和相邻块的主题描述作为元数据拼进去。这样搜索的时候,一个块不仅包含自己的内容,还知道自己「属于哪个部分」。
这个改动让精确检索的命中率从62%提到了83%。不是算法变了,是信息密度变高了。每个检索回来的块都能独立回答一个问题,不再需要拼图。
RAG的工程化远没到终点
很多人把RAG想得很简单,文档切一切,用embedding建个索引,查一下拿去喂给大模型。跑通了就以为做完了。
实际跑上生产你会发现一堆问题。用户输入的查询本身质量就很差,口语化严重,语义不完整。大模型生成的时候可能自己添油加醋。检索到的相关文档可能有多个但在互相矛盾。用户等了五六秒才收到回复,体验太差。
这套系统的天花板目前不靠大模型,而在于信息能不能被准确地找到、送到、用上。检索搞不定的事,大模型也搞不定。
顺着上面的思路,我们在检索层稳定之后还做了一件事,用Ai好记把公司的技术直播、产品讨论会录音全部转成了结构化笔记,喂进知识库。
每次出一个新版本,对应的技术讲解视频解析完,笔记自动归到知识库里对应的目录下。检索层再跑一遍,新知识就吞进去了。
之前有一场关于数据库连接池重构的技术分享,讲了很多细节,当时觉得记下来就行。
两个月后真的有人遇到了同样的问题,从知识库里直接搜到了那次会议的笔记,省了让团队重新排查一遍的时间。
知识库只有持续喂才有价值。而检索层优化,就是在帮每次喂进去的内容找到最适合被翻出来的时机。