1. 前言
本文主要论证从零开始搭建爬虫->向量数据库->LLM大模型知识库过程,文章中不依赖任何爬虫、LangChain、Chat GLM等框架,从最原始角度通俗易懂、直观的解读大模型与向量数据库结合过程,给大家提供现阶段热门企业大模型解决方案建设思路和方向。
目前流行的中文开源大模型非ChatGLM(智普)、baichuan(百川)等莫属。虽然认知能力赶不上ChatGPT 3.5,但是它的开源吸引了广大的AI研究者。
目前大语言模型存在最大的问题在于:
1、研究成本高,如果搭建一个13B以及以上的模型,全量运行需要24GB以上显存,如果进行量化质量又达不到要求,前期研究就要投入大量成本并且如果有多个LLM项目并行开发就会遇到项目组之间抢资源问题;
2、训练成本高,回报率随机,对于广大进行“炼丹”的“仙人”们都知道,炼丹最大问题在于整理的训练集、训练轮数及各种参数可能导致炼出废丹,并且知识的日益更新,如果要更新知识就要重新训练;
3、胡乱说话(幻想),幻想就是你问一个问题,它有板有眼儿的给你回答,你不是专业人士可能就会被它的回答误导了。LLM的幻想并非真正的幻想,而是由其训练方式和数据源所决定的,LLM通过大量的互联网文本数据进行训练,这些数据包含了各种话题和语境。
以上就是目前LLM模型常见的问题,对于模型的研发者和使用者都是头痛问题。针对企业级AI应用,目前有个大家探索的方案就是向量数据库+LLM大模型结合,解决研究成本、训练及胡乱说话问题,通过知识库中准确的内容弥补数据的不足导幻想。
其原理就是将知识要点存储到向量数据库,在提问时通过分词或大模型对提问内容进行分解,从向量数据库提取出关键内容,然后再将内容喂给LLM模型,从而得到想要的答案,从而实现了AI数据库的可维护性,这个模型可以用于OpenAI API也可以用于LLM私有化模型。
接下来,我们从探索的角度来研究向量数据库+LLM大模型的应用(这里不使用LangChain 东西,因为他们封装很深不适合从原理上研究探索)
2. 实现目标
本次目标是搭建一个腾讯云向量数据库LLM知识问答系统:
1、搭建向量数据库(这里使用 腾讯云向量数据库Tencent Cloud VectorDB);
2、开发知识库采集及存储工具
(1) 编写爬虫工具,实现知识库数据爬取;
(2) 编写数据存储服务
3、开发LLM大模型对话功能,并将向量数据库知识库加入到大模型对话中来;
环境准备:
Python:3.10
LLM:ChatGLM 3
运行环境:Windows11 WSL2 Ubuntu22.04
开发工具:VsCode
3. 开发爬虫及知识库存储工具
3.1. 环境搭建
创建一个独立的python虚拟环境,内容存储再venv中
python-m venv venv
激活venv执行:
vectorenv\Scripts\activate.bat
3.2. 爬虫工具开发
确定要爬取的URL地址:
https://cloud.tencent.com/document/product/1709
编写Crawling.py爬虫,爬取向量知识库内容
引入依赖包:
import requestsimport jsonimport refrom bs4 import BeautifulSoup
引用依赖:
pip install bs4pip install lxml
定义相关变量:
seed = "https://cloud.tencent.com/document/product/1709"baseUrl="https://cloud.tencent.com"appendUrlList=[]appendDataList = []
获取栏目所及子栏目所有URL地址,这里通过textarea的J-qcSideNavListData CSS进行定位,并从文本中得到JSON没描述信息。
def getCrawl(seed):seeds = []seeds.append(seed)textdata = requests.get(seed).textsoup = BeautifulSoup(textdata,'lxml')nodes = soup.select("textarea.J-qcSideNavListData")jsonObj=json.loads(nodes[0].getText())["list"]seeds.append(nodes)getChild(jsonObj) def getChild(nowObj): if nowObj is not None:for n in nowObj:links= baseUrl+n["link"]data={"title":n["title"],"link":links}appendUrlList.append(data)if n.get("children") is not None:getChild(n.get("children"))
遍历爬取到的地址信息,来获取指定页面正文内容,这里对正文中的html标签需要去除,不然会有大量干扰内容:
def crawlData():getCrawl(seed)for data in appendUrlList:url = data["link"]print("正在爬取:"+data["title"]+""+data["link"])textdata = requests.get(url).textsoup = BeautifulSoup(textdata,'lxml')nodes = soup.select("div.J-markdown-box")if nodes is not None and len(nodes)>0:text = nodes[0].get_text()text =