
向量嵌入驱动着现代搜索和检索增强生成 (RAG) 应用。嵌入式向量捕获数据对象(例如文本)的语义含义,并将其表示为数字数组。在当今的生成式人工智能应用中,这些向量嵌入通常由所谓的嵌入模型生成。

作为向量数据库,Weaviate 存储向量嵌入并基于向量搜索检索数据对象,因此与各种模型提供商及其广泛的嵌入模型集成。
但是,您如何选择适合您的搜索或 RAG 应用的正确嵌入模型?正如您将在本文中了解的那样,这取决于您的用例和具体要求。
步骤 1:确定您的用例
通用模型是否足以满足您的需求,或者您是否有特定需求,例如模态(例如,仅文本或多模态)、主题领域(例如,编码、法律、医学、多语言等)和部署模式?在大多数情况下,从您所需模态的通用模型开始将是一个合理的基线。
步骤 2:选择基线模型
大规模文本嵌入基准 (MTEB) 排行榜是获取当前范围广泛的专有和开源文本嵌入模型概览的好起点。对于每个嵌入模型,MTEB 列出了各种指标,例如模型大小、内存使用量、嵌入维度、最大令牌数以及检索、摘要等任务的得分。
以下是一些选择最适合您应用的模型的注意事项
- 任务:在 MTEB 排行榜的顶部,您会看到各种选项卡。首先,您需要确定您想要一个通才,或者是否可以找到与您的特定用例匹配的任务(分类、聚类、检索、摘要等)。例如,如果您正在构建 RAG 应用,您可能需要更详细地查看“检索”任务。如果您有更具体的需求,例如特定语言(例如,英语、中文、法语、波兰语)或领域(例如,法律),您也可能需要完善您的选择。
- 得分:这将显示模型在特定基准数据集或多个基准数据集上的表现如何。根据任务的不同,使用不同的评估指标。通常,这些指标的值介于 0 和 1 之间,较高的值表示更好的性能。
- 模型大小和内存使用量:这些可以帮助您了解运行模型所需的计算资源。虽然检索性能随着模型大小的增加而提高,但重要的是要注意,模型大小也会直接影响延迟。此外,值得注意的是,较大的模型也可能过拟合,从而在生产环境中表现不佳。因此,您希望为生产设置找到良好的延迟-性能权衡。理想情况下,从一个小型、轻量级模型开始,以便能够构建一个您可以快速迭代的基线。一旦您的管道正常工作,您可以稍后用一个更大、更强大的模型替换它。
- 嵌入维度:这是嵌入向量的长度。虽然较大的嵌入维度可以捕获数据中更细微的细节和关系,但它们不一定总是更好。您真的需要 2048 个维度来与 PDF 聊天吗?可能不需要。另一方面,较小的嵌入维度可以实现更快的推理,并且更节省存储空间和内存。因此,您希望在捕获数据复杂性和运营效率之间找到一个好的平衡。
- 最大令牌数:这是可以转换为单个嵌入的最大令牌数。对于常见的 RAG 应用,嵌入的良好块大小通常大约是一个段落的文本或更少。在这种情况下,最大令牌数为 512 的模型应该足够了。但是,在某些情况下,您需要嵌入更长的源文本,这需要具有更大上下文窗口的模型。

