RAG概述
为了更好的解决大模型幻觉的问题,业界提出了基于知识检索与大模型生成相结合的技术:RAG(Retrieval - Augmented Generation)即检索增强生成。
在当前大模型应用开发中,RAG为解决通用大模型知识有限和知识更新不及时等问题提供了有效方案,也得到了广泛的应用。
RAG的工作原理
通用大模型的能力在完成训练后其知识就固定了,而RAG则能够为大模型补充外部知识库检索的能力,从而使生成的内容更加准确和具有针对性。它的核心思想是在回答用户问题时,不局限于大模型训练所用的知识库,还能动态的从企业私有数据库中获取最新的相关数据来增强回答。
- 数据准备
首先,我们需要有一个知识库,这个知识库可以是非结构化的文档集合、数据库中的结构化数据等等。但我们需要提前对这批数据进行处理,如数据清洗、去除噪声、格式转换等操作,使其成为适合后续向量化处理的格式。 - 嵌入(Embedding)
接下来需要将知识库中的数据通过嵌入模型转化为向量表示,嵌入模型也都可以为预训练模型,如智源开源的BAAI/BGE系列模型。在此之前还有一个重要工作:chunk,需要将数据切分成一定大小的chunk块再进行向量化存储;切分过程可能会有以下问题:
● 切块过大:切块过大可能会导致内容检索效率低以及语义表示不精确等问题;
● 切块过小:切块过小可能会导致上下文信息丢失以及增加检索开销等问题。
这些问题大家可根据自己数据集特征进行动态调整即可,后续我也会更新更深度文章介绍解决之道~ - 向量存储
向量存储直接存储到向量数据库即可,常用的数据库如:
● Faiss:由 Facebook 开发并维护,一个用于快速搜索相似性和密集向量的聚类的开源库;
● Chroma:开源的嵌入式向量数据库,具有轻量级、易用的特点;
● Milvus:由 Zilliz 开源的向量数据库,专为处理超大规模向量数据而设计;
● PGVector:PostgreSQL 的开源扩展,建立在 Faiss 库之上,适用于基于 PostgreSQL 数据库的应用程序需要进行向量搜索和分析的场景。 - 向量检索
当收到用户的查询问题时,同样将问题通过嵌入模型转换为向量。然后在向量空间中,利用向量相似性搜索算法(如余弦相似度等)在知识库的向量表示中查找与问题向量最相似的几个文本向量。这些最相似的文本片段就是与问题相关的知识。 - 内容生成
使用提示词模版将检索到的相关知识片段和用户问题一起输入到语言生成模型中,大模型将基于这些信息生成与之相关的回答。
这个生成模型可以是基于 Transformer 架构的各种模型,如 GPT 系列等;也可以使用各大厂商的模型API。至此生成的回答不仅利用了模型本身的知识,还融合了从知识库中检索到的外部知识。
RAG开发示例
以下是一个使用 Python 和一些常见库实现的简单 RAG 示例。我们使用一个简单的文本文件作为知识库,并结合大模型的回答为大家演示一下整个RAG的流程。
-
准备工作
首先,我们需要安装必要的库。主要使用Chroma作为向量数据库以及使用LangChain作为开发框架,使用以下命令即可完成安装:pip install chromadb pip install langchain
安装完成后,将用到的相关依赖库导入到代码文件中即可:
import os from langchain_community.embeddings import HuggingFaceBgeEmbeddings from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.retrievers import ParentDocumentRetriever from langchain.storage import InMemoryStore from langchain_chroma import Chroma from langchain_community.document_loaders import TextLoader
-
定义大模型
这里用月之暗面的API作为演示,大家可根据项目需要自行切换基础模型;from openai import OpenAI class LLM_Moon: def __init__(self): self.client = OpenAI( api_key='sk-xxxxxx', base_url='https://api.moonshot.cn/v1', ) def request(self, question): completion = self.client.chat.completions.create( model='moonshot-v1-8k', messages=[ {'role': 'user', 'content': question} ], temperature=0.3 ) return completion.choices[0].message.content
-
初始化向量模型和数据库
这里我们使用智源开源的向量模型:bge-large-zh-v1.5,首先定义BGE模型的位置和文件路径。然后,我们初始化HuggingFaceBgeEmbeddings模型,该模型将用于生成文档的嵌入。接着,我们创建了一个Chroma向量数据库实例,用于存储和检索这些嵌入。BGE_MODEL_PATH = "bge-large-zh-v1.5" FILE_PATH = "data.txt" embeddings = HuggingFaceBgeEmbeddings( model_name=BGE_MODEL_PATH, model_kwargs={'device': 'cpu'}, encode_kwargs={'normalize_embeddings': True}, query_instruction="为这个句子生成表示以用于检索相关文章:" ) vectorstore = Chroma( collection_name='digital-administration-v1', embedding_function=embeddings, persist_directory='./vectorstore_2' )
-
定义检索器
为了有效地检索文档,我们需要定义父块和子块的切分大小。这里我们使用了RecursiveCharacterTextSplitter来切分文档。chunk块的大小大家根据实际文档特征和调试表现灵活调整即可,我们设置父块的大小为500、子块的大小为200。# 定义父块切分大小 parent_splitter = RecursiveCharacterTextSplitter(chunk_size=500) # 定义子块切分大小 child_splitter = RecursiveCharacterTextSplitter(chunk_size=250) store = InMemoryStore() search_kwargs = { "k": 5 } # 定义文档检索对象 retriever = ParentDocumentRetriever( vectorstore=vectorstore, docstore=store, child_splitter=child_splitter, parent_splitter=parent_splitter, search_kwargs=search_kwargs )
-
加载和存储文档
使用LangChain提供的TextLoader文本加载器来加载文件中的文本内容,并将这些文档添加到检索器中。# 文件读取 docs = [] loader = TextLoader("data.txt", encoding='utf-8') docs.extend(loader.load()) retriever.add_documents(docs)
-
构造对话函数
最后,我们定义了一个chat函数,该函数接受一个问题作为输入,使用检索器获取相关的文档,并使用提示词模版封装向量数据库检索出来的内容。然后,我们使用一个LLM模型(例如LLM_Moon)来生成回答。def chat(question): retriever_res = retriever.get_relevant_documents(question) searchdocs = [] for x in retriever_res: searchdocs.append(x.page_content) req_prompt = generate_prompt(question, searchdocs) return model.request(req_prompt)
-
对话
直接调用chat函数即可完成RAG检索和对话的结果生成:print(chat("介绍下你自己"))
大模型会结合提示词中给出的问题相关文档以及问题,给出更合理的回答。
-
示例代码
import os from langchain_community.embeddings import HuggingFaceBgeEmbeddings from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.retrievers import ParentDocumentRetriever from langchain.storage import InMemoryStore from langchain_chroma import Chroma from langchain_community.document_loaders import TextLoader from prompt_utils import generate_prompt from llm_base import LLM_Moon model = LLM_Moon() # 定义bge模型位置 BGE_MODEL_PATH = "bge-large-zh-v1.5" FILE_PATH = "data.txt" # 初始化向量模型 embeddings = HuggingFaceBgeEmbeddings( model_name=BGE_MODEL_PATH, model_kwargs={'device': 'cpu'}, encode_kwargs={'normalize_embeddings': True}, query_instruction="为这个句子生成表示以用于检索相关文章:" ) # 初始化向量数据库 vectorstore = Chroma( collection_name='digital-administration-v1', embedding_function=embeddings, persist_directory='./vectorstore_2' ) # 定义父块切分大小 parent_splitter = RecursiveCharacterTextSplitter(chunk_size=500) # 定义子块切分大小 child_splitter = RecursiveCharacterTextSplitter(chunk_size=250) store = InMemoryStore() search_kwargs = { "k": 5 } # 定义文档检索对象 retriever = ParentDocumentRetriever( vectorstore=vectorstore, docstore=store, child_splitter=child_splitter, parent_splitter=parent_splitter, search_kwargs=search_kwargs ) # 加载文件夹中的文件内容 def extract_file_dirs(directory): file_paths = [] for root, dirs, filelist in os.walk(directory): for file in filelist: fp = os.path.join(root, file) file_paths.append(fp) return file_paths # 文件读取 docs = [] loader = TextLoader("data.txt", encoding='utf-8') docs.extend(loader.load()) retriever.add_documents(docs) def chat(question): retriever_res = retriever.get_relevant_documents(question) searchdocs = [] for x in retriever_res: searchdocs.append(x.page_content) req_prompt = generate_prompt(question, searchdocs) return model.request(req_prompt) print(chat("介绍下你自己"))
结论
通过使用RAG外挂知识库的方式,我们可以构建一个强大的大模型应用,该应用能利用检索到的相关信息来生成更准确、更相关的回答。这种方法在问答系统、聊天机器人和其他需要结合私有知识库来生成内容的应用中非常有用。
标签:指南,RAG,检索,splitter,模型,langchain,实战,import,向量 From: https://blog.csdn.net/qq_25893567/article/details/143821251