返回博客
找回重要的,而不是什么都捞回来:语义搜索的阈值
技术4 分钟阅读

找回重要的,而不是什么都捞回来:语义搜索的阈值

为什么这对你很重要

当你问 LIA「我之前跟你说过老王那家餐馆什么来着?」,她不会去找你这句话里的确切字词。她按含义来找。每一条记忆、每一篇日记、你文档中的每一个段落,都会被转换成一串数字,也就是一个embedding(嵌入向量),用来表示它的意思。含义相近的两段文字,嵌入向量也相近,它们的相似程度用一个分数来衡量。

剩下的问题是:分数达到多少,一条记忆才算足够接近、值得用上。太低,LIA 会在回答里塞进无关的记忆:回答变得混乱,你还要为噪声支付 token。太高,她会错过她其实知道的东西。这个阈值看起来像个技术细节;但决定 LIA 记性好不好的,正是它。

我想要的

我希望每种用途都有自己的阈值,并在贴近真实的测试上选出来。找回一条有用的记忆、发现你兴趣中的重复项、为一份文档挑选段落,并不是同一个问题。我还希望每个阈值都按它犯错的代价来选择。

具体怎么做

每个嵌入模型都有自己编码含义的方式。当 LIA 换用 Google 的嵌入模型时,所有阈值都重新校准了:这个模型不再仅仅因为两段无关的文字用同一种语言写成,就把它们拉近;旧模型的阈值已经毫无意义。对每个阈值,我都在测试集上测量了它错误放行了什么、又漏掉了什么。

  • 搜索还是去重。要帮你想起一条记忆,适中的阈值就够了。要判定两个兴趣其实是同一个,它们必须几乎完全相同。一条记忆甚至带有两个嵌入向量:一个对应它的内容,一个对应应该唤起它的关键词。
  • 犯错的代价。在给你的兴趣去重时,有两个阈值犯的错误数量完全一样。较低的那个会错误地合并不同的主题,比如 Android 和 iOS:你对其中一个的兴趣会消失在另一个里,无法挽回。较高的那个会放过几个重复项,它们看得见,也容易纠正。我留下了较高的那个,因为光数错误还不够:还得看是哪些错误。理由就写在代码里,紧挨着这个值。
  • 六种语言,一个阈值。对于知识空间,这个阈值在 LIA 的六种语言中分别测量过,最佳值处处相同。这正好:一份德语文档也可能回答你用中文提出的问题,而按语言设定的阈值不知道该选哪一个。另外还有一个小小的加分,奖励确切的字词,让产品名称或编号这类引用不会丢失。
  • 会学习的阈值。对于你的日记,一个固定值并不适合所有人:分数取决于每个人写什么、写了多少篇。所以这个阈值会根据你来调整,每天最多迈一小步,并且限定在两个它无法越过的边界之间。有一个开关可以把它固定在默认值。

嵌入向量还得先算出来

如果嵌入向量没有算出来,阈值选得再好也没用。这个计算要通过一个在线服务,它限制每分钟的调用次数。所以 LIA 的后台任务会错开启动时间,不会在同一秒里一起出发。如果服务仍然饱和,LIA 会重试有限的几次;而她自己的限流在拿不准时会放行请求,好让你的回答保住记忆。

局限

  • 没有哪个阈值能把相关内容和其余内容完美分开。两个不同的主题可能非常相像,而同一个想法的两种说法却可能差得很远。阈值始终是一种折中,所以我把它选在错误较轻的那一边。
  • 两个不同模型的嵌入向量无法互相比较:换模型就必须全部重新校准。
  • 语义搜索目前依赖 Google 的一项服务。它无法离线工作。

延伸阅读:你的文档,一问便知:知识空间;只给模型看重要的东西:减轻 LIA 工作负担的服务。

#embeddings#similarity#calibration#gemini#thresholds#f1-score