步骤 3:在您的用例上评估模型
虽然 MTEB 排行榜是一个很好的起点,但您应该谨慎并怀疑地对待其结果。请记住,这些结果是自行报告的。也有可能某些模型会产生虚高的性能得分,因为它们可能将 MTEB 数据集包含在训练数据中,因为它们是公开可用的。最后,模型基准测试的数据集可能不能准确代表您正在处理的数据。因此,我们建议您在自己的数据集上评估嵌入模型,如下面所示。您可以在我们的recipes GitHub 仓库中找到相关代码。
准备数据集
为此,您可以生成一个小型、手工标记的数据集,其中包含 50 到 100 个数据对象,并查看您可以实现什么样的性能。我们将创建一个包含八种不同糕点的最小数据集,以遵循Zain 和 JP 的讨论以及我们之前的关于评估指标的博客文章中使用的示例。您可以在相关的 GitHub 仓库中找到 .csv 文件。
| pastry_id | pastry_name | pastry_description |
|---|---|---|
| 1 | Bagel | 经典圆形面包,内部有嚼劲,外皮金黄,非常适合涂抹奶油奶酪、烟熏三文鱼或您最喜欢的涂抹酱。 |
| 2 | Roll | 柔软蓬松,这些小圆面包是任何餐点的多功能伴侣。新鲜出炉时享用,或切片做成三明治,里面填满您选择的肉类、奶酪和蔬菜。 |
| 3 | Donut | 尽情享受这些甜美、油炸的美味。无论是糖霜、粉末还是填充着颓废的奶油和水果果酱,每一口都是美味和怀旧的爆发。 |
| 4 | Muffin | 湿润嫩滑,这些玛芬饼充满风味。无论您喜欢经典的蓝莓、放纵的巧克力片还是丰盛的麸皮,总有一款玛芬饼可以满足您的渴望。 |
| 5 | Croissant | 黄油分层酥皮完美折叠,创造出精致而令人难以抗拒的美味。您可以纯粹享用,填充咸味馅料,或与您最喜欢的咖啡搭配。 |
| 6 | Scone | 酥脆但嫩滑,这些司康饼是舒适的缩影。您可以纯粹享用,或点缀着水果、坚果或巧克力片,并配上一块凝脂奶油和果酱。 |
| 7 | Pretzel | 外脆内软,这些椒盐卷饼是喜欢咸味零食的梦想。您可以以传统形状扭曲享用,或蘸上甜味或咸味配料,以获得令人愉悦的扭转。 |
| 8 | Sandwich | 新鲜出炉的面包是这些丰盛三明治的基础。堆上肉类、奶酪、脆皮蔬菜和美味涂抹酱,即可享用一份在旅途中令人满意的餐点。 |
创建嵌入
现在,让我们生成并存储相应的向量嵌入到我们的 Weaviate 向量数据库中。为此,您将首先连接到嵌入模式中的 Weaviate 客户端以简化操作(但您可以在本地实例化 Weaviate 客户端或使用我们的托管云服务)。
import weaviate
import os
# Connect to Weaviate client in embedded mode for simplicity
client = weaviate.connect_to_embedded(
headers = {
"X-OpenAI-Api-Key": os.environ["OPENAI_API_KEY"]
}
)
然后,您将配置一个名为 "Pastries" 的数据集合,并配置属性和向量化器。本示例使用 OpenAI 的 text-embedding-3-small 嵌入模型在导入和查询时自动向量化数据。请注意,我们稍后将重复此步骤,使用 text-embedding-3-large 来比较这两个模型。为此,您可能需要查看如何删除集合。
import weaviate.classes as wvc
from weaviate.classes.config import Property, DataType
# Create data collection
pastries = client.collections.create(
name="Pastries",
vectorizer_config=wvc.config.Configure.Vectorizer.text2vec_openai(model='text-embedding-3-small'),
properties=[
Property(name="pastry_name", data_type=DataType.TEXT),
Property(name="pastry_description", data_type=DataType.TEXT),
]
)
最后,您可以导入您的数据
# Import data objects
pastry_objects = list()
for _, row in df.iterrows():
properties = {
"pastry_name": row.pastry_name,
"pastry_description": row.pastry_description
}
pastry_objects.append(properties)
pastries.data.insert_many(pastry_objects)
检索
现在,您可以运行一些查询
from weaviate.classes.query import MetadataQuery
response = pastries.query.near_text(
query="Sweet pastry",
limit=4,
return_metadata=MetadataQuery(distance=True)
)
评估性能
本节比较了两个 OpenAI 嵌入模型,text-embedding-3-small 和 text-embedding-3-large,用于三个示例查询。请注意,每个查询的期望输出是主观的。但这正是重点:您必须决定您希望您的用例获得什么结果。
有各种评估指标可用,例如精确率、召回率、MRR、MAP 和 NDCG。在本节中,我们将使用精确率和召回率作为评估指标。
查询 1:“甜点”
相关项目:甜甜圈、玛芬、司康饼(请注意,此列表是主观的,因为我们已经决定了哪些内容与此查询相关)
结果
| Rank | text-embedding-3-small | text-embedding-3-large |
|---|---|---|
| 1 | ✅甜甜圈 | ❌羊角面包 |
| 2 | ❌羊角面包 | ✅甜甜圈 |
| 3 | ❌小圆面包 | ✅司康饼 |
| 4 | ❌贝果 | ❌三明治 |
| 精确率 | 0.25 | 0.5 |
| 召回率 | 0.33 | 0.67 |
查询 2:“适合午餐”
相关项目:三明治、贝果、小圆面包、椒盐卷饼(请注意,此列表是主观的,因为我们已经决定了哪些内容与此查询相关)
结果
| Rank | text-embedding-3-small | text-embedding-3-large |
|---|---|---|
| 1 | ✅三明治 | ✅三明治 |
| 2 | ✅小圆面包 | ✅小圆面包 |
| 3 | ✅贝果 | ✅贝果 |
| 4 | ❌司康饼 | ❌羊角面包 |
| 精确率 | 0.75 | 0.75 |
| 召回率 | 0.75 | 0.75 |
查询 3:“与果酱搭配良好”
相关项目:贝果、羊角面包、小圆面包(请注意,此列表是主观的,因为我们已经决定了哪些内容与此查询相关)
结果
| Rank | text-embedding-3-small | text-embedding-3-large |
|---|---|---|
| 1 | ❌三明治 | ❌司康饼 |
| 2 | ✅贝果 | ✅贝果 |
| 3 | ❌司康饼 | ❌甜甜圈 |
| 4 | ✅小圆面包 | ❌三明治 |
| 精确率 | 0.5 | 0.25 |
| 召回率 | 0.67 | 0.33 |
在三个示例查询中,text-embedding-3-small 和 text-embedding-3-large 的平均精确率均为 0.5,平均召回率均为 0.58,尽管它们为查询返回了不同的结果。如您所见,您需要增加数据集中数据对象的数量和查询的数量才能评估嵌入模型。但是,这个小示例应该为您提供一个良好的起点,以构建您自己的评估管道。
步骤 4:迭代
在您使用小型基线模型为您的用例构建了初始管道后,您可以尝试几种不同的嵌入模型,看看是否可以优于您的基线选择。
可选步骤:微调
微调嵌入模型只是一个可选步骤。理想情况下,您可以找到一个合适的现成模型,而微调可能仅在最后一点性能提升时才需要。
总结
本文灵感来源于最近 Zain 和 JP 之间的讨论。它讨论了您可以采取的步骤,以选择适合您的搜索或生成式 AI 应用程序的正确嵌入模型。您可以在 YouTube 上收听完整的讨论,并在我们的 recipes GitHub 仓库中找到相关代码。
准备开始构建了吗?
请查看 快速入门教程,或使用 Weaviate Cloud (WCD) 的免费试用版构建令人惊叹的应用程序。