一、找到相似的资料,为什么还没有完成查找
小叶在做一个校园资料助手。它接收同学的问题,从已经收集的文件中找出可以参考的段落,再把段落和出处交给回答问题的AI。此时有同学问:“讨论室预约怎么取消?”系统已经知道对方问的是北区、本学期正在执行的安排,但还不知道预约从几点开始。
资料库里有五份记录。下面的校区、文件、规定和后续数值全是教学设定,并不代表任何实际学校的政策。
| 编号 | 记录内容 | 适用范围 |
|---|---|---|
| A | 讨论室预约说明会的公告,提到会介绍取消事项,没有给出操作办法 | 北区,本学期 |
| B | 学习空间预约撤销条款,给出操作入口及时间条件 | 北区,本学期 |
| C | 上学期的旧条款,写着提交后不能自行撤销 | 北区,已失效 |
| D | 另一个校区的预约撤销办法 | 南区,本学期 |
| E | 投影设备借用说明 | 北区,本学期 |
本例假设这些适用范围已经核实,并作为文件旁边的字段保存。B的完整条款是:预约者至少提前两小时,可以在“我的预约”中撤销;距离开始不足两小时,应联系值班台,是否获准另行确认。
同学需要的不是一篇频繁出现“讨论室”“预约”“取消”的文字,而是当前情境下能够回答操作问题的依据。A很像在谈同一件事,却没有办法;C直接谈取消,但已经失效;D可能写得很完整,却属于南区。即使计算程序把它们排得很整齐,查找仍可能失败。
本讲要建立的正是这条联系:向量中的接近,是用某种表示和某种规则算出来的;它能帮助缩小查找范围,但是否找到了合适资料,还取决于对象、任务及原文。理解这一点之后,我们才能判断是表示出了问题、搜索漏了候选,还是找到了材料却用错了。
二、一段文字怎样变成可以比较的向量
先用看得见的字段理解表示
最直接的办法,是先约定一个词表,再记录每个词出现多少次。暂时只保留三个词,顺序固定为“讨论室、预约、取消”。查询“讨论室预约怎么取消?”的表示便是(1,1,1)。每个分量都有可以检查的含义,换了词表顺序就必须同步调整全部记录。
再看一句公告:“讨论室预约说明会介绍讨论室预约与取消事项,欢迎参加。”按这三个词在句中出现的次数,得到(2,2,1)。这是人工约定的简单计数,不涉及真实中文分词程序。与查询做内积得到5。
这个计算没有错。它确实表明公告与查询共享了这些词,而且前两个词反复出现。问题在于,计数没有记录“只是预告说明会”与“实际给出取消办法”的区别。表示只留下某些信息,就只能在这些信息上比较。
如果词表有几万个词,而一段文字只用到其中少部分,向量的大多数位置为零,通常称为稀疏表示。非零项的位置指出用了哪些词,其数值记录次数或权重。这里的维数指词表提供了多少个坐标位置,不是说这一段文字具有几万个独立主题。
词的权重也可以改变。“资料”“活动”若几乎每篇都出现,区分作用往往较弱;罕见的设备型号可能更能帮助定位。TF-IDF把文内出现程度和词在资料库中的稀有程度结合起来,是一种经典做法。它改善的是词项的区分作用,并不会自动使公告变成操作条款。信息检索教材的TF-IDF说明给出了这一向量表示思路。
换一种说法,原来的坐标可能看不见
若同学改问:“活动不办了,房间怎么退订?”在刚才三个词的严格计数规则下,查询会变成零向量。它没有变成一个没有意思的问题,只是没有命中当前词表的三个词。直接把零向量送去算余弦,既会遇到分母为零,也暴露了表示层面的缺失。
可以增加词表、做同义词处理,也可以学习另一种表示。嵌入通常指用一个映射,把文字、图像或其他对象变成向量。用于文本检索的嵌入模型,希望把对当前任务有关联的表达放到适于匹配的位置,使“取消预约”和“撤销预订”不必字面相同也有机会被找出来。
学习得到的向量常是许多实数分量构成的稠密表示。它的某一维一般不能直接读成“取消程度”,另一维也不必叫“讨论室程度”。含义由许多分量共同承担;我们使用整体关系,而不是给每个坐标随意配一个中文词。
训练怎样规定“有关联”,会影响这种空间。若训练任务是寻找重复问题,模型关心两句话是否在问类似的事;若训练任务是从长段落里找到问题的答案,模型需要学习问题与回答材料之间的匹配。相同的向量维数,并不保证这两种训练得到同样的查找能力。
这也解释了为什么不能看到模型把两个词放得很近,就宣称它完整理解了相应制度。相似关系可能保留了主题,却没有充分区分否定、时间和适用对象。是否真正支持小叶的查询,需要拿符合任务的资料与问题检验。
查询与文档需要进入配套的比较空间
把资料转成向量的映射记为f,资料d的表示为f(d)。如果查询采用另一套配套的映射g,查询q的表示为g(q)。匹配计算发生在g(q)与f(d)之间。两套映射可以相同,也可以有为查询和文档分别设计的处理,但它们必须被设计或校准为可以相互比较。
资料是“至少提前两小时,可在个人页面撤销”,查询是“怎么取消”,它们并不是两句互相替换的话。把查询和文档看成不同角色,有助于理解为什么检索模型可能提供不同的查询入口和文档入口。Sentence Transformers的语义搜索说明区分了相似问题检索与问答资料检索,并说明相应编码方法。
不能只检查“两个数组都有768个数”就把它们放在一起用。假设一个二维系统把某对象记为(1,0),另一个系统整体旋转坐标后记为(0,1)。新系统内部可能同样好用,但拿旧查询(1,0)直接与新资料(0,1)算内积,会得到零;若查询与资料一起旋转,原来的关系才保留。
真实模型之间的差异不一定只是一场旋转。这个例子只说明:分量数相同是能够执行数组运算的条件之一,并不是语义坐标已经对齐的证明。更换模型或编码方式时,需要让资料和查询采用兼容版本,重新验证匹配效果;不能用“维度没变”跳过这一步。
三、相似度算出了什么,排序为什么会改变
用一组透明的数观察打分
接下来另设一组二维向量,让计算过程可见。它们不是前面三词计数的降维结果,也不是任何真实模型的输出;我们只用它们模拟五条记录已经取得向量之后的排序。查询向量取q=(1,0)。
| 记录 | 教学向量 | 向量长度 | 与q的内积 | 与q的余弦相似度 |
|---|---|---|---|---|
| A:说明会公告 | (4,3) | 5 | 4 | 0.80 |
| B:现行撤销条款 | (0.96,0.28) | 1 | 0.96 | 0.96 |
| C:旧条款 | (1,0) | 1 | 1 | 1 |
| D:南区条款 | (0.8,0.6) | 1 | 0.8 | 0.80 |
| E:设备借用 | (0,1) | 1 | 0 | 0 |
对非零向量,余弦相似度是:
这里d在公式中表示某条记录的向量,q表示查询向量,分数没有单位。分子包含方向配合及两边长度的影响;除去长度以后,比较留下方向关系。实际用于学习嵌入时,是否采用这一规则,应与模型的训练和任务评价相配套。
按原内积从大到小,A排在最前,因为它的长度明显更大;按余弦排序,C最前,B第二,A与D并列。公告向量的较大长度,在这里足以让原内积超过方向更贴近查询的B。这个例子说明了两种规则为什么不同,并没有证明所有检索任务都该选余弦。
本例接下来选用余弦,只把它作为寻找候选的规则。C即使达到1,仍是失效条款。数值为1说明它与查询在这份教学表示中同向,不能把“同向”直接翻译成“当前正确答案”。同理,真实模型给出0.96,并不等于有96%的概率可以照此操作。

