词、token、上下文表示和句向量不是同一个层次的对象。检索前先确认“向量到底怎样生成”,往往比先选向量数据库更重要。

把四个对象分开

对象 含义 需要确认
token ID 词表中的离散编号 tokenizer 与词表版本
输入嵌入 根据 ID 查得的向量 属于哪套模型参数
上下文表示 随当前文本上下文计算的隐藏状态 使用哪一层、怎样处理位置和掩码
句子或片段向量 用于整体文本比较的表示 训练目标、池化、归一化和查询指令

有上下文的表示再做 Mean Pooling,不等同于对一组固定词向量求平均。不能据“均值与顺序无关”就推断所有采用 Mean Pooling 的句向量模型都丢失语序:池化之前的表示可能已经编码了顺序和上下文。

相似度不是自动校准的置信度

Sentence Transformers 支持余弦、点积等相似度;对非零、已做 L2 归一化的向量,点积等于余弦。官方相似度说明

下面只是手工向量的算术实验,不会生成真实文本嵌入,也不证明任何句子的语义关系。

import numpy as np

def unit_rows(matrix):
    matrix = np.asarray(matrix, dtype=float)
    norms = np.linalg.norm(matrix, axis=1, keepdims=True)
    if (norms == 0).any():
        raise ValueError("zero vectors have no cosine direction")
    return matrix / norms

query = np.array([[1., 1.]])
docs = np.array([[1., 1.], [10., 0.], [-1., -1.]])
dot_scores = (query @ docs.T)[0]
cos_scores = (unit_rows(query) @ unit_rows(docs).T)[0]
assert int(dot_scores.argmax()) == 1
assert int(cos_scores.argmax()) == 0
assert np.isclose(cos_scores[2], -1.0)
print("dot-product and cosine rankings can differ")

向量维数相同只说明数组可以相乘,不说明它们处于同一个语义空间。不同模型、版本、查询前缀或预处理方式得到的向量,不应未经验证就混入一个索引。

给索引保存一份生成约定

我会与每批向量一起记录:模型与 tokenizer 版本、查询和文档的提示格式、最大长度及截断策略、片段划分方式、池化与归一化、距离函数、原文标识与访问权限。

模型或切分规则改变后,通常需要重新向量化,并通过固定的相关性标注集检查召回。高余弦不代表“90%正确”,否定、数值、实体差异和专业术语尤其需要专项测试。检索到相似段落也不等于段落支持最终回答,后者还需要证据核验。

来源与核验边界

本篇结合疏锦行大模型专题《词向量技术演进史》讲义,重组为检索表示的接口约定,并避免“子词彻底消灭所有未知输入”“均值池化必然无用”等绝对表述。向量算术示例已运行;没有训练或评测真实嵌入模型。视频尚未逐节核验,原课件不公开。