在 Weaviate 中使用 OpenAI Q&A 模块进行问答
本 Notebook 适用于以下场景:
- 您的数据未进行向量化
- 您希望基于 OpenAI completions 端点对数据运行问答(了解更多)。
- 您希望使用 Weaviate 和 OpenAI 模块(text2vec-openai)为您生成向量嵌入。
本 Notebook 将引导您完成设置 Weaviate 实例、连接到它(使用 OpenAI API 密钥)、配置数据模式、导入数据(这将自动为您的数据生成向量嵌入)以及运行问答的简单流程。
什么是 Weaviate
Weaviate 是一个开源向量搜索引擎,它将数据对象与其向量一起存储。这允许将向量搜索与结构化过滤相结合。
Weaviate 使用 KNN 算法创建向量优化索引,从而使您的查询运行速度极快。在此处了解更多信息:here。
Weaviate 让您可以使用您喜欢的 ML 模型,并无缝扩展到数十亿个数据对象。
部署选项
无论您的场景或生产设置如何,Weaviate 都有适合您的选项。您可以在以下设置中部署 Weaviate:
- 自我托管 – 您可以使用 docker 在本地部署 Weaviate,或在任何您想要的服务器上部署。
- SaaS – 您可以使用 Weaviate Cloud Service (WCS) 来托管您的 Weaviate 实例。
- 混合 SaaS – 您可以在自己的私有云服务中部署 Weaviate
编程语言
Weaviate 提供四种 客户端库,允许您从应用程序与 Weaviate 通信:
此外,Weaviate 还提供了一个 REST 层。基本上,您可以使用任何支持 REST 请求的语言来调用 Weaviate。
演示流程
演示流程如下:
- 先决条件设置:创建 Weaviate 实例并安装所需的库
- 连接:连接到您的 Weaviate 实例
- 模式配置:配置您数据的数据模式
- 注意:在这里我们可以定义要使用的 OpenAI 嵌入模型
- 注意:在这里我们可以配置要索引的属性
- 导入数据:加载演示数据集并将其导入 Weaviate
- 注意:导入过程将自动索引您的数据 - 基于模式中的配置
- 注意:您无需显式向量化数据,Weaviate 将与 OpenAI 通信为您完成
- 运行查询:查询
- 注意:您无需显式向量化查询,Weaviate 将与 OpenAI 通信为您完成
- 注意:
qna-openai
模块会自动与 OpenAI completions 端点通信
运行完此 Notebook 后,您应该对如何设置向量数据库以及如何使用嵌入进行各种酷炫操作有一个基本的了解。
Weaviate 中的 OpenAI 模块
所有 Weaviate 实例都配备了 text2vec-openai 和 qna-openai 模块。
第一个模块负责在导入(或任何 CRUD 操作)和运行搜索查询时处理向量化。第二个模块与 OpenAI completions 端点通信。
无需手动向量化数据
这对您来说是个好消息。使用 text2vec-openai,您无需手动向量化数据,因为 Weaviate 会在必要时为您调用 OpenAI。
您需要做的就是:
- 在连接到 Weaviate 客户端时提供您的 OpenAI API 密钥
- 在模式中定义要使用的 OpenAI 向量化器
先决条件
在开始此项目之前,我们需要设置以下内容:
- 创建一个
Weaviate
实例 - 安装库
weaviate-client
datasets
apache-beam
- 获取您的 OpenAI API 密钥
===========================================================
创建 Weaviate 实例
要创建 Weaviate 实例,我们有两种选择:
- (推荐路径)Weaviate Cloud Service – 在云中托管您的 Weaviate 实例。免费沙盒应该足以满足此食谱的需求。
- 使用 Docker 在本地安装和运行 Weaviate。
选项 1 – WCS 安装步骤
使用 Weaviate Cloud Service (WCS) 创建免费的 Weaviate 集群。
- 创建一个免费帐户和/或登录到 WCS
- 创建一个
Weaviate Cluster
并进行以下设置:- 沙盒:
Sandbox Free
- Weaviate 版本:使用默认值(最新)
- OIDC 身份验证:
Disabled
- 沙盒:
- 您的实例应该在一两分钟内准备就绪
- 记下
Cluster Id
。该链接将带您进入集群的完整路径(稍后连接它时需要)。它应该类似于:https://your-project-name.weaviate.network
选项 2 – 使用 Docker 的本地 Weaviate 实例
使用 Docker 在本地安装和运行 Weaviate。
- 下载 ./docker-compose.yml 文件
- 然后打开您的终端,导航到您的 docker-compose.yml 文件所在的位置,然后使用以下命令启动 docker:
docker-compose up -d
- 一旦准备就绪,您的实例应该可以在 http://localhost:8080 上访问
注意。要关闭您的 docker 实例,您可以调用:docker-compose down
了解更多
要了解有关将 Weaviate 与 Docker 结合使用的更多信息,请参阅 安装文档。
===========================================================
安装所需的库
在运行此项目之前,请确保已安装以下库:
Weaviate Python 客户端
Weaviate Python 客户端允许您从 Python 项目与 Weaviate 实例进行通信。
datasets & apache-beam
要加载示例数据,您需要 datasets
库及其依赖项 apache-beam
。
# 安装 Weaviate Python 客户端
!pip install weaviate-client>3.11.0
# 安装 datasets 和 apache-beam 以加载示例数据集
!pip install datasets apache-beam
===========================================================
准备您的 OpenAI API 密钥
OpenAI API 密钥
用于在导入时对数据进行向量化,以及用于查询。
如果您没有 OpenAI API 密钥,可以从 https://beta.openai.com/account/api-keys 获取。
获取密钥后,请将其添加到您的环境变量中,名为 OPENAI_API_KEY
。
# 导出 OpenAI API 密钥
!export OPENAI_API_KEY="your key"
# 测试您的 OpenAI API 密钥是否已正确设置为环境变量
# 注意。如果您在本地运行此 Notebook,则需要重新加载您的终端和 Notebook,环境变量才能生效。
import os
# 注意。或者,您可以像这样设置一个临时环境变量:
# os.environ['OPENAI_API_KEY'] = 'your-key-goes-here'
if os.getenv("OPENAI_API_KEY") is not None:
print ("OPENAI_API_KEY is ready")
else:
print ("OPENAI_API_KEY environment variable not found")
连接到您的 Weaviate 实例
在本节中,我们将:
- 测试环境变量
OPENAI_API_KEY
– 请确保您已完成 #Prepare-your-OpenAI-API-key 步骤 - 使用您的
OpenAI API Key
连接到您的 Weaviate - 并测试客户端连接
客户端
完成此步骤后,client
对象将用于执行所有与 Weaviate 相关的操作。
import weaviate
from datasets import load_dataset
import os
# 连接到您的 Weaviate 实例
client = weaviate.Client(
url="https://your-wcs-instance-name.weaviate.network/",
# url="http://localhost:8080/",
auth_client_secret=weaviate.auth.AuthApiKey(api_key="<YOUR-WEAVIATE-API-KEY>"), # 如果您没有为 Weaviate 实例使用身份验证(例如,本地部署的实例),请注释掉此行
additional_headers={
"X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
}
)
# 检查您的实例是否在线并准备就绪
# 这应该返回 `True`
client.is_ready()
模式
在本节中,我们将:
- 配置您数据的数据模式
- 选择 OpenAI 模块
这是第二步也是最后一步,需要 OpenAI 的特定配置。 完成此步骤后,其余说明将仅涉及 Weaviate,因为 OpenAI 的任务将自动处理。
什么是模式
在 Weaviate 中,您创建 模式 来捕获您将搜索的每个实体。
模式是您告诉 Weaviate 的方式:
- 应使用哪个 OpenAI 嵌入模型来向量化数据
- 您的数据由什么组成(属性名称和类型)
- 哪些属性应被向量化和索引
在此食谱中,我们将使用一个 Articles
数据集,其中包含:
title
content
url
我们希望向量化 title
和 content
,但不向量化 url
。
为了向量化和查询数据,我们将使用 text-embedding-3-small
。对于问答,我们将使用 gpt-3.5-turbo-instruct
。
# 清除模式,以便我们可以重新创建它
client.schema.delete_all()
client.schema.get()
# 定义模式对象,对 `title` 和 `content` 使用 `text-embedding-3-small`,但跳过 `url`
article_schema = {
"class": "Article",
"description": "A collection of articles",
"vectorizer": "text2vec-openai",
"moduleConfig": {
"text2vec-openai": {
"model": "ada",
"modelVersion": "002",
"type": "text"
},
"qna-openai": {
"model": "gpt-3.5-turbo-instruct",
"maxTokens": 16,
"temperature": 0.0,
"topP": 1,
"frequencyPenalty": 0.0,
"presencePenalty": 0.0
}
},
"properties": [{
"name": "title",
"description": "Title of the article",
"dataType": ["string"]
},
{
"name": "content",
"description": "Contents of the article",
"dataType": ["text"]
},
{
"name": "url",
"description": "URL to the article",
"dataType": ["string"],
"moduleConfig": { "text2vec-openai": { "skip": True } }
}]
}
# 添加 Article 模式
client.schema.create_class(article_schema)
# 获取模式以确保其正常工作
client.schema.get()
导入数据
在本节中,我们将:
- 加载 Simple Wikipedia 数据集
- 配置 Weaviate Batch 导入(以提高导入效率)
- 将数据导入 Weaviate
注意:
如前所述。我们无需手动向量化数据。
text2vec-openai 模块将负责处理此问题。
### 步骤 1 - 加载数据集
from datasets import load_dataset
from typing import List, Iterator
# 我们将使用 datasets 库来获取 Simple Wikipedia 数据集进行嵌入
dataset = list(load_dataset("wikipedia", "20220301.simple")["train"])
# 为了测试,演示目的限制为 2.5k 篇文章
dataset = dataset[:2_500]
# 为了更大的演示目的,限制为 25k 篇文章
# dataset = dataset[:25_000]
# 对于免费的 OpenAI 账户,您可以使用 50 个对象
# dataset = dataset[:50]
### 步骤 2 - 配置 Weaviate Batch,包括
# - 起始批次大小为 100
# - 根据性能动态增加/减少
# - 添加超时重试以防万一出现问题
client.batch.configure(
batch_size=10,
dynamic=True,
timeout_retries=3,
# callback=None,
)
### 步骤 3 - 导入数据
print("正在导入文章")
counter=0
with client.batch as batch:
for article in dataset:
if (counter %10 == 0):
print(f"正在导入 {counter} / {len(dataset)} ")
properties = {
"title": article["title"],
"content": article["text"],
"url": article["url"]
}
batch.add_data_object(properties, "Article")
counter = counter+1
print("导入文章完成")
# 测试所有数据是否已加载 – 获取对象计数
result = (
client.query.aggregate("Article")
.with_fields("meta { count }")
.do()
)
print("对象计数: ", result["data"]["Aggregate"]["Article"], "\n")
# 通过检查一个对象来测试一篇已成功处理的文章
test_article = (
client.query
.get("Article", ["title", "url", "content"])
.with_limit(1)
.do()
)["data"]["Get"]["Article"][0]
print(test_article['title'])
print(test_article['url'])
print(test_article['content'])
对数据进行问答
如上所述,我们将向新索引发送一些查询,并根据与现有向量的接近程度获得结果
def qna(query, collection_name):
properties = [
"title", "content", "url",
"_additional { answer { hasAnswer property result startPosition endPosition } distance }"
]
ask = {
"question": query,
"properties": ["content"]
}
result = (
client.query
.get(collection_name, properties)
.with_ask(ask)
.with_limit(1)
.do()
)
# 检查错误
if ("errors" in result):
print ("\033[91m您可能已经用完了当前分钟的 OpenAI API 调用次数 – 限制为每分钟 60 次。")
raise Exception(result["errors"][0]['message'])
return result["data"]["Get"][collection_name]
query_result = qna("Did Alanis Morissette win a Grammy?", "Article")
for i, article in enumerate(query_result):
print(f"{i+1}. { article['_additional']['answer']['result']} (Distance: {round(article['_additional']['distance'],3) })")
query_result = qna("What is the capital of China?", "Article")
for i, article in enumerate(query_result):
if article['_additional']['answer']['hasAnswer'] == False:
print('未找到答案')
else:
print(f"{i+1}. { article['_additional']['answer']['result']} (Distance: {round(article['_additional']['distance'],3) })")
感谢您的跟随,您现在已经具备了设置自己的向量数据库并使用嵌入来完成各种酷炫操作的知识——尽情享受吧!对于更复杂的用例,请继续完成此仓库中的其他食谱示例。