您的位置:首页 > 汽车 > 新车 > 【Langchain大语言模型开发教程】基于Langchain的私人助手

【Langchain大语言模型开发教程】基于Langchain的私人助手

2024/12/21 19:31:44 来源:https://blog.csdn.net/qq_47982709/article/details/140937807  浏览:    关键词:【Langchain大语言模型开发教程】基于Langchain的私人助手

终于学习完了Langchain框架的核心内容,最后基于langchain技术实现一个个人知识库助手的小项目,将这些内容串联起来,在实际中进行应用。

工具清单:

1、langchain框架

2、chroma向量数据库

3、embedding模型(bge-large-zh-v1.5、bge-large-en-v1.5)

4、rerank模型(bge-reranker-v2-m3)

5、gradio前端框架

6、LLM(GLM4系列模型)

1、数据读取与数据库构建

我们使用langchain提供的文本加载器来进行各种类型数据的加载;

def file_loader(file, loaders):if isinstance(file, tempfile._TemporaryFileWrapper):file = file.nameif not os.path.isfile(file):[file_loader(os.path.join(file, f), loaders) for f in os.listdir(file)]returnfile_type = file.split('.')[-1]if file_type == 'pdf':loaders.append(PyMuPDFLoader(file))elif file_type == 'md':pattern = r"不存在|风控"match = re.search(pattern, file)if not match:loaders.append(UnstructuredMarkdownLoader(file))elif file_type == "txt":loaders.append(TextLoader(file))elif file_type == "docx":loaders.append(Docx2txtLoader(file))return

得到数据后,由于Token上下文的限制,LLM不能一次将整个文档全都读入,我们需要将文档进行切分得到chunk;langchain为我们提供了多种文本分割器,每个文本分割器都根据 chunk_size (块大小)和 chunk_overlap (块与块之间的重叠大小)进行分割;

  • chunk_size 指每个块包含的字符或 Token的数量;
  • chunk_overlap 指两个块之间共享的字符数量,用于保持上下文的连贯性,避免分割丢失上下文信息;

 这里我们选择使用RecursiveCharacterTextSplitter,按字符串分割文本,递归地尝试按不同的分隔符进行分割文本;

我们得到分割后的文本后,我们就可以将数据存储到数据库中了,所有我们这里就需要一个embedding模型,embedding可以将文本映射到一个高维的向量空间,实现一个文本到数据的映射,而相似的文本编码后得到的向量就会相近;

最后我们初始化数据库,并将数据可持久化到硬盘,方便我们后续直接加载;

def create_db(files=DEFAULT_DB_PATH, persist_directory=DEFAULT_PERSIST_PATH, embeddings="bge-large-zh-v1.5"):if files == None:return "can't load empty file"if type(files) != list:files = [files]loaders = [][file_loader(file, loaders) for file in files]docs = []for loader in loaders:if loader is not None:docs.extend(loader.load())# 切分文档text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150)split_docs = text_splitter.split_documents(docs)print(len(split_docs))if type(embeddings) == str:embeddings = get_embedding(embedding=embeddings)# 加载数据库vectordb = Chroma.from_documents(documents=split_docs,embedding=embeddings,persist_directory=persist_directory  # 允许我们将persist_directory目录保存到磁盘上)vectordb.persist()return vectordb

2、 构建RAG问答链

由了刚刚构建的数据库,我们这里直接将其接入到问答流程;

