当前位置: 首页 > news >正文

使用 RAG 创建 LLM 应用程序

如果您考虑为您的文件或网站制作一个能够回应您的个性化机器人,那么您来对地方了。我可以帮助您使用Langchain和RAG策略来创建这样一个机器人。

了解ChatGPT的局限性和LLMs

ChatGPT和其他大型语言模型(LLMs)经过广泛训练,以理解语言的语义和连贯性。尽管它们具有令人印象深刻的能力,但这些模型也存在一些限制,需要在特定用例中进行仔细考虑。

一个重要的挑战是可能出现幻觉,模型可能会生成不准确或与上下文无关的信息。

想象一下,要求模型改进您公司的政策;在这种情况下,ChatGPT和其他大型语言模型可能会难以提供准确的回答,因为它们缺乏对您公司数据的训练。

相反,它们可能会生成毫无意义或无关的回复,这可能没有帮助。那么,我们如何确保LLM理解我们的特定数据,并相应地生成回复呢?这就是检索增强生成(RAG)等技术发挥作用的地方。

 RAG是什么?

RAG或检索增强生成使用三种主要工作流程来生成并提供更好的响应

  • 信息检索:当用户提出问题时,AI系统从维护良好的知识库或外部来源(如数据库、文章、API或文档存储库)中检索相关数据。

    这是通过将查询转换为机器可以理解的数字格式或向量来实现的。

  • LLM: 然后将检索到的数据呈现给LLM或大型语言模型,以及用户的查询。 LLM使用这些新知识和其训练数据来生成响应。

  • 最终,LLM生成的响应更准确和相关,因为它已经通过检索到的信息进行了增强。

    我是说我们从我们的知识库中为LLM提供了一些额外信息,这使得LLMs能够提供更具上下文相关和事实性的回答,解决了模型仅仅是在产生幻觉或提供无关答案的问题。

再举个公司政策的例子。假设你有一个处理与公司政策相关查询的人力资源机器人。

现在,如果有人询问有关政策的具体内容,机器人可以从知识库中提取最新的政策文件,将相关上下文传递给精心设计的提示,然后进一步传递给LLM以生成回应。

为了让事情更简单,想象一个LLM就像你博学的朋友,似乎什么都知道,从地理到计算机科学,从政治到哲学。现在,想象你自己问这个朋友一些问题:

  • 周末谁负责洗我的衣服?
  • “谁住在我隔壁?”
  • 我更喜欢哪个牌子的花生酱?

很可能你的朋友无法回答这些问题。大多数时候是这样。

但假设这位遥远的朋友随着时间变得更加亲近,他经常来你家,很了解你的父母,你们经常一起出去玩,你们一起外出,等等等等.. 你懂的。

我的意思是他正在获取关于你的个人和内部信息。现在,当你提出同样的问题时,他可以以更相关的方式回答这些问题,因为他更适合你的个人见解。

同样,一个LLM在提供额外信息或访问您的数据时,不会猜测或产生幻觉。相反,它可以利用这些访问的数据提供更相关和准确的答案。

具体步骤如下,用于创建任何RAG应用程序..

  1. 从您的数据来源中提取相关信息。
  2. 把信息分成小块。
  3. 将这些块存储为它们的嵌入到一个向量数据库中。
  4. 创建一个提示模板,该模板将与查询和上下文一起输入到LLM中。
  5. 使用相同的嵌入模型将查询转换为其相关的嵌入。
  6. 从向量数据库中获取与查询相关的 k 个相关文档。
  7. 将相关文件传递给LLM并获取回复。

 常见问题解答

  1. 我们将在这个任务中使用Langchain,基本上它就像一个包装器,让你更好地交流和管理你的LLM操作。请注意,Langchain更新非常快,一些功能和其他类可能会移动到不同的模块中。

    所以如果有什么东西不起作用,只需检查一下你是否从正确的来源导入了库!

  2. 我们将使用Hugging Face,这是一个用于构建、训练和部署最先进的机器学习模型的开源库,特别是关于自然语言处理。要使用HuggingFace,我们需要访问令牌,请在这里获取您的访问令牌。

  3. 对于我们的模型,我们将需要两个关键组件:一个LLM(大型语言模型)和一个嵌入模型。虽然像OpenAI这样的付费来源提供了这些,但我们将利用开源模型,以确保所有人都能够访问。

  4. 现在我们需要一个向量数据库来存储我们的嵌入。为此,我们有LanceDB——它就像一个超级智能的数据湖,可以处理大量信息。它是一流的向量数据库,使其成为处理向量嵌入等复杂数据的首选。而最棒的部分呢?

    它不会在你的口袋里留下一丝痕迹,因为它是开源的,可以免费使用!

  5. 为了简化流程,我们的数据摄取过程将涉及使用一个URL和一些PDF文件。如果需要,您可以整合其他数据源,但目前我们将专注于这两种数据源。

有了Langchain作为接口,Hugging Face用于获取模型,再加上开源组件,我们已经准备就绪!这样一来,我们既能节省一些开支,又能拥有所需的一切。让我们继续下一步。

 环境设置

我正在使用 MacBook Air M1,需要注意的是,某些依赖和配置可能会因使用的系统类型而有所不同。现在打开你喜欢的编辑器,创建一个 Python 环境并安装相关的依赖。

# Create a virtual environment
python3 -m venv env# Activate the virtual environment
source env/bin/activate# Upgrade pip in the virtual environment
pip install --upgrade pip# Install required dependencies
pip3 install lancedb langchain langchain_community prettytable sentence-transformers huggingface-hub bs4 pypdf pandas# This is optional, I did it for removing a warning
pip3 uninstall urllib3
pip3 install 'urllib3<2.0'

现在在相同的目录中创建一个 .env 文件,将您的 Hugging Face api 凭据放在其中,就像这样

HUGGINGFACEHUB_API_TOKEN = hf_KKNWfBqgwCUOHdHFrBwQ.....

确保名称“HUGGINGFACEHUB_API_TOKEN”保持不变,因为这对于身份验证至关重要。

如果您喜欢直接的方法,而不依赖外部包或文件加载,您可以在代码中直接配置环境变量,就像这样。

HF_TOKEN = "hf_KKNWfBqgwCUOHdHFrBwQ....."
os.environ["HUGGINGFACEHUB_API_TOKEN"] = HF_TOKEN

在项目的根目录中创建一个名为data的文件夹,用于存储PDF文档的中央存储库。您可以添加一些用于测试的示例PDF;例如,我正在使用Yolo V7和Transformers论文进行演示。重要的是要注意,这个指定的文件夹将作为我们数据摄取的主要来源。

好像一切都井井有条,我们已经准备就绪了!

步骤1:提取相关信息

为了让您的RAG应用程序运行起来,我们首先需要做的是从各种数据源中提取相关信息。无论是网页、PDF文件、notion链接、谷歌文档,都需要首先从其原始来源中提取信息。

import os
from langchain_community.document_loaders import WebBaseLoader, PyPDFLoader, DirectoryLoader# Put the token values inside the double quotes
HF_TOKEN = "hf_*******"
os.environ["HUGGINGFACEHUB_API_TOKEN"] = HF_TOKEN# Loading the web url and data 
url_loader = WebBaseLoader("https://gameofthrones.fandom.com/wiki/Jon_Snow")
documents_loader = DirectoryLoader('data', glob="./*.pdf", loader_cls=PyPDFLoader)# Creating the instances
url_docs = url_loader.load()
data_docs = documents_loader.load()# Combining all the data that we ingested
docs = url_docs + data_docs

这将摄取URL链接和PDF中的所有数据。

步骤2:将信息分解成较小的部分

我们已经拥有开发RAG应用所需的所有数据。现在,是时候将这些信息分解成更小的部分。之后,我们将利用嵌入模型将这些部分转换为它们各自的嵌入。但为什么这很重要呢?

就像这样想:如果你被要求一次性阅读一本100页的书,然后被问及一个特定的问题,从整本书中检索必要的信息来回答将是具有挑战性的。

然而,如果你被允许将书分成更小、可管理的部分——比如每部分10页——并且每个部分都标有从0到9的索引,那么这个过程就变得简单得多。

当相同问题在此分解后提出时,您可以根据其索引轻松找到相关的块,然后提取需要回答问题的信息。

把这本书想象成你提取的信息,每10页代表一小部分数据,目录页则是嵌入。基本上,我们会对这些部分应用嵌入模型,将信息转化为它们各自的嵌入。

作为人类,我们可能无法直接理解或与这些嵌入产生共鸣,但它们可以作为我们应用程序中块的数值表示。这就是你可以在Python中做到这一点的方式。

from langchain.text_splitter import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 50)
chunks = text_splitter.split_documents(docs)

现在chunk_size参数指定了一个块可以包含的最大字符数,而chunk_overlap参数指定了相邻两个块之间应该重叠的字符数。

将chunk_overlap设置为50后,相邻块的最后50个字符将彼此共享。

这种方法有助于防止重要信息分散在两个块中,确保每个块包含足够的上下文信息,以便进行后续处理或分析。

相邻块边界共享的信息可以使文本内容更流畅地过渡和理解。

选择chunk_size和chunk_overlap参数的最佳策略很大程度上取决于文档的性质和应用程序的目的。

步骤3:创建嵌入并将其存储到向量数据库中

我们有两种主要方法来为我们的文本块生成嵌入。第一种方法涉及下载模型,管理预处理,并独立进行计算。

我们也可以利用Hugging Face的模型中心,该中心提供了各种预训练模型,用于各种自然语言处理任务,包括嵌入生成。

选择后一种方法可以让我们利用Hugging Face的嵌入模型之一。通过这种方法,我们只需将我们的文本块提供给所选的模型,从而避免在本地机器上进行资源密集型的计算。💀

Hugging Face的模型中心提供了许多嵌入模型的选项,您可以浏览排行榜,选择最适合您需求的模型。目前,我们将继续使用"sentence-transformers/all-MiniLM-L6-v2"。这个模型在我们的任务中非常快速和高效!!

from langchain_community.embeddings import HuggingFaceEmbeddingsembedding_model_name = 'sentence-transformers/all-MiniLM-L6-v2'
embeddings = HuggingFaceEmbeddings(model_name=embedding_model_name, model_kwargs={'device': 'cpu'})

这是一种查看每个块嵌入数量的方法

query = "Hello I want to see the length of the embeddings for this document."
len(embeddings.embed_documents([query])[0])# 384

我们已经有了我们块的嵌入,现在我们需要一个向量数据库来存储它们。

说到向量数据库,市面上有很多选项,适合各种需求。像Pinecone这样的数据库提供了足够的性能和先进的功能,但价格昂贵。

另一方面,像FAISS或Chroma这样的开源替代方案可能缺少一些额外功能,但对于那些不需要大规模可扩展性的人来说已经足够了。

但等等,我要来个大新闻,最近我发现了LanceDB,它是一个开源的向量数据库,类似于FAISS和Chroma。LanceDB的独特之处不仅在于它的开源性质,还在于它无与伦比的可扩展性。

其实,仔细一看,我意识到我之前没有充分突出LanceDB的真正价值主张!!

令人惊讶的是,LanceDB是目前最具可扩展性的向量数据库,甚至超过了Pinecone、Chroma、Qdrant等其他数据库。在您的笔记本电脑上本地扩展至十亿个向量,这是只有LanceDB才能实现的壮举。

我的意思是,这种能力是一个改变游戏规则的因素,特别是当你把它与其他向量数据库进行比较时,即使是处理一亿个向量的数据库也会遇到困难。

更令人惊叹的是,LanceDB设法以极低的成本实现了前所未有的可扩展性,我是说,他们提供的实用工具和数据库工具的价格比最接近的竞争对手要便宜得多。

现在,我们将通过调用 lancedb.connect("lance_database") 创建LanceDB向量数据库的实例。这行代码基本上是建立了一个到名为“lance_database”的LanceDB数据库的连接。接下来,我们使用create_table函数在数据库中创建一个名为“rag_sample”的表。

现在我们使用单个数据条目初始化了这个表,其中包括由embed_query函数生成的数值向量。因此,“Hello World”文本首先被转换为它的数值表示(嵌入的花哨名称),然后被映射到 id 号码1。就像一个键值对。最后,mode="overwrite"参数确保如果表"rag_sample"已经存在,它将被新数据覆盖。

所有文本块都会发生这种情况,非常简单。这是在Python中的样子。

import lancedb
from langchain_community.vectorstores import LanceDBdb = lancedb.connect("lance_database")
table = db.create_table("rag_sample",data=[{"vector": embeddings.embed_query("Hello World"),"text": "Hello World","id": "1",}],mode="overwrite",
)docsearch = LanceDB.from_documents(chunks, embeddings, connection=table)

不是什么高深的科学哈!

第四步:创建一个提示模板,该模板将被提供给LLM

好的,现在是提示模板。当您向ChatGPT提出问题并得到回答时,实际上是在为模型提供提示,以便它能理解问题是什么。

当公司训练模型时,他们决定要使用什么样的提示来调用模型并提出问题。例如,如果您正在使用“Mistral 7B instruct”并且希望获得最佳结果,建议使用以下聊天模板:

<s>[INST] Instruction [/INST] Model answer</s>[INST] Follow-up instruction [/INST]

注意, 和 是特殊标记,用于表示字符串的开头(BOS)和结尾(EOS),而 [INST] 和 [/INST] 则是常规字符串。

就是 Mistral 7B 指令是这样制作的,模型会寻找特殊标记以更好地理解问题。不同类型的 LLMs 有不同类型的指示提示。

现在对于我们的案例,我们将使用huggingfaceh4/zephyr-7b-alpha,这是一个文本生成模型。

只是为了明确,Zephyr-7B-α并没有通过RLHF(强化学习与人类反馈)等技术对其进行人类偏好的调整或格式化,也没有像ChatGPT那样进行响应的过滤,因此该模型可能会产生问题输出(特别是在被提示时)。

我会使用ChatPromptTemplate类来创建聊天模型的提示模板,而不是编写自己的提示。通俗地说,我让ChatPromptTemplate来为我创建指定的提示。

这是一个示例提示模板,是从手动消息中生成的。

from langchain_core.prompts import ChatPromptTemplatechat_template = ChatPromptTemplate.from_messages([("system", "You are a helpful AI bot. Your name is {name}."),("human", "Hello, how are you doing?"),("ai", "I'm doing well, thanks!"),("human", "{user_input}"),]
)messages = chat_template.format_messages(name="Bob", user_input="What is your name?")

如果你不想编写手册说明,你可以使用from_template函数来生成一个更通用的提示模板,我在这个项目中使用了这个方法。就是这样。

from langchain_core.prompts import ChatPromptTemplatetemplate = """
{query}
"""prompt = ChatPromptTemplate.from_template(template)

我们的提示已经设置好了!我们设计了一条单一的消息,假设它是来自一个人类 xD。如果您没有使用from_messages函数,ChatPromptTemplate将通过保留一些额外的系统消息,确保您的提示与语言模型无缝配合。

现在这个设置应该可以运行,但是通过更通用的提示可以实现更好的结果,总是有改进的空间。

第五步:使用相同的嵌入模型将查询转换为其相关的嵌入。

现在,让我们谈谈我们想要问我们的RAG应用程序的查询或问题。我们不能只是将查询传递给我们的模型,并期望得到信息。相反,我们需要通过先前用于块的相同嵌入模型传递查询。为什么这很重要?

嗯,通过嵌入查询,我们使模型能够高效地与先前处理过的文本块进行比较。这使得诸如查找相似文档或生成相关回复之类的任务成为可能。

为了更好地理解,想象一下你和你的朋友说不同的语言,比如英语和印地语,你们需要理解彼此的书写。如果你的朋友递给你一张印地语的页面,你不会直接理解它。

所以,你的朋友先翻译它,将印地语翻译成英语给你。所以现在如果你的朋友用印地语问你一个问题,你可以先把那个问题翻译成英语,然后查找相关的答案。

同样,我们最初将文本信息转换为它们对应的嵌入。现在,当您提出一个查询时,它会经过类似的转换,使用之前应用于处理我们文本块的相同嵌入模型,转换为数字形式。

这一一贯的方法可以有效地检索相关的回答。

第六步:获取K个文档。

现在,让我们来谈谈检索器。它的工作是深入向量数据库并执行搜索,以找到相关的文档。

它返回一组文件编号,我们称之为“k”,这些文件根据它们与您提出的查询或问题的上下文相关性进行排名。您可以将“k”设置为参数,指示您想要多少相关文件-无论是2、5还是10。通常,如果您有较少的数据,最好使用较低的“k”,大约为2。对于较长的文件或更大的数据集,建议将“k”设置在10到20之间。

可以采用不同的搜索技术来更有效快速地从向量数据库中获取相关文档。选择取决于各种因素,如您的具体用例、数据量、所使用的向量数据库类型以及问题的上下文。

retriever = docsearch.as_retriever(search_kwargs={"k": 3})
docs = retriever.get_relevant_documents("what did you know about Yolo V7?")
print(docs)

当您运行此代码时,检索器将从向量数据库中获取3个最相关的文档。所有这些文档将成为我们的LLM模型生成查询响应的上下文。

步骤7:将相关文件传递给LLM并获取回应。

到目前为止,我们已要求我们的检索器从数据库中获取一组相关文件。现在,我们需要一个语言模型(LLM)根据这个上下文生成一个相关的回应。

为了确保稳健性,让我们记住在这篇博客的开头,我提到LLMs像ChatGPT这样的模型有时会生成无关的回复,特别是在涉及特定用例或情境时。