图一:左侧保留原长度,右侧把非零向量化为单位长度。A与D单位化后重合;q与C重合。这里的两个坐标只是教学坐标,不代表两个可直接命名的语义属性。
排序可以等价,输出数值未必相同
把查询和所有资料向量都化为单位向量后,直接内积就是余弦。此时单位向量间的平方欧氏距离满足:
因此最大余弦与最小单位向量距离给出相同排序。B的余弦是0.96,对应平方距离0.08;A的余弦是0.8,对应平方距离0.4。这里是同一组单位向量上的不同记分方式,不能把未经单位化的原距离也当成相同规则。
这个关系在使用向量索引时很实用。有的接口返回相似度,数值越大越靠前;有的返回平方距离,数值越小越靠前。Faiss官方文档明确说明其L2类型返回平方欧氏距离,并给出归一化后与内积的关系。若相似度门槛设为0.9,在上述单位化条件下应对应平方距离不超过0.2,而不是也拿距离去和0.9比较。Faiss的距离类型说明
还有一个容易忽略的细节:只把查询向量乘以一个正数,会使它与每条资料的原内积都乘相同倍数,因此这一个查询的排序不变;不同资料向量各自的长度却可能改变相互名次。于是“只归一化查询后,结果顺序没变”不能证明原内积已经等同余弦。排序不变、分数不变、阈值判断不变,是三件需要分开核对的事。
四、一次比较很多条资料,矩阵中的行列是谁
五条资料向量按行存入矩阵D,形状为5×2;查询q有两个分量。先沿每行计算资料长度,再逐行单位化。下面只执行教学向量运算,不调用任何嵌入模型。
import numpy as np
ids = np.array(["A", "B", "C", "D", "E"])
D = np.array([[4., 3.], [0.96, 0.28], [1., 0.],
[0.8, 0.6], [0., 1.]])
q = np.array([1., 0.])
lengths = np.linalg.norm(D, axis=1, keepdims=True)
assert np.all(lengths > 0) and np.linalg.norm(q) > 0
D_unit = D / lengths
q_unit = q / np.linalg.norm(q)
scores = D_unit @ q_unit
order = np.argsort(-scores, kind="stable")
print(ids[order].tolist())
print(np.round(scores[order], 2).tolist())
# ['C', 'B', 'A', 'D', 'E']
# [1.0, 0.96, 0.8, 0.8, 0.0]
输出的每个分数属于一条资料,顺序由ids与D的行一一对应。稳定排序使并列的A、D沿用输入顺序;这只是本例让结果可复核的约定,不代表A在语义上比D更好。改变资料存储顺序后,并列名次可以交换,但对应的向量和编号必须一起移动。
如果有m个查询,每个有p个分量,按行组成Q;n条资料组成n×p的D。两边逐行单位化后,全部查询与资料的分数矩阵为:
S的第i行是第i个查询对全部资料的分数,第j列是全部查询对第j条资料的分数。要给每个查询找候选,应在每一行内排序。若误在列内排序,得到的是“这篇资料最接近哪些查询”,数组形状可能完全合法,所回答的问题却已改变。
这里转置不是为了把式子摆得好看,而是让一份查询与一份资料的对应分量逐项配对。A04中的矩阵乘法,在本讲就成为一张批量匹配表。知道每个轴代表什么,比记住某行代码的写法更能帮助我们检查AI生成的程序。
真实数据还要处理零向量、非有限数值和编码失败。零向量在三词计数例里表示当前词表没有捕获查询,在另一个系统里可能来自空文本或失败的预处理。应先查它是怎样产生的,再决定补充表示、回到词法查找或要求改写问题。给分母加一个很小的数可以避免某些报错,却不能凭空恢复没有记录的信息。
五、前几名是谁,取决于先在哪个范围里查
top-k只规定数量,没有保证每条都能用
top-k表示按给定分数取排在前面的k条。例如先取前两条,当前教学分数会返回C和B。如果库中没有合适答案,top-k通常仍能返回几条最接近的记录;“最接近”是相对于这个候选库而言,不是一份充分相关的保证。
相似度阈值则提出另一种问题:分数至少达到多少才保留。设一个演示门槛0.9,C和B会留下,A、D、E会被排除。门槛与k可以组合使用,但0.9只是此处的算例设置,没有通过真实问题验证,不能照搬成通用部署标准。
因此候选数量可能为零。一个能够明确返回“当前没有找到足够依据”的流程,比强行把第一名称为答案更符合查资料的任务。是否追加搜索、澄清问题或交给人工核实,应由后续流程决定;向量排序本身没有解决这个选择。
已知的适用范围应该真正参与查找
本例已知要北区现行安排,因此C和D不属于可用资料。校区和有效期这些伴随正文保存的字段,称为元数据。它们并不因为没有被写进向量分数,就可以在判断中省掉。
先限定到北区现行记录,剩下A、B、E。再按余弦排前两条,得到B和A。B是需要细读的现行条款;A只是可以进一步核查的候选,不能因排第二就混入回答依据。
eligible = np.array([True, True, False, False, True])
allowed = np.flatnonzero(eligible)
within = np.argsort(-scores[allowed], kind="stable")
selected = allowed[within[:2]]
print(ids[selected].tolist())
# ['B', 'A']
先取全库第一名再过滤,得到的是C,删掉后一个结果也不剩;但合法范围内明明有B。原因不在B分数太低,而在过早截断让它没有机会进入后续步骤。若先取全库前两名再过滤,则只剩B,仍不等于合法范围内的前两名B、A。

