跳到主要内容

在Weaviate中使用OpenAI Q&A模块进行问答

nbviewer

本笔记本适用于以下场景: * 您的数据未经过向量化处理 * 您希望在基于OpenAI completions端点的数据上运行Q&A(了解更多) * 您希望使用Weaviate与OpenAI模块(text2vec-openai)为您生成向量嵌入。

本笔记本将带您完成一个简单的流程,设置Weaviate实例,连接到它(使用OpenAI API密钥),配置数据架构,导入数据(这将自动生成您数据的向量嵌入),并运行问答。

什么是Weaviate

Weaviate是一个开源的向量搜索引擎,它将数据对象与它们的向量一起存储。这允许将向量搜索与结构化过滤相结合。

Weaviate使用KNN算法创建一个向量优化的索引,这使得您的查询运行非常快速。了解更多信息,请点击这里

Weaviate让您可以使用您喜爱的ML模型,并且可以无缝扩展到数十亿个数据对象。

部署选项

无论您的场景或生产设置如何,Weaviate都有适合您的选项。您可以在以下设置中部署Weaviate: * 自托管 - 您可以在本地使用docker部署Weaviate,或者在任何您想要的服务器上部署。 * SaaS - 您可以使用Weaviate Cloud Service (WCS)来托管您的Weaviate实例。 * 混合SaaS - 您可以在您自己的私有云服务中部署Weaviate。

编程语言

Weaviate提供四种客户端库,允许您从您的应用程序进行通信: * Python * JavaScript * Java * Go

此外,Weaviate还有一个REST层。基本上,您可以从支持REST请求的任何语言调用Weaviate。

演示流程

演示流程如下: - 先决条件设置:创建一个Weaviate实例并安装所需的库 - 连接:连接到您的Weaviate实例 - 架构配置:配置数据的架构 - 注意:在这里我们可以定义要使用哪个OpenAI嵌入模型 - 注意:在这里我们可以配置要索引哪些属性 - 导入数据:加载演示数据集并将其导入Weaviate - 注意:导入过程将根据架构中的配置自动索引您的数据 - 注意:您不需要显式地对数据进行向量化,Weaviate将与OpenAI通信以代表您执行此操作 - 运行查询:查询 - 注意:您不需要显式地对查询进行向量化,Weaviate将与OpenAI通信以代表您执行此操作 - 注意qna-openai模块会自动与OpenAI的完成端点进行通信

完成本笔记后,您应该对如何设置和使用用于问答的向量数据库有一个基本的了解。

Weaviate中的OpenAI模块

所有Weaviate实例都配备有text2vec-openaiqna-openai模块。

第一个模块负责在导入(或任何CRUD操作)时处理向量化,并在运行搜索查询时处理向量化。第二个模块与OpenAI完成端点进行通信。

无需手动向量化数据

这对你来说是个好消息。使用text2vec-openai,您无需手动向量化数据,因为Weaviate会在必要时为您调用OpenAI。

您只需要: 1. 在连接到Weaviate客户端时提供您的OpenAI API密钥 2. 在架构中定义要使用的OpenAI向量化器

先决条件

在开始这个项目之前,我们需要设置以下内容:

  • 创建一个 Weaviate 实例
  • 安装库
    • weaviate-client
    • datasets
    • apache-beam
  • 获取您的OpenAI API密钥

=========================================================== ### 创建一个 Weaviate 实例

要创建一个 Weaviate 实例,我们有两个选项:

  1. (推荐路径)Weaviate 云服务 - 在云中托管您的 Weaviate 实例。免费的沙箱应该足够用于这个教程。
  2. 使用 Docker 在本地安装和运行 Weaviate。

选项 1 - WCS 安装步骤

使用Weaviate 云服务(WCS)创建一个免费的 Weaviate 集群。 1. 创建一个免费帐户并/或登录WCS 2. 使用以下设置创建一个 Weaviate 集群: * 沙箱:Sandbox Free * Weaviate 版本:使用默认值(最新版本) * OIDC 认证:Disabled 3. 您的实例应该在一两分钟内准备就绪 4. 记下 集群 ID。链接将带您到集群的完整路径(稍后您将需要连接到它)。应该类似于:https://your-project-name.weaviate.network

选项 2 - 使用 Docker 在本地安装 Weaviate 实例