然而,这一次,我们将提供我们自己数据的背景作为LLM的参考。因此,它将考虑这个参考以及它的一般能力来回答问题。这就是使用RAG的整个理念!

现在,让我们深入实施我们的RAG设置中的语言模型(LLM)部分。我们将使用Hugging Face Hub中的zephyr模型架构。以下是我们在Python中的操作方式:

from langchain_community.llms import HuggingFaceHub# Model architecture
llm_repo_id = "huggingfaceh4/zephyr-7b-alpha"
model_kwargs = {"temperature": 0.5, "max_length": 4096, "max_new_tokens": 2048}
model = HuggingFaceHub(repo_id=llm_repo_id, model_kwargs=model_kwargs)

在这段代码片段中,我们正在使用Hugging Face Hub 实例化我们的语言模型。具体来说,我们选择了放置在这个存储库ID“huggingfaceh4/zephyr-7b-alpha”中的zephyr 7 billion 模型。选择这个模型并非任意;正如我之前所说,这是基于模型对我们特定任务和需求的适用性。

由于我们已经只实施开源组件,Zephyr 70亿足够好地生成有用的响应,而且开销最小,延迟低。

这个模型带有一些额外的参数来微调其行为。我们将温度设置为0.5,这控制着生成文本的随机性。

较低的温度往往会导致更保守和可预测的输出,当温度设置为最大值1时,模型会尽可能地创造性,因此根据您的用例需要的输出类型,您可以调整此参数。

为了简单起见和演示目的,我将其设置为0.5,以确保我们获得体面的结果。接下来是max_length参数,它定义了生成文本的最大长度,包括您的提示和响应的大小。

max_new_tokens设置了可以生成的最大新标记数量的阈值。一般来说,max_new_tokens应始终小于或等于max_length参数。为什么?想想看。。

第八步:创建一个用于调用LLM的链。

我们的RAG应用程序所需的一切都已准备就绪,我们需要做的最后一件事是创建一个调用查询中的LLM以生成响应的链。

有不同类型的链条适用于不同的使用情况,如果你希望你的 LLM 能够在一段时间内记住聊天的上下文,就像ChatGPT一样,你需要一个可以在多个对话片段之间共享的记忆实例,对于这种情况,有可用的对话链条。

目前我们只需要一个链条,它可以将我们检索到的上下文组合起来,并将其与查询一起传递给LLM以生成响应。

from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthroughrag_chain = ({"context": retriever,  "query": RunnablePassthrough()}| prompt| model| StrOutputParser()
)response = rag_chain.invoke("Who killed Jon Snow?")

我们有我们的提示,模型,上下文和查询!它们都被合并成一个单一的链条。这基本上就是所有链条所做的事情!现在在运行最终代码之前,我想快速检查一下这两个辅助函数: RunnablePassthrough() 和 StrOutputParser() 。

在 LangChain 中的 RunnablePassthrough 类用于传递输入,保持不变或带有额外的键。在我们的链中,提示期望以“context”和“question”键的形式接收输入。然而,用户输入只包括“question”或“query”。在这里, RunnablePassthrough 被用来将用户的问题传递到“question”键下,同时使用检索器检索上下文。这只是确保提示的输入符合预期的格式。

通常, StrOutputParser 在RAG链中被用来将模型的输出解析成易于理解的字符串。简单来说,它负责将模型的输出转换成更连贯和语法正确的句子,通常更容易被人类理解阅读!
 就是这样!

 登陆日

为了确保即使响应被截断,我们也能获取完整的想法,我实现了一个名为 get_complete_sentence() 的函数。基本上,这个函数帮助从文本中提取最后一个完整的句子。因此,即使响应达到我们设定的最大标记限制并在中途被截断,我们仍然能够获得对消息的连贯理解。

为了实际测试,我建议将一些小型PDF存储在项目的数据文件夹中。您可以选择与您希望聊天机器人互动的各种主题或领域相关的PDF。

另外,提供一个URL作为聊天机器人的参考可能有助于测试。例如,您可以使用维基百科页面、研究论文或与您的测试目标相关的任何其他在线文档。

在我的测试中,我使用了包含有关《权力的游戏》中琼恩·雪的信息的网址,以及变形金刚论文和 YOLO V7 论文的 PDF 文件来评估机器人的表现。让我们看看我们的机器人在不同内容中的表现如何。

import os
import time
import lancedb
from langchain_community.vectorstores import LanceDBfrom langchain_community.llms import HuggingFaceHub
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import LanceDB
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.document_loaders import WebBaseLoader, PyPDFLoader, DirectoryLoader
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from prettytable import PrettyTableHF_TOKEN = "hf*********"
os.environ["HUGGINGFACEHUB_API_TOKEN"] = HF_TOKEN# Loading the web URL and breaking down the information into chunks
start_time = time.time()loader = WebBaseLoader("https://gameofthrones.fandom.com/wiki/Jon_Snow")
documents_loader = DirectoryLoader('data', glob="./*.pdf", loader_cls=PyPDFLoader)# URL loader
url_docs = loader.load()# Document loader
data_docs = documents_loader.load()# Combining all the information into a single variable
docs = url_docs + data_docs# Specify chunk size and overlap
chunk_size = 256
chunk_overlap = 20
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
chunks = text_splitter.split_documents(docs)# Specify Embedding Model
embedding_model_name = 'sentence-transformers/all-MiniLM-L6-v2'
embeddings = HuggingFaceEmbeddings(model_name=embedding_model_name, model_kwargs={'device': 'cpu'})# Specify Vector Database
vectorstore_start_time = time.time()
database_name = "LanceDB"
db = lancedb.connect("src/lance_database")
table = db.create_table("rag_sample",data=[{"vector": embeddings.embed_query("Hello World"),"text": "Hello World","id": "1",}],mode="overwrite",
)
docsearch = LanceDB.from_documents(chunks, embeddings, connection=table)
vectorstore_end_time = time.time()# Specify Retrieval Information
search_kwargs = {"k": 3}
retriever = docsearch.as_retriever(search_kwargs = {"k": 3})# Specify Model Architecture
llm_repo_id = "huggingfaceh4/zephyr-7b-alpha"
model_kwargs = {"temperature": 0.5, "max_length": 4096, "max_new_tokens": 2048}
model = HuggingFaceHub(repo_id=llm_repo_id, model_kwargs=model_kwargs)template = """
{query}
"""prompt = ChatPromptTemplate.from_template(template)rag_chain_start_time = time.time()
rag_chain = ({"context": retriever, "query": RunnablePassthrough()}| prompt| model| StrOutputParser()
)
rag_chain_end_time = time.time()def get_complete_sentence(response):last_period_index = response.rfind('.')if last_period_index != -1:return response[:last_period_index + 1]else:return response# Invoke the RAG chain and retrieve the response
rag_invoke_start_time = time.time()
response = rag_chain.invoke("Who killed Jon Snow?")
rag_invoke_end_time = time.time()# Get the complete sentence
complete_sentence_start_time = time.time()
complete_sentence = get_complete_sentence(response)
complete_sentence_end_time = time.time()# Create a table
table = PrettyTable()
table.field_names = ["Task", "Time Taken (Seconds)"]# Add rows to the table
table.add_row(["Vectorstore Creation", round(vectorstore_end_time - vectorstore_start_time, 2)])
table.add_row(["RAG Chain Setup", round(rag_chain_end_time - rag_chain_start_time, 2)])
table.add_row(["RAG Chain Invocation", round(rag_invoke_end_time - rag_invoke_start_time, 2)])
table.add_row(["Complete Sentence Extraction", round(complete_sentence_end_time - complete_sentence_start_time, 2)])# Additional information in the table
table.add_row(["Embedding Model", embedding_model_name])
table.add_row(["LLM (Language Model) Repo ID", llm_repo_id])
table.add_row(["Vector Database", database_name])
table.add_row(["Temperature", model_kwargs["temperature"]])
table.add_row(["Max Length Tokens", model_kwargs["max_length"]])
table.add_row(["Max New Tokens", model_kwargs["max_new_tokens"]])
table.add_row(["Chunk Size", chunk_size])
table.add_row(["Chunk Overlap", chunk_overlap])
table.add_row(["Number of Documents", len(docs)])print("\nComplete Sentence:")
print(complete_sentence)# Print the table
print("\nExecution Timings:")
print(table)

为了提高可读性并以结构化的表格格式呈现执行信息,我使用了 PrettyTable 库。您可以使用命令 pip3 install prettytable 将其添加到您的虚拟环境中。

所以这是我在不到1分钟内收到的回复,对于初学者来说相当可观。所需时间可能会因系统配置而异,但我相信您只需几分钟就能得到不错的结果。

所以,如果需要更长时间,请耐心等待。

Human: 
Question : Who killed Jon Snow?Answer: 
In the TV series Game of Thrones, Jon Snow was stabbed by his 
fellow Night's Watch members in season 5, episode 9, 
"The Dance of Dragons." However, he was later resurrected by Melisandre 
in season 6, episode 3, "Oathbreaker." So, technically, 
no one killed Jon Snow in the show.Execution Timings:
+------------------------------+----------------------------------------+
|             Task             |          Time Taken (Seconds)          |
+------------------------------+----------------------------------------+
|     Vectorstore Creation     |                 16.21                  |
|       RAG Chain Setup        |                  0.03                  |
|     RAG Chain Invocation     |                  2.06                  |
| Complete Sentence Extraction |                  0.0                   |
|       Embedding Model        | sentence-transformers/all-MiniLM-L6-v2 |
| LLM (Language Model) Repo ID |     huggingfaceh4/zephyr-7b-alpha      |
|       Vector Database        |                LanceDB                 |
|         Temperature          |                  0.5                   |
|      Max Length Tokens       |                  4096                  |
|        Max New Tokens        |                  2048                  |
|          Chunk Size          |                  256                   |
|        Chunk Overlap         |                   20                   |
|     Number of Documents      |                   39                   |
+------------------------------+----------------------------------------+

玩得开心,尝试各种数据来源!你可以尝试更改网站地址,添加新的PDF文件,或者稍微改变模板。这些都很有趣,你永远不知道会得到什么!

 接下来呢?

这里有很多东西可以调整。

我们可以切换到更有效的嵌入模型以获得更好的索引,尝试不同的检索技术来改进检索器,添加重新排序器以提高文档的排名,或者使用一个上下文窗口更大、响应时间更快的更先进的LLM。

基本上,每个 RAG 应用程序都只是基于这些因素的增强版本。然而,RAG 应用程序的基本工作原理始终保持不变。

相关文章:

使用 RAG 创建 LLM 应用程序

如果您考虑为您的文件或网站制作一个能够回应您的个性化机器人&#xff0c;那么您来对地方了。我可以帮助您使用Langchain和RAG策略来创建这样一个机器人。 了解ChatGPT的局限性和LLMs ChatGPT和其他大型语言模型&#xff08;LLMs&#xff09;经过广泛训练&#xff0c;以理解…...

第13章 网络 Page744~746 asio核心类 ip::tcp::endPoint

2. ip::tcp::endpoint ip::tcp::socket用于连接TCP服务端的 async_connect()方法的第一个入参是const endpoint_type& peer_endpoint. 此处的类型 endpoint_type 是 ip::tcp::endpoint 在 在 ip::tcp::socket 类内部的一个别名。 libucurl 库采用字符串URL表达目标的地…...

面试浏览器框架八股文十问十答第一期

面试浏览器框架八股文十问十答第一期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;什么是 XSS 攻击&#…...

多线程的基本原理学习

由一个问题引发的思考 线程的合理使用能够提升程序的处理性能&#xff0c;主要有两个方面&#xff0c;第一个是能够利用多核cpu以及超线程技术来实现线程的并行执行&#xff1b;第二个是线程的异步化执行相比于同步执行来说&#xff0c;异步执行能够很好的优化程序的处理性能提…...

C/C++进制转换

十进制转化为二进制 进制转化#include <iostream> using namespace std;void change(int); int main() {int num;cout << "请输入一个十进制数: ";cin >> num;cout << "转化后的二进制数为: ";change(num);return 0; } void chan…...

使用 Coze 搭建 TiDB 助手

导读 本文介绍了使用 Coze 平台搭建 TiDB 文档助手的过程。通过比较不同 AI Bot 平台&#xff0c;突出了 Coze 在插件能力和易用性方面的优势。文章深入讨论了实现原理&#xff0c;包括知识库、function call、embedding 模型等关键概念&#xff0c;最后成功演示了如何在 Coze…...

Arduino程序简单入门

文章目录 一、结构1.1 setup()1.2 loop() 二、结构控制2.1 if2.2 if...else2.3 switch case2.4 for2.5 while2.6 do...while2.7 break2.8 continue2.9 return2.10 goto 三、扩展语法3.1 ;&#xff08;分号&#xff09;3.2 {}&#xff08;花括号&#xff09;3.3 //&#xff08;单…...

QT+OSG/osgEarth编译之八十三:osgdb_ogr+Qt编译(一套代码、一套框架,跨平台编译,版本:OSG-3.6.5插件库osgdb_ogr)

文章目录 一、osgdb_ogr介绍二、文件分析三、pro文件四、编译实践一、osgdb_ogr介绍 osgDB是OpenSceneGraph(OSG)库中的一个模块,用于加载和保存3D场景数据。osgDB_ogr是osgDB模块中的一个插件,它提供了对OGR(开放地理空间联盟)库的支持。 OGR是一个开源的地理空间数据…...

开年炸裂-Sora/Gemini

最新人工智能消息 谷歌的新 Gemini 模型 支持多达 1M的Token&#xff0c;可以分析长达一小时的视频 1M Token可能意味着分析700,000 个单词、 30,000 行代码或11 小时的音频、总结、改写和引用内容。 Comment&#xff1a;google公司有夸大的传统&#xff0c;所以真实效果需要上…...

vue前端系统启动报错Module not found: Error: Can‘t resolve ‘sass-loader‘

1、确认项目中是否已安装 node-sass 包。sass-loader 是依赖于 node-sass 包的&#xff0c;如果没有安装 node-sass 包&#xff0c;也会导致无法找到 sass-loader 包。 npm ls node-sass安装 node-sass 包&#xff1a; npm install --save-dev node-sass2、确认项目中是否已安…...

HTML | DOM | 网页前端 | 常见HTML标签总结

文章目录 1.前端开发简单分类2.前端开发环境配置3.HTML的简单介绍4.常用的HTML标签介绍 1.前端开发简单分类 前端开发&#xff0c;这里是一个广义的概念&#xff0c;不单指网页开发&#xff0c;它的常见分类 网页开发&#xff1a;前端开发的主要领域&#xff0c;使用HTML、CS…...

乡政府|乡政府管理系统|基于Springboot的乡政府管理系统设计与实现(源码+数据库+文档)

乡政府管理系统目录 目录 基于Springboot的乡政府管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、活动信息管理 3、新闻类型管理 4、新闻动态管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推…...

存储系统如何规避数据静默错误SDC?

存储系统规避数据静默错误&#xff08;Silent Data Corruption, SDC&#xff09;是一项复杂且关键的任务&#xff0c;涉及多个层次的技术和策略。数据静默错误是指在存储或传输过程中发生的错误&#xff0c;这些错误未被检测出来&#xff0c;因此无法立即纠正&#xff0c;可能导…...

《Linux 简易速速上手小册》第8章: 安全性与加固(2024 最新版)

文章目录 8.1 防火墙与安全策略8.1.1 重点基础知识8.1.2 重点案例&#xff1a;配置 iptables 以保护 Web 服务器8.1.3 拓展案例 1&#xff1a;使用 firewalld 配置动态防御区域8.1.4 拓展案例 2&#xff1a;配置 ufw 以简化管理 8.2 SSH 安全最佳实践8.2.1 重点基础知识8.2.2 重…...

Ubuntu Desktop 显示文件路径

Ubuntu Desktop 显示文件路径 1. GUI hot key2. CLIReferences 1. GUI hot key Ctrl L: 显示文件路径 2. CLI right click -> Open in Terminal -> pwd strongforeverstrong:~/Desktop$ pwd /home/strong/DesktopReferences [1] Yongqiang Cheng, https://yongqiang…...

【Java程序设计】【C00270】基于Springboot的moba类游戏攻略分享平台(有论文)

基于Springboot的moba类游戏攻略分享平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的游戏攻略分享平台 本系统分为系统功能模块、管理员功能模块、以及用户后台功能模块。 系统功能模块&#xff1a;在平台首…...

【旧文更新】【优秀毕设】人脸识别打卡/签到/考勤管理系统(OpenCV+最简基本库开发、可移植树莓派 扩展网络图像推流控制 验证码及Excel邮件发送等功能)

【旧文更新】【优秀毕设】人脸识别打卡/签到/考勤管理系统&#xff08;OpenCV最简基本库开发、可移植树莓派 扩展网络图像推流控制 验证码及Excel邮件发送等功能&#xff09; 文章目录 关于旧文新发毕设结构主页面验证码识别效果管理页面人脸信息采集管理实时数据更新签到结果…...

模型 4i(趣味、利益、互动、个性)理论

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_总纲目录。重在提升认知。以用户为中心营销。 1 模型 4i(趣味、利益、互动、个性)理论的应用 1.1 4i理论在电子商务中的应用 小米公司在其电子商务平台上运用了 4i理论&#xff0c;取得了较好的效果。具体表现如下…...

解线性方程组(二)——Jacobi迭代法求解(C++)

迭代法 相比于直接法求解&#xff0c;迭代法使用多次迭代来逐渐逼近解&#xff0c;其精度比不上直接法&#xff0c;但是其速度会比直接法快很多&#xff0c;计算精度可控&#xff0c;特别适用于求解系数矩阵为大型稀疏矩阵的方程组。 Jacobi迭代法 假设有方程组如下&#xf…...

信息安全技术基础知识

一、考点分布 信息安全基础&#xff08;※※&#xff09;信息加密解密技术&#xff08;※※※&#xff09;密钥管理技术&#xff08;※※&#xff09;访问控制及数字签名技术&#xff08;※※※&#xff09;信息安全的保障体系 二、信息安全基础 信息安全包括5个基本要素&#…...

使用Taro开发鸿蒙原生应用——快速上手,鸿蒙应用开发指南

导读 本指南为开发者提供了使用 Taro 框架开发鸿蒙原生应用的快速入门方法。Taro&#xff0c;作为一个多端统一开发框架&#xff0c;让开发者能够使用一套代码同时适配多个平台&#xff0c;包括鸿蒙系统。文章将详细介绍如何配置开发环境&#xff0c;以及如何利用 Taro 的特性…...

C语言指针(初阶)

文章目录 1:内存与地址1.1内存1.2:如何理解编址 2:指针变量与地址2.1:指针变量与解引用操作符2.1.1:指针变量2.1.2:如何拆解指针类型2.1.3:解引用操作符 2.2:指针变量的大小 3:指针变量类型的意义代码1解引用修改前解引用修改后 代码2解引用修改前解引用修改后 4:const修饰指针…...

Python循环语句——for循环的嵌套使用

一、引言 在Python编程中&#xff0c;循环是控制程序流程的重要工具&#xff0c;它允许我们重复执行某段代码&#xff0c;直到满足特定的条件为止。其中&#xff0c;for循环是Python中最常用的循环类型之一。而嵌套循环&#xff0c;即在一个循环内部再嵌套另一个循环&#xff…...

Java创建线程真的有三种方式吗?

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨ &#x1f440;&#x1f440;&#x1f440; 个人博客&#xff1a;小奥的博客 &#x1f44d;&#x1f44d;&#x1f44d;&#xff1a;个人CSDN ⭐️⭐️⭐️&#xff1a;传送门 &#x1f379; 本人24应届生一枚&#xff0c;技术和水平有限&am…...

17-k8s控制器资源-job控制

job控制器&#xff1a;就是一次性任务的pod控制器&#xff0c;pod完成作业后不会重启&#xff0c;其重启策略是&#xff1a;Never 1&#xff0c;job控制器案例描述 启动一个pod&#xff0c;执行完成一个事件&#xff0c;然后pod关闭&#xff1b; 事件&#xff1a;计算π的值&a…...

lazarus:LCL 嵌入 fpwebview 组件,做一个简单浏览器

从 https://github.com/PierceNg/fpwebview 下载 fpwebview-master.zip 简单易用。 先请看 \fpwebview-master\README.md cd \lazarus\projects\fpwebview-master\demo\lclembed 修改 lclembed.lpr 如下&#xff0c;将 fphttpapp. 注释掉&#xff0c;因为我用不上 a simple…...

c++类和对象新手保姆级上手教学(上)

前言&#xff1a; c其实顾名思义就是c语言的升级版&#xff0c;很多刚学c的同学第一感觉就是比c语言难学很多&#xff0c;其实没错&#xff0c;c里的知识更加难以理解可以说杂且抽象&#xff0c;光是类和对象&#xff0c;看起来容易&#xff0c;但想完全吃透&#xff0c;真的挺…...

可变参数(c/c++)

目录 一、C语言版本 二、C的实现方法 2.1数据包 2.2sizeof...运算符 2.3可变参数模板的使用 2.4emplace_back() 有时候我们在编写函数时&#xff0c;可能不知道要传入的参数个数&#xff0c;类型 。比如我们要实现一个叠加函数&#xff0c;再比如c语言中的printf,c中的emp…...

【数据结构】图

文章目录 图1.图的两种存储结构2.图的两种遍历方式3.最小生成树的两种算法&#xff08;无向连通图一定有最小生成树&#xff09;4.单源最短路径的两种算法5.多源最短路径 图 1.图的两种存储结构 1. 图这种数据结构相信大家都不陌生&#xff0c;实际上图就是另一种多叉树&…...

32.3K Star,再见 Postman,这款开源 API 客户端更香

Hi&#xff0c;骚年&#xff0c;我是大 G&#xff0c;公众号「GitHub指北」会推荐 GitHub 上有趣有用的项目&#xff0c;一分钟 get 一个优秀的开源项目&#xff0c;挖掘开源的价值&#xff0c;欢迎关注。 使用 API 工具来调试接口是后端开发经常会使用的&#xff0c;之前一直…...

Python循环语句——continue和break

一、引言 在Python编程中&#xff0c;循环是常见的控制流语句&#xff0c;它允许我们重复执行一段代码&#xff0c;直到满足某个条件为止。而在循环中&#xff0c;continue和break是两个非常重要的控制语句&#xff0c;它们可以帮助我们更加灵活地控制循环的行为。 二、contin…...

C++面向对象程序设计-北京大学-郭炜【课程笔记(三)】

C面向对象程序设计-北京大学-郭炜【课程笔记&#xff08;三&#xff09;】 1、构造函数&#xff08;constructor&#xff09;1.1、基本概念 2、赋值构造函数2.1、基本概念2.1、复制构造函数起作用的三种情况2.2、常引用参数的使用 3、类型转换构造函数3.1、什么事类型转换构造函…...

Linux:搭建docker私有仓库(registry)

当我们内部需要存储镜像时候&#xff0c;官方提供了registry搭建好直接用&#xff0c;废话少说直接操作 1.下载安装docker 在 Linux 上安装 Docker Desktop |Docker 文档https://docs.docker.com/desktop/install/linux-install/安装 Docker 引擎 |Docker 文档https://docs.do…...

