利用LangChain实现RAG

  检索增强生成(Retrieval-Augmented Generation, RAG)结合了搜寻检索生成能力和自然语言处理架构,透过这个架构,模型可以从外部知识库搜寻相关信息,然后使用这些信息来生成response。要完成检索增强生成主要包含四个步骤:

1.TextLoad:

2.TextSplit:

3.Generate and save Embedding:

4.Search relavant context and get final anwser.

DocumentLoader

  Langchain的document_loader目录下提供多种Load不同类型文档的方法,文档大类型总体可以分为结构化文档和非结构化文档。不同Loader的API信息如下图所示,更多Loader相关的API信息可查看这里。

下面是Load csv格式文件数据的代码和结果,import CSVLoader,print load的结果。可以看到,结果是一个List,List中每一个item是一个Document对象,包含page_content 和metadata数据,metadata包含source和row两个信息。

除了Load csv格式文件,还可以load pdf文件,import PyPDFLoader,load后的数据也是一个List,list中的每个value是Document对象,具体结果如下所示:

  在Load PDF格式文档的时候,可以选择多种Loader,例如UnstructuredPDFLoader,MathpixPDFLoader,OnlinePDFLoader,PyPDFium2Loader,PDFMinerLoader,PyMuPDFLoader,PyPDFDirectoryLoader,PDFPlumberLoader。另外,在load PDF文档时还可以通过参数控制是否需要解析图片上的文字信息等。总之,PDF的loader是非常成熟和丰富的。

除了load PDF格式文档,当然还支持txt格式,markdown格式,html格式等文档,在load的时候可以通过参数选择是否显示load进度,是否使用多线程进行load,多线程load可提升load效率。代码如下所示:

loader = DirectoryLoader('testdata', glob="**/*.txt",show_progress=True, use_multithreading=True)docs = loader.load()print(docs)

TextSplitter

  langchain提供了多种TextSplitter,具体如下图所示,这些spliter中比较常用的有TextSplitter,CharacterTextSplitter,RecursiveCharacterTextSplitter等。

下面是调用CharacterTextSplitter对文本进行切割,需要指定separator,chunk_size,chunk_overlap等参数。chunk_size:定义文本应该被分割成的最大块的大小。在这个例子中,设置为 1000,所以每个块最多包含 1000 个字符。这只是一个最大字符数量控制,真正在分割的时候还要参考separator。chunk_overlap:块之间的最大重叠量。这里设置为 200,所以连续块之间最多可以有 200 个字符的重叠。length_function:用于计算块长度的函数。在这个例子中,使用内置的 len 函数,所以块的长度就是它的字符数.

from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(separator = "\n\n",chunk_size = 1000,chunk_overlap  = 200,length_function = len,is_separator_regex = False,
)

  上面是最简单的文本切割方式,在切割分本时,我们需要尽量保证文本的语句含义不要丢失,即相关性很强的内容最好能放到一个chunk内,上面的切割方式虽然简单,但是容易把文本含义丢失。所以除了上面最简单的切割方式外,langchain还提供了RecursiveCharacterTextSplitter 切割方式。该切割方式的默认separator是["\n\n", "\n", " ", ""]。文本分割器首先尝试在每个双换行符 ("\n\n") 处拆分文本,这通常用于分隔文本中的段落。如果生成的块过大,它接着尝试在每个换行符 ("\n") 处拆分,这通常用于分隔句子。如果块仍然过大,它最后尝试在每个空格 (" ") 处拆分,这用于分隔单词。如果块仍然过大,它会在每个字符 ("") 处拆分,尽管在大多数情况下,这种细粒度的拆分是不必要的。这种方法的优点是它尽量保留了语义上下文,通过保持段落、句子和单词的完整性。这些文本单元往往具有强烈的语义关系,其中的单词在意义上通常密切相关,这对于许多自然语言处理任务是有益的。

   根据经验,采用RecursiveCharacterTextSplitter进行文本切割时,chunk_size设置在500-1000分为内效果较好,chunk_overlap设置在chunk_size大小的10%-20%左右。

  如果文档内容包含格式信息,例如html,markdown等,langchain还提供了HTMLHeaderTextSplitter和MarkdownHeaderTextSplitter切割方式。即在切割的时候按标题头切割,如果是在一个标题下的内容就放在一起。这样能最大程度保证相关性强的内容被切割在一个chunk里面。除了对文本进行切割,Langchain还可以对Code进行切割。下面的代码中就是加载代码目录地址,对该目录下的代码进行切割。

repo_path = "/Users/taoli/study/Python/langchain/langchain"
loader = GenericLoader.from_filesystem(repo_path,glob="**/*",suffixes=[".py"],parser=LanguageParser(language=Language.PYTHON, parser_threshold=500),
)
documents = loader.load()
python_splitter = RecursiveCharacterTextSplitter.from_language(language=Language.PYTHON, chunk_size=1000, chunk_overlap=100
)
texts = python_splitter.split_documents(documents)

Embedding model

  介绍完了Splitter,接着来看看Embedding。langchain支持多种Embedding model的载入。部分Embedding model如下图所示,更多Embedding信息可查看这里。比较常用的有OpenAIEmbeddings和HuggingFaceEmbeddings。

  如下面代码所示,在调用向量数据库的classmethod from_document,就需要指定调用的Embedding方法,可以使用HuggingFace中某个特定的Embedding模型,也可以直接使用OpenAIEmbedding。设置Embedding后,调用from_document方法,就会把texts中的内容转换成向量并存放在向量数据库中,用于后面的检索获取。

db = Chroma.from_documents(texts, HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2"))
db = Chroma.from_documents(texts,OpenAIEmbeddings)

在调用from_document方法时,除了指定embedding function,texts内容外,还可以指定persist_directory,即持久化向量信息的目录等多个参数信息。

Search relavant context and get final anwser

  介绍完Embedding后,再来看看相关性检索和得到最终结果的部分。如下面代码所示,在获取到向量库对象后,需要转换成retriever。Retriever类可以根据输入的查询问题,从文档中检索相关性高的内容并返回,检索器不需要存储文档,只需要返回(或检索)文档。向量存储可以用作检索器的支撑,但还有其他类型的检索器。

retriever = db.as_retriever(search_type="mmr",search_kwargs={"k": 8})llm = ChatOpenAI(model_name="gpt-3.5-turbo")
qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever, chain_type_kwargs={"prompt": rag_prompt})
result = qa_chain({"query": "What classes are derived from the Chain class?"})
print(result)memory = ConversationSummaryMemory(llm=llm, memory_key="chat_history", return_messages=True
)
qa = ConversationalRetrievalChain.from_llm(llm, retriever=retriever, memory=memory)
questions = ["What is the class hierarchy?","What classes are derived from the Chain class?","What one improvement do you propose in code in relation to the class hierarchy for the Chain class?",
]
for question in questions:result = qa(question)print(f"-> **Question**: {question} \n")print(f"**Answer**: {result['answer']} \n")

在调用as_retriever()方法中可以指定search_type,search_type主要包括两种:query- Similarity Search and Max Marginal Relevance Search (MMR Search),其中MMR Search旨在提高搜索结果的多样性,常用于推荐系统。如果想检索更准确则推荐选择query- Similarity Search,默认的search_type也是query- Similarity Search。

search_kwargs中可以传入多个参数,常见的参数包括:

k 定义返回多少个文档;默认为 4。
如果search_type是 "similarity_score_threshold" ,可以设置score_threshold,即减少相关性的分数阀值。
fetch_k 确定传递给MMR算法的文档数量;默认为 20。
lambda_mult 控制MMR算法返回结果的多样性,1表示最小多样性,0表示最大多样性。默认为 0.5。
filter 允许您根据文档的元数据定义文档检索的筛选条件。如果Vectorstore不存储任何元数据,则此选项无效。

  获取到retriver后,在检索文档生成答案时,有多种方式,既可以通过RetrievalQA这个chain, 还可以通过ConversationalRetrievalChain来获取最终的答案。在调用chain的时候还可以指定chain_type,langchain提供了四种类型的chain_type.Stuff,Refine,Map Reduce和Map re-rank.默认是使用Stuff类型。

Stuff:stuff文件链("stuff "是指 "to stuff "或 "to fill")是最直接的文件链。它接收一个文件列表,将它们全部插入一个提示,并将该提示传递给一个LLM。这条链非常适合于文件数量较少且大多数调用只传递几个文件的应用。

Refine:完善文档链通过循环输入文档和迭代更新其答案来构建一个响应。对于每个文档,它将所有非文档输入、当前文档和最新的中间答案传递给LLM链,以获得一个新的答案。由于Refine链每次只向LLM传递一个文档,所以它很适合需要分析更多文档的任务,这条链会比Stuff文档链等调用更多的LLM。当然,也有一些任务是很难迭代完成的。例如,当文档之间经常相互参照,或者当一个任务需要许多文档的详细信息时,Refine链的表现就很差。下图是Refine的过程源代码中Refine背后的Prompt信息。

Map_Reduce: map reduce文档链首先对每个文档单独应用LLM链(map步骤),将链的输出视为一个新的文档。然后,它将所有的新文档传递给一个单独的组合文档链,以获得一个单一的输出(Reduce步骤)。

Map re_rank:map re-rank文件链对每个文件进行初始提示,不仅试图完成一项任务,而且对其答案的确定程度进行评分。得分最高的回答会被返回。

  在使用chain生成最终答案时,如果调用ConversationalRetrievalChain,可以在from_llm中传入如下的参数,包括chain_type,自定义的prompt等。例如要传入自定义的prompt,那么可以通过condense_question_prompt传入,或者通过combine_docs_chain_kwargs参数传入:

  combine_docs_chain_kwargs={"prompt": TEST_PROMPT},

  在使用chain生成最终答案时,如果调用RetrievalQA的from_chain_type方法,可以通过chain_type_kwargs传入自定义prompt等参数。

   以上就是RAG的过程,总结而言包含Document Loader,Document splitter,Embedding,Search and get final answer四个步骤。步骤示意图如下所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/140697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java进阶(垃圾回收GC)——理论篇:JVM内存模型 垃圾回收定位清除算法 JVM中的垃圾回收器

前言 JVM作为Java进阶的知识,是需要Java程序员不断深度和理解的。 本篇博客介绍JVM的内存模型,对比了1.7和1.8的内存模型的变化;介绍了垃圾回收的语言发展;阐述了定位垃圾的方法,引用计数法和可达性分析发以及垃圾清…

如何实现Debian工控电脑USB接口安全管控

Debian 作为工控电脑操作系统具有稳定性、安全性、自定义性和丰富的软件包等优势,适用于要求高度可靠性和安全性的工控应用。 Debian 作为工控电脑操作系统在工业控制领域有很大优势,包括: 稳定性:Debian 的发布版以其稳定性而闻…

find和grep命令的简单使用

find和grep命令的简单使用 一、find例子--不同条件查找 二、grep正则表达式的简单说明例子--简单文本查找例子--结合管道进行查找 一、find find 命令在指定的目录下查找对应的文件。 find [path] [expression]● path 是要查找的目录路径,可以是一个目录或文件名…

MS321V/358V/324V低压、轨到轨输入输出运放

MS321V/MS358V/MS324V 是单个、两个和四个低压轨到轨输 入输出运放,可工作在幅度为 2.7V 到 5V 的单电源或者双电源条件 下。在低电源、空间节省和低成本应用方面是最有效的解决方案。 这些放大器专门设计为低压工作( 2.7V 到 5V )…

Electron-vue出现GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案

GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案 使用版本解决方案解决总结 使用版本 以下是我解决此问题时使用的electron和vue等的一些版本信息 【附】经过测试 electron 的版本为 13.1.4 时也能解决 解决方案 将项目下的 .electron-vue/dev-runner.js…

为什么要用“交叉熵”做损失函数

大家好啊,我是董董灿。 今天看一个在深度学习中很枯燥但很重要的概念——交叉熵损失函数。 作为一种损失函数,它的重要作用便是可以将“预测值”和“真实值(标签)”进行对比,从而输出 loss 值,直到 loss 值收敛,可以…

Python数据结构:元组(Tuple)详解

1.介绍和基础操作 Python中的元组(Tuple)是不可变有序序列,可以容纳任意数据类型(包括数字、字符串、布尔型、列表、字典等)的元素,通常用圆括号() 包裹。与列表(List)类似&#xff…

擎创动态 | 再获上海区政府肯定,擎创科技被评为年度优秀高新技术企业

11月6日,上海市静安区副区长张慧和市北高新集团总裁陈军一行来到擎创科技调研指导,由擎创科技高管张健和陈莹陪同交流。 陈莹女士首先向副区长一行详细介绍了擎创科技的发展现状、落地实践效益以及未来的规划布局。在公司的成长过程中,得到静…

Windows 10 下使用Visual Studio 2017 编译CEF SDK

1.下载CEF SDK 由于需要跑在32位的机器,所以选择下载32位的SDKCEF Automated Builds 选择 Current Stable Build (Preferred) ,这是当前稳定版本,CEF版本118 下载成功解压 2.下载编译工具 CMake 下载地址:CMake 配置CMake指向…

Containerd接入Harbor仓库

在使用容器时,避免不了会使用到私有仓库,一般都是采用 harbor 作为私有仓库,docker 对接 harbor 仓库非常简单,哪 containerd 如何对接 harbor 呢? 在内网使用 harbor 根据个人习惯,一般都是非 http 并且是…

PHP 服装销售管理系统mysql数据库web结构layUI布局apache计算机软件工程网页wamp

一、源码特点 PHP 服装销售管理系统是一套完善的web设计系统mysql数据库 ,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 php服装销售管理系统1 二、功能介绍 (1)员工管理:对员工信息…

卷积神经网络中参数量的计算原理及方法

手动计算参数量: 1. 卷积层参数计算方法: 参数量计算公式 卷积核高度 * 卷积核宽度 * 输入层通道数 * 输出层通道数 bias(输出层通道数) 注意:池化层没有参数(只是在已知数据区域里求个最大值)输入层通道数就是上层的卷积核数量 输出层通道数等于卷积核个数:输入层通道数经过…

jenkins CSV编码导致乱码问题解决

问题:生产报告会乱码的问题,一般是有编码格式引起的。我遇到的问题是,jmeter需要读取csv的数据作为参数。但是我们并不知道csv保存是什么编码格式,有可能不是utf-8的编码格式,所以会导致中文乱码的问题 解决方案&#…

机器学习中的假设检验

正态性检验相关分析回归分析 所谓假设检验,其实就是根据原假设来构造一种已知分布的统计量来计算概率,根据概率值大小来判断能否拒绝原假设,从而得到一种结论。假设检验的过程就是,构造一个原假设成立条件下的事件A,计…

使用Nodejs搭建简单的web网页并实现公网访问

🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 使用Nodejs搭建简单的web网页并实现公网访问 前言 Node.js是建立在谷歌Chrome的JavaScript引擎…

Python:Unittest框架快速入门:用例、断言、夹具、套件、HTML报告、ddt数据驱动

快速看了套Unittest的入门教程 软件测试全套资料赠送_哔哩哔哩_bilibili软件测试全套资料赠送是快速入门unittest测试框架!全实战详细教学,仅此一套!的第1集视频,该合集共计11集,视频收藏或关注UP主,及时了…

copilot 产生 python工具函数并生成单元测试

stock.py 这个文件,我只写了注释(的开头),大部分注释内容和函数都是copilot # split a string and extract the environment variable from it # input can be , pathabc, pathabc;pathdef, pathabc;pathdef;pathghi # output i…

如何结合内网穿透实现公网远程访问Linux AMH服务器管理面板

文章目录 1. Linux 安装AMH 面板2. 本地访问AMH 面板3. Linux安装Cpolar4. 配置AMH面板公网地址5. 远程访问AMH面板6. 固定AMH面板公网地址 AMH 是一款基于 Linux 系统的服务器管理面板,它提供了一系列的功能,包括网站管理、FTP 管理、数据库管理、DNS 管…

假冒 Skype 应用程序网络钓鱼分析

参考链接: https://slowmist.medium.com/fake-skype-app-phishing-analysis-35c1dc8bc515 背景 在Web3世界中,涉及假冒应用程序的网络钓鱼事件相当频繁。慢雾安全团队此前曾发表过分析此类网络钓鱼案例的文章。由于Google Play在中国无法访问,许多用户…

STM32--系统滴答SysTick

一、SysTick是什么? Systick定时器是一个24bit的倒计时(向下计数)定时器,功能就是实现简单的延时。 SysTick 是一种系统定时器,通常在嵌入式系统中使用。它是 ARM Cortex-M 处理器的一个特殊定时器,用于提…