图二:同一套余弦分数,左图标出不适用的C、D,右图只在A、B、E中排序。过滤改变的是允许比较的集合,并未重新计算语义向量。
真实索引可能提供搜索时过滤,也可能先多取一些候选再过滤。后者若想得到足够的合格候选,必须考虑继续取回或重新搜索,不能默认扩大一次数量就永远足够。本讲的小表可以直接精确过滤;大型索引如何实现,要检查实际接口及其保证。
过滤也不是万能的。只有适用字段真实、完整、维护及时,过滤才有依据。若文件没有标学期,不能把缺失值直接当成现行。此时问题是资料条件尚未确定,应保留待核状态,而不是用较高的余弦去替代缺失的事实。
六、一条向量代表整本手册,还是代表一个可用片段
查找单位决定有用信息怎样进入比较
现在把B想象成一本长手册中的一个段落,手册还包括开放时间、设备、电源和文明使用要求。如果整本手册只生成一个向量,查询是在和整本的表示比较。模型究竟能保留多少具体条款、是否处理了全部文本,要看输入长度限制和编码方法,不能因为文件上传成功就认定每一段都参与了表示。
若把手册分成若干片段,各自编码,取消条款便有了单独进入候选的机会。分块改变的是检索单位:原来从若干本书里找相近的书,现在从若干段里找可能直接有用的段。它并没有创造新知识,却改变了哪些内容能够被单独比较。
块并非越小越好。假如只留下“可以在‘我的预约’中撤销”,把前面的“至少提前两小时”切到另一块,系统可能找到一个与问题在语义上非常贴近的片段,却丢掉决定操作是否适用的条件。这种错误不能靠把相似度算得更精确来解决。
反过来,把整章二十种操作都挤成一块,单个问题对应的信号又可能被其他内容混在一起,交给回答模型的上下文也更长。分块要围绕可以独立解释的规则、段落或操作单元组织,再检查它们是否保留适用对象、时间条件和例外。
找到一个片段以后,怎样补回必要上下文
一种做法是让用于搜索的片段较集中,同时保存它的父文档、标题和相邻位置。命中某条后,再取回完整条款或所属小节作为阅读材料。这样搜索单位可以与最终提供给AI的上下文单位不同。
例如B的搜索片段可以围绕撤销操作,但取回后应包含“至少提前两小时”和“不足两小时联系值班台”的完整范围。若只拿命中的一句话去作答案,就把检索结果截短成了另一条规则。检查上下文,是恢复原文件已有的条件,不是由AI猜出缺掉的条件。
适量重叠也可以降低边界刚好切断条件的风险,但重叠会让同一条款多次出现。返回的前五条如果只是同一段的五个近似副本,并不意味着找到了五份独立依据。最好保留文档编号、片段位置和内容版本,让后续能够去重并追溯。
这一点会影响评价。如果按片段数统计命中,复制一份正确片段可能让看起来相关的结果变多;若用户需要的是三份不同文件,重复片段却没有增加文件覆盖。评价前先确定要找的是片段、文档还是独立证据,不能在计算后才选择最漂亮的口径。
标题也会改变表示。“取消”这个单独小标题很短,和“北区学习空间/本学期/预约撤销”所提供的信息不同。把上下文适当地带入编码,可能帮助检索区分对象,但标题本身若过时或错误,也会把问题一起带进去。表示前的数据整理,是匹配质量的一部分。
七、先广一点找候选,再认真判断它能否回答
召回与重排各自承担什么
资料较多时,可以先用便于批量比较的表示取得一批候选,再让另一个步骤细读“问题—候选原文”这一对。前一阶段通常称为召回,目标是让可能有用的资料进入范围;后一阶段称为重排,对已经进入的候选重新评价和排序。
本例中,向量匹配先取出B、A。细读时会发现B给出撤销入口和时间条件,A只预告有一场说明会。两者在同一个主题里,能否支撑回答却不同。重排应该关注这种与任务有关的差异,而不是再数一次它们有几个共同词。
一种常见架构让查询与文档分别生成向量,文档向量可预先保存,这通常叫双编码器。另一种让查询与一段候选同时进入模型,直接产生这一对的匹配分数,通常叫交叉编码器。后一种方式可以利用两份文本之间更细的共同处理,但每个查询和候选都要重新组合,计算成本与批量向量查找不同。Sentence Transformers的召回与重排说明介绍了这种分工。
这里没有保证任何一个重排器一定改善结果。它也可能忽略否定词、误解例外或偏好写得像答案的无依据段落。需要用实际问题评价它,而不能因为步骤变多就默认质量提高。
重排还受候选范围限制。如果第一阶段根本没有取到B,普通的候选重排不会自动看见库里的B。把十条错误材料反复排序,仍可能只是把错误排得更整齐。因此遇到失败,需要先看正确资料是否进入候选,再决定改表示、增加检索范围,还是改后面的判断。
词法匹配与语义匹配可以互补
“退订”与“撤销预约”适合检验语义表示能否跨说法找到关联;“投影仪型号PX-217”却包含需要精确保留的型号。若一个模型把PX-217与PX-271都看作近似的设备描述,分数高并不能弥补编号错误。对这类字段,直接匹配词项或结构化字段可能更可靠。
小叶可以让词法检索与向量检索分别提供候选,再按记录编号合并、去重,进入统一的后续核对。这种混合方式的目的,是让两种表示各自看见不同的线索。它不是在宣称其中一种总比另一种高级。
若要合并分数,不能把一个几十点的词法分数与0到1附近的余弦直接相加,就认为两者同等重要。它们的尺度、分布和训练含义可能不同。可以先合并候选集合,也可以根据验证数据设计融合规则;应先说明方案怎样使用两种信号,再讨论它是否改善了查找。
召回数量与最终提供给回答模型的资料数量也不同。先找二十段,是为给后续留下选择余地;最终可能只需要一条完整有效的规则。把二十段全部塞给回答模型,可能引入旧规、重复内容和无关事项。数量的选择要对应各阶段目的,不能把“找得更多”直接当成“回答得更好”。
八、资料越来越多以后,怎样理解近似搜索
先保留一个能够解释的精确基准
若n条资料各有p个分量,单个查询逐条算内积,大致需要n×p次分量乘法以及相应加法。写成矩阵运算可以提高计算效率,穷举时仍要让查询与每条资料比较。
例如100万条、每条768个32位浮点分量,只存向量本体就需要约30.72亿字节,即3.072GB,约2.86GiB。文档、编号、过滤字段以及索引结构还会另占空间。这里是按四字节一个分量推算的存储量,不是某款数据库的实测占用。
对于可处理的小库或验证子集,先做穷举的精确搜索很有价值。它给出在固定表示和固定打分规则下,真正排在最前的向量。以后换快一些的方法,就知道改变来自搜索过程,还是来自模型表示本身。
精确只针对搜索问题。在尚未排除失效条款的全库中,若C与查询的余弦最高,精确搜索就会把它放在前面;它并没有同时证明C是合适的现行答案。几何上的最邻近与任务上的最有用,需要分别评价。
近似方法把搜索工作减少在哪里
近似最近邻搜索,常缩写为ANN,尝试减少查询时需要细比的记录。比如先把空间划成若干区域,查询只进入部分区域;或者沿记录之间的连接寻找较近的候选。它们节省工作,但可能错过某些本该排在前面的向量。
可以想象先把资料分到几个抽屉,只检查最可能的几个。若真正最近的向量恰好在没有打开的抽屉,后面对已打开抽屉查得再细,也找不到它。这是对搜索机制的比喻,不是说语义主题天然存在不会重叠的分区。
Faiss把穷举内积搜索的IndexFlatIP与非穷举的分区、图等索引区分列出;其分区说明也指出,只访问部分区域可能漏掉最近邻。Faiss索引说明能帮助核对工具所谓“更快”具体减少了什么工作,而不是把所有向量库都当成同一种搜索。
扩大搜索范围通常需要更多计算,并可能找回之前漏掉的近邻;压缩向量还可能改变某些细小的分数差别。要记录速度、内存和找回程度,不能只报“查询只用了几毫秒”。这些取舍可以在任务允许的范围内选择,但必须先知道漏掉的是哪些候选、是否影响最终查找。
索引评估中会比较近似结果与精确top-k的重合程度。例如,另设一次索引测试,精确前三条是A、B、C,近似前三条是A、D、E,只重合一条,重现比例是1/3。它回答“近似方法找回了多少精确近邻”,并不直接回答“找到多少能够帮助同学的资料”。后一问题需要独立的相关性判断。
九、怎样知道匹配真的比原来好
先确定什么算相关,才知道分母是什么
评估应从问题及需要的资料开始。对“讨论室预约怎么取消”,当前有效且给出操作条件的B可以算相关;只谈说明会的A不算能够回答本问题的资料。若换成“这周有哪些预约说明会”,A的角色就会改变。相关性是资料相对于一个信息需要的判断,不是文档永久贴着的好坏标签。
为了观察指标,另设一个已完整核对的小资料库,针对某个问题共有三条相关记录B、F、H。某系统返回顺序是A、B、D、F、H;这些编号只用于这个新的评价算例,不沿用前面五份资料的内容。先假设每个编号代表一条不同记录,没有重复片段。
取前k条时,精确率P@k关注返回的k条里多少条相关;召回率R@k关注全部相关记录里找回多少条。设前k条有r条相关,库中已确认的相关记录共R条,则:
这里假设确实返回k条且R大于零。若允许少于k条,应另外写清返回集合精确率或所用P@k约定;若库中没有相关项,召回率的分母为零,要单列无答案问题的处理,不能随手填成100%。
当前前两条只有B相关,所以P@2=1/2,R@2=1/3;前四条找到B、F,P@4仍是1/2,R@4升到2/3;取到第五条时,P@5=3/5,R@5=1。精确率不一定随k单调变化,新增一条相关结果可能让它上升;对于固定的一份排序,召回率随着范围扩大不会下降。

