【AIGC】基于检索增强技术(RAG)构建大语言模型(LLM)应用程序

本文涉及的产品
模型训练 PAI-DLC,100CU*H 3个月
交互式建模 PAI-DSW,每月250计算时 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
简介: 【5月更文挑战第7天】基于检索增强技术(RAG)构建大语言模型(LLM)应用程序实践

[toc]


在之前的博客文章中,我们已经描述了嵌入是如何工作的,以及RAG技术是什么。本节我们我们将使用 LangChain 库以及 RAG 和嵌入技术在 Python 中构建一个简单的 LLM 应用程序。

我们将使用 LangChain 库在 Python 中构建一个简单的 LLM 应用程序。LangChain是一个流行的库,它使构建这样的应用程序变得非常容易。

我们的 RAG 应用程序将使用私有数据扩展 LLM 的知识。在这种情况下,它将是一个包含一些文本的 PDF 文件。

也可以通过使用 OpenAI 代理并通过将特定文件上传到 OpenAI 的服务器来扩展其知识库来实现类似的目标。但是,这种方法需要将我们的机密数据存储在 OpenAI 的服务器上,这可能并不总是符合我们的隐私偏好。

1.安装条件

在一开始,我们必须安装应用程序将使用的所有必需模块。让我们在终端的项目目录中编写此命令

pip install langchain-community==0.0.11 pypdf==3.17.4 langchain==0.1.0 python-dotenv==1.0.0 langchain-openai==0.0.2.post1 faiss-cpu==1.7.4 tiktoken==0.5.2 langchainhub==0.1.14

让我们创建一个“data”目录并将 PDF 文件放入其中。 我们还必须在项目目录中创建一个 main.py 文件,我们将在其中存储应用程序的整个代码。

在 main.py 文件中,我们将创建用于存储逻辑的 main() 函数。该文件将如下所示:

def main():
  print("Hello World!")

if __name__ == "__main__": 
  main()

2.导入PDF文件

我们将使用LangChain提供的名为PyPDFLoader的文档加载器。

from langchain_community.document_loaders import PyPDFLoader

pdf_path = "./data/2210.03629.pdf"

def main():
  loader = PyPDFLoader(file_path=pdf_path)
  documents = loader.load()
  print(documents) 

if __name__ == "__main__": 
  main()

首先,我们应该创建一个 PyPDFLoader 对象的实例,我们将路径传递给文件。下一步是简单地调用此对象的 load 函数,并将加载的文件保存在 documents 变量中。它将是一个由 Document 对象组成的数组,其中每个对象都是我们文件的一页的表示形式。

print() 函数应该输出一个类似于这样的数组:

[Document(page_content='[...]', metadata={'source': pdf_path, page: 1}), Document(page_content='[...]', metadata={'source': pdf_path, page: 2}), ...]

3.切割文件

我们不想将整个文档作为上下文发送到 LLM。为什么?在关于RAG的文章中对此进行了更详细的描述。为了拆分文档,我们将使用 LangChain 提供的一个名为 CharacterTextSplitter 的类,我们可以从 langchain 库中导入它:

from langchain.text_splitter import CharacterTextSplitter

然后我们可以创建一个实例并调用 split_documents() 函数,将加载的文档作为参数传递。

def main():
  loader = PyPDFLoader(file_path=pdf_path) 
  documents = loader.load() 
  text_splitter = CharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separator="\n" ) 
  docs = text_splitter.split_documents(documents)

让我们简要描述一下这里发生了什么。

首先,我们将创建一个 CharacterTextSplitter 对象,该对象采用多个参数:

  • chunk_size - 定义以令牌为单位的单个块的最大大小。
  • chunk_overlap - 定义块之间的重叠大小。这有助于通过确保块不会以扭曲其含义的方式拆分来保留拆分文本的含义。
  • separator - 定义将用于描述块的分隔符。

在 docs 变量中,我们将得到一个 Document 对象数组 - 与 PyPDFLoader 类的 load() 函数相同。

4.准备环境变量

下一步是将这些块转换为数字向量,并将它们存储在向量数据库中。这个过程叫做嵌入,也有一篇关于它的博文,所以我们现在不会详细介绍它。

对于嵌入过程,我们需要一个外部嵌入模型。为此,我们将使用 OpenAI 嵌入。为此,我们必须生成一个 OpenAI API 密钥。
但在此之前,我们必须创建一个 .env 文件,用于存储此密钥。

现在,我们需要在 platform.openai.com/docs/overview 页面上创建一个帐户。 之后,我们应该通过创建一个新的密钥在 platform.openai.com/api-keys 页面上生成一个 API 密钥。

复制密钥并将其粘贴到 .env 文件中,如下所示:

OPENAI_API_KEY=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

让我们通过导入 load_dotenv 函数将环境变量加载到我们的项目中:

from dotenv import load_dotenv

并在 main 函数的开头调用它:

def main(): 
    load_dotenv()
    loader = PyPDFLoader(file_path=pdf_path) 
    documents = loader.load() 
    text_splitter = CharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separator="\n" ) 
    docs = text_splitter.split_documents(documents)

5.直线嵌入功能

首先,我们必须导入 OpenAIEmbeddings 类:

from langchain_openai import OpenAIEmbeddings

我们应该创建这个类的实例。让我们将其分配给 'embeddings' 变量,如下所示:

embeddings = OpenAIEmbeddings()

6.设置向量数据库

我们已经加载并准备了我们的文件,我们还为嵌入模型创建了一个对象实例。我们现在已准备好将块转换为数字向量并将它们保存在向量数据库中。我们将使用 FAISS 矢量数据库将所有数据保存在本地。Facebook AI 相似度搜索 (Faiss) 是 Facebook AI 设计的一款工具,用于对密集向量进行有效的相似性搜索和聚类。

首先,我们需要导入 FAISS 实例:

from langchain_community.vectorstores.faiss import FAISS

并实现转换和保存嵌入的过程:

def main(): 
    load_dotenv() 
    loader = PyPDFLoader(file_path=pdf_path) 
    documents = loader.load() 
    text_splitter = CharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separator="\n" ) 
    docs = text_splitter.split_documents(documents) 
    embeddings = OpenAIEmbeddings() 
    vectorstore = FAISS.from_documents(docs, embeddings)    
    vectorstore.save_local("vector_db")

我们在代码中添加了两行。第一行采用我们的拆分块 (docs) 和嵌入模型将块从文本转换为数字向量。之后,我们将转换后的数据保存在本地的“vector_db”目录中。

7.创建提示

为了准备提示,我们将使用“langchain”中心。我们将从那里提取一个名为“langchain-ai/retrieval-qa-chat”的提示。这个提示是专门为我们的案例设计的,允许我们从提供的上下文中向模型询问事物。在引擎盖下,提示如下所示:

Answer any use questions based solely on the context below:
<context> 
{context}
</context>

让我们从“langchain”库导入一个"hub":

from langchain import hub

然后,只需使用“pull()”函数从中心检索此提示并将其存储在变量中:

retrieval_qa_chat_prompt = hub.pull("langchain-ai/retrieval-qa-chat")

8.设置大语言模型

接下来我们需要的是一个大型语言模型——在我们的例子中,它将是 OpenAI 模型之一。同样,我们需要一个 OpenAI 密钥,但我们已经将它与嵌入一起设置,因此我们不需要再做一次。

让我们继续导入模型:

from langchain_openai import ChatOpenAI, OpenAIEmbeddings

并将其分配给我们 main 函数中的一个变量:

llm = ChatOpenAI()

9.从数据库检索上下文数据

我们已经完成了向量数据库、嵌入和 LLM(大型语言模型)的准备工作。现在,我们需要使用链条连接所有东西。为此,我们需要“langchain”提供的两种类型的链。

第一个是 'create_stuff_documents_chain',我们需要从 'langchain' 库中导入它:

from langchain.chains.combine_documents import create_stuff_documents_chain

接下来,传递我们的大型语言模型 (LLM) 并提示它。

combine_docs_chain = create_stuff_documents_chain(llm, retrieval_qa_chat_prompt)

此函数返回一个 LCEL Runnable 对象,该对象需要上下文参数。运行它将如下所示:

combine_docs_chain.invoke({
   "context": docs, "input": "What is REACT in machine learning meaning?"})

10.仅检索相关数据作为上下文

它会起作用,但在这种情况下,我们将传递所有块 - 整个文档 - 作为上下文。在我们的例子中,文件有 33 页,这个上下文太大,我们可能会遇到这样的错误:

openai.BadRequestError: Error code: 400 - {'error': {'message': "This model's maximum context length is 4097 tokens. However, your messages resulted in 33846 tokens. Please reduce the length of the messages.", 'type': 'invalid_request_error', 'param': 'messages', 'code': 'context_length_exceeded'}}

为了解决这个问题,我们只需要将与查询相关的信息作为上下文传递。我们将通过将此链与另一条链相结合来实现这一点,该链将仅从数据库中检索对我们重要的块,并自动将它们作为上下文添加到提示中。

让我们从“langchain”库中导入该链:

from langchain.chains import create_retrieval_chain

首先,我们需要将数据库准备为检索器,这将启用对与查询相关的块的语义搜索。

retriever = FAISS.load_local("vector_db", embeddings).as_retriever()

因此,我们加载我们的目录,其中存储转换为向量的块并将其传递给嵌入函数。最后,我们将其作为检索器返回。

现在,我们可以组合我们的链:

retrieval_chain = create_retrieval_chain(retriever, combine_docs_chain)

在后台,它将从数据库中检索相关块,并将它们作为上下文添加到我们的提示中。我们现在要做的就是使用我们的查询作为输入参数调用此链:

response = retrieval_chain.invoke({
   "input": "What is REACT in machine learning meaning?"})

作为响应,我们将收到一个包含三个变量的对象:

  • input - 我们的查询;

  • context - 我们作为上下文传递给提示的文档(块)数组;

  • answer - 由大型语言模型 (LLM) 生成的查询的答案。

10.LLM app 全部代码

我们用 .pdf 文件中的数据扩展了 LLM 模型的知识库。该模型现在能够根据我们在提示中提供的上下文来回答我们的问题。

from dotenv import load_dotenv
from langchain import hub
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores.faiss import FAISS

pdf_path = "./data/2210.03629.pdf"


def main():
    load_dotenv()

    loader = PyPDFLoader(file_path=pdf_path)
    documents = loader.load()

    text_splitter = CharacterTextSplitter(
        chunk_size=1000, chunk_overlap=50, separator="\n"
    )
    docs = text_splitter.split_documents(documents)

    embeddings = OpenAIEmbeddings()

    vectorstore = FAISS.from_documents(docs, embeddings)
    vectorstore.save_local("vector_db")

    retrieval_qa_chat_prompt = hub.pull("langchain-ai/retrieval-qa-chat")

    llm = ChatOpenAI()

    combine_docs_chain = create_stuff_documents_chain(llm, retrieval_qa_chat_prompt)

    retriever = FAISS.load_local("vector_db", embeddings).as_retriever()
    retrieval_chain = create_retrieval_chain(retriever, combine_docs_chain)

    response = retrieval_chain.invoke(
        {"input": "What is REACT in machine learning meaning?"}
    )

    print(response["answer"])


if __name__ == "__main__":
    main()

小结

遵守前面博客中的约定,输出一节基于RAG进行大语言模型构建的内容,我们共划分了10个小节分别进行了详细介绍,希望对初学者有很好的指导作用。

小编是一名热爱人工智能的专栏作者,致力于分享人工智能领域的最新知识、技术和趋势。这里,你将能够了解到人工智能的最新应用和创新,探讨人工智能对未来社会的影响,以及探索人工智能背后的科学原理和技术实现。欢迎大家点赞,评论,收藏,让我们一起探索人工智能的奥秘,共同见证科技的进步!

相关实践学习
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
目录
相关文章
|
3天前
|
机器学习/深度学习 人工智能 自然语言处理
AIGC技术深度解析:生成式AI的革命性突破与产业应用实战
蒋星熠Jaxonic,AI技术探索者,深耕生成式AI领域。本文系统解析AIGC核心技术,涵盖Transformer架构、主流模型对比与实战应用,分享文本生成、图像创作等场景的实践经验,展望技术趋势与产业前景,助力开发者构建完整认知体系,共赴AI原生时代。
44 1
|
5月前
|
人工智能 算法 数据库
美团面试:LLM大模型存在哪些问题?RAG 优化有哪些方法?_
美团面试:LLM大模型存在哪些问题?RAG 优化有哪些方法?_
|
6月前
|
人工智能 算法 物联网
ComfyUI:搭积木一样构建专属于自己的AIGC工作流(保姆级教程)
通过本篇文章,你可以了解并实践通过【ComfyUI】构建自己的【文生图】和【文生动图】工作流。
ComfyUI:搭积木一样构建专属于自己的AIGC工作流(保姆级教程)
|
6月前
|
机器学习/深度学习 人工智能 自然语言处理
AIGC技术发展与应用实践(一文读懂AIGC)
AIGC(人工智能生成内容)是利用AI技术生成文本、图像、音频、视频等内容的重要领域。其发展历程包括初期探索、应用拓展和深度融合三大阶段,核心技术涵盖数据收集、模型训练、内容生成、质量评估及应用部署。AIGC在内容创作、教育、医疗、游戏、商业等领域广泛应用,未来将向更大规模、多模态融合和个性化方向发展。但同时也面临伦理法律和技术瓶颈等挑战,需在推动技术进步的同时加强规范与监管,以实现健康可持续发展。
|
5月前
|
人工智能 开发框架 搜索推荐
27.4K Star!这个LLM应用宝库让你秒变AI全栈高手,RAG和AI Agent一网打尽!
想要快速入门LLM应用开发?想要了解最新的RAG和AI Agent技术?这个收获27.4K Star的开源项目集合了当下最热门的LLM应用案例,从简单的PDF对话到复杂的多智能体系统应该有尽有。无论你是AI开发新手还是经验丰富的工程师,这里都能找到适合你的项目!
223 0
|
6月前
|
机器学习/深度学习 人工智能 自然语言处理
金鸡百花电影节AIGC电影《三岔口》:构建于想象之上的现实世界
金鸡百花电影节AIGC电影《三岔口》:构建于想象之上的现实世界
|
5月前
|
机器学习/深度学习 人工智能 自然语言处理
技术创新领域,AI(AIGC)是否会让TRIZ“下岗”?
法思诺创新直播间探讨了AI(AIGC)是否将取代TRIZ的问题。专家赵敏认为,AI与TRIZ在技术创新领域具有互补性,结合两者更务实。TRIZ提供结构化分析框架,AI加速数据处理和方案生成。DeepSeek、Gemini等AI也指出,二者各有优劣,应在复杂创新中协同使用。企业应建立双轨知识库,重构人机混合创新流程,实现全面升级。结论显示,AI与TRIZ互补远超竞争,结合二者是未来技术创新的关键。
182 0
|
7月前
|
人工智能 自然语言处理 数据可视化
Agentic Reasoning:推理界RAG诞生!牛津大学框架让LLM学会『组队打怪』:动态调用搜索/代码代理,复杂任务准确率飙升50%
Agentic Reasoning 是牛津大学推出的增强大型语言模型(LLM)推理能力的框架,通过整合外部工具提升多步骤推理、实时信息检索和复杂逻辑关系组织的能力。
299 1
|
5月前
|
机器学习/深度学习 存储 缓存
加速LLM大模型推理,KV缓存技术详解与PyTorch实现
大型语言模型(LLM)的推理效率是AI领域的重要挑战。本文聚焦KV缓存技术,通过存储复用注意力机制中的Key和Value张量,减少冗余计算,显著提升推理效率。文章从理论到实践,详细解析KV缓存原理、实现与性能优势,并提供PyTorch代码示例。实验表明,该技术在长序列生成中可将推理时间降低近60%,为大模型优化提供了有效方案。
920 15
加速LLM大模型推理,KV缓存技术详解与PyTorch实现
|
3月前
|
机器学习/深度学习 自然语言处理 算法
万字长文详解|DLRover LLM Agent:大模型驱动的高效集群资源调优
本文介绍了DLRover LLM Agent,展示了基于 LLM 上下文学习能力的优化算法设计理念以及在DLRover 资源调优上的应用方法和效果。

热门文章

最新文章