用Langchain和Deep Lake查询您的文件!
使用Langchain和Deep Lake查询文件!
介绍
像Langchain和Deep Lake这样的大型语言模型在文档问答和信息检索方面取得了长足的进步。这些模型对世界了解很多,但有时候,它们难以知道自己不知道某件事。这导致它们编造东西来填补空白,这是不好的。
然而,一种名为“检索增强生成”(RAG)的新方法似乎很有希望。使用RAG来查询带有私有知识库的LLM。它通过从数据源中添加额外信息来帮助这些模型变得更好。这使它们更具创新性,并在没有足够信息时有助于减少错误。
RAG通过增强提示信息来改进专有数据,从而提高这些大型语言模型的知识,同时减少幻觉的发生。
学习目标
1. 了解RAG方法及其优势
2. 了解文档问答中的挑战
3. 简单生成和检索增强生成之间的区别
4. 在类似文档问答的行业应用案例中实际实施RAG
通过完成本篇学习文章,您应该对检索增强生成(RAG)及其在文档问答和信息检索中提高LLM性能的应用有坚实的理解。
本文是数据科学博文馆的一部分。
入门指南
关于文档问答,理想的解决方案是在问问题时为模型提供所需的具体信息。然而,确定哪些信息是相关的可能是棘手的,并取决于大型语言模型的预期任务。这就是RAG概念的重要性所在。
让我们看看RAG流程是如何工作的:
检索增强生成
RAG是一种尖端的生成式AI架构,它利用语义相似性自主识别相关信息以回应查询。以下是RAG的简明概述:
- 向量数据库:在RAG系统中,您的文档存储在专门的向量数据库中。每个文档都根据嵌入模型生成的语义向量进行索引。这种方法可以快速检索与给定查询向量密切相关的文档。每个文档都被分配一个表示其语义含义的数字表示(向量)。
- 查询向量生成:当提交一个查询时,相同的嵌入模型会生成代表查询的语义向量。
- 基于向量的检索:随后,模型利用向量搜索来识别与查询向量密切对齐的数据库中的文档。这一步是确定最相关文档的关键。
- 响应生成:在检索到相关文档后,模型将它们与查询一起使用以生成响应。这种策略使模型能够在需要时精确访问外部数据,增强其内部知识。
示意图
下面的示意图总结了上述所有步骤:
从上面的图中,有两个重要的要点:
- 在简单生成中,我们永远不会知道源信息。
- 当模型过时或其知识截止时间在查询提出之前时,简单生成可能导致错误的信息生成。
通过RAG方法,我们的LLM的提示将是我们给出的指令、检索上下文和用户的查询。现在,我们有了检索到的信息的证据。
所以,不需要多次对不断变化的信息场景进行繁琐的训练,您可以将更新的信息添加到向量存储/数据存储中。用户下次可以提出类似的问题,其答案现在已经改变(以XYZ公司的一些财务记录为例)。您已经准备就绪。
希望这样会让您对RAG的工作原理有所了解。现在,让我们进入正题。是的,代码。
我知道您来这里不是为了闲聊。👻
让我们跳转到好的部分!
1:创建VSCode项目结构
打开VSCode或您喜欢的代码编辑器,并按照以下方式创建项目目录(仔细按照文件夹结构) –
记得使用Python ≥ 3.9创建虚拟环境,并在requirements.txt文件中安装依赖项。(别担心,我会分享资源的GitHub链接。)
2:创建检索和嵌入操作的类
在controller.py文件中,粘贴下面的代码并保存。
from retriever.retrieval import Retriever
# 创建一个Controller类来管理文档嵌入和检索
class Controller:
def __init__(self):
self.retriever = None
self.query = ""
def embed_document(self, file):
# 如果提供了'file',则嵌入文档
if file is not None:
self.retriever = Retriever()
# 为提供的文档文件创建并添加嵌入
self.retriever.create_and_add_embeddings(file.name)
def retrieve(self, query):
# 根据用户的查询检索文本
texts = self.retriever.retrieve_text(query)
return texts
这是一个帮助类,用于创建我们的Retriever对象。它实现了两个函数 –
embed_document:生成文档的嵌入
retrieve:当用户提问时检索文本
在以后的过程中,我们将更深入地了解Retriever中的create_and_add_embeddings和retrieve_text辅助函数!
3:编写我们的检索流程!
在retrieval.py文件中,粘贴下面的代码并保存。
3.1:导入必要的库和模块
import os
from langchain import PromptTemplate
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores.deeplake import DeepLake
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.document_loaders import PyMuPDFLoader
from langchain.chat_models.openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.memory import ConversationBufferWindowMemory
from .utils import save
import config as cfg
3.2:初始化Retriever类
# 定义Retriever类
class Retriever:
def __init__(self):
self.text_retriever = None
self.text_deeplake_schema = None
self.embeddings = None
self.memory = ConversationBufferWindowMemory(k=2, return_messages=True)csv
3.3:让我们来编写创建并添加文档嵌入到Deep Lake的代码
def create_and_add_embeddings(self, file):
# 如果目录"data"不存在,则创建一个名为"data"的目录
os.makedirs("data", exist_ok=True)
# 使用OpenAIEmbeddings初始化嵌入
self.embeddings = OpenAIEmbeddings(
openai_api_key=cfg.OPENAI_API_KEY,
chunk_size=cfg.OPENAI_EMBEDDINGS_CHUNK_SIZE,
)
# 使用PyMuPDFLoader从提供的文件中加载文档
loader = PyMuPDFLoader(file)
documents = loader.load()
# 使用CharacterTextSplitter将文本分成块
text_splitter = CharacterTextSplitter(
chunk_size=cfg.CHARACTER_SPLITTER_CHUNK_SIZE,
chunk_overlap=0,
)
docs = text_splitter.split_documents(documents)
# 为文本文档创建DeepLake模式
self.text_deeplake_schema = DeepLake(
dataset_path=cfg.TEXT_VECTORSTORE_PATH,
embedding_function=self.embeddings,
overwrite=True,
)
# 将拆分的文档添加到DeepLake模式中
self.text_deeplake_schema.add_documents(docs)
# 使用搜索类型“similarity”从DeepLake模式创建一个文本检索器
self.text_retriever = self.text_deeplake_schema.as_retriever(
search_type="similarity"
)
# 配置文本检索器的搜索参数
self.text_retriever.search_kwargs["distance_metric"] = "cos"
self.text_retriever.search_kwargs["fetch_k"] = 15
self.text_retriever.search_kwargs["maximal_marginal_relevance"] = True
self.text_retriever.search_kwargs["k"] = 3
3.4:现在,让我们编写一个能够检索文本的函数!
def retrieve_text(self, query):
# 以只读模式为文本文档创建一个DeepLake模式
self.text_deeplake_schema = DeepLake(
dataset_path=cfg.TEXT_VECTORSTORE_PATH,
read_only=True,
embedding_function=self.embeddings,
)
# 为向模型提供指令定义一个提示模板
prompt_template = """您是一款高级人工智能,能够分析文档中的文本并提供详细的答案给用户查询。您的目标是提供全面的回答,以消除用户需要重新访问文档的需求。如果您没有答案,请承认而不是编造信息。
{context}
问题:{question}
答案:
"""
# 使用"context"和"question"创建一个PromptTemplate
PROMPT = PromptTemplate(
template=prompt_template, input_variables=["context", "question"]
)
# 定义链式类型
chain_type_kwargs = {"prompt": PROMPT}
# 初始化ChatOpenAI模型
model = ChatOpenAI(
model_name="gpt-3.5-turbo",
openai_api_key=cfg.OPENAI_API_KEY,
)
# 创建模型的RetrievalQA实例
qa = RetrievalQA.from_chain_type(
llm=model,
chain_type="stuff",
retriever=self.text_retriever,
return_source_documents=False,
verbose=False,
chain_type_kwargs=chain_type_kwargs,
memory=self.memory,
)
# 使用用户的问题查询模型
response = qa({"query": query})
# 从llm返回响应
return response["result"]
4:查询我们的流水线并提取结果的实用函数
将以下代码粘贴到utils.py文件中:
def save(query, qa):
# 使用get_openai_callback函数
with get_openai_callback() as cb:
# 使用用户的问题查询qa对象
response = qa({"query": query}, return_only_outputs=True)
# 从llm的响应中返回答案
return response["result"]
5:用于存储密钥的配置文件…没有花哨的东西!
将以下代码粘贴到config.py文件中:
import os
OPENAI_API_KEY = os.getenv(OPENAI_API_KEY)
TEXT_VECTORSTORE_PATH = "data\deeplake_text_vectorstore"
CHARACTER_SPLITTER_CHUNK_SIZE = 75
OPENAI_EMBEDDINGS_CHUNK_SIZE = 16
最后,我们可以为演示编写我们的Gradio应用!
6:Gradio应用!
将以下代码粘贴到app.py文件中:
# 导入必要的库
import os
from controller import Controller
import gradio as gr
# 为了提高性能,禁用分词器的并行处理
os.environ["TOKENIZERS_PARALLELISM"] = "false"
# 初始化Controller类
controller = Controller()
# 定义一个处理上传PDF文件的函数
def process_pdf(file):
if file is not None:
controller.embed_document(file)
return (
gr.update(visible=True),
gr.update(visible=True),
gr.update(visible=True),
gr.update(visible=True),
)
# 定义一个响应用户消息的函数
def respond(message, history):
botmessage = controller.retrieve(message)
history.append((message, botmessage))
return "", history
# 定义一个清除对话历史记录的函数
def clear_everything():
return (None, None, None)
# 创建一个Gradio界面
with gr.Blocks(css=CSS, title="") as demo:
# 显示标题和描述
gr.Markdown("# AskPDF ", elem_id="app-title")
gr.Markdown("## 上传PDF并提问!", elem_id="select-a-file")
gr.Markdown(
"拖放一个有趣的PDF并提问!",
elem_id="select-a-file",
)
# 创建上传部分
with gr.Row():
with gr.Column(scale=3):
upload = gr.File(label="上传PDF", type="file")
with gr.Row():
clear_button = gr.Button("清除", variant="secondary")
# 创建聊天机器人界面
with gr.Column(scale=6):
chatbot = gr.Chatbot()
with gr.Row().style(equal_height=True):
with gr.Column(scale=8):
question = gr.Textbox(
show_label=False,
placeholder="例如:文档关于什么?",
lines=1,
max_lines=1,
).style(container=False)
with gr.Column(scale=1, min_width=60):
submit_button = gr.Button(
"请问我 🤖", variant="primary", elem_id="submit-button"
)
# 定义按钮
upload.change(
fn=process_pdf,
inputs=[upload],
outputs=[
question,
clear_button,
submit_button,
chatbot,
],
api_name="upload",
)
question.submit(respond, [question, chatbot], [question, chatbot])
submit_button.click(respond, [question, chatbot], [question, chatbot])
clear_button.click(
fn=clear_everything,
inputs=[],
outputs=[upload, question, chatbot],
api_name="clear",
)
# 启动Gradio界面
if __name__ == "__main__":
demo.launch(enable_queue=False, share=False)
准备好你的🧋,因为现在是时候看看我们的流水线是如何工作的了!
要启动Gradio应用程序,请打开一个新的终端实例并输入以下命令:
python app.py
注意:确保虚拟环境已激活,并且你在当前项目目录中。
Gradio将在本地服务器上启动您的应用程序的新实例,如下所示:
你只需要按住CTRL并点击本地主机URL(最后一行),你的应用程序将在浏览器中打开。
耶!
我们的Gradio应用程序来了!
让我们放一个有趣的PDF文件!我将使用这个Kaggle存储库中包含《哈利·波特》第1章PDF的PDF文件,其中包含了《哈利·波特》第1至7章的PDF格式。
呼光!愿光明与你同在🪄
现在,只要你上传文件,就会激活查询文本框,如下所示:
现在让我们进入最令人期待的部分——问答!
哇! 😲
我喜欢答案的准确性!
此外,看看Langchain的记忆如何保持链状态,将过去运行的上下文纳入其中。
它记得她在这里是我们心爱的麦格教授!❤️🔥
应用程序工作的简短演示!
RAG的实用且负责任的方法对于各个研究领域的数据科学家来说非常有用,可以构建准确且负责任的人工智能产品。
1. 在医疗保健诊断中,将RAG用于帮助医生和科学家诊断复杂的医疗状况,通过将患者记录、医学文献、研究论文和期刊集成到知识库中,帮助在做出关键决策和进行医疗研究时检索最新信息。
2. 在客户支持方面,公司可以方便地使用由RAG驱动的对话式人工智能聊天机器人来帮助解决客户的查询、投诉以及有关产品和手册的信息,通过提供准确的回答来改善客户体验!
3. 在金融科技领域,分析师可以将实时金融数据、市场新闻和历史股价纳入他们的知识库中,RAG框架将快速高效地回应有关市场趋势、公司财务、投资和收入的查询,帮助进行强有力且负责任的决策。
4. 在教育科技市场中,可以部署由RAG制作的聊天机器人,以帮助学生解决他们的疑问,根据大量的教科书、研究文章和教育资源库提供建议、全面的答案和解决方案。这使学生能够在不需要大量手动研究的情况下加深对学科的理解。
范围是无限的!
结论
在本文中,我们探讨了使用Langchain和Deep Lake的RAG机制,其中语义相似性在确定相关信息方面起着关键作用。通过向量数据库、查询向量生成和基于向量的检索,这些模型在需要时精确地访问外部数据。
结果呢?更精确、上下文适当的响应,以及丰富的专有数据。希望您喜欢并在其中学到了一些东西!随时从我的GitHub存储库下载完整的代码,进行尝试。
重点要点
- RAG简介:Retrieval Augmented Generation(RAG)是大型语言模型(LLM)中的一种有前途的技术,通过添加来自其自身数据源的额外信息来增强其知识,使其更加智能,减少在缺乏信息时的错误。
- 文档问答中的挑战:大型语言模型在文档问答(QnA)方面取得了显著进展,但有时会难以区分何时缺少信息,从而导致错误。
- RAG流程:RAG流程利用语义相似性来识别相关的查询信息。它涉及向量数据库、查询向量生成、基于向量的检索和响应生成,最终提供更精确和上下文适当的响应。
- RAG的好处:RAG允许模型为其检索到的信息提供证据,减少在快速变化的信息场景中频繁重新训练的需求。
- 实际实施:本文提供了一个实施RAG流程的实际指南,包括设置项目结构、创建检索和嵌入类、编码检索流程以及构建用于实时交互的Gradio应用程序。
常见问题
本文中显示的媒体不归Analytics Vidhya所有,由作者自行决定使用。