律师在合同检索框里输入“赔偿上限”,排在第一的是一段写得很漂亮的赔偿条款概述,来自对口的协议类型,但里面没有上限。真正把责任限定在十二个月费用的那条,排在第十四位,在首屏之外,也在律师的耐心之外。支撑这次检索的嵌入模型,在公开榜单的平均分上接近榜首。那个平均分,从来没被问过你的文档。
![]()
这是领域检索里再普通不过的失败。通用模型很擅长学“话题相似”,而领域查询往往要更窄的东西:那个被定义的术语、那条具体义务、那个限定条款的数字。模型能找到对的街区,仍然可能敲错门。
怎么选嵌入模型和重排模型?答案不在榜单平均分里,而在你自己标注的查询集上。下面这套方法,就是为这件事准备的。
第一步:查询集从真实输入里来
从人们真正敲进去的东西开始。查询可以从搜索日志、工单,或者专家之间互相提的问题里拉。自己编的查询比真实的更干净,问题恰恰在这里:真实查询短、含糊,塞满行业黑话。
每条查询都要记下能回答它的文档或段落。这份标注集是整个流程里最值钱的产物,因为后面每一个决定都要拿它来量。标注的粒度要和你检索的粒度一致:索引存的是条款,就标条款,别标整份合同。
难例要故意放进去。近乎重复的模板文本、有特殊含义的定义术语、正确答案是一个数字的查询,都该在集合里。一个全是简单查询的集合,会给每个模型都打高分,什么也告诉不了你。
第二步:榜单只看对的那几列
公开基准仍然是搭候选名单的正确方式,前提是你读的是和任务匹配的那部分。MTEB(Massive Text Embedding Benchmark)覆盖检索、重排、分类、聚类和语义相似度,并发布 MTEB(eng, v2) 这类变体,以及面向法律、医疗、代码文本的领域基准。
总平均分把这些任务混在一起。一个在聚类和相似度上出色的模型,可以在平均分上排得很高,检索能力却很一般。做搜索系统,就按检索那几列排序,再按和你语料相近的领域基准排序。把结果当成候选名单,而不是可以信任的排名。
第三步:先用硬约束砍掉不能上线的
任何测试之前,先删掉你根本没法部署的模型。四项约束承担了大部分筛选工作:许可证、上下文长度、语言、模型体积。三到五个嵌入模型加两到三个重排模型,是能管得过来的名单;再多,这场对比就变成研究项目了。名单里要留一个通用基线,否则你判断不了领域模型是不是真的挣到了它的位置。
第四步:用 recall@k 逐个测嵌入模型
用每个候选模型把语料嵌入一遍,跑标注查询。recall@k 问的问题很简单:在能回答这条查询的段落里,有多少出现在前 k 条结果中?k 要按下一阶段能看到多少来定。如果重排模型只看前 50 条,就测嵌入模型的 recall@50,因为重排救不回一条根本没送到它面前的段落。
别只看平均值。按查询类型拆开看结果,亲手读失败案例。一个总分领先、却在每条数字类查询上都输的模型,对合同类产品可能就是错的选择。recall 之外还要记延迟和索引体积,因为更大的嵌入维度意味着你未来索引的每一份文档都要多付存储。用 Matryoshka 方式训练的模型可以截断到更少的维度,截断后的 recall 也值得测一遍。
有一个设置毁掉的对比实验比任何模型选择都多:查询指令。E5 系列模型期待“query:”或“passage:”前缀,Qwen3 嵌入模型在查询侧要接任务指令。每个候选都按它模型卡上写的方式跑,否则你测的是自己的预处理,不是模型。
第五步:加重排,量变化
重排模型通常是交叉编码器,把查询和每条候选段落放在一起读,给这一对打分;也存在晚交互和列表式重排。它比向量检索慢,所以只看列表顶部,而它经常正好修掉开头那个场景里的失败:对的话题排在了对的答案前面。
要量用户看到的东西。对每个嵌入模型的前 k 条做重排,比较重排前后的 nDCG@10,这个指标奖励把正确段落放在靠前位置;MTEB 的检索任务报的也是同一个指标。同时记录重排模型在你这个 k 上的 p95 延迟,因为每条查询给五十对文本打分,是查询链路上最贵的一步。
结果通常长这样:重排缩小了各嵌入模型之间的差距,更小的模型配上重排,可能打赢单用大模型,把重排的每查询成本算进去之后,服务成本还更低。只有你自己的数字能说明这在你的语料上是否成立。
第六步:定表示方式,算清重建索引的账
稠密向量抓语义。稀疏表示,比如 SPLADE 一类模型,保留精确词匹配,对零件编号、法条引用和定义术语有帮助。混合检索把两者合起来。多向量模型,ColBERT 家族,每个 token 保留一个向量,用晚交互打分,代价是索引更大。
测那种针对你观察到的失败的表示方式,而不是最复杂的那种。然后把账算诚实:以后换嵌入模型,意味着每一份文档都要重新嵌入。Qdrant、Weaviate 这类存储允许你在同一个集合里把新向量加在旧向量旁边,切换会温和一些,但嵌入这一趟跑不掉。相比之下,重排模型可以换掉而不碰索引。
候选如果是托管 API,这场对比就是循环换 API key。如果自托管,为了测试而同时服务五六个模型,可能成为整个工作里最耗时的部分。Superlinked 的推理引擎 SIE 能压缩这一步:模型按需加载,GPU 显存满了就按最近最少使用淘汰,换候选只是请求里改一个模型 ID,而不是重新部署。
在 SIE Cloud 上,对比可以直接用云端模型:Qwen3-Embedding-4B、Snowflake 的 arctic-embed-l-v2.0、稀疏与多向量形态的 bge-m3、GTE-ModernColBERT,以及 0.6B 和 4B 的 Qwen3 重排模型,各自按云端价目表计价。自托管时,更宽的模型目录还能加入 gte-modernbert-base、multilingual-e5-large-instruct、bge-reranker-v2-m3、mxbai-rerank-large-v2 等候选,并有文档化的路径通过配置文件接入其他 Hugging Face 模型。当评测语料不能离开你的环境时,自托管也是该选的方式。
同一套函数给每个候选打分:gold 把每条查询 ID 映射到能回答它的段落索引集合;真实语料上,段落编码要分批做,向量存下来。把每个嵌入模型的前 50 条喂给重排,再算 nDCG@10,就能填出第五步那张表。
FAQ
标注集要多大,数字才有意义?够把你关心的候选分开就行。几十条查询就能暴露大的差异,比如一个在每条数字类查询上都失败的模型。要区分两个都很强的嵌入模型,通常需要几百条,并按真实流量比例分布在各类查询上。按你检索的单元标注,放入难负例,比较模型期间保持集合固定。之后从生产环境的失败案例里补查询,那正是第一版集合漏掉的情况。
该微调嵌入模型,还是先加重排?先加重排。它除了评测集不需要额外训练数据,一次改动就能撤掉,也不强制重建索引。在稳定、标注充分的领域上,微调嵌入模型可以打赢它,但会带来训练流水线、要维护的新模型版本,以及每次模型变更后的全量重嵌入。等重排已经到平台期、标注集也大到足以训练而不至于过拟合时,再考虑微调。
为什么不直接用 OpenAI 的嵌入模型了事?领域查询会以开头那个场景的方式失败:通用模型把对的话题排在了对的答案前面。把这场对比跑起来。SIE 上的专用嵌入模型和重排模型,一个 API 上的开放权重,就是这场测试和你最终保留的模型的生产层。SIE Cloud 和自托管用同一套 SDK,通过标注集的候选,就留在你测它的地方。
领域检索的模型选择是个测量问题。用真实流量搭查询集,从对的基准列里筛候选,在你的语料上测 recall,加重排,然后才定表示方式和重建索引。对比在 SIE Cloud 上跑;同一份代码对着自托管集群也能跑它目录里有的模型。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.