​如何创建 RAG 系统来获得对数据的强大访问权限(含代码)

​如何创建 RAG 系统来获得对数据的强大访问权限(含代码)

首页动作格斗访问代码零更新时间:2024-04-26

Gihub:https://github.com/mcks2000/llm_notebooks/tree/main/search_mail_data

RAG 系统是一种创新的信息检索方法。它利用传统的信息检索方法,如向量相似性搜索,并结合最先进的大语言模型技术。这些技术相结合,构成了一个强大的系统,可以通过简单的提示访问大量信息。

动机

我写这篇文章的动机是我在尝试查找旧邮件时遇到的挫败感。我通常有一些有关邮件的信息,例如联系人是谁或模糊地电子邮件的主题是什么。尽管如此,在 Gmail 中进行直接单词搜索时,我必须更加具体,这使得查找我正在寻找的特定邮件变得具有挑战性。我想要一个 RAG 系统,允许我提示我的电子邮件搜索它们。因此,如果我需要一封来自大学的关于某个主题的旧电子邮件,我可以提示诸如“我在 公司 第二年注册了哪些技术课程?”之类的内容。与此提示等效的直接单词搜索具有挑战性,因为我需要在提示中提供更具体的信息。相反,RAG 系统可以找到邮件,因为它具有所有必需的数据。

检索数据

制作 RAG 系统的第一步是找到您希望 RAG 系统使用的数据。就我而言,我想搜索电子邮件,虽然我将讨论的方法也适用于任何其他数据源。我下载了所有电子邮件,您可以在takeout.google.com上找到这些电子邮件。在那里,您可以选择仅下载邮件并按导出。这将发送一个链接到您的电子邮件,您可以从中下载所有邮件信息。如果您有其他电子邮件客户端,则可以使用类似的方法下载所有电子邮件信息。

此外,除了电子邮件之外,您还可以在本教程中使用其他数据源。一些例子是:

这些示例的共同点是它们包含文本信息。但是,您也可以将此信息应用于其他类型的信息,例如图像或音频。RAG 系统面临的挑战不是搜索数据,因为您可以轻松地对不同形式的数据(如文本、照片和音频)进行矢量化。相反,更重要的问题将是生成文本、音频或图像,尽管有一些方法可以实现。然而,本文将仅讨论从文本信息生成文本答案。

预处理数据

下载数据后,需要对其进行预处理,这是大多数机器学习流程中的重要步骤。我下载了电子邮件,因此我的预处理步骤将介绍如何预处理下载的电子邮件,尽管您可以对其他类型的数据应用相同的思维过程。

从 takeout.google.com 下载数据后,您的下载文件夹中将出现一个 zip 文件夹。解压 zip 文件夹,然后找到名为All mail Include Spam and Trash.mbox 的文件,其中包含所有必要的邮件信息。将此文件移动到您正在使用的编程文件夹中,然后您可以使用StackOverflow中的以下部分代码从该文件中读出最重要的信息:

StackOverflow:https://stackoverflow.com/questions/59681461/read-a-big-mbox-file-with-python/59682472#59682472

首先,安装并导入包:

# install packages !pip install beautifulsoup4 !pip install pandas !pip install tqdm # import packages import pandas as pd import email from email.policy import default from tqdm import tqdm from bs4 import BeautifulSoup #to clean the payload

然后创建一个类来读取 mbox 文件:

# code for class from <https://stackoverflow.com/questions/59681461/read-a-big-mbox-file-with-python/59682472#59682472> class MboxReader: def __init__(self, filename): self.handle = open(filename, 'rb') assert self.handle.readline().startswith(b'From ') def __enter__(self): return self def __exit__(self, exc_type, exc_value, exc_traceback): self.handle.close() def __iter__(self): return iter(self.__next__()) def __next__(self): lines = [] while True: line = self.handle.readline() if line == b'' or line.startswith(b'From '): yield email.message_from_bytes(b''.join(lines), policy=default) if line == b'': break lines = [] continue lines.append(line)