这里我们需要传入一些必要的参数,然后加载一下我们的向量数据库,并根据该向量数据库构建一个检索器,作为我们的基本检索器,我们使用rerank模型将检索到的chunk进行进一步的精排,从而提升查询结果相关性;

    def __init__(self, model: str, temperature: float = 0.0, top_k: int = 4, api_key: str = None, file_path: str = None,persist_path: str = None, embedding=None, template=default_template_rq):print(persist_path)self.model = modelself.temperature = temperatureself.top_k = top_kself.file_path = file_pathself.persist_path = persist_pathself.api_key = api_keyself.embedding = embeddingself.template = templateself.vectordb = get_vectordb(self.file_path, self.persist_path, self.embedding)self.prompt = PromptTemplate(input_variables=["context", "question"], template=self.template)self.retriever = self.vectordb.as_retriever(search_type="similarity",search_kwargs={'k': 10})self.reranker = HuggingFaceCrossEncoder(model_name="../embedding/BAAI/bge-reranker-v2-m3",model_kwargs={'device': 'cuda'})print(f"向量库中存储的数量:{self.vectordb._collection.count()}")

接下来就是我们的问答环节,用户发出一个问题,我们根据用户指定的一些参数(temperature、top-k等)来初始化我们的大语言模型和重排器,我们使用langchain框架提供的RetrievalQA链来构建我们的问答链;

    def answer(self, question: str = None, temperature=None, top_k=4):""""核心方法,调用问答链arguments: - question:用户提问"""if len(question) == 0:return ""if temperature is None:temperature = self.temperatureif top_k is None:top_k = self.top_kllm = model_to_llm(self.model, temperature, self.api_key)compressor = CrossEncoderReranker(model=self.reranker, top_n=top_k)compression_retriever = ContextualCompressionRetriever(base_compressor=compressor,base_retriever=self.retriever)# 自定义 QA 链qa_chain = RetrievalQA.from_chain_type(llm=llm,retriever=compression_retriever,return_source_documents=True,chain_type_kwargs={"prompt": self.prompt})result = qa_chain({"query": question})answer = result["result"]source_documents = result["source_documents"]answer = re.sub(r"\\n", '<br/>', answer)return answer, source_documents

 以上就是我们问答助手的整个流程,接下来我们可以使用gradio框架快速的搭建起我们的交互界面;

我们问一个问题:

如何保持持续行动(刻意学习中的一个内容)

 

这是我们在数据库中检索到的内容: 

