已经有一组文档向量时,可以先用 NearestNeighbors 做小规模精确检索,不必为运行检查搭建数据库。它返回的是矩阵行号和距离;把行号映射回自己保存的文档 ID,才是读者能使用的检索结果。本文只处理现成向量,不生成文本 embedding,也不把人工向量的相似度冒充真实语义效果。
以下代码在 Windows、Python 3.11、scikit-learn 1.7.2、NumPy 2.4.6 的本地环境运行核对。数据是教学用人工构造样例,不是业务测评;示例数字只用于检查代码路径。

先准备环境
在自己可写的目录打开终端。首次运行先创建虚拟环境;Windows 用下面的命令,macOS/Linux 把激活命令换成 source .venv/bin/activate。安装只需要在该环境里进行一次。
python -m venv .venv
.venv\Scripts\activate
python -m pip install scikit-learn==1.7.2 numpy==2.4.6
先核对向量与 ID 的契约
库向量应是“文档数 × 维度”的二维数组,查询也要是“查询数 × 同一维度”。库向量和查询向量必须处于可比较的同一向量空间,并遵守所用编码模型规定的文档/查询输入配置;长度相同不意味着向量可比较。文档 ID 和向量行必须同序,且 ID 不重复。
NearestNeighbors 官方文档说明 fit、kneighbors 和返回数组。下面明确使用 brute 与 cosine,适合检查小规模数据的精确结果,不宣称建立了近似索引或长期持久化数据库。
执行一次检索并返回文档 ID
保存代码为 search_vectors.py,运行 python search_vectors.py。用三个维度的手工向量做几何演示,便于直接核算结果。
import numpy as np
from sklearn.neighbors import NearestNeighbors
ids = np.array(['doc-A', 'doc-B', 'doc-C', 'doc-D'])
vectors = np.array([[1, 0, 0], [0.8, 0.6, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float64)
query = np.array([[1, 0, 0]], dtype=np.float64)
assert len(ids) == len(vectors) and len(set(ids)) == len(ids)
assert query.shape[1] == vectors.shape[1]
assert np.isfinite(vectors).all() and np.isfinite(query).all()
assert np.all(np.linalg.norm(vectors, axis=1) > 0)
assert np.all(np.linalg.norm(query, axis=1) > 0)
index = NearestNeighbors(metric='cosine', algorithm='brute')
index.fit(vectors)
distances, positions = index.kneighbors(query, n_neighbors=2)
for row in range(len(query)):
print('query:', row)
for distance, pos in zip(distances[row], positions[row]):
print(ids[pos], 'distance:', round(float(distance), 6),
'cosine similarity:', round(1-float(distance), 6))
assert ids[positions[0, 0]] == 'doc-A'
assert np.allclose(distances[0], [0, 0.2])
怎样验证距离方向没有写反
本地运行第一名为 doc-A,余弦距离 0.0,相似度 1.0;第二名为 doc-B,距离 0.2,相似度 0.8。距离越小越接近,不能把距离直接按从大到小排序。对于此处的余弦距离,相似度写为 1 减距离;余弦相似度还可能为负,不是始终处于 0 到 1 的概率。
脚本同时核对行数、维度、有限值和非零范数。零向量没有可用方向,遇到零向量应先定位生成失败或空文本,保留错误记录,而不是替换成一个随机向量继续检索。
接入实际文档时保存什么
为每行保存稳定文档 ID、对应正文或来源路径、向量模型版本和生成时间。查询处理必须与库向量采用同样约定。替换模型或维度后,需要重新生成和验证全库向量,不能把新旧结果混在一个矩阵里。
一次可先用三类查询核验:明确应命中的文档、措辞不同但意思相近的文档、库内没有答案的查询。检查返回 ID 对应的正文,不能只看分数。kneighbors 即便面对无关查询,也会返回最近的几个点,所以还需用自己任务的正反样本设定接受规则;本文没有提供可跨数据集通用的阈值。
边界与常见疑问
n_neighbors 不可大于已拟合样本数;批量查询的每一行应分别映射结果。距离相同的记录可能出现不同的并列顺序,不要把并列名次当成质量差异。如果查询本来就是库内文档,要依据 ID 排除自身,再取需要的推荐数;本题的外部查询没有这种处理需求。
brute 会直接比较查询与库向量,数据量增加时应实际测量内存和延迟。若任务需要大规模近似检索、磁盘保存、过滤或增量更新,应另选并验证对应索引或数据库。本文的完成结果是一份正确映射文档 ID 的小规模精确检索结果。
Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30839.html