基于LangChain实现RAG(大模型使用通义千问)
RAG(Retrieval-Augmented Generation)是一种结合了检索和生成的方法,旨在提高自然语言处理任务的性能。相对于预训练和微调,RAG的优势在于能够利用外部知识源,如知识图谱或文档数据库,以增强模型的理解和生成能力。此外,RAG还可以通过检索相关信息来减少对大规模预训练数据的依赖,从而降低计算成本。
RAG(Retrieval-Augmented Generation)是一种结合了检索和生成的方法,旨在提高自然语言处理任务的性能。相对于预训练和微调,RAG的优势在于能够利用外部知识源,如知识图谱或文档数据库,以增强模型的理解和生成能力。此外,RAG还可以通过检索相关信息来减少对大规模预训练数据的依赖,从而降低计算成本。
RAG内容
其全过程可以分为三个步骤:首先,模型会根据输入的查询或问题,从外部知识源(如知识图谱或文档数据库)中检索相关信息;然后,将这些检索到的信息与原始输入结合,形成一个更丰富的上下文;最后,模型基于这个增强的上下文生成回答或文本。通过这种方式,RAG能够利用外部知识源来增强模型的理解和生成能力,从而提高自然语言处理任务的性能。

代码实战
1、首先是要将外挂的知识存储起来,之后大模型会使用,而要存储的话首先需要将文本进行向量化,所以需要文本向量化模型来实现
2、将文本向量化后需要将向量化后的文本信息存储到数据库中,这里使用免费的数据库chroma或者其他的,Milvus在windows上使用起来较为困难,因此可以再试试别的
3、上述过程是也就是检索过程,而增强过程是预先设定一个prompt从检索出来的K个结果中得到最终最符合的结果
4、生成过程使用LLM来根据上面的结果生成
向量化
这里使用的是从huggingface上下载好的模型,也可以使用modelscope下载
from sentence_transformers import SentenceTransformer
### 向量化尝试
hug_path="jina-embeddings-v3"
hug_model=SentenceTransformer(hug_path,trust_remote_code=True)
# hug_model
几种不同的任务:
1、'retrieval.query':查询任务,通常用于检索系统中的查询语句。在此任务中,输入的文本被视为查询,模型将生成一个嵌入向量,用于在检索系统中与其他文档进行匹配。
2、'retrieval.passage':文段任务,通常用于检索系统中的文档片段(passage)。与查询任务类似,但此时输入文本通常是一个文段,模型会生成一个嵌入向量,用于与查询文本进行匹配。
3、'separation':分离任务,用于将不同的文本部分分开处理。通常用于多任务学习或多种类型文本混合的场景,将不同部分的输入文本分开编码,进行后续处理。
4、'classification':分类任务,用于文本分类。模型会将输入文本编码为嵌入向量,然后可以用于分类任务,例如情感分析、话题分类等。
5、'text-matching':文本匹配任务,用于比较两个文本之间的相似性。模型会生成两个文本的嵌入向量,并计算它们之间的相似度,常用于句子对的匹配、自然语言推理(NLI)等任务。
texts=["今天的天气非常好,适合外出","今天有什么新鲜事吗?"]
task="retrieval.query"
### embedding维度是1024.默认的
embeddings=hug_model.encode(
sentences=texts,
task=task,
prompt_name=task
)
modelscope下载的模型使用如下:
1、当输入包含“soure_sentence”与“sentences_to_compare”时,会输出source_sentence中首个句子与sentences_to_compare中每个句子的向量表示,以及source_sentence中首个句子与sentences_to_compare中每个句子的相似度。
2、当输入仅含有soure_sentence时,会输出source_sentence中每个句子的向量表示以及首个句子与其他句子的相似度
3、默认维度是1024,运行有点慢所以还是用huggingface的
from modelscope.models import Model
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks
ms_path="nlp_gte_sentence-embedding_chinese-large"
ms_model=pipeline(
Tasks.sentence_embedding,
model=ms_path,
sequence_length=512
)
inputs = {
"source_sentence": ["我爱吃苹果,不爱吃香蕉"],
"sentences_to_compare": [
"不可以,早晨喝牛奶不科学",
"水果有益健康,多吃对身体有好处",
]
}
result = ms_model(input=inputs)
print (result)
"""
{'text_embedding': array([[ 0.01306 , -0.00872 , 0.0252 , ..., 0.03326 , 0.0208 ,
-0.02281 ],
[ 0.0563 , 0.012085, -0.00875 , ..., 0.02194 , -0.010544,
0.0023 ],
[ 0.02997 , 0.02797 , 0.03415 , ..., 0.03763 , -0.01416 ,
-0.0358 ]], dtype=float16), 'scores': [0.2822265625, 0.607421875]}
"""
inputs = {
"source_sentence": [
"不可以,早晨喝牛奶不科学",
]
}
result = ms_model(input=inputs)
print (result)
"""
{'text_embedding': array([[ 0.05634 , 0.01208 , -0.00878 , ..., 0.02194 , -0.01056 ,
0.002277]], dtype=float16), 'scores': []}
"""
文本分块存储
由于需要存储的文件大小会比较大,里面的内容较多,大语言模型LLM的输入是有限的,现在比较多的是几十k的,但是如果输入的是小说或者其他的新闻报道的话文字本身比较多,大模型输入有限,可以将输入的文本进行分块处理,将分出的块来进行向量化操作,这里使用红楼梦作为输入文本。
### 下载数据,这里选择西游记
import requests
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
# 指定本地 PDF 文件的路径
pdf_path = "./data/红楼梦pdf.pdf"
# 使用 PyPDFLoader 加载 PDF 文件
loader = PyPDFLoader(pdf_path)
# 提取 PDF 中的所有页面文本
documents = loader.load()
# 打印PDF文件的文本内容
print(documents[500])
"""
Document(metadata={'source': '../data/红楼梦pdf.pdf', 'page': 500}, page_content='且贾珍等也慕他的名,酒盖住了脸,就求他串了两出戏。下来,\n移席和他一处坐著,问长问短,说此说彼。 \n\u3000\u3000那柳湘莲原是世家子弟,读书不成,父母早丧,素性爽侠,\n不拘细事,酷好耍枪舞剑,赌博吃酒,以至眠花卧柳,吹笛弹\n筝,无所不为。因他年纪又轻,生得又美,不知他身分的人,\n却误认作优伶一类。那赖大之子赖尚荣与他素习交好,故他今\n日请来坐陪。不想酒后别人犹可,独薛蟠又犯了旧病。他心中\n早已不快,得便意欲走开完事,无奈赖尚荣死也不放。赖尚荣\n又说:“方才宝二爷又嘱咐我,才一进门虽见了,只是人多不\n好说话,叫我嘱咐你散的时候别走,他还有话说呢。你既一定\n要去,等我叫出他来,你两个见了再走,与我无干。”说著,\n便命小厮们到里头找一个老婆子,悄悄告诉“请出宝二爷\n来。”那小厮去了没一盏茶时,果见宝玉出来了。赖尚荣向宝\n玉笑道:“好叔叔,把他交给你,我张罗人去了。”说著,一\n径去了。 \n\u3000\u3000宝玉便拉了柳湘莲到厅侧小书房中坐下,问他这几日可到\n秦钟的坟上去了。湘莲道:“怎么不去?前日我们几个人放鹰\n去,离他坟上还有二里。我想今年夏天的雨水勤,恐怕他的坟\n站不住。我背著众人,走去瞧了一瞧,果然又动了一点子。回\n家来就便弄了几百钱,第三日一早出去,雇了两个人收拾好\n了。”宝玉道:“怪道呢,上月我们大观园的池子里头结了莲\n蓬,我摘了十个,叫茗烟出去到坟上供他去,回来我也问他可\n被雨冲坏了没有。他说不但不冲,且比上回又新了些。我想著,\n不过是这几个朋友新筑了。我只恨我天天圈在家里,一点儿做\n不得主,行动就有人知道,不是这个拦就是那个劝的,能说不\n能行。虽然有钱,又不由我使。”湘莲道:“这个事也用不著\n你操心,外头有我,你只心里有了就是。眼前十月初一,我已\n499')
"""
text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = text_splitter.split_documents(documents)
本文使用下载到本地的模型来将分块内容向量化
from langchain.embeddings import SentenceTransformerEmbeddings
from langchain.vectorstores import Chroma
embedding = SentenceTransformerEmbeddings(model_name=hug_path)
# 将文本和嵌入存储到 Chroma 数据库
persist_directory="../data/chroma"
# 存储到向量数据库里
db = Chroma.from_documents(documents=chunks,embedding=embedding,persist_directory=persist_directory)
# 持久化数据,并释放内存
db.persist()
db = None
# 从磁盘中加载数据
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding)
检索增强生成
本文使用通义千问的大模型来实现生成操作
from langchain.schema.runnable import RunnablePassthrough
from langchain.schema.output_parser import StrOutputParser
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.messages import HumanMessage
from langchain.prompts import ChatPromptTemplate
import os
chatLLM = ChatTongyi(
streaming=False,
)
# 定义一个检索器组件。这个检索器会根据用户的查询和嵌入块之间的语义相似度,提供额外的上下文信息
retriever = vectordb.as_retriever()
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| chatLLM
| StrOutputParser()
)
query = "剧情进行到哪一步了"
rag_chain.invoke(query)
"""
'根据提供的文档内容,剧情主要涉及以下几个情节:\n\n1. 周瑞家的给贾府中的姑娘奶奶们送花,其中包括给林黛玉送花的情节。\n2. 林黛玉当时并不在自己的房间,而是在贾宝玉的房间玩九连环。\n3. 宝玉和警幻仙姑的一段对话,提到“薄命司”、“金陵十二钗正册”等。\n\n这些片段显示故事发生在《红楼梦》中的一部分,具体来说是关于宝玉和一些丫鬟、仙姑之间的互动。但是,没有明确的信息表明这是剧情发展的哪一个特定阶段。因此,根据当前提供的信息,我们无法准确指出剧情进行到哪一步了。如果需要更详细的剧情发展情况,可能需要提供更多的上下文信息。基于现有信息,只能确定上述几个场景是故事的一部分。如果您有更具体的问题或者需要了解某个角色的特定情节,请告知。'
"""
参考:
2、https://www.modelscope.cn/models/iic/nlp_gte_sentence-embedding_chinese-large/summary
3、RAG实战案例:如何基于 LangChain 实现智能检索生成系统_langchain和rag的关系-CSDN博客
4、https://blog.csdn.net/sinat_29950703/article/details/138605070
5、langchain 链式写法-使用本地 embedding 模型,Faiss 检索_langchain embedding-CSDN博客
6、LangChain整合Chroma实现本地知识库问答_langchain 本地embedding 文档问答-CSDN博客
更多推荐




所有评论(0)