基于ChatGLM+Langchain离线搭建本地知识库(免费)

目录

简介

服务部署

实现本地知识库

测试

番外


简介

ChatGLM-6B是清华大学发布的一个开源的中英双语对话机器人。基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存)。

LangChain提供了丰富的生态,可以非常方便的封装自己的工具,并接入到LangcChain的生态中,从而实现语言模型的交互,将多个组件链接在一起,并集成额外的资源,例如 API 和数据库。

服务部署

我是在一台离线服务器上,GPU内存16G,其中python3.10以上,torch1.10以上。首先github下载ChatGLM-6B(https://github.com/THUDM/ChatGLM-6B),方便调用接口,里面有一个 requirements.txt文件,直接安装里面环境即可,然后在Huggingface下载模型chatglm-6b(https://huggingface.co/THUDM/chatglm3-6b),最后将下载好的模型离线打包到离线服务器上。如下所示,其中kownledge文件夹里面包含了我要输入的知识文档(自己的一些文档、pdf、csv文件等)。

当环境搭建好之后,进入ChatGLm-6B文件夹下,打开api.py文件,将tokenizer和model的模型路径修改成从Huggingface下载下来的chatglm-6b模型路径,这里我用的是相对路径。

然后在服务器上运行api.py文件,服务在端口8000运行。

写一个测试代码api_access.py,看看服务是否能被正常使用。值得注意的是,如果你是在本地运行,这里的url写localhost:8000或者127.0.0.1:8000,如果是服务器运行,则写服务器的ip地址。

import requestsdef chat(prompt, history):resp = requests.post(#url = 'http://127.0.0.1:8000',url = 'http://172.27.171.194:8000',json = {"prompt": prompt, "history": history },headers = {"Content-Type": "application/json;charset=utf-8"})return resp.json()['response'], resp.json()['history']history = []
while True:response, history = chat(input("Question:"), history)print('Answer:',response)

运行结果如下所示,说明该api服务能够正常使用。

实现本地知识库

首先在Huggingface下载向量化模型,我选择了text2vec-base-chinese(https://huggingface.co/shibing624/text2vec-base-chinese/tree/main)

然后编写一个embedding.py文件,主要存放各种方法,完整代码如下所示。值得注意的是,由于我的服务器有多张显卡,因此我将cuda设置为1,你如果只有一张显卡,就直接是cuda:0。

from langchain_community.document_loaders import  Docx2txtLoader, PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from transformers import BertModel, BertTokenizer
import torch
import os# -*- coding: utf-8 -*-class EmbeddingFunction:def __init__(self, embedding_function):self.embedding_function = embedding_functiondef embed_query(self, query):return self.embedding_function(query)def embed_documents(self, documents):return [self.embedding_function(doc) for doc in documents]class EmbeddingRetriever:def __init__(self):# 加载embeddingself.embedding_model_dict = {"text2vec3": "shibing624/text2vec-base-chinese","bert-base-chinese": "/home/ai/bert-base-chinese",}def load_documents(self,directory='kownledge'):documents = []for item in os.listdir(directory):if item.endswith("docx") or item.endswith("pdf"):split_docs = self.add_document(directory, item)documents.extend(split_docs)return documentsdef add_document(self, directory='kownledge', doc_name=''):file_path = os.path.join(directory, doc_name)if doc_name.endswith("docx"):loader = Docx2txtLoader(file_path=file_path)elif doc_name.endswith("pdf"):loader = PyPDFLoader(file_path=file_path)data = loader.load()text_spliter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)split_docs = text_spliter.split_documents(data)return split_docsdef load_embedding_mode(self,model_name="text2vec3"):model_path = self.embedding_model_dict[model_name]tokenizer = BertTokenizer.from_pretrained(model_path)model = BertModel.from_pretrained(model_path).to("cuda:1")def embedding_function(text):inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True, max_length=512).to("cuda:1")with torch.no_grad():outputs = model(**inputs)embedding = outputs.last_hidden_state.mean(dim=1).squeeze().cpu().numpy().tolist()return embeddingreturn embedding_functiondef store_chroma(self,docs, db):db.add_documents(docs)db.persist()return db

简单解释如下,在load_documents和add_document方法中,由于我的知识文档是docx和pdf格式的,因此我就只写了两个类型,你如果有其他类型比如csv或者txt可以修改调用方式,如:

from langchain_community.document_loaders import  TextLoader,CSVLoader

测试

编写一个问答代码my_qa.py,完整代码如下所示,记得修改url地址。

from langchain_community.vectorstores import Chroma
import requests
from embedding import EmbeddingRetriever,EmbeddingFunction# -*- coding: utf-8 -*-def chat(prompt, history=None):plyload = {"prompt": prompt, "history": [] if not history else history}headers = {"Content-Type": "application/json"}resp = requests.post(url = 'http://172.27.171.194:8000',json = plyload,headers = headers).json()return resp['response']retriever = EmbeddingRetriever()
embedding_function = EmbeddingFunction(retriever.load_embedding_mode())
db = Chroma(embedding_function=embedding_function, persist_directory='VectorStore')# 添加知识文档
if True:documents = retriever.add_document(doc_name='课程表.docx')#documents = retriever.load_documents()db = retriever.store_chroma(documents,db)while True:query = input("question:")similar_docs = db.similarity_search(query,k=3)prompt = "基于以下给出的资料,回答问题:\n"for doc in similar_docs:prompt += f"{doc.page_content}\n"prompt += f"问题: {query}"response = chat(prompt,[])print("Bot:", response)

简单解释如下:

在服务器上运行python my_qa.py,结果如下:

可以看到,准确度还是相当不错的。如果自己输入的知识库数量越多,回答越准确。

最后看看我的服务器上的文档位置。

可能出现的问题

1、解决transformers和sentence-transformers版本冲突问题

使用pip install -U sentence-transformers下载sentence-transformers时会下载最新版2.7.0并且把最新版的transformers4.39.3一起附带下载下来,但是在ChatGLM中要求的transformers版本是4.27.1,因此如果使用最新版的transformers在运行api.py接口时会报错提示没有xxxx属性。解决方式有两种,第一种就是手动降低版本(但可能会报出其他错误),第二种就是修改chatglm-6b的配置文件,如下所示:

就是将从Huggingface下载的模型chatglm-6b下的tokenization_chatglm.py文件进行修改,将第222行的代码注释,放在第196行,也就是super().__init__上面。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信息系统架构模型_2.面向服务架构(SOA)模式

前面讲的客户机/服务器模式,无论多少层的C/S软件结构,对外来讲,都只是一个单结点应用(无论它由多个不同层的“服务”相互配合来完成其功能),具体表现为一个门户网站、一个应用系统等。而多个单点应用相互通…

浅析SPI接口

SPI是串行外设接口(Serial Peripheral Interface)的缩写,它是一种同步串行通信接口,用于微控制器和外围设备(如传感器、SD卡、其他微控制器等)之间的通信。SPI接口通常用于短距离通信,因为它不支…

VR全景技术在养老院的应用优势浅析

随着时代的快速发展,人口老龄化越来越严重,如何利用VR技术提升养老服务的质量,成为了社会各界关注的焦点。为养老院拍摄制作VR全景,不仅能够为养老院的老人子女们跨越空间限制,实现与家人的情感连接,还可以…

The 2023 ICPC Asia Hefei Regional Contest

目录 B. Queue Sorting 应该还会再补几题 B. Queue Sorting 题解: Dilworth定理: 【偏序关系与偏序集、Hasse图、极大元、极小元、全序关系、最大元、良序集/三小时讲不完离散数学之集合论/考研复试/期末复习考前冲刺/近世代数/抽象代数】https://www.bilibili.c…

NX二次开发,在指定的装配节点下新建或者添加组件

目录 一、概述 二、存在的问题 三、在指定的装配节点下新建或者添加组件的实现 四、结果显示 一、概述 最近学习装配内容,说一说体会吧,用起来很爽,开发起开是真的别扭啊,而且,网上可以收到的关于装配的知识有很多…

element 输入框禁止输入空格以及复制的值进去删除空格(vue自定义指令)开箱即用

实例图: 代码: //输入框禁止输入空格 Vue.directive(noSpace, {bind(el) {//禁止输入空格el.addEventListener("keydown", function (event) {if (event.keyCode 32) {event.preventDefault();}});//复制值时去掉空格el.addEventListener(&q…

PY32F403系列单片机,32位M4内核MCU,主频最高144MHZ

PY32F403系列单片机是基于Arm Cortex-M4核的32位通用微控制器产品。内置的FPU和DSP功能支持浮点运算和全部DSP指令。通过平衡成本,性能,功耗来获得更好的用户体验。 PY32F403单片机典型工作频率可达144MHZ,内置高速存储器,丰富的…

Android Studio连接MySQL8.0

【序言】 移动平台这个课程要做一个app的课设,我打算后期增加功能改成毕设,就想要使用MySQL来作为数据库,相对于SQLlite来说,我更熟悉MySQL一点。 【遇到的问题】 一直无法连接上数据库,开始的时候查了很多资料&#…

【C语言】/*操作符(上)*/

目录 一、算数操作符:、-、*、/、% 1.1 和 - 1.2 * 1.3 / 1.4 % 二、赋值操作符: 和符合赋值 2.1 连续赋值 2.2 复合赋值(自操作) 三、单目操作符:、--、(正号)、-(负号) 3.1 和 -- 3.1.1 前置 3.1.2 后置 3.1.3 前置-- …

【RAG 论文】Contriever:对比学习来无监督训练文本嵌入模型

论文:Unsupervised Dense Information Retrieval with Contrastive Learning ⭐⭐⭐⭐⭐ Facebook Research, arXiv:2112.09118 Code:github.com/facebookresearch/contriever 一、论文速读 本文使用对比学习的方法来对文本检索模型做无监督学习训练&am…

数据结构(一)绪论

2024年5月11日 一稿 数据元素数据项 逻辑结构 集合 线性结构 树形结构 图结构 物理结构 数据运算 算法 时间复杂度

【贪心算法】哈夫曼编码Python实现

文章目录 [toc]哈夫曼编码不同编码方式对比前缀码构造哈夫曼编码哈夫曼算法的正确性贪心选择性质证明 最优子结构性质证明 总结 Python实现时间复杂性 哈夫曼编码 哈夫曼编码是广泛用于数据文件压缩的十分有效的编码方法,其压缩率通常为 20 % 20\% 20%到 90 % 90\%…