然后,您可以使用以下命令将邮件信息提取到 pandas 数据框:

path = r"<PATH TO MBOX FILE>/All mail Including Spam and Trash.mbox" mbox = MboxReader(path) MAX_EMAILS = 5 current_mails = 0 all_mail_contents = "" mail_from_arr, mail_date_arr, mail_body_arr = [],[],[] for idx,message in tqdm(enumerate(mbox)): # print(message.keys()) mail_from = f"{str(message['From'])}\\n".replace('"','').replace('\\n','').strip() mail_date = f"{str(message['Date'])}\\n".replace('"','').replace('\\n','').strip() payload = message.get_payload(decode=True) if payload: current_mails = 1 if current_mails > MAX_EMAILS: break soup = BeautifulSoup(payload, 'html.parser') body_text = soup.get_text().replace('"','').replace("\\n", "").replace("\\t", "").strip() mail_from_arr.append(mail_from) mail_date_arr.append(mail_date) mail_body_arr.append(body_text) all_mail_contents = body_text " "

说明:

这段代码将邮件信息保存到数组和所有邮件内容的字符串中。您可以将其保存到文件中:

df = pd.DataFrame({'From':mail_from_arr, 'Date':mail_date_arr, 'Body':mail_body_arr}) df.to_pickle("df_mail.pkl") # write all mail contents to txt with open("all_mail_contents.txt", "w", encoding="utf-8") as f: f.write(all_mail_contents)

您需要的所有信息现在都已存储在文件中,可供 RAG 系统检索。

其他选项

在开始实施 RAG 系统之前,我还想提一下一些不那么花哨但仍然可靠的 RAG 替代方案。RAG是一个来自信息检索领域的搜索系统。信息检索至关重要,因为它使我们能够访问大量可用数据。例如,信息检索技术可用于任何搜索引擎,例如谷歌。TF-IDF于1972年实现,至今仍然是一种可靠的信息搜索算法。我自己用它实现了一个搜索引擎系统,您可以在下面的文章中看到它,您会对算法仍然有效的效果印象深刻。

BM25是对TF-IDF的改进,只需对TF-IDF代码稍作修改即可轻松实现。我提到其他信息搜索选项(如 TF-IDF 和 BM25)的观点是,完整的 RAG 系统可能并不总是必要的。如果您只需要直接访问信息,那么更简单的选择仍然有效。

实施 RAG

现在是实施 RAG 系统的时候了。我将使用 Langchain 框架,这是一个快速设置可定制 RAG 系统的优秀工具。我按照 Langchain 文档定制了自定义数据的代码来创建此部分。

首先,您必须安装并加载所有必需的包:

# install packages !pip install langchain !pip install gpt4all !pip install chromadb !pip install llama-cpp-python !pip install langchainhub # import packages from langchain_community.document_loaders import WebBaseLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.embeddings import GPT4AllEmbeddings from langchain_community.vectorstores import Chroma from langchain_community.llms import LlamaCpp from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import PromptTemplate from langchain.docstore.document import Document from langchain import hub from langchain_core.runnables import RunnablePassthrough, RunnablePick import pandas as pd准备数据

然后,加载您在预处理数据步骤中创建的数据集。请注意,在本例中我仅使用邮件内容,但您也可以添加其他信息,例如发件人和每封电子邮件的数据。

# load custom dataset with open("all_mail_contents.txt", "r", encoding="utf-8") as f: all_mail_contents = f.read()

