Press "Enter" to skip to content

构建你的第一个LML应用所需知道的一切

文档加载器、嵌入、向量存储和提示模板的逐步教程

使用上下文注入构建自己的聊天机器人 — 图片作者

目录

您可以通过点击图片浏览本文。

如果您只是想要一个简短的教程,来了解如何构建一个简单的LLM应用程序,您可以跳到第6节“创建向量存储”,在那里您将拥有构建最小化LLM应用程序所需的所有代码片段,包括向量存储、提示模板和LLM调用。

构建你的第一个LML应用所需知道的一切 机器学习 第2张

构建你的第一个LML应用所需知道的一切 机器学习 第3张

构建你的第一个LML应用所需知道的一切 机器学习 第4张

构建你的第一个LML应用所需知道的一切 机器学习 第5张

构建你的第一个LML应用所需知道的一切 机器学习 第6张

构建你的第一个LML应用所需知道的一切 机器学习 第7张

构建你的第一个LML应用所需知道的一切 机器学习 第8张

构建你的第一个LML应用所需知道的一切 机器学习 第9张

目录

为什么我们需要LLMs

语言的发展使我们人类走得如此之远,它使我们能够高效地分享知识并以我们今天所知道的形式进行协作。因此,我们大部分的集体知识仍然通过不组织的书面文本来保存和传递。

过去20年来采取的旨在数字化信息和流程的倡议,往往集中于在关系型数据库中累积越来越多的数据。这种方法使传统的分析机器学习算法能够处理和理解我们的数据。

然而,尽管我们极力将越来越多的数据以结构化的方式存储,我们仍无法捕捉和处理我们的所有知识。

大约80%的公司数据是非结构化的,例如工作描述、简历、电子邮件、文本文档、幻灯片、语音记录、视频和社交媒体

公司数据分布 — 图片作者

到GPT3.5的发展和进步标志着一个重要的里程碑,因为它使我们能够有效地解释和分析各种数据集,无论它们的结构或缺乏结构如何。如今,我们拥有可以理解和生成各种内容的模型,包括文本、图像和音频文件。

那么,我们如何利用它们的能力来满足我们的需求和数据呢?

微调 vs. 上下文注入

一般来说,我们有两种根本不同的方法来使大型语言模型回答LLM无法知道的问题: 模型微调上下文注入

微调

微调是指使用额外的数据训练现有的语言模型以优化其特定任务的方法。

与从头开始训练语言模型不同,使用预训练模型,如BERT或LLama,并通过添加用例特定的训练数据来适应特定任务的需求。

斯坦福大学的一个团队使用LLM Llama 进行微调,使用了5万个用户/模型交互的示例。结果是一个聊天机器人,它与用户交互并回答查询。这个微调步骤改变了模型与最终用户交互的方式。

→ 微调的误解

PLLMs(预训练语言模型)的微调是一种调整模型特定任务的方法,但它并不能真正让你将自己的领域知识注入到模型中。这是因为模型已经在大量的通用语言数据上进行了训练,你的具体领域数据通常不足以覆盖模型已经学习的内容。

因此,当你微调模型时,它可能偶尔提供正确的答案,但它经常会失败,因为它严重依赖于它在预训练期间学到的信息,这些信息可能不准确或与你的特定任务无关。换句话说,微调帮助模型适应它的通信方式,但不一定是它通信的内容。(保时捷AG,2023)

这就是上下文注入发挥作用的地方。

上下文学习 / 上下文注入

在使用上下文注入时,我们不是修改LLM本身,而是专注于提示本身,并向提示注入相关上下文。

因此,我们需要考虑如何为提示提供正确的信息。在下面的图中,您可以看到整个过程的示意图。我们需要一个能够将文本片段彼此比较的过程。

Similarity search in our unstructured data — Image by the author

这可以通过嵌入来完成。使用嵌入,我们将文本转换为向量,从而使我们能够在多维嵌入空间中表示文本。空间中彼此靠近的点通常在相同的上下文中使用。为了防止这种相似性搜索持续不断地进行,我们将我们的向量存储在向量数据库中并索引它们。

微软向我们展示了Bing Chat如何工作。Bing结合了LLM理解语言和上下文的能力以及传统Web搜索的效率。

本文的目的是演示创建一个简单的解决方案的过程,该解决方案使我们能够分析自己的文本和文档,然后将从中获得的见解纳入我们的解决方案返回给用户的答案中。我将描述实现端到端解决方案所需的所有步骤和组件。

那么我们如何利用LLM的能力来满足我们的需求呢?让我们一步一步地过一遍。

一步一步地教程——您的第一个LLM应用程序

在接下来的内容中,我们将利用LLMs来回答有关我们个人数据的询问。为了实现这一点,我首先将我们个人数据的内容转移至向量数据库中。这一步是至关重要的,因为它使我们能够高效地搜索文本中的相关部分。我们将利用这些来自我们数据的信息和LLMs的能力来解释文本以回答用户的问题。

我们还可以引导聊天机器人仅根据我们提供的数据回答问题。这样,我们可以确保聊天机器人专注于手头的数据并提供准确和相关的回答。

要实现我们的用例,我们将严重依赖LangChain。

什么是LangChain?

“LangChain是一个基于语言模型开发应用程序的框架。”(Langchain, 2023)

因此,LangChain是一个Python框架,旨在支持创建各种LLM应用程序,例如聊天机器人、摘要工具以及基本上任何您想要创建的工具,以利用LLM的强大功能。该库结合了我们需要的各种组件。我们可以将这些组件连接在所谓的链中。

Langchain的最重要的模块是(Langchain, 2023):

  1. 模型:各种模型类型的接口
  2. 提示:提示管理、提示优化和提示序列化
  3. 索引:文档加载器、文本分割器、向量存储——使访问数据更快速、更高效
  4. 链:链超越了单个LLM调用,它们允许我们设置调用序列

在下面的图像中,您可以看到这些组件在哪里发挥作用。我们使用索引模块中的文档加载器和文本分割器加载和处理自己的非结构化数据。提示模块允许我们将找到的内容注入到我们的提示模板中,最后,我们使用模型模块将提示发送到我们的模型。

Components you need for your LLM app — Image by the author

5. 代理:代理是使用LLMs进行选择以执行哪些操作的实体。在执行操作之后,他们观察该操作的结果并重复该过程,直到完成任务。

Agents decide autonomously how to perform a particular task — Image by the author

我们在第一步中使用Langchain来加载文档、分析文档并使其高效可搜索。索引文本后,识别对回答用户问题有关联的文本片段应该变得更加高效。

我们简单应用程序所需的是当然是LLM。我们将使用通过OpenAI API的GPT3.5。然后我们需要一个向量存储器,使我们能够将LLM与我们自己的数据一起使用。如果我们想为不同的查询执行不同的操作,我们需要一个代理来决定每个查询应该发生什么。

让我们从头开始。我们首先需要导入我们自己的文档。

以下部分描述了包含在LangChain的加载器模块中的哪些模块,以从不同的来源加载不同类型的文档。

1. 使用Langchain加载文档

LangChain能够从各种来源加载许多文档。您可以在LangChain文档中找到可能的文档加载器列表。其中包括用于HTML页面、S3存储桶、PDF、Notion、Google Drive等的加载器。

对于我们的简单示例,我们使用可能未包含在GPT3.5的训练数据中的数据。我使用了关于GPT4的维基百科文章,因为我假设GPT3.5对GPT4的了解有限。

对于这个最小的例子,我没有使用LangChain的任何加载器,我只是使用BeautifulSoup直接从维基百科[许可证:CC BY-SA 3.0]中抓取文本。

请注意,应根据网站的使用条款和所需使用的文本和数据的版权/许可证状态来收集网站数据。

import requestsfrom bs4 import BeautifulSoupurl = "https://en.wikipedia.org/wiki/GPT-4"response = requests.get(url)soup = BeautifulSoup(response.content, 'html.parser')# find the content divcontent_div = soup.find('div', {'class': 'mw-parser-output'})# remove unwanted elements from divunwanted_tags = ['sup', 'span', 'table', 'ul', 'ol']for tag in unwanted_tags:    for match in content_div.findAll(tag):        match.extract()print(content_div.get_text())

构建你的第一个LML应用所需知道的一切 机器学习 第15张

2. 将文档拆分为文本片段

接下来,我们必须将文本分成称为文本块的较小部分。每个文本块代表嵌入空间中的一个数据点,使计算机能够确定这些块之间的相似性。

下面的文本片段正在使用来自langchain的文本分割器模块。在这种情况下,我们指定了100的块大小和20的块重叠。通常使用更大的文本块,但您可以进行一些实验以找到您的用例的最佳大小。您只需要记住,每个LLM都有一个令牌限制(对于GPT 3.5,为4000令牌)。由于我们正在将文本块插入我们的提示中,因此我们需要确保整个提示不超过4000个令牌。

from langchain.text_splitter import RecursiveCharacterTextSplitterarticle_text = content_div.get_text()text_splitter = RecursiveCharacterTextSplitter(    # Set a really small chunk size, just to show.    chunk_size = 100,    chunk_overlap  = 20,    length_function = len,)texts = text_splitter.create_documents([article_text])print(texts[0])print(texts[1])

构建你的第一个LML应用所需知道的一切 机器学习 第16张

这将我们的整个文本拆分如下:

Langchain文本分割器-作者提供的图像

3. 从文本块到嵌入

现在,我们需要使文本组件可理解且可与我们的算法进行比较。我们必须找到一种方法将人类语言转换为数字形式,由位和字节表示。

该图像提供了一个简单的示例,对大多数人来说可能很明显。但是,我们需要找到一种方法,使计算机理解名称“查尔斯”与男性相关,而不是女性,并且如果查尔斯是男性,则他是国王而不是女王。

使计算机理解语言-作者提供的图像

在过去的几年中,出现了新的方法和模型,实现了这一点。我们想要的是一种方式,能够将单词的含义转换为n维空间中的向量,以便我们能够将文本块相互比较甚至计算它们的相似度。

嵌入模型通过分析单词通常使用的上下文来尝试学习这一点。由于茶、咖啡和早餐通常在相同的上下文中使用,因此它们在n维空间中比茶和豌豆更接近。茶和豌豆听起来相似,但很少一起使用。(AssemblyAI,2022)

嵌入分析单词使用的上下文,而不是单词本身-作者提供的图像

嵌入模型为嵌入空间中的每个单词提供一个向量。最后,通过使用向量表示它们,我们能够执行数学计算,例如计算单词之间的相似性作为数据点之间的距离。

二维嵌入空间中的随机英文单词-作者提供的图像

将文本转换为嵌入式向量有几种方法,例如Word2Vec、GloVe、fastText或ELMo。

嵌入式模型

为了在嵌入式向量中捕获单词之间的相似性,Word2Vec使用一个简单的神经网络。我们使用大量文本数据训练此模型,并希望创建一个能够为每个单词分配一个n维嵌入式空间中的点并以向量形式描述其含义的模型。

在训练过程中,我们为数据集中的每个唯一单词分配一个输入层中的神经元。在下面的图像中,您可以看到一个简单的例子。在这种情况下,隐藏层仅包含两个神经元。之所以是两个,是因为我们要在二维嵌入空间中映射单词。(现有的模型实际上更大,因此以更高维度表示单词 – 例如,OpenAI的Ada嵌入式模型使用1536维)在训练过程结束后,各个权重描述了嵌入空间中的位置。

在此示例中,我们的数据集仅包括一个句子:“Google是一家技术公司”。句子中的每个单词都是神经网络(NN)的输入。因此,我们的网络有五个输入神经元,每个单词一个。

在训练过程中,我们专注于为每个输入单词预测下一个单词。当我们从句子开头开始时,与单词“Google”相对应的输入神经元接收值为1,而其他神经元接收值为0。我们的目标是训练网络在此特定情况下预测单词“is”。

Word2Vec: Learning word embeddings — Image by the author

实际上,有多种方法来学习嵌入式模型,每种方法在训练过程中都有自己独特的预测输出方式。常用的两种方法是CBOW(连续词袋)和Skip-gram。

在CBOW中,我们将周围的单词作为输入,并旨在预测中间的单词。相反,在Skip-gram中,我们将中间的单词作为输入,并尝试预测出现在其左侧和右侧的单词。但是,我不会深入研究这些方法的复杂性。让我们只说这些方法为我们提供了嵌入式,这些表示通过分析大量文本数据的上下文来捕获单词之间的关系。

CBOW vs. Skip-gram — Image by the author

如果您想了解更多关于嵌入式的信息,在互联网上有丰富的信息可用。但是,如果您喜欢可视化和分步指南,您可能会发现观看Josh Starmer的StatQuest中的Word Embedding and Word2Vec有所帮助。

回到嵌入式模型

我刚才试图使用一个简单的例子在二维嵌入空间中解释的内容也适用于更大的模型。例如,标准的Word2Vec向量具有300个维度,而OpenAI的Ada模型具有1536个维度。这些预训练向量使我们能够以如此精确的方式捕捉单词之间的关系和含义,以至于我们可以使用它们进行计算。例如,使用这些向量,我们可以发现法国+柏林-德国=巴黎,快+暖-快=更暖。 (Tazzyman,n.d.)

Calculate with embeddings — Image by the author

接下来,我们要使用OpenAI API不仅使用OpenAI的LLM,还要利用他们的嵌入式模型。

注意:嵌入式模型和LLM之间的区别在于,嵌入式模型专注于创建单词或短语的向量表示以捕捉其含义和关系,而LLM是多功能模型,训练有素,可根据提供的提示或查询生成连贯且上下文相关的文本。

OpenAI 嵌入模型

与 OpenAI 的各种 LLM 一样,您还可以选择各种嵌入模型,例如 Ada、Davinci、Curie 和 Babbage。其中,Ada-002 目前是速度最快且最具成本效益的模型,而 Davinci 通常提供最高的准确性和性能。然而,您需要自己尝试并找到最佳模型以适用于您的用例。如果您想要详细了解 OpenAI 嵌入,可以参考 OpenAI 文档。

我们在嵌入模型中的目标是将文本块转换为向量。在 Ada 的第二代模型中,这些向量具有 1536 个输出维度,这意味着它们代表着 1536 维空间中的特定位置或方向。

OpenAI 在其文档中将这些嵌入向量描述如下:

“数值相似的嵌入也是语义相似的。例如,”canine companions say“的嵌入向量将比“meow”的嵌入向量更类似于“woof”的嵌入向量。”(OpenAI,2022)

在嵌入空间中,语义相似的单词或短语彼此更接近 —— 图片由 OpenAI 提供

让我们试试。我们使用 OpenAI 的 API 将我们的文本片段转换为嵌入向量,如下所示:

import openaiprint(texts[0])embedding = openai.Embedding.create(    input=texts[0].page_content, model="text-embedding-ada-002")["data"][0]["embedding"]len(embedding)

构建你的第一个LML应用所需知道的一切 机器学习 第24张

我们将文本,如包含“2023 文本生成语言模型”的第一个文本块,转换为具有 1536 维的向量。通过为每个文本块执行此操作,我们可以在一个 1536 维空间中观察哪些文本块更接近和相似。

让我们试试。我们的目标是通过为问题生成嵌入向量,然后将其与空间中的其他数据点进行比较,以将用户的问题与文本块进行比较。

哪个文本片段在语义上更接近用户的问题?— 图片由作者提供

当我们将文本块和用户的问题表示为向量时,我们获得了探索各种数学可能性的能力。为了确定两个数据点之间的相似性,我们需要计算它们在多维空间中的接近程度,这是通过距离度量实现的。有几种方法可用于计算点之间的距离。Maarten Grootendorst 在他的一篇小猪AI文章中总结了其中的九种方法。

常用的距离度量方法是余弦相似度。因此,让我们尝试计算我们的问题和文本块之间的余弦相似度:

import numpy as npfrom numpy.linalg import norm# 计算用户问题的嵌入向量users_question = "What is GPT-4?"question_embedding = get_embedding(text=users_question, model="text-embedding-ada-002")# 创建一个列表来存储计算出的余弦相似度cos_sim = []for index, row in df.iterrows():   A = row.ada_embedding   B = question_embedding   # 计算余弦相似度   cosine = np.dot(A,B)/(norm(A)*norm(B))   cos_sim.append(cosine)df["cos_sim"] = cos_simdf.sort_values(by=["cos_sim"], ascending=False)

构建你的第一个LML应用所需知道的一切 机器学习 第26张

现在,我们可以选择要向 LLM 提供的文本块数量来回答问题。

下一步是确定我们想要使用哪个 LLM。

4. 定义您想要使用的模型

Langchain 提供了各种模型和集成,包括 OpenAI 的 GPT 和 Huggingface 等。如果我们决定使用 OpenAI 的 GPT 作为我们的大型语言模型,第一步是定义我们的 API 密钥。目前,OpenAI 提供了一些免费使用能力,但一旦我们超过每月一定数量的令牌,我们就需要切换到付费账户。

如果我们使用GPT来回答类似于使用Google搜索引擎的短问题,成本仍然相对较低。然而,如果我们使用GPT来回答需要提供广泛背景信息的问题,例如个人数据,查询很快就会累积成千上万的标记。这会显著增加成本。但是不要担心,您可以设置成本限制。

什么是标记?

简单来说,标记基本上是一个词或一组词。但是,在英语中,单词可以有不同的形式,例如动词时态、复数或复合词。为了处理这个问题,我们可以使用子词标记化,将单词分解成更小的部分,如其根、前缀、后缀和其他语言元素。例如,“tiresome”这个词可以分成“tire”和“some”,而“tired”可以分成“tire”和“d”。通过这样做,我们可以认识到“tiresome”和“tired”具有相同的词根和类似的派生词。 (Wang, 2023)

OpenAI在其网站上提供了一个标记化器,以便了解标记的概念。根据OpenAI的说法,一个标记通常对应于一般英文文本的~4个字符。这相当于大约3/4个词(因此100个标记~= 75个单词)。您可以在OpenAI的网站上找到一个Tokenizer App,以了解实际上算作标记的内容。

设置使用限制

如果您担心成本,您可以在OpenAI用户门户中找到一个选项来限制月度成本。

您可以在OpenAI的用户帐户中找到API密钥。最简单的方法是在Google中搜索“OpenAI API密钥”。这会直接将您带到设置页面,以创建一个新密钥。

要在Python中使用,您必须将密钥保存为一个新的环境变量,名称为“OPENAI_API_KEY”:

import osos.environment["OPENAI_API_KEY"] = "testapikey213412"

在定义模型时,您可以设置一些首选项。 OpenAI Playground为我们提供了在决定要使用哪些设置之前,玩弄不同参数的可能性:

在Playground WebUI的右侧,您会发现OpenAI提供了几个参数,允许我们影响LLM的输出。值得探索的两个参数是模型选择和温度。

您可以选择从各种不同的模型中选择。 Text-davinci-003模型目前是最大和最强大的。另一方面,像Text-ada-001这样的模型更小、更快、更经济。

下面,您可以看到OpenAI的定价列表摘要。与最强大的模型Davinci相比,Ada更便宜。因此,如果Ada的性能符合我们的需求,我们不仅可以节省金钱,而且可以实现更短的响应时间。

您可以从Davinci开始,然后评估我们是否也可以使用Ada来获得足够好的结果。

所以让我们在Jupyter Notebook中试一试。我们使用langchain连接到GPT。

from langchain.llms import OpenAIllm = OpenAI(temperature=0.7)

如果您想查看所有属性的列表,请使用__dict__:

llm.__dict__

构建你的第一个LML应用所需知道的一切 机器学习 第27张

如果我们不指定特定的模型,langchain连接器默认使用“text-davinci-003”。

现在,我们可以直接在Python中调用模型。只需调用llm函数并提供您的提示作为输入。

构建你的第一个LML应用所需知道的一切 机器学习 第28张

现在您可以问GPT任何关于常见人类知识的问题。

构建你的第一个LML应用所需知道的一切 机器学习 第29张

GPT只能提供有限的信息,这些信息不包括其训练数据中未包含的主题。这包括不公开可用的具体细节或在训练数据最后更新之后发生的事件。

构建你的第一个LML应用所需知道的一切 机器学习 第30张

那么,我们如何确保模型能够回答关于当前事件的问题呢?

如前所述,有一种方法可以做到这一点。我们需要在提示中给模型提供必要的信息。

为了回答有关英国现任首相的问题,我使用了来自维基百科文章“英国首相”的信息来提供提示。总结一下这个过程,我们要做的是:

  • 加载文章
  • 将文本拆分成文本块
  • 计算文本块的嵌入
  • 计算所有文本块与用户问题之间的相似度
import requestsfrom bs4 import BeautifulSoupfrom langchain.text_splitter import RecursiveCharacterTextSplitterimport numpy as npfrom numpy.linalg import norm##################################################################### 加载文本#####################################################################要爬取的维基百科页面的URLurl = 'https://en.wikipedia.org/wiki/Prime_Minister_of_the_United_Kingdom'# 向URL发送GET请求response = requests.get(url)# 使用BeautifulSoup解析HTML内容soup = BeautifulSoup(response.content, 'html.parser')# 找到页面上的所有文本text = soup.get_text()##################################################################### 拆分文本####################################################################text_splitter = RecursiveCharacterTextSplitter(    # 设置一个非常小的块大小,只是为了演示。    chunk_size = 100,    chunk_overlap  = 20,    length_function = len,)texts = text_splitter.create_documents([text])for text in texts:    text_chunks.append(text.page_content)##################################################################### 计算嵌入####################################################################df = pd.DataFrame({'text_chunks': text_chunks})# 创建包含所有文本块的新列表text_chunks=[]for text in texts:    text_chunks.append(text.page_content)# 从文本嵌入ada模型中获取嵌入def get_embedding(text, model="text-embedding-ada-002"):   text = text.replace("\n", " ")   return openai.Embedding.create(input = [text], model=model)['data'][0]['embedding']df['ada_embedding'] = df.text_chunks.apply(lambda x: get_embedding(x, model='text-embedding-ada-002'))##################################################################### 计算与用户问题的相似度#####################################################################计算用户问题的嵌入users_question = "英国现任首相是谁?"question_embedding = get_embedding(text=users_question, model="text-embedding-ada-002")

现在我们尝试找到与用户问题最相似的文本块:

from langchain import PromptTemplatefrom langchain.llms import OpenAI# 计算用户问题的嵌入users_question = "英国现任首相是谁?"question_embedding = get_embedding(text=users_question, model="text-embedding-ada-002")# 创建一个列表来存储计算的余弦相似度cos_sim = []for index, row in df.iterrows():   A = row.ada_embedding   B = question_embedding   # 计算余弦相似度   cosine = np.dot(A,B)/(norm(A)*norm(B))   cos_sim.append(cosine)df["cos_sim"] = cos_simdf.sort_values(by=["cos_sim"], ascending=False)

构建你的第一个LML应用所需知道的一切 机器学习 第31张

文本块看起来很混乱,但让我们尝试一下,看看GPT是否足够聪明,能够处理它。

现在,我们已经确定了可能包含相关信息的文本段落,我们可以测试我们的模型是否能够回答这个问题。为了实现这个目标,我们必须以清晰传达我们所需任务的方式构建我们的提示。

5. 定义我们的提示模板

现在我们有了包含我们正在寻找的信息的文本片段,我们需要建立一个提示。在提示中,我们还要指定模型回答问题的期望模式。当我们定义模式时,我们正在指定所需的行为样式,以便我们想要的LLM生成答案。

LLM可用于各种任务,以下是广泛可能性的几个示例:

  • 摘要:“将以下文本摘要为3段供高管使用:[TEXT]
  • 知识提取:“基于这篇文章:[TEXT],人们在购买房屋之前应该考虑什么?”
  • 编写内容(例如邮件、信息、代码):编写一封电子邮件给简,询问我们项目的文件更新情况。使用非正式、友好的语气。”
  • 语法和风格改进:“将此纠正为标准英语,并将语气改为更友好的:[TEXT]
  • 分类:“将每条消息分类为支持票据类型:[TEXT]”

在我们的示例中,我们想要实现一个从维基百科中提取数据并像聊天机器人一样与用户交互的解决方案。我们希望它能像一个积极进取、乐于助人的帮助台专家一样回答问题。

为了引导LLM走向正确的方向,我在提示中添加了以下指令:

“你是一个喜欢帮助人的聊天机器人!仅使用提供的上下文回答以下问题。如果你不确定,答案也没有明确在上下文中,就说‘对不起,我不知道该怎么回答你’。”

通过这样做,我设置了一个限制,只允许GPT利用我们数据库中存储的信息。这种限制使我们能够提供我们的聊天机器人所依赖的源来生成响应,这对于可追溯性和建立信任至关重要。此外,它还帮助我们解决了生成不可靠信息的问题,并允许我们提供可用于决策的企业设置答案。

作为上下文,我只是使用了与问题相似度最高的前50个文本块。由于我们通常可以用一个或两个文本段回答大多数问题,更大的文本块大小可能会更好。但我会让你自己找出最适合你使用情况的最佳大小。

from langchain import PromptTemplatefrom langchain.llms import OpenAI# define the LLM you want to usellm = OpenAI(temperature=1)# calcuate the embeddings for the user's questionusers_question = "Who is the current Prime Minster of the UK?"question_embedding = get_embedding(text=users_question, model="text-embedding-ada-002")# create a list to store the calculated cosine similaritycos_sim = []for index, row in df.iterrows():   A = row.ada_embedding   B = question_embedding   # calculate the cosine similiarity   cosine = np.dot(A,B)/(norm(A)*norm(B))   cos_sim.append(cosine)df["cos_sim"] = cos_simdf.sort_values(by=["cos_sim"], ascending=False)# define the context for the prompt by joining the most relevant text chunkscontext = ""for index, row in df[0:50].iterrows():    context = context + " " + row.text_chunks# define the prompt templatetemplate = """You are a chat bot who loves to help people! Given the following context sections, answer thequestion using only the given context. If you are unsure and the answer is notexplicitly writting in the documentation, say "Sorry, I don't know how to help with that."Context sections:{context}Question:{users_question}Answer:"""prompt = PromptTemplate(template=template, input_variables=["context", "users_question"])# fill the prompt templateprompt_text = prompt.format(context = context, question=users_question)llm(prompt_text)

通过使用特定的模板,我将上下文和用户的问题合并到我们的提示中。产生的响应如下:

构建你的第一个LML应用所需知道的一切 机器学习 第32张

令人惊讶的是,即使这个简单的实现似乎也产生了一些令人满意的结果。让我们继续询问系统关于英国首相的一些问题。我将保持一切不变,只替换用户的问题:

users_question = "Who was the first Prime Minister of the UK?"

构建你的第一个LML应用所需知道的一切 机器学习 第33张

它似乎在某种程度上正在运行。然而,我们现在的目标是将这个缓慢的过程转化为一个强大而高效的过程。为了实现这一目标,我们引入了一个索引步骤,将我们的嵌入和索引存储在一个向量存储器中。这将增强整体性能并减少响应时间。

6. 创建向量存储器(向量数据库)

向量存储器是一种针对存储和检索可表示为向量的大量数据进行优化的数据存储。这些类型的数据库允许根据各种标准进行高效的查询和检索数据子集,例如相似度度量或其他数学操作。

将我们的文本数据转换为向量是第一步,但这还不足以满足我们的需求。如果我们将向量存储在数据帧中,并在每次查询时逐步搜索单词之间的相似度,整个过程将非常缓慢。

为了高效地搜索嵌入,我们需要对它们进行索引。索引是向量数据库的第二个重要组成部分。索引提供了一种将查询映射到向量存储中最相关的文档或项的方法,而无需计算每个查询和每个文档之间的相似性。

近年来,发布了许多向量存储。特别是在LLM领域,向量存储周围的关注已经爆炸:

近年来发布的向量存储 — 图片由作者提供

现在让我们选择其中一个并尝试为我们的用例使用它。与我们在前面的部分所做的类似,我们再次计算嵌入并将它们存储在向量存储中。为此,我们使用LangChain和chroma的合适模块作为向量存储。

  1. 收集我们要用来回答用户问题的数据:
图片由作者提供
import requestsfrom bs4 import BeautifulSoupfrom langchain.embeddings.openai import OpenAIEmbeddingsfrom langchain.text_splitter import CharacterTextSplitterfrom langchain.vectorstores import Chromafrom langchain.document_loaders import TextLoader# 要爬取的Wikipedia页面的URLurl = 'https://en.wikipedia.org/wiki/Prime_Minister_of_the_United_Kingdom'# 发送GET请求到URLresponse = requests.get(url)# 使用BeautifulSoup解析HTML内容soup = BeautifulSoup(response.content, 'html.parser')# 找到页面上的所有文本text = soup.get_text()text = text.replace('\n', '')# 在写模式下打开一个名为'output.txt'的新文件,并将文件对象存储在一个变量中with open('output.txt', 'w', encoding='utf-8') as file:    # 将字符串写入文件    file.write(text)

2. 加载数据并定义如何将数据分成文本块

图片由作者提供
from langchain.text_splitter import RecursiveCharacterTextSplitter# 加载文档with open('./output.txt', encoding='utf-8') as f:    text = f.read()# 定义文本分割器text_splitter = RecursiveCharacterTextSplitter(        chunk_size = 500,    chunk_overlap  = 100,    length_function = len,)texts = text_splitter.create_documents([text])

3. 定义您要使用的嵌入模型,以计算文本块的嵌入并将其存储在向量存储中(这里是chroma)

图片由作者提供
from langchain.embeddings.openai import OpenAIEmbeddingsfrom langchain.vectorstores import Chroma# 定义嵌入模型embeddings = OpenAIEmbeddings()# 使用文本块和嵌入模型填充我们的向量存储db = Chroma.from_documents(texts, embeddings)

4. 计算用户问题的嵌入,找到我们的向量存储中相似的文本块并使用它们构建提示

图片由作者提供
from langchain.llms import OpenAIfrom langchain import PromptTemplateusers_question = "谁是英国现任首相?"# 使用我们的向量存储查找相似的文本块results = db.similarity_search(    query=user_question,    n_results=5)# 定义提示模板template = """您是一个喜欢帮助人们的聊天机器人!根据以下上下文部分回答问题,只使用给定的上下文。如果您不确定答案并且文档中没有明确写出,说“对不起,我不知道如何帮助您。”上下文部分:{context}问题:{users_question}答案:"""prompt = PromptTemplate(template=template, input_variables=["context", "users_question"])# 填充提示模板prompt_text = prompt.format(context = results, users_question = users_question)# 使用定义的LLM回答问题llm(prompt_text)

构建你的第一个LML应用所需知道的一切 机器学习 第39张

摘要

为了使我们的LLM能够分析和回答关于我们的数据的问题,我们通常不会对模型进行微调。相反,在微调过程中,目标是提高模型有效响应特定任务的能力,而不是教它新的信息。

对于Alpaca 7B,LLM(LLaMA)被微调为行为和交互类似于聊天机器人。重点是完善模型的响应,而不是教它完全新的信息。

所以为了能够回答关于我们自己的数据的问题,我们使用上下文注入方法。使用上下文注入创建LLM应用程序是一个相对简单的过程。主要的挑战在于组织和格式化存储在向量数据库中的数据。这一步对于有效地检索上下文相关的信息和确保可靠的结果至关重要。

本文的目的是演示使用嵌入模型、向量存储和LLM处理用户查询的极简主义方法。它展示了这些技术如何共同工作,提供相关和准确的答案,甚至对不断变化的事实也是如此。

喜欢这个故事吗?

  • 免费订阅以在我发布新故事时获得通知。
  • 想要阅读超过3篇免费故事吗? — 成为小猪AI会员,每月5美元。您可以使用我的推荐链接来支持我,当您注册时,我将不会有任何额外费用。

欢迎在LinkedIn上联系我!

参考资料

AssemblyAI(导演)。 (2022年1月5日)。 词嵌入的完整概述。 https://www.youtube.com/watch?v=5MaWmXwxFNQ

Grootendorst,M.(2021年12月7日)。 数据科学中的9种距离度量。 小猪AI。 https://towardsdatascience.com/9-distance-measures-in-data-science-918109d069fa

Langchain。 (2023)。 欢迎来到LangChain-🦜🔗 LangChain 0.0.189。 https://python.langchain.com/en/latest/index.html

Nelson,P.(2023)。 搜索和非结构化数据分析趋势|

Accenture。 搜寻和内容分析博客。 https://www.accenture.com/us-en/blogs/search-and-content-analytics-blog/search-unstructured-data-analytics-trends

OpenAI。 (2022)。 介绍文本和代码嵌入。 https://openai.com/blog/introducing-text-and-code-embeddings

OpenAI(导演)。 (2023年3月14日)。 GPT-4可以做什么? https://www.youtube.com/watch?v=oc6RV5c1yd0

Porsche AG。 (2023年5月17日)。 ChatGPT& enterprise knowledge:“我如何为我的业务部门创建聊天机器人?” #NextLevelGermanEngineering。 https://medium.com/next-level-german-engineering/chatgpt-enterprise-knowledge-how-can-i-create-a-chatbot-for-my-business-unit-4380f7b3d4c0

Tazzyman,S.(2023)。 神经网络模型。 NLP-Guidance。 https://moj-analytical-services.github.io/NLP-guidance/NNmodels.html

Wang,W.(2023年4月12日)。 深入了解基于Transformer的模型。 小猪AI。

Leave a Reply

Your email address will not be published. Required fields are marked *