[Document(page_content='些工作量。平时要更加严格地要求自己了。我有时候时间充裕,一天会多\n写两篇文章,即使某天真的安排不出时间,也全然不会有“完蛋,我中断\n了”的感觉。树挪死,人挪活,持续行动的核心在于持续稳定。\n成长会里有位朋友在某知名通信企业任职,有一次谈到加班,她\n说:“很多公司的加班是今天做昨天的事情,或者今天做今天还没完成的事\n情,反正加班是因为做不完事情,而我们的加班是因为今天要把明天的事\n情做完,这个月把下个月的事情做完,所以能够永远赶在竞争对手前面。”\n另外一个例子是,在成长会的一些练习小组里每天都会有任务。往往\n出现这样一种情况:有一些成员从周一到周五,没有按时完成对应的任\n务,于是拖到周六,用一天的时间把所有作业都补完。很多人会觉得这好\n像挺正常,平常都做不完,周末再补,其实这是大部分人碌碌无为的原\n因。\n换一个场景你可能就会觉得这很荒谬,我们平常吃饭,每天每餐都要\n吃,到了点要吃,饿了就要吃。你会不会说我从周一到周五不吃饭,我周\n六一天把前面五天的饭全吃了?你没法五天不吃饭,你也无法一天补吃原\n来五天的饭。做事情就像吃饭一样,每天都要吃饭,于是这会变成一个常\n规项目。持续行动也应该如此。', metadata={'author': 'Scalers', 'creationDate': "D:20201006233519+00'00'", 'creator': 'calibre 3.39.1 [https://calibre-ebook.com]', 'file_path': '../knowledge_db/刻意学习.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'page': 91, 'producer': 'calibre 3.39.1 [https://calibre-ebook.com]', 'source': '../knowledge_db/刻意学习.pdf', 'subject': '', 'title': '刻意学习', 'total_pages': 235, 'trapped': ''}), Document(page_content='持续的事情,或者你也就走出了两三步,就迫不及待地想分享一些“牛×的\n方法”“秘籍成果”。\n这就像传销一样。一个人做了一点点事情,先把自己感动了,然后开\n始把这种感动转换成文字,营造了一个“感动场”,营造因为自己感动而产\n生的幻象。然后这个文字传播出去,立即引发一群人的感动和对牛×的憧\n憬,于是这群人在什么都没有做的情况下,便开始了新一轮的情绪高潮,\n高潮过后继续传播……于是这种氛围从公众号蔓延到社群……但是一轮一\n轮下来,你还是什么都没有做,那只是一群人产生了一些精神垃圾,然后\n找到另一群人接盘而已。这就跟开着印钞机印钞票,增发货币,是一个道\n理。\n当然,在持续行动中,我们需要正向反馈。每到一个关键节点,我们\n停下来整理整理思绪,甚至给自己一个小小的庆贺,这的确是有必要的。\n因为本质上这是一种正向反馈,有利于形成正循环。所以你看我过去每逢\n一百天都会有那么一篇总结文章,但是你也能看出越到后面的文章,我的\n心态越平和。\n如果我们在持续行动和持续进步,如果我们是在持续成长,那我们现\n在所取得的成绩,在未来都不值一提。如果我们每天都是在怀念自己以前', metadata={'author': 'Scalers', 'creationDate': "D:20201006233519+00'00'", 'creator': 'calibre 3.39.1 [https://calibre-ebook.com]', 'file_path': '../knowledge_db/刻意学习.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'page': 53, 'producer': 'calibre 3.39.1 [https://calibre-ebook.com]', 'source': '../knowledge_db/刻意学习.pdf', 'subject': '', 'title': '刻意学习', 'total_pages': 235, 'trapped': ''}), Document(page_content='因。\n换一个场景你可能就会觉得这很荒谬,我们平常吃饭,每天每餐都要\n吃,到了点要吃,饿了就要吃。你会不会说我从周一到周五不吃饭,我周\n六一天把前面五天的饭全吃了?你没法五天不吃饭,你也无法一天补吃原\n来五天的饭。做事情就像吃饭一样,每天都要吃饭,于是这会变成一个常\n规项目。持续行动也应该如此。\n在我刚开始写作的时候,总会担心万一有什么不可抗拒的事情,让我\n中断了写作,于是纠结不已。后面我发现这只是无谓的担心。生活中有很\n多人总是在为没有发生的事情担心,但也仅仅是担心却不做预案。以前我\n也是如此,后来才发现,不管发生什么,总是可以想办法在一天的繁忙中\n找出时间来做事情。\n白天再忙,总要起床,起床后的一段时间不会有人打扰你,于是你可\n以再起早一些,就有了属于自己的时间了;睡觉之前也有不被打扰的时\n间,这个时间也可以用来做事,只是你需要有足够的体力让自己不会感到\n困乏,于是体育锻炼的重要性就显现出来了。\n这么一来,我总能找到一些时间干自己的事情,于是就更加安心地持\n续行动了。在我持续写作的时间里,有人和我说自己想多做一些事情,却', metadata={'author': 'Scalers', 'creationDate': "D:20201006233519+00'00'", 'creator': 'calibre 3.39.1 [https://calibre-ebook.com]', 'file_path': '../knowledge_db/刻意学习.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'page': 91, 'producer': 'calibre 3.39.1 [https://calibre-ebook.com]', 'source': '../knowledge_db/刻意学习.pdf', 'subject': '', 'title': '刻意学习', 'total_pages': 235, 'trapped': ''})]

这是我们调用大语言模型后的答案:

保持持续行动需要:1. 严格自我要求,确保每天稳定完成任务,避免堆积工作。2. 提前规划,像吃饭一样将行动变成日常习惯,不断前行。3. 正向反馈,适时庆祝关键节点,形成正循环。谢谢你的提问! 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com