RAG实操教程,LangChain + Llama2 | 创造你的个人LLM

RAG实操教程,LangChain + Llama2 | 创造你的个人LLM

image.png 本文将逐步指导您创建自己的RAG(检索增强生成)系统,使您能够上传自己的PDF文件并向LLM询问有关PDF的信息。本教程侧重于图中蓝色部分,即暂时不涉及Gradio(想了解已接入Gradio的,请参考官网)。相关技术栈包括以下内容:

  1. LLM: Llama2
  2. LLM API: llama.cpp service
  3. Langchain:
  4. Vector DB: ChromaDB
  5. Embeding: sentence-Tranformers

核心在于 Langchain,它是用于开发由语言模型支持的应用程序的框架。LangChain 就像胶水一样,有各种接口可以连接LLM模型与其他工具和数据源,不过现在 LangChain 正在蓬勃发展中,许多文件或API改版很多。以下我使用最简单的方式示范。

步骤1. 环境设置

首先设置 Python 环境,我使用 conda 创建环境,并安装以下库,我在 Jupyter 环境完成示例。

 # python=3.9
 ipykernel
 ipywidgets
 langchain
 PyMuPDF
 chromadb
 sentence-transformers
 llama-cpp-python

步骤2. 读入文件处理并导入数据库。

image.png

首先我们要将外部信息处理后,放到 DB 中,以供之后查询相关知识,这边的步骤对应到上图框起来的部分,也就是橘色的 1. 文本拆分器 和 2. embedding。

a). 使用文件加载器

Langchain 提供了很多文件加载器,总共大约有55种,包括word、csv、PDF、GoogleDrive、Youtube等,使用方法也很简单。这里我创建了一个虚拟人物 Alison Hawk 的 PDF 信息,并使用read in,Alison Hawk 的 PDF 信息。请注意需要安装 PyMuPDFLoader 才能使用。PyMuPDFLoader PyMuPDF

 from langchain.document_loaders import PyMuPDFLoader
 loader = PyMuPDFLoader("LangChain/Virtual_characters.pdf")
 PDF_data = loader.load()

文本分割器会将文档或文字分割成一个个 chunk,用以预防文档的信息超过 LLM 的 tokens,有一些研究在探讨如何将 chunk 优化。我们后续文章中讨论。

这两种常用的工具之间的区别在于,如果块大小超过指定阈值,它们会递归地将文本分割为更小的块。LangChain提供这两种方式,并且主要参数如下:

 - RecursiveCharacterTextSplitter 
 - CharacterTextSplitter

  • chunk size:决定分割文字时每个内存块中的最大字元数。它指定每个内存块的大小或长度。
  • chunk_overlap:决定分割文字时连续内存块之间重叠的字元数。它指定前一个内存块的多少应包含在下一个内存块中。
 from langchain.text_splitter import RecursiveCharacterTextSplitter
 text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=5)
 all_splits = text_splitter.split_documents(PDF_data)

在上面的代码中我们指定chunk_size=100, chunk_overlap=5, 这样的意思就是我们每块的文档中是 100 个字符,chunk_overlap 表示字符重复的个数,这样可以避免语义被拆分后不完整。

c) 加载嵌入模型

然后使用嵌入将步骤(b)分割的块文本转换为向量,LangChain提供了许多嵌入模型的接口,例如OpenAICohereHugging FaceWeaviate等,请参考LangChain官网。

这边我使用Hugging FaceSentence Transformers,它提供了许多种pretrain模型,可以根据你的需求或应用情境选择,我选择,其他model细节可以看到HuggingFace。注意要先安装才能使用。all-MiniLM-L6-v2sentence-Tranformers

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

d) 将Embedding结果汇入VectorDB

我们会将嵌入后的结果存储在VectorDB中,常见的VectorDB包括ChromaPineconeFAISS等,这里我使用Chroma来实现。ChromaLangChain整合得很好,可以直接使用 LangChain的接口进行操作。

 # embed 并存储文本
 # 指定 persist_directory 将会把嵌入存储到磁盘上。
 from langchain.vectorstores import Chroma
 persist_directory = 'db'
 vectordb = Chroma.from_documents(documents=all_splits, embedding=embedding, persist_directory=persist_directory)

步骤3. 启用LLM服务

image.png 你可以通过两种方法启动LLM模型并连接到LangChain。一种是使用LangChain的LlamaCpp接口来实现,这时由LangChain帮助你启动llama2服务;另一种方法是用其他方式搭建Llama2的API服务,例如使用llama.cpp的服务器启动API服务等。

a).使用LangChain的LlamaCpp

使用LlamaCpp接口加载model,它会帮你启动Llama的服务,这方法较简单,直接使用下面code就可以执行,model_path指定到你的模型中,例子中我使用量化过后的Llama2 Chat。注意这边要安装llama-cpp-python

 from langchain.callbacks.manager import CallbackManager
 from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
 from langchain_community.llms import LlamaCpp
 model_path = "llama.cpp/models/llama-2-7b-chat/llama-2_q4.gguf"
 ​
 llm = LlamaCpp(
     model_path=model_path,
     n_gpu_layers=100,
     n_batch=512,
     n_ctx=2048,
     f16_kv=True,
     callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]),
     verbose=True,
 )

img

您可以尝试进行测试,看看 llm 服务是否已启动:

llm("What is Chain known for?")

b). 使用 API 服务

如果你已经使用其他方式架设 LLMAPI 服务,或者是使用 openai 的 API 的话,你需要使用 LangChainChatOpenAI 接口。我这边示范是 llama.cppserver 服务,它提供了类别 OpenAI 的API,因此我们能直接用同个接口来操作,以下是该接口的一些相关参数:

open_ai_key:由于并没有使用真正的 OpenAI API,因此可以随意填写。 openai_api_base:为模型API的Base URL max_tokens:规范模型回答的长度

 from langchain.chat_models import ChatOpenAI
 llm = ChatOpenAI(openai_api_key='None', openai_api_base='http://127.0.0.1:8080/v1')

步骤4.设定你的Prompt

一些LLM可以使用特定的Prompt。例如,Llama可使用特殊token,细节可以参考twitter。我们可以使用ConditionalPromptSelector根据模型类型设定Prompt,如以下:

 from langchain.chains import LLMChain
 from langchain.chains.prompt_selector import ConditionalPromptSelector
 from langchain.prompts import PromptTemplate
 ​
 DEFAULT_LLAMA_SEARCH_PROMPT = PromptTemplate(
     input_variables=["question"],
     template="""<<SYS>> \n You are an assistant tasked with improving Google search \
 results. \n <</SYS>> \n\n [INST] Generate THREE Google search queries that \
 are similar to this question. The output should be a numbered list of questions \
 and each should have a question mark at the end: \n\n {question} [/INST]""",
 )
 ​
 DEFAULT_SEARCH_PROMPT = PromptTemplate(
     input_variables=["question"],
     template="""You are an assistant tasked with improving Google search \
 results. Generate THREE Google search queries that are similar to \
 this question. The output should be a numbered list of questions and each \
 should have a question mark at the end: {question}""",
 )
 ​
 QUESTION_PROMPT_SELECTOR = ConditionalPromptSelector(
     default_prompt=DEFAULT_SEARCH_PROMPT,
     conditionals=[(lambda llm: isinstance(llm, LlamaCpp), DEFAULT_LLAMA_SEARCH_PROMPT)],
 )
 ​
 prompt = QUESTION_PROMPT_SELECTOR.get_prompt(llm)

使用LLMChain将提示与llm连接在一起,另外LangChain最近的更新采用了“替代”,当您看到其他文章中使用时请注意。invoke run run

 llm_chain = LLMChain(prompt=prompt, llm=llm)
 question = "What is china known for?"
 llm_chain.invoke({"question": question})

步骤5. 文本检索 + 查询LLM

我们已经将 PDF 信息导入 DB,并启动了 LLM 服务,接下来要连接整个 RAG 步骤:

  • 用户发送 QA
  • 从 DB 中检索文本
  • 将 QA 与检索的文本结合发给 LLM
  • LLM 基于信息进行回答

首先要创建 Retriever,它可以根据非结构化的 QA 返回相应文件,LangChain 提供了多种方式,并整合第三方工具,目前有许多研究探讨如何基于 QA 查找对应文件。

请注意,已弃用的功能是使用 RetrievalQA 结合 Retriever、QA 和 llm。现在应该使用 ,如果看到其他文章中提到,请留意。VectorDBQA``RetrievalQA

 retriever = vectordb.as_retriever()
 ​
 qa = RetrievalQA.from_chain_type(
     llm=llm, 
     chain_type="stuff", 
     retriever=retriever, 
     verbose=True
 )

步骤6.使用你的RAG

到这里我们就串好整个RAG的流程,接下来我们来问问Alison Hawk的信息(PDF纪录的虚拟人物名称)

 query = "Tell me about Alison Hawk's career and age"
 qa.invoke(query)

img

LLM已经获取了从数据库中取得的Alison Hawk上传的PDF文件,并且知道她是一位28岁的研究员。

Jupyter 代码

 from langchain.document_loaders import PyMuPDFLoader
 from langchain.text_splitter import RecursiveCharacterTextSplitter
 from langchain.vectorstores import Chroma
 from langchain.embeddings import HuggingFaceEmbeddings
 from langchain.llms import LlamaCpp
 from langchain.chains import RetrievalQA
 loader = PyMuPDFLoader("Virtual_characters.pdf")
 PDF_data = loader.load()
 text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=5)
 all_splits = text_splitter.split_documents(PDF_data)
 # Embed and store the texts
 # Supplying a persist_directory will store the embeddings on disk
 persist_directory = 'db'
 model_name = "sentence-transformers/all-MiniLM-L6-v2"
 model_kwargs = {'device': 'cpu'}
 embedding = HuggingFaceEmbeddings(model_name=model_name,
                                   model_kwargs=model_kwargs)
 ​
 vectordb = Chroma.from_documents(documents=all_splits, embedding=embedding, persist_directory=persist_directory)
 from langchain.callbacks.manager import CallbackManager
 from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
 from langchain_community.llms import LlamaCpp
 ​
 llm = LlamaCpp(
     model_path="llama-2_q4.gguf",
     n_gpu_layers=100,
     n_batch=512,
     n_ctx=2048,
     f16_kv=True,
     callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]),
     verbose=True,
 )
 from langchain.chains import LLMChain
 from langchain.chains.prompt_selector import ConditionalPromptSelector
 from langchain.prompts import PromptTemplate
 ​
 DEFAULT_LLAMA_SEARCH_PROMPT = PromptTemplate(
     input_variables=["question"],
     template="""<<SYS>> 
     You are a helpful assistant eager to assist with providing better Google search results.
     <</SYS>> 
     
     [INST] Provide an answer to the following question in 150 words. Ensure that the answer is informative, \
             relevant, and concise:
             {question} 
     [/INST]""",
 )
 ​
 DEFAULT_SEARCH_PROMPT = PromptTemplate(
     input_variables=["question"],
     template="""You are a helpful assistant eager to assist with providing better Google search results. \
         Provide an answer to the following question in about 150 words. Ensure that the answer is informative, \
         relevant, and concise: \
         {question}""",
 )
 ​
 QUESTION_PROMPT_SELECTOR = ConditionalPromptSelector(
     default_prompt=DEFAULT_SEARCH_PROMPT,
     conditionals=[(lambda llm: isinstance(llm, LlamaCpp), DEFAULT_LLAMA_SEARCH_PROMPT)],
 )
 ​
 prompt = QUESTION_PROMPT_SELECTOR.get_prompt(llm)
 prompt
 llm_chain = LLMChain(prompt=prompt, llm=llm)
 question = "What is China known for?"
 llm_chain.invoke({"question": question})
 retriever = vectordb.as_retriever()
 ​
 qa = RetrievalQA.from_chain_type(
     llm=llm, 
     chain_type="stuff", 
     retriever=retriever, 
     verbose=True
 )
 query = "Tell me about Alison Hawk's career and age"
 qa.invoke(query)

读者福利:如果大家对大模型感兴趣,这套大模型学习资料一定对你有用

对于0基础小白入门:

如果你是零基础小白,想快速入门大模型是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以根据这些资料规划好学习计划和方向。

包括:大模型学习线路汇总、学习阶段,大模型实战案例,大模型学习视频,人工智能、机器学习、大模型书籍PDF。带你从零基础系统性的学好大模型!

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓
在这里插入图片描述

👉AI大模型学习路线汇总👈

大模型学习路线图,整体分为7个大的阶段:(全套教程文末领取哈)

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

👉大模型实战案例👈

光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

👉大模型视频和PDF合集👈

观看零基础学习书籍和视频,看书籍和视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
在这里插入图片描述
在这里插入图片描述

👉学会后的收获:👈

• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

👉获取方式:

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓
在这里插入图片描述

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值