跳到主要内容

你的嵌入模型在训练中从未见过的专业术语检索库

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个检索团队针对其产品目录发布了一个开箱即用的嵌入模型 (embedding model)。评估集——从上个月搜索日志中抓取的几百个查询——回传的 recall@10 达到了 0.91。他们将其推向生产环境。三周后,支持部门开始转发工单:一位用户搜索了某个零件的具体 SKU,结果得到了五个看起来很有道理但错误的零件。另一位用户搜索了一个功能的内部代号,结果得到了一个无关功能的营销名称。评估集从未捕捉到这一点,因为评估集是从系统已经处理过的查询中提取的——即关于常用术语的查询。作为业务核心的长尾术语 (jargon) 从未被采样。

模型并没有失败。模型完全按照其训练要求执行了任务,只是针对的是一个不包含团队提供语料库的词汇分布。团队将嵌入视为一种领域中性的原语 (domain-neutral primitive)——一个从文本到向量的函数——而实际上,它是一份关于它可以解析哪些词汇的契约,是与别人的训练语料库签署的。

双峰覆盖问题

嵌入模型是在互联网规模的语料库(Common Crawl、维基百科、书籍、代码)上训练的。它们内化的词汇分布反映了公开互联网最常讨论的内容。领域特定术语——药物名称、内部产品代号、合同条款、零件编号、科学记数法、仅存在于某一行业内部的术语——很少出现或根本不出现。

结果是一种双峰覆盖模式。常用标记 (common tokens)(动词、介词、流行产品名称、众所周知的概念)在嵌入空间中密集表示;模型在许多语境中见过它们,并学会了区分它们的语义邻域。稀有标记——领域词汇所在的长尾部分——则坐落在稀疏、区分度差的区域。多个截然不同的稀有术语坍缩到同一个邻域,因为模型从未有足够的信号来推开它们。

2025 年记录这种失败模式的研究对此直言不讳:稠密检索器 (dense retrievers) 在长尾实体上失败,因为模型内部的标记分布“忘记”了这些实体的某些标记。一个稀有药物名称的嵌入并不是该药物的真实嵌入——它是分词器 (tokenizer) 将其拆分成的子词片段 (subword pieces) 的嵌入,这些片段被平均成一个向量,指向那些恰好共享这些片段的常用词。两个具有重叠子词的不同药物名称最终在嵌入空间中成为邻居,不是因为它们语义相似,而是因为它们的分词结果相似。检索系统会很自然地将一个作为另一个的结果返回。

这就是开头段落中团队遇到的失败模式。产品目录包含嵌入模型从未作为完整标记见过的零件编号和 SKU。模型将每一个都嵌入为对其子词组件的模糊覆盖。检索就变成了针对分词器产物的某种模糊匹配,而不是针对意义。

为什么评估套件没有捕捉到它

评估套件没有捕捉到它,是因为评估套件是从错误的分布中提取的。团队根据生产系统已经处理过的查询构建了评估集。由于选择偏差,系统已经处理过的查询正是系统所擅长的——常用术语、释义、导航式查找。长尾的术语密集型查询要么不在日志中(因为用户已经放弃并直接使用了 SKU 列),要么数量非常少,以至于被总体的召回率数字淹没了。

即使是知道要平衡评估集的团队,也往往平衡错了方向。他们根据查询长度、用户细分、类别进行分层抽样。他们没有根据查询的词汇分布相对于嵌入模型训练语料库的词汇分布进行分层。这种分层才是真正重要的,而且几乎没有人去计算。

MTEB 和 BEIR 基准测试在大规模上也存在同样的问题。它们聚合了许多任务并产生一个单一的数字,让你能够对模型进行排名,但排名榜首的模型在词汇分布与基准测试不同的特定领域中,表现仍然可能不佳。将排行榜得分视为领域质量信号,与将查询日志评估视为覆盖率信号是同一类范畴错误——两者都是针对模型已经训练或评估过的文本进行衡量,而不是针对你自己的语料库实际包含的文本。

该团队需要的纪律是一个领域词汇评估,将稀有术语固定下来,并专门针对它们衡量检索效果。根据语料库词汇的长尾部分构建评估集,而不是根据查询日志的头部。这两个分布完全不同,在一个分布上表现良好的模型在另一个分布上可能会悄无声息地失效。

实践中“糟糕”的表现是什么样的

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates