这是我今天在维也纳 ICML 会议上被问到的一个问题。
在咖啡休息时间,一位 Jina 用户向我提出了一个源自 LLM 社区最近讨论的问题。他问我们的 embedding 模型是否能判断出 9.11 小于 9.9,而许多 LLM 在这个任务中会得出相反的结论。
"说实话,我不知道,"我回答道。当他详细解释这个能力对他的应用程序的重要性,并提出分词可能是问题的根源时,我点头表示同意 —— 我的脑海中已经开始涌现进行实验以找出答案的想法。
在这篇文章中,我想测试我们的 embedding 模型 jina-embeddings-v2-base-en(2023 年 10 月发布)和 Reranker 模型 jina-reranker-v2-multilingual(2024 年 6 月发布)是否能准确比较数字。为了将测试范围扩展到 9.11 和 9.9 的简单比较之外,我设计了一系列包含各种类型数字的实验:小整数、大数、浮点数、负数、货币、日期和时间。目标是评估我们的模型在处理不同数字格式时的效果。
tag实验设置
完整实现可以在下面的 Colab 中找到:

实验设计相当简单。例如,要检查 embedding 模型是否理解 [1, 100] 之间的数字,步骤如下:
- 构建文档:为
1到100的每个数字生成"字符串字面量"文档。 - 调用 Embedding API:使用 Embedding API 为每个文档获取 embedding。
- 计算余弦相似度:计算每两个文档之间的成对余弦相似度,创建相似度矩阵。
- 绘制散点图:使用散点图可视化结果。相似度矩阵中的每个元素 映射到一个点,其中:X 轴:;Y 轴: 的相似度值
如果增量 为零,即 ,则语义相似度应该最高。随着增量 的增加,相似度应该降低。理想情况下,相似度应该与增量值成线性比例。如果我们观察不到这种线性关系,那么模型很可能无法理解数字,并可能产生诸如 9.11 大于 9.9 这样的错误。
Reranker 模型遵循类似的程序。主要区别在于我们遍历构建的文档,将每个文档设置为 query,在前面添加提示 "what is the closest item to...",并将所有其他文档作为 documents 进行排序。Reranker API 返回的相关性分数直接用作语义相似度度量。核心实现如下所示。
def rerank_documents(documents):
reranker_url = "https://api.jina.ai/v1/rerank"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
# Initialize similarity matrix
similarity_matrix = np.zeros((len(documents), len(documents)))
for idx, d in enumerate(documents):
payload = {
"model": "jina-reranker-v2-base-multilingual",
"query": f"what is the closest item to {d}?",
"top_n": len(documents),
"documents": documents
}
...tag模型能否比较 [1, 2, 3, ..., 100] 之间的数字?
每个增量的散点图及其均值和方差。左:jina-embeddings-v2-base-en;右:jina-reranker-v2-multilingual。documents = [str(i) for i in range(1, 101)]
tag如何阅读这些图表
在继续更多实验之前,让我先解释如何正确阅读这些图表。首先,从上面两张图中我的观察是,embedding 模型表现良好,而 reranker 模型表现不太理想。那么,我们在看什么,为什么会这样?
X 轴表示当我们从文档集合中均匀采样 和 时,索引 的增量或 。这个增量范围是 。由于我们的文档集在构建时是有序的,即 越小, 和 在语义上越接近; 和 相距越远, 和 之间的相似度就越低。这就是为什么你会看到相似度(Y 轴表示)在 处达到峰值,然后向左右两侧线性下降。
理想情况下,这应该形成一个尖峰或"向上箭头"形状,就像 ^。但情况并非总是如此。如果你固定 X 轴上的一点,比如 ,沿着 Y 轴看,你会发现相似度值的范围从 0.80 到 0.95。这意味着,尽管增量都是 25,但 可能是 0.81,而 可能是 0.91。
青色趋势线显示了每个 X 值处的平均相似度及其标准差。另外,请注意相似度应该线性下降,因为我们的文档集是均匀间隔的,确保了相邻文档之间的等距间隔。
注意,embedding 图表总是对称的,并在 处具有最大 Y 值 1.0。这是因为对于 和 来说,余弦相似度是对称的,且 。
相反,reranker 图表总是不对称的,这是因为在 reranker 模型中查询和文档扮演不同的角色。最大值可能不是 1.0,因为 意味着我们使用 reranker 计算 "what is the closest item to 4" 与 "4" 之间的相关性分数。仔细想想,没有保证 会导致 Y 值最大。
tag模型能否比较 [-100, -99, -98, ..., -1] 之间的负数?
每个增量的散点图及其均值和方差。左:jina-embeddings-v2-base-en;右:jina-reranker-v2-multilingual。这里我们想测试模型是否能在负数空间中判断语义相似度。documents = [str(-i) for i in range(1, 101)]
tag模型能否比较更大区间 [1000, 2000, 3000, ..., 100000] 的数字?
在这里,我们想测试模型在比较间隔为 1000 的数字时是否能判断语义相似性。documents = [str(i*1000) for i in range(1, 101)]带有每个增量均值和方差的散点图。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag模型能否比较任意范围内的数字,例如 [376, 377, 378, ..., 476]?
在这里,我们想测试模型是否能在任意范围内比较数字的语义相似性,所以我们将数字移到某个随机范围documents = [str(i+375) for i in range(1, 101)]。带有每个增量均值和方差的散点图。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag模型能否比较大数字 [4294967296, 4294967297, 4294967298, ..., 4294967396]?
在这里,我们想测试模型在比较非常大的数字时是否能判断语义相似性。与上一个实验的思路类似,我们将范围进一步移至一个大数字。documents = [str(i+4294967296) for i in range(1, 101)]带有每个增量均值和方差的散点图。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag模型能否比较浮点数 [0.0001, 0.0002, 0.0003, ...,0.1]?(无固定位数)
在这里,我们想测试模型在比较浮点数时是否能判断语义相似性。documents = [str(i/1000) for i in range(1, 101)]带有每个增量均值和方差的散点图。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag模型能否比较货币数字 [2, 100]?
在这里,我们想测试模型在比较货币数字时是否能判断语义相似性。documents = ['$'+str(i) for i in range(1, 101)]带有每个增量均值和方差的散点图。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag模型能否比较日期 [2024-07-24, 2024-07-25, 2024-07-26, ..., 2024-10-31]?
在这里,我们想测试模型在比较 YYYY-MM-DD 格式的日期数字时是否能判断语义相似性。today = datetime.today(); documents = [(today + timedelta(days=i)).strftime('%Y-%m-%d') for i in range(100)]带有每个增量均值和方差的散点图。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag模型能否比较时间 [19:00:07, 19:00:08, 19:00:09,..., 20:39:07]?
在这里,我们想要测试模型在比较时间格式的数字时(即 hh:mm:ss)是否能识别语义相似性。now = datetime.now(); documents = [(now + timedelta(minutes=i)).strftime('%H:%M:%S') for i in range(100)]散点图显示了每个差值的平均值和方差。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag观察结果
以下是对上述图表的一些观察:
tag重排序模型
- 重排序模型在比较数字方面表现欠佳。即使在最简单的 [1, 100] 范围内的数字比较中,其表现也不理想。
- 需要注意的是,我们在使用重排序器时采用了特殊的查询提示构造方式,即
what is the closest item to x,这可能也会影响结果。
tag嵌入模型
- 嵌入模型在比较 [1, 100] 范围内的小整数或 [-100, 1] 范围内的负数时表现相对较好。但当移动这个范围到其他值、增加更多间隔或处理更大或更小的浮点数时,其性能会显著下降。
- 在某些固定间隔(通常是每 10 步)可以观察到规律性的峰值。这种行为可能与分词器如何处理字符串有关,可能将字符串分词为"10"或"1"和"0"。
tag日期和时间理解
- 有趣的是,嵌入模型似乎对日期和时间有很好的理解,在大多数情况下能正确比较它们。在日期图中,每 30/31 步出现峰值,对应于每月的天数。在时间图中,每 60 步出现峰值,对应于每小时的分钟数。
- 重排序模型在某种程度上也能捕捉到这种理解。
tag可视化与"零"的相似度

