我帮人排查过不少RAG项目,十有八九的问题不在模型,而在检索。文档明明在里面,用户用自然语言问就是查不到;日志里recall低得吓人,排在后面的正确答案根本进不了LLM的上下文。这类问题反复出现,根本原因往往不是某个环节出bug,而是整个向量检索系统在设计阶段就少走了一步。
这篇内容我想把过去几年做知识库问答、搜索系统、RAG落地过程中沉淀下来的东西,按9个核心步骤完整拆一遍。从业务目标分析开始,到数据切分、模型选型、存储选型、索引结构、召回策略、重排机制,再到离线评测和线上监控,每一步解决什么问题、有哪些经验参数、会遇到什么坑,尽量一次讲透。适合正在搭RAG后台的开发者、准备做向量检索方案选型的后端工程师,以及想系统理解检索系统的算法同学。
1. 先别谈数据库:场景与数据问题决定了检索上限
很多人一上来就问我“该用哪个向量数据库”,这个顺序本身就错了。向量检索系统不是数据库选型题,而是数据题。数据怎么切、检索要满足什么目标,这两件事没定,选什么库都是空中楼阁。
1.1 第1步:把业务目标翻译成检索指标,而不是直接选库
先说一个我印象很深的案例。某知识库项目要做合同条款问答,团队成员把文档全部导进向量库,用默认配置搭了一套demo,发现问“违约金上限怎么约定”时,答案几乎永远是错的。查了半天,发现合同原文里大量条款分散在不同章节,单段检索只能捞到局部内容,真正的汇总性答案压根不在任何一个chunk里。
这个案例的核心教训是:先回答“检索结果要给谁用”。如果给LLM当上下文,那么召回精度和全率高不高直接决定生成质量;如果给用户当搜索结果,排序体验、可解释性反而更关键。这两类场景对指标的要求完全不同。RAG场景我把Recall@K放第一位,K一般取5或10,意思是最优答案是否出现在前K条结果里。LLM只要能看到答案,生成质量就有保障,排序不完美也能接受。
实操上,我建议一开始就做一套最小可用评测集。从真实用户日志里抽100到200个问题,人工标注每个问题对应的正确文档ID。不用做得很重,哪怕是Excel表格也够用。有了这份标注,后面任何改动都能量化对比。这一步看起来简单,但太多团队跳过了,导致后面花了几个星期调参,连调好调坏都不知道。
再补充一点,建模时要把“检索目标”具体化。合同审查场景,用户想要的是“有没有风险条款”,正确答案可能是多个片段拼接,不是单一文档。这类需求决定了后面的切分策略、混合检索设计,甚至重排模型都要配套调整。如果不做这一步,后面每一步都可能是在错误的方向上优化。
1.2 第2步:切分策略决定检索上限,chunking不是凑字数
数据切分是整个检索系统里最不起眼但影响最大的环节。很多团队直接用固定长度硬切,比如512个字符一刀切,结果一个完整概念被拦腰截断,语义残缺;或者反过来,一个超长段落塞进一个chunk,向量的语义被稀释成“大杂烩”,跟谁都像,又跟谁都不像。
我把切分策略分成三个层次。第一层是结构切分,优先按文档本身的层级走,比如Markdown标题、HTML标签、PDF章节,这是最可靠的方式。第二层是语义切分,按段落、句子边界切,保证每个chunk在内容上尽量完整。第三层才是固定长度切分,只用于前两层无法处理的纯文本流。实操经验是:80%的场景用前两层就够了,固定长度是兜底,不是首选。
chunk size和overlap是绕不开的两个参数。我常用的范围是每块256到512个token,overlap设10%到20%。如果文档是高度结构化的条款类内容,比如合同、规范,块可以更小一点,甚至只按条款切;如果是叙述类文章、百科,块应该大一些,让上下文更完整。overlap的作用不是解决切碎问题,而是缓解边界信息丢失。但别指望它能包治百病,一个知识点被切成两半且核心信息恰好落在overlap之外,照样查不到。
补充一个很多人忽略的点:切分时把元数据一起存下来。章节路径、文档类型、发布时间、页码,这些信息在后期做过滤、做展示、做权限控制时都是必需品。我习惯把元数据设计成结构化字段存进向量库,这样搜索时能通过filter快速缩小范围,而不是把所有chunk捞出来再做内存过滤,性能差距是数量级的。
2. 向量化与存储:模型和库该怎么配对
数据和切分定了,才有资格谈模型和存储。这两者其实是配对关系:嵌入模型决定了向量的语义质量,向量数据库决定了这些向量能不能被高效地存、查、维护。分开选型后面一定吃亏。
2.1 第3步:嵌入模型选型:维度、语言、领域都要管
嵌入模型做的事情是把文本映射成高维向量,语义相近的文本向量距离就近。这个“语义空间”的质量,直接决定了检索的上限。选型时我一般看四个维度。
第一是语言能力。中文、英文、中英混合场景对模型要求差很多。中文的专名识别、简称、口语化表达处理不当,召回效果会很惨。英文的缩写和复合词又是另外一套逻辑。多语言场景还要考虑跨语言检索,这会引入额外复杂度。第二是向量维度。常见的通用向量模型输出在768维左右,轻量模型256到384维。维度越高表达力越强,但内存和计算开销也越大,小数据集上高维反而容易过拟合。第三是部署约束。离线部署、在线延迟、GPU还是CPU推理,这决定了能不能用大模型还是必须用轻量模型。第四是领域适配。通用模型在垂直领域表现可能显著退化,医疗、法律、工业文档里的行话和术语,通用语义空间往往覆盖不好。
关键原则:索引和查询必须用同一个模型。有些团队换模型做query编码,或者用不同版本的模型建索引和查询,向量空间分布不一致,召回立刻崩。还有一个容易踩的坑:部分模型使用不对称编码,比如query和document分别走不同的编码器或指令模板,这时查询编码和文档编码不能互换。实操时,我通常在自建评测集上对比两到三个候选模型的Recall@10,而不是直接看公开榜单。公开榜单分数高不代表你的领域语料表现好,这种对比实验跑一次只要半天,但能省下后面几周的返工。
2.2 第4步:向量数据库选型:先分清三种路线再谈性能
市面上的向量存储方案五花八门,但本质上就是三条路线。第一种是轻量级嵌入式向量库,适合单机、原型验证和小规模数据;部署简单,随应用一起启动,缺点是高并发、多副本、持久化都要自己解决,数据量大后容易顶不住。第二种是独立的向量数据库,支持分布式、水平扩展、自带索引管理和高级检索能力,适合生产环境大规模数据。成本是会多一个组件,运维复杂度上升。第三种是传统关系型数据库的向量插件,在已有的数据库上增加向量索引能力,对已有团队最友好,不用引入新系统,但算法能力、性能上限通常不如专用方案。
选型标准我只看三点:数据量多大、QPS要求多高、团队愿意投入多少运维成本。如果数据量在百万级以内,QPS要求不高,嵌入式方案完全够用;如果到了千万级以上,或者对高并发、高可用有硬性要求,独立向量库是必然选择;如果公司已经重度依赖某款关系库,并且数据量可控,插件方案是最平滑的路径。
这里要特别提醒:向量库的性能测试千万别只看官方benchmark。很多性能指标是在“纯向量检索、不带过滤、召回条数很少”的理想条件下测出来的。真实场景中加了metadata过滤、带了多路召回、排序逻辑更复杂,延迟可能翻几倍甚至一个数量级。我做过一个测试,纯检索P95只有60毫秒,加上权限过滤后直接飙到500毫秒以上。所以选型和压测时,一定要把真实查询模式带进去测,包括过滤条件、并发量、数据分布。
另外算一下内存预算。一个500万条、768维的向量库,float32存储原始向量大约需要500万×768×4字节,约15GB。加上图索引的结构开销,通常还要再预留30%到50%的内存。一台机器未必扛得住。如果数据量再上一个数量级,就要认真考虑量化方案,或者干脆从架构层面做分片。这一点最好在设计阶段就算清楚,别等到上线前才追加预算。
3. 索引与召回:从“能算相似度”到“真能找到”
模型和存储确定了,系统已经能跑通“向量化-入库-查询”的基本链路。但这个链路能查到什么质量的内容,取决于索引结构和召回策略。这部分是“设计精髓”所在,也是大厂架构师最花心思的地方。
3.1 第5步:索引结构:Flat、图索引、量化该选谁
向量检索本质上是在高维空间里找最近邻。数据量小的时候,暴力扫描全部向量算距离最快也最准,这种叫Flat索引。但数据量一大,暴力扫描的时间线性增长,必须靠索引来加速。
最常用的近似最近邻方案之一是HNSW,它的核心思路是构建一张多层的邻居图,检索时从顶层往下“跳”,逐步逼近目标。HNSW有三个关键参数:M控制每个节点的最大连接数,M越大图越密,召回越高,内存和构建时间也越高,常见取值在16到64区间;efConstruction控制建图时的搜索范围,常见取值100到300,建索引阶段调大只影响建库时间,不影响查询;efSearch控制查询时的搜索范围,常见取值50到200,这个值越大查询越准但延迟越高,而且它是在每次查询时动态指定的。
另一种常用方案是向量量化压缩,把原始向量压缩成更短的编码,大幅降低内存占用,比如乘积量化(PQ),常有4到8倍的内存压缩效果,但精度会有下降。很多系统会把“粗量化+倒排”和“PQ压缩”组合起来,用倒排先粗筛候选,再用压缩编码做精排。
实操上我的建议很直接:数据量小就老实上Flat,别为了“听起来高级”硬上HNSW,暴力扫描在百万级以下没有任何压力。数据量上来了,优先上HNSW。只有当内存成为瓶颈时,才考虑PQ量化。而且不要迷信默认参数,每次调整后一定要回评测集上跑Recall@K,避免为了性能牺牲召回。索引结构这件事,永远是在“快”和“准”之间做权衡,没有免费的午餐。
3.2 第6步:相似度分数与检索策略:别拿余弦值当置信度
向量索引建好了,接下来就要定义“怎么算相似”。最常见的三个指标是余弦相似度、欧式距离和内积。余弦相似度衡量的是方向一致性,不关心向量长度;欧式距离衡量的是绝对距离,数值越小越相似;内积则同时受到方向和长度影响。不同嵌入模型推荐的距离算法不同,多数模型用余弦相似度,但部分模型训练时用的是内积。需要去查模型的文档,把向量库的默认距离配置统一成模型推荐值,这一步经常被忽略,导致线上分数看起来正常,实际排序已经偏了。
更重要的一点是:相似度分数不等于相关性。很多团队喜欢设一个阈值,比如“余弦分数大于0.7才返回”,结果发现不同query的分数分布差异巨大。有的query所有文档都集中在0.2附近,有的全是0.8以上,硬阈值会误杀大量有效结果。我建议放弃全局阈值思维,改用相对排序加top-K截断。与其在分数阈值上较劲,不如把精力放在重排阶段,让更强的模型做最终判断。
检索策略上,不要只走一路。一个成熟的方案至少包含向量召回加关键词召回,也就是后面要说的混合检索。同时,几乎所有生产级检索场景都需要metadata过滤,比如按时间范围、文档类型、权限标签过滤。这里的经验是过滤条件要在索引层面下推,也就是让向量库先执行过滤再检索,而不是先召回再过滤,否则百万级数据会遇到严重的性能灾难。
3.3 第7步:混合检索与重排:用两路召回兜住边缘case
向量检索擅长语义相关性,但它有一个天然弱点:对精确术语、代码、型号、编号这类信息不够敏感。比如用户搜索“型号GX-2000的维护周期”,向量检索很可能把“GX-2000”的语义泛化掉,召回一些“类似设备”的文档,反而把精确匹配的信息漏了。这时候关键词检索能精准命中,作为第二路召回非常有效。
混合检索最简单的合并方式是RRF,倒数排名融合。每个文档在两路召回里各有一个排名,最终得分是所有路排名的倒数之和,比如score(d) = 1/(k + rank_1(d)) + 1/(k + rank_2(d)),k常取60。RRF的好处是不用调权重,对排名敏感的噪声不敏感,实际用下来非常稳。比加权分数融合省心得多,因为不同路的分数尺度完全不一样,直接加权要么被向量分数主导,要么被关键词分数主导。
重排阶段是RAG效果提升最明显的杠杆之一。粗召回阶段一般取50到100条候选,重排模型对这些(query, doc)对重新打分,最后取top 5到10条交给LLM。常用做法是用一个更强的交叉编码器模型,不再依赖向量距离,而是直接判断“这个文档是否回答这个问题”,精度比向量检索高一个档次。代价是延迟明显上升,所以只能用于少量候选重排,不能直接用在全量数据上。
但我必须强调一点:重排不是万能药。如果粗召回阶段就把正确答案漏了,重排模型根本没有机会把它排上来。所以先提升粗召回的召回率,再考虑重排精度。这也就是为什么我前面说切分、索引、多路召回每个环节都不能省,它们是环环相扣的。
4. 上线只是开始:评测闭环与持续迭代
很多团队把系统跑通、上线、看几个demo没问题就觉得完事了。实际上,上线那一刻才是检索系统真正开始被考验的时候。没有评测体系和线上监控,系统会在用户看不到的地方慢慢劣化。
4.1 第8步:离线评测:没有指标就没有优化资格
前面第1步提到的评测集,到这里就要变成完整的评测体系。我建议按四个维度扩展:真实用户query,从线上日志抽取并人工标注;合成query,用LLM生成一批相似问题来补充覆盖度;边界case,刻意加入长尾、口语化表达、错别字query;负样本,确保评测集里有一部分应该返回空结果或低相关结果的query,用来检验系统会不会乱答。
评测指标方面,召回类选Recall@K,排序类选MRR或NDCG。RAG场景我还会额外看“答案命中率”,即最终传给LLM的上下文里是否包含可以回答问题的关键片段,这个指标更接近业务效果。评测流程要固化:每次改切分参数、换模型、调索引结构,都跑一遍评测脚本,跟基线对比。最好把评测脚本接入集成测试,每次改动自动跑,防止优化了A场景却破坏了B场景。
这里有个很常见的坑:评测集太薄,指标波动看不出真伪。改动之后Recall@5从0.52涨到0.55,看起来提升,但只有200条评测数据,这个差异可能只是随机波动。所以要尽量把评测集做厚,至少500条起步,关键的bad case单独存档,定期回归。我的习惯是每处理完一批线上bad case,就把它们的query连同正确答案加入评测集,持续扩充。几个月下来,评测集就变成了团队最宝贵的资产之一。
4.2 第9步:在线监控与升级:检索系统的长期演进
上线之后,第一件事是记录日志。有人觉得日志只是排查问题的工具,但在我眼里,检索日志是整个系统持续优化的原料库。每条日志至少记录:query原文、候选文档ID和分数、多路召回情况、重排后的顺序、最终LLM返回内容、用户反馈信号。没有这些数据,后续所有改进都是拍脑袋。
在线监控指标我分两层。服务健康层看P50/P95延迟、QPS、错误率、空结果率。这里尤其关注空结果率,它突然升高大概率不是算法问题,而是数据更新任务挂了或者切分规则被误改,需要先排查数据链路。业务效果层看点选率、点赞点踩、用户feedback。知识库场景还可以记录“用户是否复制了回答内容、是否紧接着追问”这类隐性信号。
持续迭代方面,我最常做的操作是每周拉取新增日志,挑出20到30个bad case,人工分析:是切分问题、模型问题、还是数据缺失。统计bad case的占比分布,哪个类型占比高就去优化哪个环节。比如连续几周发现“术语精确匹配失败”最多,那就重点加关键词召回,而不是盲目换embedding模型。
这里有一条血泪教训:嵌入模型升级远不是换一行配置那么简单。换了模型,所有历史文档都要重新向量化,索引要全量重建,离线评测要重跑,线上还可能有一段时间查询和文档向量分布在“新旧混杂”的状态。我见过不止一个团队在这里翻车,以为模型升级是性能提升,结果召回反而崩了。任何模型升级都要走完整的“重索引—离线评测—灰度—全量”流程。
做检索系统这些年,我最大的体会是:这个系统没有“做完”的那一天。架构上可以一步到位,效果上永远有下一次优化空间。与其追求一个完美的初始方案,不如搭好评测和监控的闭环,让系统在持续迭代中变得真正好用。如果你正在搭RAG或者搜索系统,先把这9步按顺序走一遍,尤其是第1步和第8步,千万不要省——这两步是最容易被忽略、又最能拉开长期差距的环节。