如果你读过关于RAG的资料,大概率对"嵌入"这个词不陌生。把一堆文本变成一串数字,就这么简单。但这里还有一层容易被忽略的东西:把文本变成数字的方式,不止一种。

两种重要的路子是稀疏表示和稠密嵌入。它们各自怎么工作、什么时候该用哪一个,值得拆开看。

打开网易新闻 查看精彩图片

先想象一本五万词的字典

假设你有一本巨大的字典,装着你所用语言里的每一个词,比如五万个。稀疏表示做的事情,就是给这五万个词各分配一个数值,数值大小取决于这个词跟当前这句话有多相关。

大多数句子只用到其中很小一部分词。五万个位置里,只有少数几个有实际数值,其余全是零。这就是"稀疏"这个名字的由来:向量大部分是空的,只有少数非零值。

举个更简单的例子。假设词表只有十个词,按顺序排好:猫、狗、跑、快、食物、吃、蓝、天、车、开。

现在有一句话:"那只狗能跑得很快。"

它的稀疏向量大致是这样:猫0、狗1、跑1、快1、食物0、吃0、蓝0、天0、车0、开0。本质上,它记录的是哪些词出现了、有多重要。

再看第二句:"我喜欢快点吃东西。"对应的向量变成:猫0、狗0、跑0、快1、食物1、吃1、蓝0、天0、车0、开0。两个向量大部分位置都是零。

当文本里确切的词本身很重要时,这种表示方式很好用。但它的局限也正出在这里。

同义词、改写和口语化提问

第一道坎是同义词。"买"和"购买"意思相近,但基于词的传统表示会把它们当成完全不同的词项。

第二道坎是改写。两个人可以用完全不同的措辞问同一个问题,靠字面词重叠就很难把它们联系起来。

第三道坎是口语化提问。比如"我的包裹为什么这么久还没到"和"配送延迟说明",两者字面几乎没有重叠的词,可第二份文档里可能恰好装着用户需要的信息。

这正是稠密嵌入派上用场的地方。

稀疏表示主要看哪些词出现了,稠密嵌入更关心文本的语义含义。稠密嵌入把一段文本表示成一个相对较小的向量,里面装着大量数值。它不像稀疏向量那样有成千上万个对应词表、且大多为零的位置,而是可能包含几百到几千个值,其中大多数是非零的。

看一个简单的例子。第一句:"那只狗跑得很快。"第二句:"那只小狗飞奔。"仔细看,这两句话没有一个词是共用的。"狗"不等于"小狗","跑"不等于"飞奔"。如果只找匹配的词,这两句话看起来毫不相干。

稠密嵌入模型经过训练,能捕捉文本之间的语义关系。所以这两句话最终得到的嵌入可能彼此相当接近,因为它们表达的是相近的意思。这也是稠密嵌入在语义搜索里好用的原因之一。

但稠密嵌入也有自己的短板。

精确词项面前,语义相似会失灵

稠密嵌入擅长捕捉更宽泛的语义关系,可当确切的词项很重要时,它就没那么有效了。比如这几类内容:

  • 产品编码,例如 SKU-4471B
  • 确切的名称
  • 错误码
  • 冷门技术术语
  • 特定标识符

搜索一个精确的产品编码,交给侧重字面词项匹配的方法,可能比只靠语义相似度更合适。

嵌入把文本变成数字,但变成数字的方式不止一种。稀疏表示保留显式的词汇信号,在确切的词项重要时有用;稠密嵌入捕捉更宽泛的语义关系,在同一个意思可以用不同说法表达时有用。理解这个差别,也就能解释为什么RAG系统有时会同时用不止一种检索方法,而不是只依赖稠密嵌入。