AIGC:【LLM(四)】——LangChain+ChatGLM:本地知识库问答方案

news2024/11/24 2:58:06

文章目录

    • 一.文件加载与分割
    • 二.文本向量化与存储
      • 1.文本向量化(embedding)
      • 2.存储到向量数据库
    • 三.问句向量化
    • 四.相似文档检索
    • 五.prompt构建
    • 六.答案生成

LangChain+ChatGLM项目(https://github.com/chatchat-space/langchain-ChatGLM)实现原理如下图所示 (与基于文档的问答 大同小异,过程包括:1 加载文档 -> 2 读取文档 -> 3/4文档分割 -> 5/6 文本向量化 -> 8/9 问句向量化 -> 10 在文档向量中匹配出与问句向量最相似的top k个 -> 11/12/13 匹配出的文本作为上下文和问题一起添加到prompt中 -> 14/15提交给LLM生成回答 )
在这里插入图片描述

一.文件加载与分割

加载文件:这是读取存储在本地的知识库文件的步骤
读取文件:读取加载的文件内容,通常是将其转化为文本格式
文本分割(Text splitter):按照一定的规则(例如段落、句子、词语等)将文本分割

def _load_file(self, filename):
        # 判断文件类型
        if filename.lower().endswith(".pdf"):  # 如果文件是 PDF 格式
            loader = UnstructuredFileLoader(filename)   # 使用 UnstructuredFileLoader 加载器来加载 PDF 文件
            text_splitor = CharacterTextSplitter()      # 使用 CharacterTextSplitter 来分割文件中的文本
            docs = loader.load_and_split(text_splitor)  # 加载文件并进行文本分割
        else:          # 如果文件不是 PDF 格式
            loader = UnstructuredFileLoader(filename, mode="elements")  # 使用 UnstructuredFileLoader 加载器以元素模式加载文件
            text_splitor = CharacterTextSplitter()      # 使用 CharacterTextSplitter 来分割文件中的文本
            docs = loader.load_and_split(text_splitor)  # 加载文件并进行文本分割
        return docs    # 返回处理后的文件数据

二.文本向量化与存储

1.文本向量化(embedding)

这通常涉及到NLP的特征抽取,可以通过诸如TF-IDF、word2vec、BERT等方法将分割好的文本转化为数值向量。

# 初始化方法,接受一个可选的模型名称参数,默认值为 None
    def __init__(self, model_name=None) -> None:  
        if not model_name:  # 如果没有提供模型名称
            # 使用默认的嵌入模型
            # 创建一个 HuggingFaceEmbeddings 对象,模型名称为类的 model_name 属性
            self.embeddings = HuggingFaceEmbeddings(model_name=self.model_name)

2.存储到向量数据库

文本向量化之后存储到数据库vectorstore。

def init_vector_store(self):
    persist_dir = os.path.join(VECTORE_PATH, ".vectordb")  # 持久化向量数据库的地址
    print("向量数据库持久化地址: ", persist_dir)              # 打印持久化地址


    # 如果持久化地址存在
    if os.path.exists(persist_dir):  
        # 从本地持久化文件中加载
        print("从本地向量加载数据...")
        # 使用 Chroma 加载持久化的向量数据
        vector_store = Chroma(persist_directory=persist_dir, embedding_function=self.embeddings)  


    # 如果持久化地址不存在
    else:      
        # 加载知识库
        documents = self.load_knownlege()  
        # 使用 Chroma 从文档中创建向量存储
        vector_store = Chroma.from_documents(documents=documents, 
                                             embedding=self.embeddings,
                                             persist_directory=persist_dir)  
        vector_store.persist()      # 持久化向量存储
    return vector_store             # 返回向量存储

def load_knownlege(self):
    docments = []         # 初始化一个空列表来存储文档


    # 遍历 DATASETS_DIR 目录下的所有文件
    for root, _, files in os.walk(DATASETS_DIR, topdown=False):
        for file in files:
            filename = os.path.join(root, file)      # 获取文件的完整路径
            docs = self._load_file(filename)         # 加载文件中的文档


            # 更新 metadata 数据
            new_docs = []             # 初始化一个空列表来存储新文档
            for doc in docs:
                # 更新文档的 metadata,将 "source" 字段的值替换为不包含 DATASETS_DIR 的相对路径
                doc.metadata = {"source": doc.metadata["source"].replace(DATASETS_DIR, "")} 
                print("文档2向量初始化中, 请稍等...", doc.metadata)  # 打印正在初始化的文档的 metadata
                new_docs.append(doc)  # 将文档添加到新文档列表


            docments += new_docs      # 将新文档列表添加到总文档列表


    return docments      # 返回所有文档的列表

三.问句向量化

这是将用户的查询或问题转化为向量,应使用与文本向量化相同的方法,以便在相同的空间中进行比较 。

四.相似文档检索

在文本向量中匹配出与问句向量最相似的top k个,这一步是信息检索的核心,通过计算余弦相似度、欧氏距离等方式,找出与问句向量最接近的文本向量。

def query(self, q):
        """在向量数据库中查找与问句向量相似的文本向量"""
        vector_store = self.init_vector_store()
        docs = vector_store.similarity_search_with_score(q, k=self.top_k)
        for doc in docs:
            dc, s = doc
            yield s, dc

五.prompt构建

匹配出的文本作为上下文和问题一起添加到prompt中,这是利用匹配出的文本来形成与问题相关的上下文,用于输入给语言模型。

六.答案生成

最后,将这个问题和上下文一起构成的prompt提交给在线(例如GPT-4/ChatGPT)或本地化部署大语言模型,让它生成回答。

class KnownLedgeBaseQA:
    # 初始化
    def __init__(self) -> None:
        k2v = KnownLedge2Vector()      # 创建一个知识到向量的转换器
        self.vector_store = k2v.init_vector_store()     # 初始化向量存储
        self.llm = VicunaLLM()         # 创建一个 VicunaLLM 对象

    # 获得与查询相似的答案
    def get_similar_answer(self, query):
        # 创建一个提示模板
        prompt = PromptTemplate(
            template=conv_qa_prompt_template, 
            input_variables=["context", "question"]  # 输入变量包括 "context"(上下文) 和 "question"(问题)
        )


        # 使用向量存储来检索文档
        retriever = self.vector_store.as_retriever(search_kwargs={"k": VECTOR_SEARCH_TOP_K}) 
        docs = retriever.get_relevant_documents(query=query)  # 获取与查询相关的文本


        context = [d.page_content for d in docs]     # 从文本中提取出内容
        result = prompt.format(context="\n".join(context), question=query) # 格式化模板,并用从文本中提取出的内容和问题填充
        return result                 # 返回结果

这种通过组合langchain+LLM的方式,特别适合一些垂直领域或大型集团企业搭建通过LLM的智能对话能力搭建企业内部的私有问答系统,也适合个人专门针对一些英文paper进行问答,比如比较火的一个开源项目:ChatPDF,其从文档处理角度来看,实现流程如下(图源):
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/841777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka3.4 SASL/kerberos/ACL 证以及 SSL 加密连接

Kafka3.4 SASL/kerberos ACL 证以及 SSL 加密连接 序 前面我们使用 kafka3.3.1 on zookeeper 的模式进行多网段监听的 kafka 集群,顺便搭建起 kafkaui 后发现一些问题,我们 kafka 集群没有连接认证,万一谁知道了我们的 kafka 连接地址&…

如何免费申请SSL证书

如何免费申请SSL证书 文章目录 如何免费申请SSL证书前言1. 向域名平台申请SSL证书1.1 购买“免费证书” 2. 进一步进行创建证书设置2.1 对证书的关联域名进行补充 3. 云解析DNS3.1 进行验证信息 前言 我们可以成功地将自己购买的域名,绑定到连接本地群晖NAS的数据隧…

Element plus el-table 鼠标滚动失灵的问题及解决办法

Bug:ElementUI el-table 鼠标滚轮下滑动失灵的情况 我测出来的这个问题条件很苛刻,需要达到以下几个条件才会触发: 1.element plus(其他版本没试) 2.el-table-column组件有fixed属性时 3.template标签中有el-butto…

【EI/SCOPUS会议征稿】第三届数字经济与计算机应用国际学术会议(DECA2023)

第三届数字经济与计算机应用国际学术会议(DECA2023) The 3rd International Conference on Digital Economy and Computer Application 第三届数字经济与计算机应用国际学术会议 (DECA 2023) 将于2023年9月22-24日在中国上海召开。会议主题主要围绕数…

【2.1】Java微服务:详解Hystrix

✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。 🍎个人主页:Meteors.的博客 💞当前专栏: 深度学习 ✨特色专栏: 知识分享 &…

每天五分钟机器学习:梯度下降算法和正规方程的比较

本文重点 梯度下降算法和正规方程是两种常用的机器学习算法,用于求解线性回归问题。它们各自有一些优点和缺点,下面将分别对它们进行详细的讨论。 区别 1. 梯度下降算法是一种迭代的优化算法,通过不断迭代调整参数来逼近最优解。它的基本思想是根据目标函数的梯度方向,沿…

Vue-组件二次封装

本次对el-input进行简单封装进行演示 封装很简单,就给激活样式的边框(主要是功能) 本次封装主要使用到vue自带的几个对象 $attrs:获取绑定在组件上的所有属性$listeners: 获取绑定在组件上的所有函数方法$slots: 获取应用在组件内的所有插槽 …

MATLAB的设置路径

在主页下的 或者在命令行输入path,命令行会出现所有路径 必须要将某些函数.m文件以及一些类文件包含在路径当中,否则在脚本代码中输入代码时,不会有代码提示

【Azure】office365邮箱测试的邮箱账号因频繁连接邮箱服务器而被限制连接 引起邮箱显示异常

azure微软office365邮箱会对频繁连接自身邮箱服务器的IP地址进行,连接邮箱服务器IP限制,也就是黑名单,释放时间不确定,但至少一天及以上。 解决办法,换一个IP,或者新注册一个office365邮箱再重试。 以下是…

Mysql5.7 、MySQL 8.0 加密、解密函数

PASSWORD 8.0版本取消了,只能在5.7中使用 返回字符串str的加密版本,41位长的字符串,加密结果不可逆 格式 select PASSWORD(xxx) from DUAL;MD5 5.7和8.0 都支持 返回字符串str的MD5加密后的值,若参数为null,则…

不同风格Tabs

风格 通过type设置风格&#xff0c;支持三种风格card、borderCard、line 核心代码 组件双向绑定 modelVal: {type: Number | String,required: true}, model: {prop: modelVal,event: change} this.$emit(change, this.active) 代码 <template><div:class"[…

【链表OJ 1】移除链表元素val

大家好&#xff0c;欢迎来到我的博客&#xff0c;此题是关于链表oj的第一题&#xff0c;此后还会陆续更新博客&#xff0c;如有错误&#xff0c;欢迎大家指正。 来源:https://leetcode.cn/problems/remove-linked-list-elements/description/ 题目: 方法一:定义prev和cur指针…

基于STM32微控制器的物联网(IoT)节点设计与实现

基于STM32微控制器的物联网(IoT)节点的设计和实现。我们讨论物联网节点的基本概念和功能,并详细介绍了STM32微控制器的特点和优势。然后,我们将探讨如何使用STM32开发环境和相关的硬件模块来设计和实现一个完整的物联网节点。最后,我们将提供一个示例代码,展示如何在STM3…

侯捷 C++面向对象编程笔记——9 复合 委托

9 复合 委托 9.1 Composition 复合 类似于c中结构里有结构——class里有class deque 是一个已经存在的功能很多的类&#xff08;两头进出的队列&#xff09;&#xff1b;利用deque的功能来实现queue的多种操作 该例只是复合的一种情况——设计模式 Adapter 9.1.1 复合下的构造…

【JavaEE进阶】Spring创建与使用

文章目录 一. 创建 Spring 项目1.1 创建一个Maven项目1.2 添加Spring依赖1.4. 创建一个启动类 二. 将 Bean 对象存放至 Spring 容器中三. 从 Spring 容器中读取到 Bean1. 得到Spring对象2. 通过Spring 对象getBean方法获取到 Bean对象【DI操作】 一. 创建 Spring 项目 接下来使…

实时服务器监控

为 IT 基础架构建立适当的监控系统的重要性不容低估&#xff0c;管理员使用的监控解决方案可确保通过消除瓶颈和优化资源使用以获得最佳性能来充分发挥基础架构的潜力。 多年来&#xff0c;IT 基础架构变得越来越复杂&#xff0c;对网络监控的需求也随之增加&#xff0c;虽然网…

R语言3_安装SeurateData

环境Ubuntu22/20, R4.1 在命令行中键入&#xff0c; apt-get update apt install libcurl4-openssl-dev libssl-dev libxml2-dev libcairo2-dev libgtk-3-dev # libcairo2-dev :: systemfonts # libgtk :: textshaping进入r语言交互环境&#xff0c;键入&#xff0c; instal…

运动蓝牙耳机哪个最好、最好用的运动蓝牙耳机推荐

在奔跑的律动中&#xff0c;一款优秀的运动耳机能为我们带来动力。今天&#xff0c;我为大家推荐五款经过精心挑选的运动耳机&#xff0c;它们不仅具备卓越的音质和稳定的连接性&#xff0c;还采用舒适的佩戴设计和耐用的防水功能&#xff0c;可以让我们在运动中畅享音乐的同时…

数据结构之栈和队列---c++

栈和队列的简单介绍 栈 栈是一个“先进后出”结构 队列 入队演示 队列是一种“先进先出”的结构 出队演示 接下来我们开始本次的内容 栈实现队列 分析 1.我们可以老老实实的写一个栈然后将所有的接口函数实现出来&#xff0c;最后再进行实现队列&#xff0c;但是显然…

git开发过程中的使用

1、先创建本地分支&#xff0c;然后修改代码 2、本地提交 push 3、合并为主分支 回到master分支