使用 LangChain、Deep Lake 和 OpenAI 进行问答
本笔记本展示了如何使用 LangChain、Deep Lake 作为向量存储以及 OpenAI 嵌入来实现问答系统。我们将按以下步骤进行:
- 加载 Deep Lake 文本数据集
- 初始化 LangChain 的 Deep Lake 向量存储
- 将文本添加到向量存储
- 在数据库上运行查询
- 完成!
您还可以遵循其他教程,例如对任何类型的数据(PDF、json、csv、文本)进行问答:在 Deep Lake 中存储的 与任何数据聊天、代码理解 或 PDF 问答,或 推荐歌曲。
安装依赖
让我们安装以下包。
!pip install deeplake langchain openai tiktoken
身份验证
在此处提供您的 OpenAI API 密钥:
import getpass
import os
os.environ['OPENAI_API_KEY'] = getpass.getpass()
··········
加载 Deep Lake 文本数据集
在此示例中,我们将使用 cohere-wikipedia-22 数据集的 20000 个样本子集。
import deeplake
ds = deeplake.load("hub://activeloop/cohere-wikipedia-22-sample")
ds.summary()
\
由于您没有写入权限,因此以只读模式打开数据集。
-
此数据集可以通过 ds.visualize() 在 Jupyter Notebook 中可视化,或在 https://app.activeloop.ai/activeloop/cohere-wikipedia-22-sample 查看。
|
hub://activeloop/cohere-wikipedia-22-sample 加载成功。
Dataset(path='hub://activeloop/cohere-wikipedia-22-sample', read_only=True, tensors=['ids', 'metadata', 'text'])
tensor htype shape dtype compression
------- ------- ------- ------- -------
ids text (20000, 1) str None
metadata json (20000, 1) str None
text text (20000, 1) str None
让我们看几个样本:
ds[:3].text.data()["value"]
['24 小时制是一种计时方式,其中一天从午夜到午夜运行,分为 24 小时,编号从 0 到 23。它不使用上午或下午。此系统在美国和加拿大讲英语的地区也被称为军用时间,或在英国(现在很少使用)被称为大陆时间。在世界某些地区,它被称为铁路时间。此外,国际标准时间表示法(ISO 8601)基于此格式。',
'24 小时制的时间以小时:分钟(例如,01:23)或小时:分钟:秒(01:23:45)的形式书写。小于 10 的数字前面有一个零(称为前导零);例如 09:07。在 24 小时制下,一天从午夜 00:00 开始,最后一分钟从 23:59 开始,到 24:00 结束,这与第二天的 00:00 相同。12:00 只能是中午。午夜称为 24:00,表示一天的结束,00:00 表示一天的开始。例如,您会说“星期二 24:00”和“星期三 00:00”来表示完全相同的时间。',
'然而,美国军方不愿说 24:00——他们不喜欢为同一事物命名两次,所以他们总是说“23:59”,也就是午夜前一分钟。']
LangChain 的 Deep Lake 向量存储
让我们定义一个 dataset_path
,这是您的 Deep Lake 向量存储将存储文本嵌入的地方。
dataset_path = 'wikipedia-embeddings-deeplake'
我们将设置 OpenAI 的 text-embedding-3-small
作为我们的嵌入函数,并在 dataset_path
初始化 Deep Lake 向量存储...
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import DeepLake
embedding = OpenAIEmbeddings(model="text-embedding-3-small")
db = DeepLake(dataset_path, embedding=embedding, overwrite=True)
...并使用 add_texts
方法一次一个批次地填充它。
from tqdm.auto import tqdm
batch_size = 100
nsamples = 10 # 用于测试。替换为 len(ds) 以附加所有内容
for i in tqdm(range(0, nsamples, batch_size)):
# 查找批次结束
i_end = min(nsamples, i + batch_size)
batch = ds[i:i_end]
id_batch = batch.ids.data()["value"]
text_batch = batch.text.data()["value"]
meta_batch = batch.metadata.data()["value"]
db.add_texts(text_batch, metadatas=meta_batch, ids=id_batch)
0%| | 0/1 [00:00<?, ?it/s]
creating embeddings: 0%| | 0/1 [00:00<?, ?it/s] [A
creating embeddings: 100%|██████████| 1/1 [00:02<00:00, 2.11s/it]
100%|██████████| 10/10 [00:00<00:00, 462.42it/s]
Dataset(path='wikipedia-embeddings-deeplake', tensors=['text', 'metadata', 'embedding', 'id'])
tensor htype shape dtype compression
------- ------- ------- ------- -------
text text (10, 1) str None
metadata json (10, 1) str None
embedding embedding (10, 1536) float32 None
id text (10, 1) str None
在数据库上运行用户查询
可以通过 db.vectorstore.dataset
访问底层的 Deep Lake 数据集对象,并且可以使用 db.vectorstore.summary()
摘要数据结构,该结构显示了 4 个具有 10 个样本的张量:
db.vectorstore.summary()
Dataset(path='wikipedia-embeddings-deeplake', tensors=['text', 'metadata', 'embedding', 'id'])
tensor htype shape dtype compression
------- ------- ------- ------- -------
text text (10, 1) str None
metadata json (10, 1) str None
embedding embedding (10, 1536) float32 None
id text (10, 1) str None
我们将使用 GPT-3.5-Turbo 作为我们的 LLM 在向量存储上设置 QA。
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
# 重新加载向量存储,以防它尚未初始化
# db = DeepLake(dataset_path = dataset_path, embedding_function=embedding)
qa = RetrievalQA.from_chain_type(llm=ChatOpenAI(model='gpt-3.5-turbo'), chain_type="stuff", retriever=db.as_retriever())
让我们尝试运行一个提示并检查输出。此 API 内部执行嵌入搜索,以查找最相关的数据以馈送到 LLM 上下文。
query = 'Why does the military not say 24:00?'
qa.run(query)
'军方不愿说 24:00,因为他们不喜欢为同一事物命名两次。相反,他们总是说“23:59”,也就是午夜前一分钟。'
瞧!