1.RAG技术概述
1.1定义
1.2工作原理
2.LlamaIndex概述
- 下面开始实践部分
3.LangChain RAG实践
因为llamaindex使用本地需要冗杂的配置,并且下载了很久都没有反应,尤其是调用(时好时坏,我怀疑是NLTK那里出问题了,但是没有证据),在学习完成RAG原理后我使用langchain实现了这个章节,这里embedding用到了豆包的embedding模型,需要自己去火山方舟引擎申请你自己的id和key,下一个章节我会使用llamaindex实现RAG。
具体流程:
Loading:文档加载器把Documents 加载为以LangChain能够读取的形式。
Splitting:文本分割器把Documents 切分为指定大小的分割,我把它们称为“文档块”或者“文档片”。
Storage:将上一步中分割好的“文档块”以“嵌入”(Embedding)的形式存储到向量数据库(Vector DB)中,形成一个个的“嵌入片”。
Retrieval:应用程序从存储中检索分割后的文档(例如通过比较余弦相似度,找到与输入问题类似的嵌入片)。
Output:把问题和相似的嵌入片传递给语言模型(LLM),使用包含问题和检索到的分割的提示生成答案。
3.1配置环境
- 这里安装环境error不要紧张,如果出现错误可以后期自行修改,因为这个不是严格按照版本要求,如果要求其他的包比如PyPDF或者Doc2txt可以直接使用
pip install
进行下载
pip install --upgrade 'volcengine-python-sdk[ark]'
pip install langchain==0.3.7
pip install langchain_community==0.3.7
pip install langchain_openai==0.2.8
pip install unstructured
pip install unstructured[md]
pip install python-magic
pip install python-magic-bin
#如果您使用linux系统,需要使用apt install libmagic1
#https://github.com/ahupp/python-magic/issues/313
pip install numpy==1.26.3
3.2数据准备
自行准备下载md文档并设置路径:
https://github.com/InternLM/xtuner
3.3文本分割
接下来需要将加载的文本分割成更小的块,以便进行嵌入和向量存储。这个步骤中,我们使用 LangChain中的RecursiveCharacterTextSplitter 来分割文本。
其中chunk_size=200表示分割后的每个文本块大小为200个字符,chunk_overlap=30表示相邻的文本块有30个字符的重复,以确保语义连贯性和上下文检索。
3.4向量数据库存储
紧接着,我们将这些分割后的文本转换成嵌入的形式,并将其存储在一个向量数据库中。在这个例子中,我们会使用豆包Embedding来生成嵌入,然后使用 Qdrant 这个向量数据库来存储嵌入(这里需要pip install qdrant-client)。
同样需要在火山引擎中创建推理接入点,并且需要获取ID作为model(观沧海是本人在稀土掘金的账号,不存在版权问题,如有别人引用请联系本人或者标明引用来源)
- 如果对于火山引擎有不懂的可以查看引用链接中本人对于langchain的其他文章中有介绍。
火山方舟引擎官网:
3.5相关信息的获取
当内部文档存储到向量数据库之后,我们需要根据问题和任务来提取最相关的信息。此时,信息提取的基本方式就是把问题也转换为向量,然后去和向量数据库中的各个向量进行比较,提取最接近的信息。
在这里,我们正在处理的是文本数据,目标是建立一个问答系统,需要从语义上理解和比较问题可能的答案。因此,我建议使用余弦相似度作为度量标准。通过比较问题和答案向量在语义空间中的方向,可以找到与提出的问题最匹配的答案。
在这一步的代码部分,我们会创建一个聊天模型。然后需要创建一个 RetrievalQA 链,它是一个检索式问答模型,用于生成问题的答案。
在RetrievalQA 链中有下面两大重要组成部分。
- LLM是大模型,负责回答问题。
- retriever(vectorstore.as_retriever())负责根据问题检索相关的文档,找到具体的“嵌入片”。这些“嵌入片”对应的“文档块”就会作为知识信息,和问题一起传递进入大模型。
3.6生成回答并且展示
现在我们已经为后续的步骤做好了准备,下一步就是接收来自系统用户的具体问题,并根据问题检索信息,生成回答。
代码:
# 1.Load 导入Document Loaders
import os
from langchain_community.document_loaders import DirectoryLoader
from typing import Dict, List, Any
from langchain.embeddings.base import Embeddings
# from langchain.pydantic_v1 import BaseModel
from pydantic import BaseModel
from volcenginesdkarkruntime import Ark
base_dir = "/data/coding/data" # 文档的存放目录
api_key = "" #你的豆包APIKEY
base_url="https://ark.cn-beijing.volces.com/api/v3"
model = 'ep-20241111110355-2tp82' #YOURMODELID
os.environ["LLM_MODELEND"] = "ep-20241104131149-csxf9" # 你的Doubao-pro-32k模型
# 加载Documents
documents = []
loader = DirectoryLoader(
base_dir,
show_progress=True
) #默认读取全部非隐藏文件
documents = loader.load()
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
class DoubaoEmbeddings(BaseModel, Embeddings):
client: Ark = None
api_key: str = api_key
model: str
def __init__(self, **data: Any):
super().__init__(**data)
if self.api_key == "":
self.api_key = os.environ["OPENAI_API_KEY"]
self.client = Ark(
base_url=base_url,
api_key=self.api_key
)
def embed_query(self, text: str) -> List[float]:
"""
生成输入文本的 embedding.
Args:
texts (str): 要生成 embedding 的文本.
Return:
embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.
"""
embeddings = self.client.embeddings.create(model=self.mode