使用 Docker 在本地安装和运行 Weaviate。 1. 下载 ./docker-compose.yml 文件 2. 然后打开您的终端,导航到 docker-compose.yml 文件所在的位置,并使用以下命令启动 Docker:docker-compose up -d 3. 一旦准备就绪,您的实例应该在 http://localhost:8080 上可用

注意:要关闭 Docker 实例,您可以运行:docker-compose down

了解更多

要了解更多关于使用 Docker 与 Weaviate 的信息,请参阅安装文档

=========================================================== ## 安装所需库

在运行此项目之前,请确保安装以下库:

Weaviate Python客户端

Weaviate Python客户端允许您从Python项目中与Weaviate实例进行通信。

datasets & apache-beam

要加载示例数据,您需要datasets库及其依赖项apache-beam

# 安装适用于 Python 的 Weaviate 客户端
!pip install weaviate-client>3.11.0

# 安装数据集和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密钥是否已正确设置为环境变量。
# 注意:如果您在本地运行此笔记本,您需要重新加载终端和笔记本,以使环境变量生效。
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实例

在本节中,我们将:

  1. 测试环境变量 OPENAI_API_KEY - 确保您已完成#准备您的OpenAI API密钥中的步骤
  2. 使用您的OpenAI API密钥连接到您的Weaviate
  3. 并测试客户端连接

客户端

完成这一步之后,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()

数据模式

在本节中,我们将: 1. 配置数据的模式 2. 选择 OpenAI 模块

这是第二步,也是最后一步,需要进行特定于 OpenAI 的配置。 在这一步之后,其余的说明将只涉及 Weaviate,因为 OpenAI 任务将被自动处理。

什么是模式

在 Weaviate 中,您创建 模式 来捕获您将要搜索的每个实体。

模式是您告诉 Weaviate 的方式: * 应该使用什么嵌入模型来对数据进行向量化 * 您的数据由什么组成(属性名称和类型) * 哪些属性应该被向量化和索引化

在本教程中,我们将使用一个包含以下内容的 Articles 数据集: * title * content * url

我们希望对 titlecontent 进行向量化,但不包括 url

为了对数据进行向量化和查询,我们将使用 text-embedding-3-small。对于问答,我们将使用 gpt-3.5-turbo-instruct

# 清理架构,以便我们能够重新创建它。
client.schema.delete_all()
client.schema.get()

# 定义Schema对象,对`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 } }
}]
}

# 添加文章模式
client.schema.create_class(article_schema)

# 获取架构以确保其正常工作
client.schema.get()

导入数据

在本节中,我们将: 1. 加载Simple Wikipedia数据集 2. 配置Weaviate批量导入(以使导入更有效) 3. 将数据导入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"])

# 为了测试,仅限于2500篇文章用于演示目的。
dataset = dataset[:2_500]

# 为了进行更大规模的演示,限制在25,000篇文章以内
# 数据集 = 数据集[:25_000]

# 对于免费的OpenAI账户,您可以使用50个对象。
# 数据集 = 数据集[:50]

# ##步骤2 - 配置Weaviate批处理功能
# - 初始批次大小为100
# - 根据性能动态增减
# - 如果出现问题,增加超时重试次数

client.batch.configure(
batch_size=10,
dynamic=True,
timeout_retries=3,
# 回调函数=None,
)

# ##步骤3 - 导入数据

print("Importing Articles")

counter=0

with client.batch as batch:
for article in dataset:
if (counter %10 == 0):
print(f"Import {counter} / {len(dataset)} ")

properties = {
"title": article["title"],
"content": article["text"],
"url": article["url"]
}

batch.add_data_object(properties, "Article")
counter = counter+1

print("Importing Articles complete")

# 测试所有数据是否已加载 – 获取对象数量
result = (
client.query.aggregate("Article")
.with_fields("meta { count }")
.do()
)
print("Object count: ", 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[91mYou probably have run out of OpenAI API calls for the current minute – the limit is set at 60 per minute.")
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('No answer found')
else:
print(f"{i+1}. { article['_additional']['answer']['result']} (Distance: {round(article['_additional']['distance'],3) })")

感谢您的跟进,现在您已经具备了设置自己的向量数据库并使用嵌入来做各种酷炫事情的能力 - 祝您玩得开心!对于更复杂的用例,请继续阅读本存储库中的其他示例。