然后,您必须将字符串转换为 Langchain 可以读取的格式。下面的代码首先将所有文本转换为 Langchain 文档格式并初始化文本分割器,该分割器将字符串分割成具有重叠的不同块。这些块是必不可少的,因为当您向 RAG 系统询问问题时,将检索最相关的块并将其提供给 LLM 作为回答问题的上下文。块之间也有一些重叠,因此每个块都可以包含足够的信息来回答给定的问题。分割成块后,每个块都会被矢量化(转换为数字)。这是一个典型的信息检索步骤,其中您要搜索的数据被矢量化。然后,当您提出问题时,该问题也会被向量化,并且您可以通过从与问题向量距离最近的数据中获取向量来选择与问题最相关的数据。

# convert to langchain document format doc = Document(page_content=all_mail_contents, metadata={"source": "local"}) #split up text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=20) all_splits = text_splitter.split_documents([doc]) vectorstore = Chroma.from_documents(documents=all_splits, embedding=GPT4AllEmbeddings())

注意:我在 Python3.8 上运行上面最后一行时遇到问题,但它可以在 Python3.11 上现成运行。该问题是由于 Python 3.8 中的 sqllite3(Python 预装包)版本引起的。

矢量化

矢量化过程的工作原理如下。我在这里给出一个随机选择数字的例子。首先,对每个文档进行矢量化:

然后你将问题向量化:

然后你找到问题和每个文档之间的相似度;例如,对于余弦相似度,这会输出 0 到 1 之间的单个数字数组,如下所示:

然后,您选择与问题最相似的文档。如果您需要两个文档,则应选择文档 1 和 3。

加载LLM

准备好数据后,您必须加载大型语言模型。语言模型有很多选择,但我将重点关注免费模型。Langchain 是一个可以轻松使用LLM的包装器,但您仍然需要自己下载LLM。然而,这不一定是一个复杂的过程,我将向您展示两种方法。

第一个选项,也是我的首选,是 Llama2

您必须下载模型并将其转换为 Langchain 可以轻松使用的 .gguf 格式。然后您可以将该模型用于:

n_gpu_layers = 1 n_batch = 512 # Make sure the model path is correct for your system! llm = LlamaCpp( model_path=r"<path to model>\\ggml-model-f16_q4_1.gguf", n_gpu_layers=n_gpu_layers, n_batch=n_batch, n_ctx=1024, f16_kv=True, # MUST set to True, otherwise you will run into problem after a couple of calls verbose=True, )

其中模型路径是模型的路径,n_ctx 是您要使用的上下文大小。上下文大小越大越好,但也需要更多计算,这是您必须考虑的权衡。

第二个更容易访问的选项是使用 Langchain 教程中提到的 GPT4All。不管顾名思义,GPT4All 都有可供您使用的开源模型。然后,您可以下载 Tiny LLama HuggingFace(tinyllama-1.1b-chat-v1.0.Q5_K_M.gguf模型)。如果您想要提高性能,您也可以寻找更大的 Llama 模型,尽管使用较小的模型仍然可以获得不错的结果。

下载模型后,将其移至本地文件夹。然后您可以使用以下命令加载模型:

from langchain_community.llms import GPT4All llm = GPT4All( model=r"<root path to your model>\\tinyllama-1.1b-chat-v1.0.Q5_K_M.gguf", max_tokens=2048, )

然后您就可以开始执行下面的LLM了!

使用LLM

如果你想使用你的语言模型,你可以像这样调用它:

question = "What is Medium" llm.invoke(question)

我的 Llama2 模型给出的响应是:

l experience, share your expertise in a particular field, or tell a story, Medium provides a platform for you to do so.\\n2. Follow other writers: Medium has a large community of writers, and you can follow other writers whose work interests you. This way, you'll see their new publications in your feed and can discover new voices and perspectives.\\n3. Read and engage with publications: Medium publishes a wide variety of content, including articles, essays, personal stories, and more. You can read and engage with these publications by commenting, liking, or sharing them with others.

您可以使用的另一个令人兴奋的功能是相似性搜索。相似性搜索作为标准搜索算法,返回与您的问题最相似的数据点。这是通过向量化问题和数据点并选择与问题距离最小的数据点来实现的。您可以使用以下方法进行相似性搜索:

#this code can be used to see if the correct documents are retrieved. The documents retrieved should be regarding your questions, and is the data the LLM uses to answer the questions question = "What is Google" docs = vectorstore.similarity_search(question)

这对于调试 RAG 系统是否按预期检索文档来说是一个很有价值的工具。您应该查看与您提出的问题相关的文件。

如果您有一个帮助函数来格式化文档,那就最好了:

def format_docs(docs): return "\\n\\n".join(doc.page_content for doc in docs)

并形成Langchain帮助您提问。rag_prompt会向您的问题添加额外的文本,以确保 LLM 使用检索到的文档来帮助回答问题。

# retrieve relevant docs rag_prompt = hub.pull("rlm/rag-prompt") rag_prompt.messages retriever = vectorstore.as_retriever() qa_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | rag_prompt | llm | StrOutputParser() )

最后,您可以让LLM使用检索到的文档回答问题,其中包含以下内容:

qa_chain.invoke(question)

这行代码调用您创建的链,该链检索与您的问题最相关的文档,然后根据检索到的文档提示LLM士回答您的问题。

测试

定量测试 RAG 系统可能很困难,因为创建标记数据集是劳动密集型的。因此,我将在本文中进行定性测试来检查其性能。请注意,上面的实现很简单,您可以期待除了高级性能之外的其他东西。

我测试了我的 RAG 系统,首先找到了一些我想要发现的电子邮件,然后查看 RAG 系统是否可以检索我需要的信息。值得注意的是,我的许多电子邮件都将用挪威语编写,这使得 RAG 系统的某些任务变得更加困难,尽管这仍然是可能的。我不会在这里分享示例,因为我想将我的电子邮件保密,但您可以自己尝试一下。为了进行这些测试,我收集了大约 100 封包含正文的电子邮件,并询问了与这些电子邮件相关的问题。

测试1

我收到一封来自 Digipost(挪威数字邮政服务)的电子邮件。我想看看RAG系统是否可以确定我是否收到了这样的电子邮件。

我问一个问题:

question = "Have I gotten a message from Digipost?"

RAG 系统回答:

'Yes, you have received a message from Digipost.'

所以,LLM通过了测试。这个测试很有趣,因为文档检索设法检索相关电子邮件,因为 Digipost 是一个不常见的词。然而,有关 Digipost 的电子邮件是挪威语的,这更令人印象深刻。

测试2

我收到了一封来自 Microsoft 的有关云技能挑战赛的电子邮件,因此我向 RAG 询问:

question = "What is the topic of my last Microsoft email I have gotten?"

它回答:

'The topic of your last Microsoft email is learning content.'

正如您所看到的,RAG 再次正确,尽管这次的答案很模糊并且不是最佳的。

由于我认为答案有点模糊,我尝试让LLM的答案更详细:

question = "What is the topic of my last Microsoft email I have gotten? Answer in detail"

其中回答说:

'\\nBased on the provided context, the topic of your last Microsoft email is likely related to learning paths and modules in Microsoft Learn, with a mention of trending content and contact information for feedback or help.'

这样系统就可以工作了!

未来的规划

虽然系统按预期工作,但我想向这个 RAG 系统添加许多功能。以下是我正在考虑的一些未来工作:

结论

在本文中,我讨论了如何使用数据创建 RAG 系统。根据提示,这可以成为一个强大的搜索引擎来检索您所寻求的信息。要创建该系统,您首先要检索数据,例如从 Gmail 下载邮件。然后,您必须预处理数据以使其可供 RAG 系统访问。此后,所有数据将转换为 Langchain 格式并加载到 LLM 中。然后,您可以询问有关您下载的数据的问题。我还包含了两个测试,显示 RAG 系统如何响应查询并展示系统是否按预期工作。

资源:


点赞关注 获取更多资讯,并在 头条 上阅读我的短篇技术文章

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved