滴水恩情 发表于 2024-9-1 05:35:22

RAG实战教程:利用Langchain和Milvus向量数据库打造个性化本地知识库

RAG实操教程: langchain+Milvus向量数据库创建你的本地知识库

本篇文章是 Milvus 向量数据库学习的总结篇,打造自己的知识库系统。
RAG是什么

RAG 是retrieval-augmented-generation的缩写,翻译为中文的意思就检索增强,以基于最新,最准确的数据建立LLM的语料知识库。
LLM 有哪些痛点

我们知道 LLM的知识库是通过现有的网络公开的数据作为数据源来训练的,现在公开的许多模型他们基于的训练数据会比我们现在网络上公开的数据早许多,那自然就会产生一种题目,网络上最新的数据和知识 LLM是不知道。还有一种环境就是许多企业他们对自己的数据的安全做的很好,也就是私有化数据(这些数据是有代价的,也是企业的驻足之本)。这些数据网络上肯定是不存在,那自然 LLM也是不知道的。
我们在提问LLM 对于一些不知道的知识时间,LLM 许多时间是不知道怎样答复题目的。甚至会对我们的题目进行胡诌随机答复,也就是瞎说。
为什么要用 RAG

如果使用预训练好的 LLM 模型,应用在某些景象下势必会有些词不达意的题目,比方问 LLM 你个人的信息,那么它会无法答复;这种环境在企业内部也是一样,比方使用 LLM 来答复企业内部的规章条款等。
这种时间主要有三种方式来让 LLM 变得更符合你的需求:

[*] Promt Enginerring: 输入提示来指导 LLM 产生所需回应。 比方常见的 In-context Learning,通过在提示中提供上下文或范例,来形塑模型的答复方式。 比方,提供特定答复风格的示例或包罗相干的情境信息,可以引导模型产生更符合的答案。
[*] Fine tuning:
这个过程包括在特定数据集上训练 LLM,使其响应更符合特定需求。 比方,一个EDA公司会使用其内部文件 verilog code 进行 Fine tuning ,使其可以或许更准确地答复关于企业内部题目。 但是 Fine tuning必要代表性的数据集且量也有一定要求,且 Fine tuning 并不得当于在模型中增长全新的知识或应对那些必要快速迭代新场景的环境。
[*] RAG (Retrieval Augmented Generation) : 联合了神经语言模型和撷取系统。 撷取系统从数据库或一组文件中提取相干信息,然后由语言模型使用这些信息来生成答案。 我们可以把 RAG 想像成给模型提供一本书或者是文档、教程,让它根据特定的题目去找信息。 此方法实用于模型必要整合及时、最新或非常特定的信息非常有用。 但RAG并不得当教会模型理解广泛的信息或学习新的语言、格式。
https://img-blog.csdnimg.cn/img_convert/3c50ca7c1bec039170011e1cb9182924.webp?x-oss-process=image/format,png
现在的研究已经表明,RAG 在优化 LLM 方面,相较于其他方法具有明显的优势。
主要的优势可以体现在以下几点:

[*]RAG 通过外部知识来提高答案的准确性,有效地减少了虚假信息,使得产生的答复更加准确可信。
[*]使用撷取技能可以或许识别到最新的信息(用户提供),这使得 LLM 的答复能保持及时性。
[*]RAG 引用信息来源是用户可以核实答案,因此其透明透非常高,这增强了人们对模型输出结果的信托。
[*]透过获取与特定范畴数据,RAG可以或许为差别范畴提供专业的知识支持,定制本领非常高。
[*]在安全性和隐私管理方面,RAG 通过数据库来存储知识,对数据使用有较好控制性。 相较之下,经过 Fine tuning 的模型在管理数据存取权限方面不敷明确,容易外泄,这对于企业是一大题目。
[*]由于 RAG 不需更新模型参数,因此在处理大规模数据集时,经济效率方面更具优势。
不过固然RAG有许多优势在,但这3种方法并不是互斥的,反而是相辅相成的。 联合 RAG 和 Fine tuning ,甚至 Promt Enginerring 可以让模型本领的条理性得增强。 这种协同作用特别在特定情境下显得重要,可以或许将模型的效能推至最佳。 整体过程大概必要经过多次迭代和调整,才华达到最佳的成效。 这种迭代过程涵盖了对模型的持续评估和改进,以满意特定的应用需求。
https://img-blog.csdnimg.cn/img_convert/1be25ee4ce9acfe9db090954dcf4a78a.webp?x-oss-process=image/format,png
怎样解决上面的题目

那怎样让 LLM 知道这些最新/私有的数据的知识呢❓
那就是 RAG。通过将模型建立在外部知识来源的基础上来增补答复。从而提高 LLM生成答复的质量。
在基于 LLM实现的问答系统中使用 RAG 有三方面的好处:


[*]确保 LLM 可以答复最新,最准确的内容。而且用户可以访问模型内容的来源,确保可以检查其声明的准确性并最终可信。
[*]通过将 LLM建立在一组外部的、可验证的究竟数据之上,该模型将信息提取到其参数中的机会更少。这减少了 LLM 泄漏敏感数据或“幻觉”不精确或误导性信息的机会。
[*]RAG 还减少了用户根据新数据不断训练模型并随着数据的变化更新训练参数的必要。通过这种方式企业可以减低相干财政本钱。
现在所有基础模型使用的是 transformer 的 AI 架构。它将大量原始数据转换为其基本布局的压缩表示形式。这种原始的表示基础模型可以适应各种任务,并对标志的、特定于范畴的知识进行一些额外的微调。
不过仅靠微调很少能为模型提供在不断变化的环境中答复高度具体题目所需的全部知识,而且微调的时间周期还比较长。所以科学家们提出了 RAG,让 LLM 可以或许访问训练数据之外的信息。RAG 答应 LLM 建立在专门的知识体系之上,以更准确的答复题目,减低幻觉的产生。
下面我将 langchain+Milvus 向量数据库创建你的本地知识库
安装 langchain

使用下面的命令可以快速安装 langchain 相干的依赖

pip install langchain

pip install langchain-community # 默认安装

pip install langchain-core # 默认安装

pip install langchain-cli # LangChain 命令行界面

pip install --upgrade --quiet pypdf # 安装pdf 加载器的依赖


文档加载器 pdf

在这篇文章中我们使用pdf作为我们的知识库文档。
加载文档的过程一般必要下面的步调:


[*]解析文档(txt、pdf、html、url、xml、markdown、json)等等为字符串(langchain已经分装了几十种文档加载器,感兴趣的可以去参考官网)。
[*]将字符串拆分为得当模型的对话窗口的大小,称为 chunk,chunk的大小必要依据模型的会话窗口设定。
[*]生存拆分好的文档生存到向量数据库中。
[*]设计向量数据库的数据库、集合、字段,索引等信息。
[*]从向量数据库中检索必要的数据
这些步调 langchain 已经给联合自己的工具连做好了封装,所以我们直接使用 langchain 来构建RAG。
from langchain_text_splitters import CharacterTextSplitter

from langchain_community.document_loaders import PyPDFLoader

file_path = 'CodeGeeX 模型API.pdf'

# 初始化pdf 文档加载器
loader = PyPDFLoader(file_path=file_path)
# 将pdf中的文档解析为 langchain 的document对象
documents = loader.load()
# 将文档拆分为合适的大小
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
docs = text_splitter.split_documents(documents)

上面有两个参数必要注意下:
chunk_size=1000
表示拆分的文档的大小,也就是上面所说的要设置为多少符合取决于所使用LLM 的窗口大小。


[*]如果设置小了,那么我们一次查询的数据的信息量就会少,势必会导致信息的缺失。
[*]如果设置大了,一次检索出来的数据就会比较大,LLM 产生的token就会多,费用贵,信息不聚焦等题目。
chunk_overlap=100
这个参数表示每个拆分好的文档重复多少个字符串。


[*] 为什么要重复:如果拆分后的chunk没有重复,很有大概会产生语义错误。
比如这样一段文本:
....小米汽车的续航里程为700公里....如果文本恰好从 700的那里拆分开的话,那给人展示的时间就会产生酒究竟是700m照旧700公里才歧义。
[*] chunk_overlap如果设置比较大的值也不符合。这样每个文档的重复度就会很大,导致有用的信息就会减少,从而 LLM 回复的内容有大概缺少关键的信息。
Miluvs 向量数据库

关于 Milvui 可以参考我的前两篇文章
下面我们安装 pymilvus 库
pip install --upgrade --quietpymilvus

如果你使用的不是 Miluvs 数据库,那也没关系,langchain 已经给我们分装了几十种向量数据库,你选择你必要的数据库即可。本文中我们是系列教程中一篇,所以我们使用 Miluvs 向量库。
Embedding model

https://img-blog.csdnimg.cn/img_convert/76c68070bc9081282cfd20199f0ee222.webp?x-oss-process=image/format,png
这里必要明确的两个功能是:


[*]embedding Model所做中工作就是将 image、Document、Audio等信息向量化.
[*]vectorBD 负责生存多维向量
我这里使用 AzureOpenAIEmbeddings 是个收费的模型。有开源的 embedding Model可以部署在本地使用,如果你的呆板性能足够好。如果要本地部署可以参考 docker 部署 llama2 模型 。
这里我使用 AzureOpenAIEmbeddings, 相干设置我放到了 .env 文件中,并使用 dotenv 加载。
# AZURE config
AZURE_OPENAI_ENDPOINT=''
AZURE_OPENAI_API_KEY=''
OPENAI_API_VERSION=2024-03-01-preview
AZURE_DEPLOYMENT_NAME_GPT35 = "gpt-35-turbo"
AZURE_DEPLOYMENT_NAME_GPT4 = "gpt-4"
AZURE_EMBEDDING_TEXT_MODEL = "text-embedding-ada-002"