另一个可能更直观的实验是直接可视化任何数字与零(即原点)之间的相似度或相关性分数。通过将参考点固定为零的嵌入,我们想看看随着数字变大,语义相似度是否线性下降。对于重排序器,我们可以将查询固定为 "0" 或 "What is the closest number to number zero?",并对所有数字进行排序,看看它们的相关性分数是否随着数字增大而减小。结果如下所示:
在这里,我们将"原点嵌入"固定为"零"的嵌入,并检查任何数字与零之间的语义相似度是否与该数字的值成比例。具体来说,我们使用 documents = [str(i) for i in range(2048)]。图中显示了每个差值的散点图及其均值和方差。左图:jina-embeddings-v2-base-en;右图:jina-reranker-v2-multilingual。
tag结论
本文展示了我们当前的嵌入和重排序模型如何处理数字比较。尽管实验设置相对简单,但它揭示了当前模型的一些基本缺陷,并为我们下一代嵌入和重排序器的开发提供了宝贵的见解。
决定模型是否能准确比较数字的两个关键因素是:
首先,分词:如果词汇表只包含数字 0-9,那么 11 可能被分词为单独的 1 和 1,或作为单个标记 11。这种选择会影响模型对数值的理解。


不同的分词器会导致对 9.11 的不同解释。这可能影响下游的上下文学习。来源:HuggingFace 上的 The Tokenizer Playground
其次,训练数据:训练语料库显著影响模型的数值推理能力。例如,如果训练数据主要包含软件文档或常见语义版本控制的 GitHub 仓库,模型可能会认为 9.11 大于 9.9,因为 9.11 是 9.9 之后的次要版本。
密集检索模型(如嵌入和重排序器)的算术能力对于涉及 RAG 和高级检索推理的任务至关重要。强大的数值推理能力可以显著提高搜索质量,特别是在处理像 JSON 这样的结构化数据时。