图三:相关记录为B、F、H,横轴表示返回前多少条。每一步都用同一套相关标签,展示精确率和召回率回答的问题不同。
信息检索教材用“返回结果中有多少相关”与“相关资料中找回多少”定义这两个指标。它们的分母不同,分别对应无关结果造成的阅读负担与遗漏资料造成的不完整。精确率与召回率说明
候选里有答案,与第一条就是答案也不同
如果用户通常只打开第一条,B排第二和排第一会带来不同体验。可以记录第一条相关结果的名次;用名次的倒数作一个简明指标,第二名对应1/2,第一名对应1。在约定的检查范围内没有相关结果时,通常记为零。对多次查询的倒数排名取平均,得到平均倒数排名。相关定义
这类指标强调尽早遇到有用结果,却不会充分奖励找到全部相关文件。若一个任务必须同时找到操作办法、例外处理和联系人,只找到其中一条就不能视为资料已经齐全。指标应随信息需要选择,不能用一个熟悉的名称代替需求。
若只标注了检索结果,没有核对库中其他记录,就不知道真正的R是多少。可以报告已标注范围下的结果或候选覆盖,不能假装已经测得全库召回率。这个限制是数据来源的问题,不是把计算保留更多小数位就能消除。
分开检验表示、索引和回答
一次失败至少可能出现在三个位置。第一,相关资料已经在库里,但表示把它排得很后;第二,固定表示的精确搜索能找到它,近似索引却漏掉;第三,资料已正确返回,后面的回答仍漏掉两小时条件。这三个问题需要的改动不同。
小叶可以保留若干类型的问题:原词提问、同义改写、明确型号、带否定的问法、旧规与新规并存,以及资料库确实没有答案的情况。先固定资料版本和相关标准,再比较方案。若每次换模型同时改分块和过滤,就很难判断到底哪一步起了作用。
调门槛或选择模型时,可以使用一批问题;选好之后,还应在未用来做这些选择的问题上检查。已经被反复调到很好的几个例子,只证明方案适应了这些例子。概率统计课程中的抽样与对照,在这里便转化为不让少数漂亮演示代替整体效果的习惯。
十、相似度阈值怎样成为一条可以检验的规则
分数不是概率,门槛必须有自己的证据
余弦在−1到1之间,某些文本表示上的常见得分可能集中在很窄范围,但不能因此把它直接当成正确率。负分表示该表示中的方向关系,也不自动对应语言里的否定;“可以取消”与“不可以取消”甚至可能因为谈同一条规则而得到很高相似度。
需要门槛时,应拿已核对的查询结果观察。例如另设八个问题,每题只看经过适用范围过滤后的第一候选,其分数从高到低为0.96、0.94、0.91、0.86、0.84、0.80、0.76、0.70;人工核对其是否足以回答问题,依次为是、否、是、是、否、是、否、否。
若以至少0.9为接受条件,会接纳前三题,其中两题的候选足够用,一题不足;接受结果中的可用比例为2/3,覆盖了八题中的3/8。若把门槛降到0.8,接纳六题,其中四题足够用、两题不足,可用比例仍为2/3,覆盖比例变为6/8。门槛变严并不保证这份有限样本中的可用比例严格上升。
这些数字只是说明怎样同时观察错误接受与覆盖,八个教学问题不能给出可靠的部署结论。实际还要看样本量、问题类型、错误代价及未参与调参的问题表现。要让分数支持接受判断,需要用明确标签检验所选门槛的效果,而不是把余弦乘100再添一个百分号。
若资料库扩大、新增了一批写法相近的文件,或换了编码模型,原分数分布与最高分的含义可能改变。门槛也应随相应版本重新检查。第一名和第二名相差很大,只说明当前两名在这个分数上有间隔;没有适当检验,间隔本身同样不是可信度证明。
相似也不天然构成可传递的类别
还有一类应用会把相似度用于去重、推荐或分组。即使每次两两比较都有明确规则,也不能自动得到稳定的等价关系。平面上三支单位向量分别指向0度、60度和120度;相邻两支余弦都是0.5,第一支与第三支却是−0.5。
若门槛设为0.49,相邻两对都算相似,首尾却不算。若规定新条目只要与组内某一条相似,就继续收入这一组,首尾也会被放进同一组。这是该分组规则的结果,不是两两相似度已经证明首尾相似。
用于查找时,这提醒我们:与一个候选接近的其他记录,不一定也同样接近原查询。用于去重时,还应区分文字重复、主题相近和同一事项的不同版本。旧规则与新规则可能最像,却恰恰需要分开保存并标明生效范围,而不是合并后丢掉关键差异。
十一、回到讨论室查询,完成一次有依据的匹配
现在可以把小叶的查找过程连起来。查询与资料使用配套表示,按已经选定的余弦打分。北区、本学期的范围先落实到元数据,C与D排除,在A、B、E中得到B、A、E的顺序。
小叶检查前两条原文,确认A只是说明会公告,B才给出撤销条件。最终取回B的完整条款及其出处、版本,不把“可以撤销”单独截出来。交给回答模型的依据应包含操作入口、至少提前两小时的条件,以及不足两小时联系值班台的安排。
回答于是可以说明:在本例设定的现行规则下,至少提前两小时,可由预约者在“我的预约”中撤销;不足两小时,应联系值班台确认。由于同学还没提供预约开始时间,本次不能判断这份预约是否满足自行撤销条件,更不能宣称预约已经取消。查到规则、判断个案适用、执行实际操作,仍是相接的不同步骤。
向量匹配在其中完成了有价值的一段工作:把大范围资料变成值得进一步阅读的候选。要让这段工作成立,表示需要保留任务相关的差异,几何计算需要与模型及数据组织一致,搜索需要在正确范围内进行,结果还要接受与任务相符的评价。
以后看到“已经接入向量库”“相似度非常高”“找到了前十条”时,我们就有办法把这些话拆成具体问题:资料怎样表示,比较的是谁,哪些条件已经过滤,真正需要的片段有没有进入候选,最后引用是否仍保留原文条件。线性代数在这里提供的不是一个保证正确的按钮,而是理解和检查匹配过程的共同语言。
十二、练习与参考分析
练习一:只归一化查询,能否得到余弦排序
查询q=(1,0),候选a=(3,4),b=(0.8,0.6)。比较原内积与余弦的排序。若把q改成(10,0),原内积排序是否改变?只把查询归一化,能否消除候选长度带来的影响?
参考分析: a的长度是5,b的长度是1。原内积分别为3、0.8,偏向a;余弦分别为0.6、0.8,偏向b。把查询放大十倍,原内积变成30、8,排序保持,因为每个分数都乘同一个正数。
只归一化查询不能消除a和b长度不同的影响。若希望用单位化内积实现余弦,应把两边各自的长度处理清楚。若只是针对固定查询做排序,把全部资料单位化而查询保留同一个非零长度,也会得到余弦的同序结果,但分数还乘着查询长度,不能照搬余弦数值门槛。这里需要区分排序与分值。
练习二:先取两条再过滤,为什么可能一条也没有
某次全库余弦顺序为C=0.99、D=0.98、B=0.93、A=0.90、E=0.50。C已过期,D属于另一校区,B、A、E均适用。任务要返回适用范围内的前两条。先取全库前两条再过滤能完成吗?把全库数量扩大到三条又怎样?
参考分析: 取前两条会拿到C、D,过滤后为空;取前三条仅能留下B,仍不足两条。真正的适用范围内前两条是B、A。不是因为库里没有足够资料,而是截断发生在范围条件之前。
本例取到第四条再过滤可以得到B、A,但这不证明任何数据库固定多取两条都够。无效结果可能占据更多靠前位置。应使用能落实过滤范围的搜索,或者明确继续取回的机制;若适用资料本来不足两条,也应如实返回数量,而不是用不适用结果补齐。
练习三:高相似片段能否独立作为规则
现行原文是:“预约者至少提前两小时,可在‘我的预约’中撤销;不足两小时,应联系值班台确认。”检索命中片段只保留“可在‘我的预约’中撤销”,相似度为0.98。小叶准备直接把这一句作为回答依据。问题是什么,应优先改变哪一步?
参考分析: 命中片段缺少决定自行撤销是否适用的时间条件,也缺少另一个时间范围的处理。0.98衡量当前表示的接近程度,不能恢复原文已被切掉的内容。优先检查分块及命中后的上下文取回,取得完整条款后再回答。
可以保留集中片段作为搜索入口,同时按原文位置补回父段或相邻条件。补回的内容应来自该版本原文,不能让回答模型自行编造。还应保留校区、学期与来源,避免取得完整文字以后又使用了失效版本。这里改善的是提供依据的完整性,不是继续抬高一个相似度门槛。
练习四:同一份排序,两个分母怎样影响判断
一个完整核对的小库有八条记录A到H,其中B、F、H对当前问题相关。系统排序开头为A、B、D、F、H。计算P@2、R@2、P@4、R@4和P@5、R@5。第一条相关结果的倒数排名是多少?若只看P@2和P@4相同,能否说查找范围扩大没有作用?
参考分析: 前两条找回一条相关结果,故P@2=1/2、R@2=1/3;前四条找回两条,P@4=1/2、R@4=2/3;前五条找齐三条,P@5=3/5、R@5=1。第一条相关结果B排第二,倒数排名为1/2。
扩大到四条,相关比例没有提高,但找到的相关记录增加了一条。若任务需要资料完整,新增的F可能重要;若用户只肯读第一条,前四条的覆盖变化又没有解决第一名无关的问题。不能由一个指标没变就否定另一种作用,也不能不看需求就把所有增加都当收益。
练习五:近似结果更接近精确结果,就一定更有用吗
固定向量及余弦下,精确前三条是A、B、C,近似搜索返回B、D、E。在已完整核对的这份小库中,只有D、E真正能够回答当前问题。近似结果对精确前三条的重现比例是多少?两种结果对实际相关资料的召回率各是多少?应怎样解释这种差异?
参考分析: 两个前三集合只共有B,所以精确近邻的重现比例为1/3。实际相关资料共D、E两条;精确前三条一条也没有,相关性召回率为0,近似结果却找回两条,相关性召回率为1。
这说明两项评价使用的参照不同:一项参照固定分数下的精确名次,另一项参照人对问题所需资料的判断。不能据此说近似搜索越不准确越好;本例恰好暴露了原表示或打分的任务适配问题。也不能因为精确搜索忠实执行了计算,就认定它已经忠实满足用户需要。应分别检查搜索近似误差和表示质量。
练习六:两两相似,能否把一串资料直接当重复项
三支单位向量分别为u=(1,0),v=(1/2,√3/2),w=(−1/2,√3/2)。以余弦至少0.49为相似条件,判断三对关系。若程序将“与已入组记录相似”的新记录继续放进同一组,最后会怎样?这是否证明u与w相似?
参考分析: u与v的余弦为1/2,v与w为−1/4+3/4=1/2,u与w为−1/2。前两对满足门槛,首尾不满足。若先由u收入v,再因v收入w,三条仍会进入同一组。
程序完成的是按连接关系扩展分组,并没有验证组内每一对都满足门槛。若任务要求每两条都近似,便需要另一种组内条件;若任务只是找互相连接的主题群,这种扩展又可能符合目的。用于去重时尤其不能把同主题、同一事项的新旧版本都当成可删除副本,应保留改变操作结论的差异。