这里各位可以依据自己的环境设定即可。
向量化+存储

上面已经分析了向量库以及embedding model的关系。我们直接使用 langchain 提供的工具连完成 embedding 和store。
# 初始化 embedding model
from langchain_openai import AzureOpenAIEmbeddings
embeddings = AzureOpenAIEmbeddings()

from langchain_community.vectorstores import Milvus
vector = Milvus.from_documents(
   documents=documents, # 设置保存的文档
   embedding=embeddings, # 设置 embedding model
   collection_name="book", # 设置 集合名称
   drop_old=True,
   connection_args={"host": "127.0.0.1", "port": "19530"},# Milvus连接配置
)

执行完成上面的代码,我们就将pdf中文档内容生存到 vector_db 中。
https://img-blog.csdnimg.cn/img_convert/80e338b5baf62c4d29052b93612900a9.webp?x-oss-process=image/format,png
字段 vector 就是生存的多维向量。
https://img-blog.csdnimg.cn/img_convert/92049d5292e98bf0375400f2b8aaf261.webp?x-oss-process=image/format,png
Milvus search

固然现在我们还没有使用 LLM 的任何本领,但是我们已经可以使用 vector 的搜索功能了。
query = "CodeGeeX模型API参数有那些?"
docs = vector.similarity_search(query)
print(docs)

# 带score搜索
query = "CodeGeeX模型API参数有那些?"
docs = vector.similarity_search_with_score(query, k=2)
print(docs)

similarity_search 与 similarity_search_with_score 的区别就是 similarity_search_with_score 搜索出来会带有一个 score 分值的字段,某些环境下这个 score 很有用。
langchain 不但仅提供了基础的搜索本领,还有其他的搜索方法,感兴趣的可以去研究下。
RAG Chat

准备工作我们已经停当,接下来我们使用langchain 构建我们的chat。
既然是聊天也就是我们跟模型的一问一答的形式来体现。这两年LLM的出现,关于 LLM 的知识内里我们估计最熟悉就是脚色设定了。


[*]什么是脚色设定:下面 OpenAI 给出的答复:
   在大型语言模型(LLM)中,脚色设定指的是为AI助手创建一个特定的人格或身份。这个设定包括AI助手的语言风格、知识范畴、代价观、举动方式等各个方面。通过这些设定,AI助手可以扮演差别的脚色,比如专业的客服、风趣幽默的聊天对象,或是特定范畴的专家顾问。
脚色设定可以让AI助手的答复更加符合特定的场景和用户的盼望。比如一个扮演医生的AI助手,会用专业术语表明病情,给出严谨的建议;而一个扮演朋侪的AI助手,会用轻松的语气聊天,给出生存化的提示。
别的,脚色设定还可以资助限定AI助手的举动界限,避免其做出不恰当或有害的回应。设定明确的脚色定位,有助于AI助手更好地理解自己的身份和职责,从而提供更加符合和有资助的答复。
总的来说,脚色设定让AI助手的对话更加自然和人性化,让用户获得更好的使用体验。同时它也是引导AI助手举动、确保其安全可控的重要本领。
在 chat中我们同样也必要以及简朴的 prompt:
template = """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know.

Question: {question}

Context: {context}

Answer:
"""


这个prompt中很明显我们设定了两个变量 question, context。
question: 这个会在后面被更换为用户的输入,也就是用户的题目。
context: 这个变量我们在后面会更换为向量检索出来的内容。
   请思索下: 我们最后提供给LLm的内容只是用户的题目呢照旧题目连带内容一起给到LLM?
chat chain

基于上面的内容我们基本的工作已经完成,下面就是我们基于 langchain构建chat。
import os
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template(template)
print(prompt)

# 加载chat model
from langchain_openai import AzureChatOpenAI
from langchain_core.runnables import RunnableParallel,RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
llm = AzureChatOpenAI(
   azure_deployment=os.environ.get('AZURE_DEPLOYMENT_NAME_GPT35')
)

retriever = vector.as_retriever()

chain = (
   RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
   | prompt
   | llm
   | StrOutputParser()
)


对于初学者大概有个题目就是:为什么这里有个 AzureChatOpenAI() 的实例 llm 。
这是个好题目,对于初学者会被各种 LLM 搞晕
页: [1]
查看完整版本: RAG实战教程:利用Langchain和Milvus向量数据库打造个性化本地知识库