用HTML、CSS和JS打造绚丽的雪花飘落效果

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetGBK"><style>* {margin: 0;padding: 0;}#box {width: 100vw;heig…...

订餐|网上订餐系统|基于springboot的网上订餐系统设计与实现(源码+数据库+文档)

网上订餐系统目录 目录 基于springboot的网上订餐系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户功能模块的实现 &#xff08;1&#xff09;用户注册界面 &#xff08;2&#xff09;用户登录界面 &#xff08;3&#xff09;菜品详情界面 &#xff08…...

从零开始学howtoheap:解题西湖论剑Storm_note

how2heap是由shellphish团队制作的堆利用教程&#xff0c;介绍了多种堆利用技术&#xff0c;后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;优化pwn虚拟机配置支持libc等指…...

Rust 基本环境安装

rust 基本介绍请看上一篇文章&#xff1a;rust 介绍 rustup 介绍 rustup 是 Rust 语言的安装器和版本管理工具。通过 rustup&#xff0c;可以轻松地安装 Rust 编译器&#xff08;rustc&#xff09;、标准库和文档。它也允许你切换不同的 Rust 版本或目标平台&#xff0c;以及…...

【电源】POE系统供电原理(二)

转载本博客文章&#xff0c;请注明出处 ​ 上一篇文章中&#xff0c;有提到POE系统工作原理及动态检测机制&#xff0c;下面我们继续介绍受电端PD技术及原理。POE供电系统包含PSE、PD及互联接口部分组成&#xff0c;如下图所示。 图1 POE供电系统 PSE控制器的主要作用&#xff…...

GPU独显下ubuntu屏幕亮度不能调节解决方法

GPU独显下屏幕亮度不能调节&#xff08;假设你已经安装了合适的nvidia显卡驱动&#xff09;&#xff0c;我试过修改 /etc/default/grub 的 GRUB_CMDLINE_LINUX_DEFAULT"quiet splash acpi_backlightvendor" &#xff0c;没用。修改和xorg.conf相关的文件&#xff0c;…...

Linux篇:网络基础1

一、网络基础&#xff1a;网络本质就是在获取和传输数据&#xff0c;而系统的本质是在加工和处理数据。 1、应用问题&#xff1a; ①如何处理发来的数据&#xff1f;—https/http/ftp/smtp ②长距离传输的数据丢失的问题&#xff1f;——TCP协议 ③如何定位的主机的问题&#…...

RK3568笔记十七:LVGL v8.2移植

若该文为原创文章&#xff0c;转载请注明原文出处。 本文介绍嵌入式轻量化图形库LVGL 8.2移植到Linux开发板ATK-RK3568上的步骤。 主要是参考大佬博客&#xff1a; LVGL v8.2移植到IMX6ULL开发板_lvgl移植到linux-CSDN博客 一、环境 1、平台&#xff1a;rk3568 2、开发板:…...

C#系列-C#访问MongoDB+redis+kafka(7)

目录 一、 C#中访问MongoDB. 二、 C#访问redis. 三、 C#访问kafka. C#中访问MongoDB 在C#中访问MongoDB&#xff0c;你通常会使用MongoDB官方提供的MongoDB C#/.NET Driver。这个驱动提供了丰富的API来执行CRUD&#xff08;创建、读取、更新、删除&#x…...

(12)Hive调优——count distinct去重优化

离线数仓开发过程中经常会对数据去重后聚合统计&#xff0c;count distinct使得map端无法预聚合&#xff0c;容易引发reduce端长尾&#xff0c;以下是count distinct去重调优的几种方式。 解决方案一&#xff1a;group by 替代 原sql 如下&#xff1a; #7日、14日的app点击的…...

记录 | 验证pytorch-cuda是否安装成功

检测程序如下&#xff1a; import torchprint(torch.__version__) print(torch.cuda.is_available()) 或者用终端 Shell&#xff0c;运行情况如下...

LeetCode 239.滑动窗口的最大值 Hot100 单调栈

给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a;nums [1,3,-1,-3,5,3,6,7], k 3 输…...

463. Island Perimeter(岛屿的周长)

问题描述 给定一个 row x col 的二维网格地图 grid &#xff0c;其中&#xff1a;grid[i][j] 1 表示陆地&#xff0c; grid[i][j] 0 表示水域。 网格中的格子 水平和垂直 方向相连&#xff08;对角线方向不相连&#xff09;。整个网格被水完全包围&#xff0c;但其中恰好有…...

如何解决缓存和数据库的数据不一致问题

数据不一致问题是操作数据库和操作缓存值的过程中&#xff0c;其中一个操作失败的情况。实际上&#xff0c;即使这两个操作第一次执行时都没有失败&#xff0c;当有大量并发请求时&#xff0c;应用还是有可能读到不一致的数据。 如何更新缓存 更新缓存的步骤就两步&#xff0…...

linux系统下vscode portable版本的python环境搭建003:venv

这里写自定义目录标题 python安装方案一. 使用源码安装&#xff08;有[构建工具](https://blog.csdn.net/ResumeProject/article/details/136095629)的情况下&#xff09;方案二.使用系统包管理器 虚拟环境安装TESTCG 本文目的&#xff1a;希望在获得一个新的系统之后&#xff…...

使用TinyXML-2解析XML文件

一、XML介绍 当我们想要在不同的程序、系统或平台之间共享信息时&#xff0c;就需要一种统一的方式来组织和表示数据。XML&#xff08;EXtensible Markup Language&#xff0c;即可扩展标记语言&#xff09;是一种用于描述数据的标记语言&#xff0c;它让数据以一种结构化的方…...

Linux:docker在线仓库(docker hub 阿里云)基础操作

把镜像放到公网仓库&#xff0c;这样可以方便大家一起使用&#xff0c;当需要时直接在网上拉取镜像&#xff0c;并且你可以随时管理自己的镜像——删除添加或者修改。 1.docker hub仓库 2.阿里云加速 3.阿里云仓库 由于docker hub是国外的网站&#xff0c;国内的对数据的把控…...