做RAG(检索增强生成)系统的朋友应该都有过这种经历:知识库搭完了,文档切好了,向量库也建起来了,结果一问业务问题,答案总是"差点意思"。要么召回的片段跟问题八竿子打不着,要么检索出来的内容明明有答案,大模型生成结果却驴唇不对马嘴。每次排查到最后,几乎都会落到同一个环节——当初Embedding模型是怎么选的。
这篇文章想聊的就是Embedding模型选型的完整思路。我从几个模拟项目里反复踩坑之后,沉淀出一套可复用的流程:选型前要梳理哪些需求、离线评测怎么做才靠谱、向量维度和阈值怎么跟检索策略配合着调、上线后监控什么指标,以及那些在测试集上看不出来、一上生产就爆的经典问题。适合正在搭RAG系统、或者系统搭完了但检索效果不理想的同学,拿着这套方法直接往自己项目里套。
全文分六块,从链路定位讲到实操流程,没有特别高深的理论,但每一步都有能落地的细节。
1. RAG检索质量为什么卡在Embedding选型上
1.1 先从一个检索失败案例说起
前阵子帮某公司调一个内部知识库问答系统,库里放的是员工手册和行政制度,文档数量不算多,总共几百篇。系统搭建用的流程也算标准:解析PDF、按固定长度切块、灌向量库、检索TopK送大模型生成。
表面看起来没什么问题,但业务同事反馈"请假相关的答案总是漏"。我拿一条真实问题测了一遍:"年假可以分几次休?"结果显示,系统召回的Top10片段里,没有一条真正提到"年假可拆分"的规则,反而出来一堆关于"病假申请流程"的内容。换成关键词式的查询"年假拆分"之后,答案倒是能出来。
问题出在哪?Embedding模型把"分几次休"和"拆分"理解成了不同的语义表达,在模型的语义空间里,这两句话的向量距离不够近,于是语义检索失败。这其实就是Embedding选型问题的典型缩影:模型的语义空间跟你的业务文本不在一个频道上。你从头到尾检查链路、调Prompt、换大模型,都可能绕不开这个底层原因。
1.2 Embedding模型在RAG链路里的真实位置
RAG系统的标准链路是:文档预处理、切片、Embedding编码、向量存储、相似度检索、重排、送入大模型生成。很多人习惯把注意力放在大模型选型和Prompt设计上,但真正决定"答案有没有被找到"的,其实是Embedding编码和检索这一段。
换句话说,检索质量决定了生成质量的天花板。如果检索返回的内容跟问题无关,大模型再怎么厉害也编不出正确答案。Embedding模型做的事情,是把一段文字映射成一个高维向量,让语义相近的文本在向量空间里距离更近。所谓"语义检索",本质上就是在这个向量空间里做最近邻搜索,通常用余弦相似度来衡量文本间距离。
这也是为什么Embedding选型不能太随便。它的语义空间怎么组织,直接决定了哪些文本会被判定为"相关"。召回质量几乎被Embedding模型的能力上限框住了,后面接再强的重排和生成模型,也只能在它召回的范围内做优化。
1.3 通用模型为什么不能一路通用到底
不少早期项目图省事,直接拿一个通用语料训练出来的Embedding模型用到底。这类模型在开放域文本上表现确实不错,但真实业务场景里的文本通常带明显领域特征。法律条文里的"当事人""不可抗力",医疗文本里的疾病缩写,工程文档里的设备型号、参数单位,这些词汇在通用语料里出现频率低、语义区分度差,模型对它们的理解天然就弱。
做一个不太严谨但很直观的类比:通用Embedding模型像个读过很多杂书的通才,聊日常话题它能接得住,聊到某个行业的行话黑话就有点跟不上。领域专用模型则像深耕某一行的老师傅,术语、句式、行文习惯都门儿清。
所以选型的第一步不是急着比较哪个模型排行榜分数高,而是先想清楚你的文本长什么样、业务查询长什么样。这正是下一节要展开的内容。
2. 选Embedding模型前先想清楚这四件事
2.1 语种构成:是纯中文、纯英文还是中英混排
第一个要梳理的是语料和查询的语种构成。这个问题看似简单,却直接影响模型选型方向。
如果业务知识库是纯中文,那就用中文语义能力突出的Embedding模型;如果语料是中英混排的,比如产品手册经常中文正文加英文术语,查询也可能是中英混杂的,那就需要模型具备跨语言对齐能力。跨语言对齐指的是,同一个意思的中文表达和英文表达,在向量空间里要落在相近的位置。
这里有个人容易踩的坑:有些模型虽然号称支持多语言,但训练语料的语种配比不均衡,中英混排文本的编码效果可能并不好。所以不要只看模型文档里写着"多语言支持",务必要在你自己的混排样本上实测。我习惯的做法是,从库里抽20条中英混排的文本,再用对应的中英文查询各测一遍,看召回情况是否对等。
2.2 领域语料:通用模型处理专业文本的真实表现
第二个问题是领域匹配度。这个比语种更容易被忽视,因为大多数项目的文档都自认为是"通用的",实际操作下来,几乎没有哪个业务知识库是真正通用的。
领域匹配可以从三个层面拆开看:一是专业术语,比如金融场景的"公允价值""久期",模型知不知道这些词跟什么上下文强相关;二是行文风格,制度文件、操作手册、FAQ问答的句式结构差异很大;三是查询表述习惯,业务同事用大白话提问,还是用比较书面的关键词提问,对模型的泛化要求完全不同。
想验证领域匹配度,不能靠感觉。后面第三部分会讲怎么用真实数据构造一个迷你评测集,用几十条真实查询把候选模型在领域上的表现测出来。这一步做扎实了,比看任何公开排行榜都管用,因为排行榜的评测集大概率跟你的业务文档不是同一类内容。
2.3 切片长度与模型上下文上限的匹配
第三个问题跟语料预处理强相关:切片策略和Embedding模型的输入上限是不是匹配。
多数Embedding模型的输入长度上限在512个token左右,换算成汉字大概几百字。如果你的切片策略是每块800个字,超出部分会被静默截断,切片后半段的语义信息直接丢失。等发现某个长段落的内容怎么都召回不到的时候,多半就是截断惹的祸。
比较稳妥的做法是:先确认候选模型的上下文上限,再反推切片长度。切片策略至少要让单块文本落在模型可编码范围内。长文档宁可多切几块、让片段带一点重叠,也不要让单块超限。我用的经验值是,每块文本控制在模型上限的80%左右,给tokenizer分词留出余量,同时相邻切片保留少量重叠,避免把完整语义拦腰截断。
2.4 部署方式与成本预算:本地还是调用服务
最后一个问题很现实:你打算本地部署开源模型,还是调用商业向量服务。
本地部署的好处是数据不出内网,可以做精细微调和定制,但需要GPU资源和运维成本。商业服务的好处是省心、效果通常不错,但按调用量计费,数据要走第三方链路,隐私敏感的场景不一定允许。
另外要算一笔账:向量维度直接决定存储成本和检索耗时。同样是10万条文本,某些模型输出1024维向量,另一些只输出256维或384维,存储占用和检索计算量能差好几倍。高维度模型不一定检索效果更好,这个我在第四部分专门展开。选型之前先把这两类成本算清楚,别等数据灌进去才发现扛不住。
3. 不靠感觉选模型:一套可落地的离线评测方法
3.1 构造评测集:从真实查询里挖样本
我见过很多团队选Embedding模型的方式:打开排行榜,选个分数高的,直接上生产。这是最容易翻车的路径,因为公开评测集的构成跟你的业务数据大概率不是一回事。
正确做法是构造一个业务评测集。操作不复杂,但需要认真做:
- 从线上日志、业务同事反馈里,整理出50到200条真实查询;
- 针对每条查询,人工标注1到3条应该在知识库里命中的文档片段;
- 再加10到20条"明知库中没有答案"的负样本查询,测试模型能不能把不相关的内容挡在外面。
这个评测集不需要很庞大,但必须来自真实业务。我自己的经验是,80条左右就能把候选模型之间的差异拉得很明显。如果连50条都凑不出来,说明业务需求还没梳理清楚,这时候谈选型为时过早。
3.2 关注哪些指标:召回率、命中率、相似度分布
评测指标不需要搞得太花哨,盯住三个就够。
第一个是Recall@K。给定查询,看模型检索返回的TopK里有没有命中标注的答案,K一般取5或10。这个指标直观回答"答案到底有没有被捞回来"。
第二个是MRR,平均倒数排名。它不光关心答案在不在TopK里,还关心答案排得多靠前。答案排第一得1分,排第二得0.5分,排第三得0.33分。两款模型召回率接近时,MRR更高的那个意味着答案通常排在更靠前的位置,后续重排和生成环节的负担会小很多。
第三个是相似度分数分布。把所有查询跟全库文本的相似度都算一遍,看命中的正样本分数和无关的负样本分数之间有没有明显分界。如果两类样本的分数重叠严重,说明模型在当前语料上区分度不够,检索时很难靠阈值做过滤。
3.3 评测时最容易犯的三个错误
用评测集测模型的时候,有三个错误很常见,我自己也犯过。
第一个是评测和线上链路脱节。有人直接拿候选Embedding模型算查询和答案文本的相似度,忽略了切片、向量索引这些环节的差异。正确的做法是,保持切块逻辑和向量库配置完全一致,只替换Embedding编码这一层,这样测出来的差异才是模型的真实差异。
第二个是测试查询跟训练语料同源。如果评测查询是从文档里直接摘出来的句子改写的,模型很可能在训练时见过相同或相近的表达,得分会虚高。查询应该尽量贴近真实用户的陈述方式,包括那些不太规范、带口语化的问法。
第三个是只看平均值不看个例。平均召回率够用,不代表没有明显拉胯的类别。评测结果出来后,把每条查询的得分列成表,重点看那些"所有模型都不行"的查询,它们往往暴露的不是模型问题,而是切片策略或者知识库本身的问题。
4. 向量维度、相似度阈值与检索策略的联合调优
4.1 向量维度不是越高越好
很多人在选Embedding模型时,会有"维度越高越强大"的错觉。实际上,维度只是模型设计的一个参数,高维度向量在近似最近邻检索里的计算开销、内存占用都更大,效果却不一定更好。
举个直观的数字:假设你有200万条文本切片,如果使用1024维向量,按float32存储,单条向量占用4KB左右,200万条就是8GB,这还没算索引的额外开销。如果换成384维,存储直接降到四分之一以下。如果再配合量化压缩,比如从float32压到int8,又能再降好几倍。
更关键的是,高维空间存在"维度诅咒"现象,维度高到一定程度,向量之间的距离区分度反而可能下降。所以选型的时候别被高维度唬住,要看实测检索效果,而不是纸面参数。相同效果下,选存储成本更低的模型,长期运维会轻松很多。
4.2 相似度阈值怎么定才合理
检索环节通常会做TopK召回,再按相似度阈值过滤。阈值设得太高,会误杀相关片段;设得太低,又会把一堆不相关内容送进生成环节,既浪费token又干扰答案。
我的做法是,在评测阶段把正样本分数分布和负样本分数分布都画出来,找两类分布的交界点,再往回调10%到20%作为初始阈值。注意,不同Embedding模型的分数尺度差异很大:有的模型正常匹配分数在0.3到0.5之间,有的在0.6到0.9之间。在A模型上验证过的经验阈值,直接搬到B模型上基本必翻车。
更稳妥的思路是,阈值只作为最后一道保险,而不是主要的过滤手段。主要过滤靠TopK截断,阈值负责挡住那些明显无关的边缘内容。这样即使换模型导致分数尺度变化,只要TopK范围内的排序质量稳定,检索效果就不会剧烈波动。
4.3 重排与混合检索:Embedding不是唯一的解
说句实在话,很多检索质量问题,不一定全靠换Embedding模型解决。更稳的方案是"Embedding召回加交叉编码器重排"的两段式结构。
召回阶段用Embedding模型把候选从全库缩到几十条,宁可多召回一些也别漏;重排阶段再用一个精排模型,把真正的答案顶到前面。精排模型能做问题与片段的交互式匹配,比双塔式的Embedding匹配更精细,对"换了说法但语义相关"的内容更敏感。
另一招是混合检索:把Embedding的语义检索和基于关键词的传统检索结果做加权合并。语义检索擅长处理换了说法的查询,关键词检索擅长处理必须包含某些专有名词的查询,两者互补性很强。我在模拟项目里测下来,混合检索经常能拉回几个点的召回率,尤其适合那些本身带大量编号、型号、代码文本的业务场景。
5. 真实项目里的坑:Embedding选型的五个常见问题
5.1 换了个说法就召回不到
这是语义检索最经典的问题:用户用口语、倒装、同义词表达,跟文档原文的写法差异太大,向量距离拉不开。比如查询"这笔费用还能不能报"和文档里的"报销范围不包括"指向的其实是同一类内容,但通用模型不一定能打通这层语义。
排查方法是把这类查询单独拉出来,看跟目标文档的余弦相似度到底是多少。如果确实不高,除了换更强的Embedding模型,还可以做两件事:一是在切片阶段,把FAQ格式的标题和正文合并编码,让标题里的关键词进到向量里;二是维护一个同义表达映射表,把高频的"换说法"硬编码进预处理逻辑,先归一化再做Embedding。
5.2 长文本被静默截断
某次排查召回漏项,发现一条知识文档内容很关键,向量里却完全没有对应信息。后来检查才意识到,切片长度超过了模型输入上限,后半段被直接截断,关键内容压根没进向量。
这个坑的隐蔽之处在于它不报错。系统照常运行,只是部分内容完全不可见。排查技巧是:找一条超长原始文本,切成片之后检查有没有片段的末尾断在半句话上,再核对模型配置里的最大输入长度。切片长度务必留出20%左右的余量,因为tokenizer的实际分词可能比预估的字符数更长,尤其中文文本的分词结果经常超出直觉估算。
5.3 相似度分数整体偏高或偏低
不同Embedding模型的分数校准差异很大。有的模型随便两条不相关文本都能算出0.8以上的相似度,有的模型高度相关的文本也只有0.5左右。如果团队中途换过一次模型,之前沉淀的阈值经验就全废了。
我习惯的处理思路是:阈值不看绝对分数,看相对排名。只要TopK候选里答案排得够靠前,阈值只是最后一道保险。如果非要设置阈值,就在离线评测阶段重新统计负样本的分数分布,按95分位或者99分位来确定过滤线,别直接套用历史经验。
5.4 领域新词和缩写词识别失败
业务场景里新名词、缩写词出现得很快,比如内部系统代号、新政策名称、产品复合命名。这些词在Embedding模型的训练语料里大概率不存在,模型只能根据词形猜测语义,检索质量自然不稳定。
我的经验是,不要指望换个Embedding模型就能解决新词问题,这是语料覆盖问题,不是模型结构问题。更实用的做法是,在预处理阶段做专有名词归一化,把缩写展开成全称再进Embedding编码;或者在检索时对这些专有名词单独走关键词匹配,再跟语义检索结果合并。等积累到一定量级,再考虑在领域数据上做增量训练,但投入产出比要自己衡量,小团队不一定划算。
5.5 评测结果忽高忽低
同一批评测集,前后两次测出来的模型排名不一致?先别怀疑模型,大概率是测试链路不干净。切片编号没固定、向量库里的数据被重复写入、甚至随机种子差异,都可能导致结果抖动。
我踩过一次比较深的坑:向量库没有清空旧数据就灌新数据,造成同一条文本存在多个版本,评测时答案虽然能命中,但真实上线时数据一致性一塌糊涂。所以做AB对比评测时,务必保证数据版本、切块参数、向量库状态完全一致,评测过程才可信。顺手记录下每次评测的数据版本号,是成本最低但收益最高的习惯。
我把这五个问题整理成一个速查表,方便现场排查时直接对照:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 换说法就召回不到 | 模型语义空间与业务表达不匹配 | 评测集单测、同义映射、混合检索 |
| 长文档内容丢失 | 切片超出模型输入上限被截断 | 核对模型上限、缩小切片尺寸 |
| 相似度分数整体偏高或偏低 | 各模型分数尺度不同 | 看相对排名、按分位离线校准 |
| 新词缩写识别失败 | 训练语料未覆盖 | 专有名词归一化、关键词兜底 |
| 评测结果不稳定 | 测试链路不干净 | 固定数据版本、清空向量库重灌 |
6. 从选型到上线的完整操作流程
6.1 需求梳理:先把业务问题翻译成技术指标
选型的起点不是模型,而是业务需求。动手之前,先用一页纸把几个问题写清楚:知识库的文本类型是什么?用户的查询是什么风格?检索结果要排多靠前才能接受?延迟和成本的上限是多少?
把这些答案翻译成技术指标,就是语种范围、领域特征、Embedding上下文上限、向量维度上限,以及离线评测要达到的Recall@K底线。写不清楚这些,后面选模型纯靠运气。很多团队选型反复横跳,本质上是业务指标没定义好,换哪个模型都感觉"差点意思"。
6.2 候选模型对比:从两三个方向各挑代表
候选模型不要选太多,两到四个就够,从不同方向各挑一个代表:比如一个通用中文模型、一个领域微调模型、一个多语言模型。预算允许的话,再配一个商业向量服务做标杆对比。
对每个候选模型,跑一遍前面说的离线评测,输出三张表:Recall@K对比、MRR对比、正负样本分数分布。哪个综合表现最好,就用哪个。如果两个模型指标接近,选部署和维护成本更低的那个,别为了一点指标差异背上长期运维负担。
6.3 上线验证:小流量灰度而不是一刀切全量
评测通过只是第一步。真正上线前,我强烈建议做一轮小流量灰度:先放5%到10%的线上查询量,对比新旧方案的检索命中率和用户反馈。灰度期至少跑一到两周,覆盖的业务查询类型尽可能广,别只拿流量高峰那几类问题凑数。
上线之后要持续监控。我习惯盯三个指标:检索TopK里出现空结果的比例、生成答案被用户点踩的频率、单次检索的P99延迟。任何一个指标明显劣化,都要回到评测集上排查,是模型问题、数据问题还是阈值问题。Embedding选型不是一次性决策。知识库内容在变,用户提问方式在变,模型也需要定期体检和迭代,通常一两个季度就要重新评估一次。
最后分享一个我个人的体会。Embedding模型的选型,本质上是在"语义空间表达能力和工程成本"之间找平衡,没有哪个模型是绝对最好的,只有跟你的业务数据最匹配的。与其花大量时间研究公开排行榜,不如先花一个下午把属于自己的评测集做出来,让数据帮你做决定。这套方法我自己用下来,几乎每个项目都能用最短的时间排除掉那些"看起来很强、实际不合适"的选项。