做 RAG 或者语义检索,多半会先去翻 MTEB 那个大表格,然后发现分数排前面的模型,放到自己的语料上未必更准,有的还更贵更慢更大。这篇不替你拍板选哪个,而是把榜单的构成、任务类型、分数口径讲一遍,再给一套从榜单到落地验证的顺序,让你能在半天内缩到两三个候选。
MTEB 到底是什么:一张表、多个任务、不是单一能力分
很多人第一次看 MTEB,会把它当成「嵌入模型的考试总分」——一个数字高的模型就全面更强。这个理解不太对。MTEB 的本质是把一批句子级、段落级的任务打成一个包一起跑,包里既有检索,也有聚类、分类、重排、语义相似度这些类型完全不同的活儿。最后给出的汇总分,是把这些异构任务的结果揉在一起算出来的,它反映的是「在这个固定任务包上平均表现如何」,不是「在你的业务上好不好用」。
| 任务类型 | 典型问法 | 对应你的什么场景 |
|---|---|---|
| 检索 | 给定问题,从一堆文档里找出最相关的几条 | 站内搜索、知识库问答、RAG 召回 |
| 聚类 | 把一堆句子按语义自动分组 | 工单归类、评论去重、话题发现 |
| 分类 | 给句子贴一个预定义标签 | 情感判断、意图识别、风控打标 |
| 重排 | 给已召回的候选重新排序 | 搜索精排、推荐兜底 |
| 语义相似度 | 判断两句话意思接近到什么程度 | 去重、匹配、同义改写检测 |
还有一个特别容易踩的坑:榜单里同一个模型名字经常出现好几行。区别可能在向量维度、池化方式、有没有加指令前缀、是不是多语言版本。名字只差一两个词,表现却可能差出明显一截。所以看之前先确认自己盯的是哪个变体——把鼠标停在模型名上,看清楚括号和后缀,再决定要不要拿它当参照。
- 先认变体:维度、池化方式、是否带指令前缀、语言范围,这四项不同就是不同模型
- 再认任务:你关心的那类任务,在榜单里是否有单独一行,别只看总表
- 最后认口径:任务集有没有扩充过、有没有修订,数字要连着当时的版本一起看
- 同一模型跨版本对比时,两次的汇总分往往不可直接相减
- 第一步:锁定变体在榜单里找到你实际打算部署的那个确切名字,包括后缀和指令前缀写法;找不到就别拿同名主版本的数据硬套。
- 第二步:锁定任务切到与你场景最接近的子任务看排名,而不是停在汇总表。检索场景就看检索,分类场景就看分类。
- 第三步:对齐口径确认任务集当前版本,再去站内 /benchmarks/registry 核对口径整理,避免拿旧截图和新榜单直接比。
- 第四步:自己验一遍从你的业务语料里抽几十条真实样本,按同一套判定标准跑一遍,用结果决定,而不是用榜单名次决定。
什么情况下这套思路不适用?如果你只是做一次粗略的候选筛选、根本没有自己的评测集,那先按榜单子任务缩小范围也没什么问题。但只要你准备长期用、或者涉及线上检索质量,就必须落到自有样本上验证,因为榜单任务的语料分布和你的业务语料几乎不会一致。
先分清你的任务落在哪一类,再看对应的那几列
打开一个嵌入模型榜单,第一件事不是看谁排第一,而是先问自己:我要解决的是哪一类问题。榜单通常把任务拆成检索、分类、聚类、重排、语义相似度好几组,每组下面又有语言和领域的子集。你拿总榜第一去做法条检索,很可能不如一个总榜中游但 Retrieval 子集扎实的模型。
| 你的场景 | 重点看哪类任务 | 容易踩的坑 |
|---|---|---|
| 知识库问答、法条检索、文档召回 | Retrieval(检索) | 被分类和聚类的分数带跑,把「能分类」当成「能召回」 |
| 打标签、意图识别 | Classification(分类) | 分类强不代表向量距离可用,检索场景会翻车 |
| 相似问题归并、去重 | Clustering / STS | 只看总榜平均分,忽略自己的语料语言 |
| 关键词强、专有名词多的检索 | 稀疏检索基线 | 默认稠密向量一定更好,其实稀疏有时更稳 |
为什么会这样?因为不同任务对向量的要求根本不一样。分类任务只要在向量空间里能被一个决策边界切开就够了,它对绝对距离不敏感;而检索要求的是「语义相近的句子在空间里真的靠得近」,这是两种能力。一个模型分类分高、检索分平,在榜单上总分可能很好看,但放到你的检索链路里就是另一回事。
- 先明确你的输入输出:是「一段话找一段话」,还是「一段话找一个标签」;
- 在榜单里只锁定对应的那一列或子集,不要看总榜平均值;
- 中文语料就优先看中文子集和跨语言子集,别用英文任务撑起来的总分做判断;
- 关键词匹配为主、专有名词多的场景,先把稀疏检索当基线跑一遍,再决定要不要换稠密模型;
- 总榜靠英文拉起来的模型,务必用你自己的中文样本实测一次再定。
还有一个常被忽略的点:榜单上很多模型的高分来自英文任务,中文和跨语言子集往往是单独一列。如果你的语料是中文,或者中英混排,直接看总榜会系统性高估某些模型。稳妥的做法是拿你自己的几十条中文查询,在候选模型上跑一遍召回,看前几条里有没有你要的答案,这比任何总分都直接。
把那张表读成一张筛选器:三列就能砍掉八成候选
排行榜上几十上百行,真正能帮你做决定的其实只有三列。先把这三列当成三道筛子,过不去的直接划掉,剩下的再去跑测试集也不迟。顺序别乱:先砍载入成本,再砍输入长度,最后砍许可证。反着来的话,容易在最后一关才发现白忙一场。
| 筛选维度 | 看什么 | 过不了会怎样 |
|---|---|---|
| 载入成本 | 向量维度 + 你用的向量库是否支持该维度和索引类型 | 存储和内存吃紧,检索延迟上来,扩容成本压不住 |
| 最大输入长度 | 模型 context 上限 vs 你切好的 chunk 长度 | 超长被静默截断,召回掉得没头没脑,还查不出原因 |
| 许可证 | 能否商用、是否要署名、模型卡有没有额外限制 | 上线后才被法务拦下,返工换模型的代价远高于现在多看一眼 |
- 第一刀:算载入成本先记下每个候选的向量维度,乘以你预计的向量条数,得出裸存储量,再乘上索引开销。维度越高,单条向量越大,向量库的落盘体积和内存驻留都跟着涨,长文档场景下尤其明显。然后到 /stacks/vector-dbs 核对:你打算用的那个库,对这个维度和索引类型是不是原生支持、有没有已知的坑。
- 第二刀:对最大输入长度把你真实业务的 chunk 分布拉出来,看的是长尾而不只是平均值。很多模型的最大输入远小于你切好的块,超出的部分不会报错,只会被截断。判断标准很简单:如果你的 chunk 有相当比例超过模型上限,要么换模型,要么重新切块并同步改检索链路,别指望靠调参数绕过。
- 第三刀:逐条对许可证不要看到「开源」就当能随便商用。按 /open-weight-license-basics 的思路逐条核:能不能商用、要不要在界面上署名、模型卡里有没有写明禁止的用途或下游限制,以及你打算怎么分发(自建服务、嵌入到产品里、还是二次微调后再发布)。这几项里只要有一条对不上,直接划掉。
- 维度不是越低越好,但明显超出你数据规模的高维模型,先问自己值不值那笔存储和延迟
- 输入长度要按 p95 甚至 p99 的 chunk 长度来对,不要只看中位数
- 同一家公司不同模型的许可证可能不一样,逐个查,别整批放过
- 许可证是法务问题,不是技术问题,拿不准就留证据、走内部确认流程
- 过完三刀还剩超过十几个,说明你的某个阈值定得太松,回去收紧
自建还是调接口:先算清哪一头更划算,再谈质量
先别急着比模型谁强,先把账算清楚。嵌入这块的开销有两个大头:一是每天要重建多少语料,二是数据能不能出内网。这两件事基本决定你是调接口还是自己部署,跟排行榜上的名次关系不大。
| 判断项 | 偏向调接口 | 偏向自建 |
|---|---|---|
| 语料重建频率 | 低频、按周甚至按月才全量刷一次 | 每天几十万条以上要反复跑全量 |
| 数据能否出内网 | 可以出,或者本来就是公开数据 | 不能出,或合规上不允许离开自己的机器 |
| 卡和运维 | 不想养卡、不想盯显存和排队 | 已经有闲置卡、有人能看住服务 |
| 流量形态 | 线上增量查询为主,量不大但要求稳定 | 离线批量为主,一次跑完可以慢慢等 |
调接口的计费口径一般是按 token 或按调用量走,具体怎么看当时是怎么算的,到 官方 API 页面(/official-api) 核对那一栏的说明。它的好处很直接:不用买卡、不用运维,突发量也能扛。坏处是批量重建会滚成本——你每天把全量语料重跑一遍,token 数就是语料规模乘以天数的量级,滚起来比想象中快。低频查询走接口基本无感,高频全量重建就很吃钱。
- 先估重建量把每天要重新嵌入的文档条数、平均长度记下来,换算成 token 量级,再乘上你打算多久重建一次。这一步只是估量级,不用精确到个位。
- 再估自建侧的显存和吞吐嵌入模型本身不大,但长文本批次照样吃显存。参考 部署测算页面(/models/deploy) 的思路,先估单卡能塞多大 batch、每秒能跑多少条,再倒推你需要的并发和卡数。
- 跑一次小样本对照抽一小批真实语料,分别走接口和自建各跑一遍,记录耗时、显存占用和稳定性。别用玩具数据测,长文本和短文本表现差很多。
- 把两条路的总账摆一起接口侧算清按量计费的滚动成本,自建侧算清卡的成本加运维人力。看哪个在你的重建频率下更扛得住,而不是只看单次单价。
混合方案其实很常见:离线全量重建用自建,一次性跑完慢慢等,省下大头的 token 钱;线上增量查询走接口,图的是稳定和不用自己扛并发。这个组合能成立有个硬前提——两边必须是同一个模型、同一个版本、同一套预处理。只要有一边换了模型或改了归一化方式,两批向量就不在一个空间里,检索结果会互相打架,召回忽高忽低还很难查。
真要自己跑,量化和精度怎么取舍
先说结论:嵌入模型对量化的敏感程度,普遍比生成模型高一截。生成模型掉一点精度你可能看不出来,嵌入模型一量化,向量空间稍微歪一点,检索召回就整片塌。所以别拿「能跑起来、能出向量」当验收标准,那只是第一步。
- INT8
- 通常是可以接受的档位,先从这里起步,再往下降级
- 更激进的档位
- 必须自己拿真实语料实测召回率,不能只看输出维度对不对
- 验收口径
- 不是「跑得通」,而是同一批 query 下 top-k 命中是否还稳
如果你只是本地试玩、数据量小、对召回不敏感,量化省显存完全值得;但如果你的场景是长尾query、专有名词多、或者top-k要卡得很紧,激进量化带来的那点召回损失就可能让下游整条链路失效。判断标准很简单:拿同一批query,量化前后各跑一次,看命中的结果集差异有多大。
- 先固定基准用未量化的模型、同一批 query、同一份语料跑一次,把每条 query 的 top-k 结果存下来当基准
- 再换量化档位只改量化设置,其他全不动,重复跑同一批 query,和基准逐条对比命中差异
- 算清代价把「省下的显存/提升的吞吐」和「丢掉的召回」摆在一起看,哪边更值只有你的业务能判断
| 参数 | 影响什么 | 压测时怎么动 |
|---|---|---|
| 批量大小 | 峰值显存、吞吐上限 | 只动它,其他两个锁死 |
| 序列长度 | 显存占用增长最快的一项 | 先按业务真实长度设,不要图省事拉满 |
| 是否开 FP16 | 显存和速度,也可能影响数值稳定 | 单独开关对比,别和量化一起改 |
- 向量归一化方式要跟训练时一致,该归一化就归一化,别自己发挥
- 池化方式(取 CLS 还是平均池化)同样要照训练配置抄,抄错等于换了个模型
- 分词器、最大长度截断策略一起核对,这些细节最容易被忽略
- 很多「自建效果差」不是模型不行,是复现配置抄错了,先在配置上找原因
- 确认配置没问题之后,再去怀疑量化和模型本身
最后留个提醒:上面说的都是通用判断,具体到某个模型在某个量化档位下到底掉多少,跟模型结构、训练数据、你的语料分布都有关系,没有放之四海皆准的结论。真要拍板,就去站内模型资料库和价格追踪页核对你关心的那个模型当前的可用档位与显存要求,再拿自己的数据跑一遍对照。
用你自己的 50 条 query 做小规模对照,比看榜半天管用
榜单是别人用他们的数据、他们的切分方式跑出来的,跟你线上真正要回答的问题未必是一回事。更省时间的做法是:从你自己的请求日志里捞几十条真实 query,人工标出每条「应该命中的文档」,做成一个小测试集,再拿它去横向比几个候选嵌入模型。规模不用大,五十条上下就够,关键是覆盖典型问法和边界问法。
- 抽 query从最近一段时间的检索日志里按业务场景分层抽样,别只挑高频的,长短问句、带不带专业术语都要有;把用户原始输入原样保留,不要顺手改写。
- 标命中每条 query 人工指定一到多个正确文档,只写文档 ID,不写理由,避免后面自己骗自己;标注时一人标、另一人复核一遍,分歧大的直接剔除。
- 跑对照把每个候选嵌入模型单独跑一遍,除模型外的参数保持完全一致,结果落成「query → 前几条命中情况」的表,方便逐条看差在哪。
- 分场景统计按短问句、长描述、含专业术语三类分别算命中率,别只汇报一个总分,三类排序经常不是同一个顺序。
| 场景 | 看什么 | 容易踩的坑 |
|---|---|---|
| 短问句(几个词) | 前几条里有没有正确文档 | 模型对语义稀疏的短输入是否稳定 |
| 长描述(整段话) | 前几条命中率,以及是否被无关长句带偏 | 切分太碎,关键信息被切走 |
| 含专业术语 | 术语本身能否召回到对应文档 | 通用语料训练的模型容易把术语当普通词 |
| 边界问法(口语、错别字、指代) | 能不能容忍输入噪声 | 拿榜上高分模型也未必扛得住 |
指标不用搞复杂,就盯「前几条命中率」。用户翻到第二页的概率本来就低,整个排序的相关性曲线再漂亮,前几位没命中,体验就是差。真要再看一个数,可以加「正确文档出现在前几条之外的比例」,用来判断是模型问题还是标注问题。
- 切分策略固定:同一批文档用同一种切法,别这个模型切长、那个模型切短,否则分不清是谁的功劳。
- 重排策略固定:要么都关掉,要么都用同一套重排,混着比没有意义。
- 只换嵌入模型这一个变量,索引构建参数、检索条数、返回条数全部锁死。
- 每次只改一处,改完重跑,记录下改动点和对应结果。
- 如果分数变化很小,先怀疑测试集太小或标注噪声太大,而不是急着换模型。
换模型的迁移动作:向量不能混用,重建是必须的
换嵌入模型最容易被低估的一步,不是选哪个模型,而是换完之后怎么迁移。很多人第一反应是「我把新的接上去,增量写新向量不就行了」——不行。不同模型输出的向量,维度可能一样,但空间坐标系完全是两回事,就像同一把尺子换了刻度原点。老向量和新向量混在一个索引里做相似度计算,检索结果会变得毫无规律,有时候看起来还能用,其实只是碰巧。
为什么不能混用:维度相同也救不了
- 向量空间
- 不同模型训练目标、语料、归一化方式都不同,同一句话在两个模型下得到的向量方向没有对应关系
- 维度相同
- 只能说明数组长度一样,不代表语义坐标对齐,距离数值没有可比性
- 归一化
- 有没有做 L2 归一化,直接决定余弦距离还是点积,配置漏一个结果全偏
- 增量陷阱
- 只给新写入的文档算新向量,等于索引里同时存在两套坐标系,召回质量断崖下跌
- 上线前必须跑一次全量重建,不能只补增量
- 重建用的是当前线上语料快照,漏掉的文档后面会变成检索黑洞
- 重建期间索引要么整体切换,要么双索引并存,别在原索引上原地覆盖
- 重建完成后旧向量文件保留一份,回滚时不需要重新算
- 把模型标识写进索引元数据,检索服务启动时校验,防止新旧索引被混读
重建窗口怎么算才不慌
重建时间长度的粗算是:语料总条数 ÷ 每秒可处理条数(批处理吞吐),得到一个理论下限。注意这是下限,不是工期。还要乘上一个余量系数覆盖失败重试、限流、单条超长被截断、队列积压。真正能落地的做法是先用一小部分语料压测出真实吞吐,再去站内 工具目录(/tools) 里找现成的批量脚本参考,把每条文档的平均耗时记下来。具体数值别照抄别人,你的语料长度分布和别人完全不一样。
| 环节 | 要算进窗口的损耗 | 怎么确认 |
|---|---|---|
| 批处理吞吐 | 平均单条耗时 × 批次放大 | 小样本压测取中位数 |
| 失败重试 | 失败率 × 重试次数 | 看任务队列重试日志 |
| 限流 | QPS 上限被打满的等待 | 跑一次高峰时段全量 |
| 切换切换 | 索引构建完到生效的校验时间 | 留出验证测试集的时间 |
重建期间线上怎么活
- 双写新老模型同时写向量,写到两个索引,检索仍走老索引,等新索引追平后再切。优点是切换瞬间无损,代价是写入成本翻倍。
- 降级重建窗口内把向量检索降级为关键词检索或缓存命中,宁可结果差点也别返回错乱结果。适用于能接受短期质量下降的场景。
- 灰度先切一小部分流量到新索引,用真实查询对比两边的召回命中情况,没问题再放量。
- 验证无论哪种方案,切换前都要用同一批查询在两个索引上跑一遍,人工抽样比对返回结果是否合理。
换完一定要做的回归
新模型上线不等于迁移结束。要做两件事:一是拿老模型时代积累的测试集,在新模型上重跑一遍,看命中分布有没有整体漂移;二是从线上抽样几条真实查询,人工看返回结果是否仍然合理。这两步做完再决定是全量切、部分切还是退回。测试集的构建和评测口径可以参考站内 指南中心(/guides) 里关于检索评测的说明,避免用错指标。
下一步把模型标识、维度、归一化配置写进索引元数据并在服务启动时断言校验,然后到站内核对当时的模型资料与维度信息。→哪些情况这份榜单帮不上忙
先记住一句话:MTEB 这类榜单测的是「通用任务上,一堆模型横向比一比」,它帮你缩范围,不帮你下结论。只要你的场景和榜单任务分布对不上,分数就只能当参考,不能当依据。下面这几种情况尤其明显,遇到时请把榜单降级成候选池入口。
| 你的情况 | 榜单为什么会失真 | 该怎么办 |
|---|---|---|
| 强领域语料,行业缩写、内部术语密集 | 榜单任务多是通用语料,词表覆盖不了你的黑话 | 先用榜单圈出若干候选,再拿自己标注的小样本实测 |
| 查询与文档长度分布差很远,比如超长文档配超短问句 | 榜单任务的长度分布和你不同,模型的长文本能力没被充分考察 | 自建贴近真实长度的评测集,重点看截断位置和召回 |
| 延迟卡在几十毫秒量级 | 榜单排序基本不看推理耗时和模型体积 | 把维度、体积、量化后的速度当硬门槛先筛一轮 |
| 业务里有大量错别字、口语、代码或表格 | 榜单很少覆盖这类脏输入 | 单独造一批脏数据样本,观察掉分幅度 |
- 强领域文本:把榜单当粗筛,不当终选,终选必须用你自己的语料跑一遍。
- 长度分布错位:先量清楚你线上查询和文档的长度分位数,再决定评测集怎么造。
- 延迟敏感:排序靠前的大模型往往体积大,可能直接出局,优先看小维度候选。
- 多语言或混合语种:确认榜单里对应语种的任务占比,占比低就别硬套。
- 结论外推:榜单上的名次只在榜单任务上有意义,换任务就要重新验。
- 第一步,量自己的分布抽一批线上真实查询和文档,统计长度分位数、语种占比、术语密度。这一步不做,后面全是拍脑袋。
- 第二步,划候选池拿榜单当前排序,从前往后取若干模型作为候选,不直接定冠军。具体名次去站内模型资料页核对当时数据,别记死数字。
- 第三步,搭小评测集从自己业务里抽几百条查询和对应文档,人工标好相关性,构造 recall@k 之类的指标,不用追求大而全。
- 第四步,过硬门槛按延迟、显存、体积先砍掉不达标的候选,剩下的再比质量。速度不达标,质量再好也用不上。
- 第五步,复测再定对通过门槛的模型跑自建集,看差距是否稳定。只有自己集上稳定领先,才敢换。
还有一个常被忽略的点:榜单是静态的,你的语料和业务却在变。今天合适的模型,等语料结构变了、查询变长了,可能就不合适。所以更稳的做法是把这套自测流程固化成脚本,隔一段时间重跑一次,而不是一年前看过一次榜单就定了。想省事的话,去站内指南中心找评测集搭建的入门说明,照着改比从零开始快。
常见问题
MTEB 分数高的模型,我直接拿来用行不行?
可以当起点,但不能当结论。榜单分数是多个任务的汇总平均,你的场景通常只对应其中一两类任务,而且语料领域、文本长度分布都不一样。稳妥做法是从榜单前若干名里筛出满足维度、上下文长度和许可证的候选,再用自己的小测试集跑一遍前几位命中率,两组结果一致再定。
中文检索一定要挑专门的国产嵌入模型吗?
不一定,但多语言模型在中文上的表现普遍不如专门优化过中文的模型。判断方法很简单:找榜单里的中文子集或者跨语种子集单独看,如果某模型总榜靠前但中文子集明显掉档,就要慎重。另外中文分词、标点、繁简混用这些细节,也建议放进你的测试集里验证。
向量维度高是不是检索就更准?
维度高通常表达能力更强,但不是线性关系,而且代价很实在:向量库体积、内存占用、单次检索延迟都会跟着涨。很多场景降维后召回率掉得很少,成本却降一半。做法是先按原维度测出基线,再试降维或者换低维模型,拿同一套测试集对比,看差距能不能接受。
换了嵌入模型,已有的向量数据还能用吗?
不能混用。不同模型的向量空间没有对齐关系,把新模型的查询向量拿去搜旧模型的库,结果基本是随机噪声。换模型就等于全量重建索引,期间要安排双写或降级方案。这一点在排迁移计划时最容易被低估,语料越大重建窗口越长,提前算好再动手。
自建嵌入模型大概要考虑哪些资源?
主要是显存和批量吞吐。嵌入模型参数量不大,但长文本、大批量一起上时显存涨得快,并发上来延迟也会跟着走。先按你实际的 chunk 长度和每天要处理的条数估一遍,再决定用多大卡、要不要量化。具体数字不建议照抄别人的配置,按自己的语料实测一轮更靠谱。