基于大语言模型的本地知识库问答(离线部署)

一、前言

知识库问答是一种应用广泛的系统,可以在许多领域发挥重要作用。不过以往的系统通常是基于固定规则、相似度检索或者seq2seq模型,这类系统开发成本较高、修改也较为麻烦,尤其在数据准备过程需要耗费大量精力。

而大语言模型(LLM)的出现打破了这种局面,在LLM的加持下,无论是系统编写还是数据准备上,工作量都大大减少,可以使用百行代码实现非常智能的知识库问答系统。

本文将分享使用开源LLM,完全离线部署知识库问答系统。

二、前置知识

2.1 大语言模型

语言模型是自然语言处理领域中一个非常重要的概念,语言模型是评估一串有序字符是句子的概率的一种模型。比较经典的有Bert系列、GPT系列等。而现在常说的大语言模型更多是指GPT系列的模型。

以往的GPT模型的训练方式非常简单,就是根据一个句子的前n个词,预测第n+1个词。这种看似非常简单的方式,却给GPT带来了非常大的自由度。

2.2 Prompt工程

比如我们可以直接把GPT应用在情感分析上,我们只需要设置一下输入的前n个词,比如:

“这部电影真烂”的情绪是

然后GPT就可以预测下一个词以及下下个词,最后得到结果“消极”。或者我们可以输入:

这部电影真烂, 消极
太好看了,

然后GPT就可以预测出“积极”。或者我们输入的内容还可以更长:

这部电影真烂, 消极
xxxx, 积极
xxxx, 消极
太好看了,

上面这种通过改变输入内容让GPT输出特定结果的方式就叫做prompt工程,通过修改prompt,我们可以让GPT完成更复杂的工作,比如问答、翻译等。下面以翻译为例,我们只需要输入prompt:

中文:不要温顺的走进那个良夜
英文:

这样就可以让GPT输出句子的英文。

2.3 模板

上面我们列举了一些Prompt示例,在实际使用时,输入的Prompt有部分内容是动态修改的,这部分可以用一些占位符来占位,比如:

这部电影真烂, 消极
{sentence},

我们只需要输入句子s,然后用s替换掉prompt中的{sentence}(字符串替换),就得到了最终输入GPT的Prompt,上面这种带有占位符的Prompt就是模板。

2.4 RLHF

早期的GPT是无监督学习,就是前面描述的根据前n个词预测下一个词。而现在主流的类GPT模型都是使用无监督学习+RLHF的方式。

首先无监督学习部分和早期GPT是一样的,做文字接龙或者类似句子接龙等任务。而RLHF则是基于人类反馈的强化学习,在这个过程中会有人类老师帮助GPT纠正输出,让GPT输出更符合人类的对话形式。也正是RLHF造就了ChatGPT。

三、实现原理

3.1 基于检索的问答

在Bert时代,还有一种基于向量相似度的问答系统。这种系统非常简单,但是前期数据的收集需要花费较多的时间,这种系统与本文要讨论的系统有许多相似的地方。

首先我们需要收集大量的问答对,比如:

江西是省会是哪?南昌
北京是南方还是北方?北方
...?xx

收集完成后,使用bert提取问题的特征向量,然后存储到向量数据库。在提问时,提取问题的特征向量,并检索出最相似的问题,并返回对应答案。

无标题-2023-07-02-2226.png

3.2 基于大语言模型知识库问答

基于检索的问答系统有几个问题,因为数据需要问答对的形式,因此数据收集需要消耗大量时间。另外回答的内容是固定的,因此输入同一个问题,会得到相同的结果。在某些系统中,这是个优点,但是如果是客服系统则过于机械。

基于大语言模型的知识库问答的也需要借助向量数据库。下面是具体实现步骤:

  1. 收集大量文档数据
  2. 对文档进行拆分,拆分成多个段
  3. 使用Bert等模型将每段文档进行embedding(提取特征向量)并存储到数据库
  4. 根据问题检索到k段最相关的文档
  5. 将文档注入Prompt,利用大语言模型回答问题。

首先是数据收集,我们不再需要问答对形式,只需要处理干净的文档形式,这样就减少了大量的工作。

因为文档通常比较大,而Bert模型(在这里也称为Embedding模型)有上下文长度的限制,因此需要将文档拆分成Embedding模型限制的大小。

而提取embedding和存储向量数据库部分则和3.1是一样的。因为文档有上下文大小的限制,同时某一个问题可能出现在文档的多个位置,因此检索时返回k个相关文档段。

最后利用Prompt工程+LLM完成最后的问答。下图是取自Llamindex的一张图:

image.png

四、代码实现

4.1 LLM

首先需要选择一个LLM,现在LLM百花齐放,可以选择的开源方案有很多,包括ChatGLM、Llama2等。这里选择Llama2作为LLM。而Llama2的部署方式也是多种多样,这里使用llamacpp部署,我们需要安装llama-cpp-python模块:

pip install llama-cpp-python

另外还需要编译转换Llama2的模型文件。具体方式参考: [www.bilibili.com/video/BV1m3…]

然后只需要编写下面的代码就可以运行llama2:

from llama_cpp import Llama  
  
model_path = "llama-2-13b-chat.Q4_0.gguf"  
llm = Llama(  
    model_path=model_path,  
    n_ctx=2048,  
    chat_format="llama-2"  
)  
response = llm('Human:你好啊\nAssistant:', stop=['Human:'])  
print(response['choices'][0]['text'])

4.2 文档处理

文档处理对应3.2中的前三步,我们可以使用langchain来完成这步操作,代码如下:

import os  
from langchain.document_loaders import DirectoryLoader  
from langchain.text_splitter import CharacterTextSplitter  
from langchain.embeddings.huggingface import HuggingFaceEmbeddings  
from langchain.vectorstores import Chroma  
  
# 加载embedding  
embedding_model_dict = {  
    "ernie-tiny": "nghuyong/ernie-3.0-nano-zh",  
    "ernie-base": "nghuyong/ernie-3.0-base-zh",  
    "text2vec": "GanymedeNil/text2vec-large-chinese",  
    "text2vec2": "uer/sbert-base-chinese-nli",  
    "text2vec3": "shibing624/text2vec-base-chinese",  
}  
  
  
def load_documents(directory="documents"):  
    """  
    加载books下的文件,进行拆分  
    :param directory:  
    :return:  
    """  
    loader = DirectoryLoader(directory)  
    documents = loader.load()  
    text_spliter = CharacterTextSplitter(chunk_size=256, chunk_overlap=0)  
    split_docs = text_spliter.split_documents(documents)  
    return split_docs  
  
  
def load_embedding_model(model_name="text2vec3"):  
    """  
    加载embedding模型  
    :param model_name:  
    :return:  
    """  
    encode_kwargs = {"normalize_embeddings": False}  
    model_kwargs = {"device": "cuda:0"}  
    return HuggingFaceEmbeddings(  
        model_name=embedding_model_dict[model_name],  
        model_kwargs=model_kwargs,  
        encode_kwargs=encode_kwargs  
    )  
  
  
def store_chroma(docs, embeddings, persist_directory="VectorStore"):  
    """  
    讲文档向量化,存入向量数据库  
    :param docs:  
    :param embeddings:  
    :param persist_directory:  
    :return:  
    """  
    db = Chroma.from_documents(docs, embeddings, persist_directory=persist_directory)  
    db.persist()  
    return db  
  
  
# 加载embedding模型  
embeddings = load_embedding_model('text2vec3')  
# 加载数据库  
if not os.path.exists('VectorStore'):  
    documents = load_documents()  
    db = store_chroma(documents, embeddings)  
else:  
    db = Chroma(persist_directory='VectorStore', embedding_function=embeddings)  


我们在当前目录下准备一个documents文件夹,在里面放入我们的txt文档即可。在langchain里面内置了包括json、csv、PDF等文档处理的类,这里可以根据自己的需求修改load_documents函数。这里需要注意两个参数:

text_spliter = CharacterTextSplitter(chunk_size=256, chunk_overlap=0)  


上面这句是拆分文档的代码。其中chunk_size是每段的长度,而chunk_overlap则是两个段之间重叠的大小。chunk_size可以根据电脑性能、Embedding模型上下文限制、LLM上下文限制来确定。而chunk_overlap可以选0.1或0.5*chunk_size。

另外上面加载的模型都是中文的Embedding,如果有其它语言需求,可以选择用多语言的Bert作为Embedding。具体参考sentence-transformers可用的模型。

4.3 将文档注入Prompt

在输入前,需要先检索相关的文档,比如我存储了“塞尔达王国之泪”的攻略,使用下面代码搜索“究极手”相关内容:

docs = db.similarity_search('究极手是干啥用的', k=5)  
for doc in docs:  
    print(doc)


得到如下输出:

page_content='尝试用右手打开神殿大门但以失败告终,这是一个自称“劳鲁”的灵体出现在了林克的身后。劳鲁告诉林克需要去岛上的神庙中回复手臂的力量才能打开大门。\n\n来到神殿旁的第一个神庙。\n\n【乌可乌侯神庙—创造之力】\n\n进入神庙与劳鲁对话,获得第一个能力—究极手。\n\n用究极手能力抓取板子搭在两个平台之间,然后再通过。\n\n来到第二个平台后,通过的方法大致相同,不过需要将旁边两块板子拼合成更长一点的长板。\n\n来到神龛前的平台,用一旁的铁钩和木板组合成一个简单移动平台,接着将移动平台挂在铁轨上,站在上面抵达对面。' metadata={'source': 'documents\\王国之泪游侠攻略.txt'}
page_content='还有一个神庙在雪山上。\n\n神庙附近有个呀哈哈,追上发光的物体即可抓到。\n\n接下来我们按照逆时针方向,把初始空岛探索一遍。(顺指针走也行,但是逆时针走对新手来说是更好的体验)\n\n继续往西走有两条路。\n\n可以在神庙下方直接用木板搭桥过去。\n\n也可以到附近的山头上,组合铁钩和木板,从铁轨滑过去。\n\n第3页:初始空岛\n\n西部\n\n初始空岛\n\n西部\n\n来到初始空岛西部,与劳鲁对话。对话木匠魔像学习砍树,旁边树桩上拿到斧子。\n\n用斧子砍树得到圆木,圆木可以组合起来作为立足处,也可以进一步劈开做成木柴。' metadata={'source': 'documents\\王国之泪游民攻略(上).txt'}
page_content='回湖边想办法渡水,因为风是向南刮的,把帆插在木筏上,就可以顺风过去,抵达第二个神庙。(有种孙悟空出海找寻菩提祖师的感觉哈哈)\n\n第4页:初始空岛\n\n伊恩伊萨神庙\n\n初始空岛\n\n伊恩伊萨神庙\n\n走上楼梯,进入神庙。\n\n拾起双手剑。\n\n使用余料建造能力,把石头安装到双手剑上,组合成石锤。(余料建造能力也有多种玩法,也可以给自己的盾上安装东西)\n\n用石锤就可以砸开挡路的石块了。\n\n看左边水池,高处有个宝箱,用石锤打碎石柱即可拿到宝箱。' metadata={'source': 'documents\\王国之泪游民攻略(上).txt'}
page_content='把立方块放到弹射器上,然后踩按钮,立方块就会被往上弹射。\n\n站在立方块上,用时光倒流上升,然后就能滑翔到终点了。\n\n神庙北面的路通往迷雾森林,暂时进不去以后再说。路上齐洛利森林有个深穴,通往地底。\n\n第153页:奥尔汀地区\n\n大妖精之泉(蒂拉)\n\n奥尔汀地区\n\n大妖精之泉(蒂拉)\n\n回到驿站,把两个轮子粘上,帮乐团修好车。\n\n给马装上牵引挽具,骑马拖着车带他们去大妖精之泉。\n\n乐团唤醒蒂拉后,她会为你标出另外三个大妖精之泉的位置。' metadata={'source': 'documents\\王国之泪游民攻略(上).txt'}
page_content='进入神庙发现黑漆漆的,可以把之前获得的采矿套装穿上照亮身旁。不过最好使的还是光亮花,建议多射几个把整个迷宫照亮。\n\n进入迷宫先右拐,用究极手拿出右侧墙壁上的石块,里面有个宝箱,用究极手把宝箱抓出来。\n\n继续往前走,岔路口右拐有个宝箱。\n\n继续往前走,岔路口右拐,把地板揭开有个宝箱,宝箱里拿到小钥匙。\n\n继续往前走,抬头看上面,用通天术上去有个宝箱。\n\n继续往前走,激光后面有个宝箱。\n\n回到入口,用小钥匙开门抵达终点。\n\n第142页:海拉鲁大森林\n\n奇乌悠悠乌神庙\n\n海拉鲁大森林\n\n奇乌悠悠乌神庙' metadata={'source': 'documents\\王国之泪游民攻略(上).txt'}


基于LLM的知识库问答需要一个特殊的Prompt来完成,具体如下如下:

根据下面的上下文(context)内容回答问题。
如果你不知道答案,就回答不知道,不要试图编造答案。
答案最多3句话,保持答案简介。
总是在答案结束时说”谢谢你的提问!“
{context}
问题:{question}


然后需要将文档注入到如下的Prompt里面,代码如下:

template = """  
根据下面的上下文(context)内容回答问题。  
如果你不知道答案,就回答不知道,不要试图编造答案。  
答案最多3句话,保持答案简介。  
总是在答案结束时说”谢谢你的提问!“  
{context}  
问题:{question}"""  
query = "究极手是干啥用的"  
docs = db.similarity_search(query, k=5)  
context = "\n".join([f"{idx + 1}.{doc.page_content}" for (idx, doc) in enumerate(docs)])  
prompt = template.format(context=context, question=query)  
print(prompt)


最后只需要将这个Prompt输入给LLM即可:

response = llm(f'Human:{prompt}\nAssistant:', stop=['Human:'])  
print(response['choices'][0]['text'])


最后输出结果如下:

 嗯,究极手是一种非常实用的能力,可以用于装配和拆解各种物品,以及对盾牌和武器进行合成拆卸。你可以用它来组合材料、砍树、打碎石块等,也可以在各种情况下进行优化和适应。


可以看到回答结果部分是正确的。

五、总结

在LLM的加持下,知识库问答的实现变得非常简单。而且现在有诸如langchain、Llamaindex之类的框架集成了许多与LLM相关的操作。另外现在LLM的开源社区非常活跃,出现了诸如Llama2、mistral-7b等优秀的开源LLM。不管是参数量、资源消耗、训练速度等都降低到在消费级显卡上完成。

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

事务的影子拷贝-系统架构师(二十)

1、(重点)企业信息集成按照组织范围分为企业内部的信息集成和外部信息集成。在企业内部信息集成中,()实现了不同系统之间的互操作,使的不同系统之间能够实现数据和方法的共享。()实现…

基于Java的外卖点餐系统设计与实现

作者介绍:计算机专业研究生,现企业打工人,从事Java全栈开发 主要内容:技术学习笔记、Java实战项目、项目问题解决记录、AI、简历模板、简历指导、技术交流、论文交流(SCI论文两篇) 上点关注下点赞 生活越过…

Linux\ubuntu系统下载中文输入法

目录 1 系统图形化安装 1.1 打开设置 1.2 选择语言 1.3 选择简体中文 1.4 再次打开设置 1.5 选择中文 1.6 退出即可安装成功 本文主要记述在ubuntu1806下安装中文输入法的过程,其实Ubuntu上可以安装的中文输入法有很多种,可以直接通过系统安装&am…

周界入侵自动监测摄像机

当今,随着科技的快速发展,周界入侵自动监测摄像机作为安全监控领域的重要创新,正逐渐成为各类场所安全防范的核心设备。这种摄像机以其先进的监测和预警功能,有效提升了安全管理的效率和实时响应能力,被广泛应用于各类…

什么是屎山代码?

为什么说再厉害的程序员,也怕屎山代码? 首先,屎山代码不是指的一种开发语言,而是对庞大项目的一个别称。 常言道,屎山传万代,代代不吱声。每次传承都会遗留大量问题,接手的人一般都不敢动代码&a…

JSONpath语法怎么用?

JSONPath 可以看作定位目标对象位置的语言,适用于 JSON 文档。 JSONPath 与 JSON 的 关系相当于 XPath 与 XML 的关系, JSONPath 参照 XPath 的路径表达式,提供了描述 JSON 文档层次结构的表达式,通过表达式对目标…

双端队列广搜——AcWing 175. 电路维修

双端队列广搜 定义 双端队列广搜(Breadth-First Search with a Deque)是一种图或树的遍历算法变体,它利用了双端队列(Deque,全称Double Ended Queue,允许在其两端进行插入和删除操作)作为数据…

vision mamba-yolov8:结合Vmamba的yolov8目标检测改进实现

1.vision mamba结构与原理 Mamba成功的关键在于S6模型,该模型为NLP任务设计,通过选择性扫描空间状态序列模型,将二次复杂度降低至线性。但由于视觉信号(如图像)的无序性,Mamba的S6模型不能直接应用&#xf…

20240701给NanoPi R6C开发板编译友善之臂的Android12系统

20240701给NanoPi R6C开发板编译友善之臂的Android12系统 2024/7/1 14:19 本文采取这个模式编译:11.6.3 编译Android Tablet版本(首次编译) echo "ROCKCHIP_DEVICE_DIR : device/rockchip/rk3588/nanopi6" > .rockchip_device.mk # export INSTALL_GAP…

给小程序接入AI服务之后,我的睡后收入又增加了

自从本人写了《[从零开始三天学会微信小程序开发]》教程以来,不断有人加我,一起交流微信小程序开发的事情,很让人开心。 也有一些人和我说,现在已经是AI时代了,怎么还用这种固定内容的模式呢?确实是的&…

K8S 集群节点缩容

环境说明: 主机名IP地址CPU/内存角色K8S版本Docker版本k8s231192.168.99.2312C4Gmaster1.23.1720.10.24k8s232192.168.99.2322C4Gwoker1.23.1720.10.24k8s233(需下线)192.168.99.2332C4Gwoker1.23.1720.10.24 1. K8S 集群节点缩容 当集群中有…

ROS2使用Python开发动作通信

1.创建接口节点 cd chapt4_ws/ ros2 pkg create robot_control_interfaces --build-type ament_cmake --destination-directory src --maintainer-name "joe" --maintainer-email "1027038527qq.com" mkdir -p src/robot_control_interfaces/action touch…

【微服务】微服务之Feign 与 Ribbon

文章目录 强烈推荐引言优点Feign示例什么是Ribbon?Ribbon 的优点Netflix Feign 和 Ribbon整合Feign 与 Ribbon 的关系Feign 与 Ribbon 结合使用的示例配置文件(application.yml)说明: Feign 与 Ribbon 结合使用的应用场景1. 动态服…

XD3C03P1G、XD3C01N3F比例方向控制阀放大板

XD3A01N2G、XD3A03N2G、XD3C03N1F、XD3C03P1G、XD3C01N3F、XD3C03N2F、XD3C01P4G、XD3C03P3G、XD3C03N2F、XD3C03N2G、XDP3A01P1F、XDP3C03N2G、XDP3A03P3G、XDP3C01NAF、XDP3C03P6G、XDP3A03PAG、XDP3A03N3F液压比例方向阀是液压系统中的关键元件,用于实现对流量、…

C#/WPF 自制截图工具

在日常使用电脑办公时,我们经常遇到需要截图然后保存图片,我们往往需要借助安装截图工具才能实现,现在我们通过C#自制截图工具,也能够轻松进行截图。 我们可以通过C#调用WindousAPI来实现截图,实例代码如下&#xff1a…

Three.js 中的光照模型

Three.js 中的光照模型 Three.js 的一个伟大抽象就是统一了所有材质的光照模型, 无论 PBR 或者 Phong。都只用两个函数给全部囊括了。 就是 RE_Direct(直接反射) 和 RE_IndirectDiffuse(间接反射)。真正做到了大一统。下面以Phong为例,具体看一下如何落地。 省流版本: // 直接…

CSF视频文件格式转换WMV格式(2024年可用)

如果大家看过一些高校教学讲解视频的话,很可能见过这样一个难得的格式,".csf ",非常漂亮 。 用暴风影音都可以打开观看,会自动下载解码。 但是一旦我们想要利用或者上传视频的时候就麻烦了,一般网站不认这…

开放式耳机哪个品牌质量最好最耐用?2024热门红榜耳机真实测评

随着人们生活质量的提高,喜爱运动的小伙伴也越来越多了,开放式蓝牙耳机的佩戴舒适度与稳定性这两个优势在很多运动场景中可以为用户带来更好的使用体验。此外,我们的音频使用、通话、游戏等应用场景在不断拓宽,蓝牙耳机的使用时间…

qt可点击的QLabel

需求——问题与思路 使用wpf实现一个可点击的超链接label相当简单(如下图),但是qt的QLabel不会响应点击事件,那就从QLabel继承一个类,然后在该类中重写mousePressEvent函数,并在该函数中对左键点击事件做响…

FPGA工程师有前途吗 ?FPGA崛起之路

全球 FPGA 市场规模犹如滚雪球般逐年扩大。 根据Gartner Group预测,2020-2026年全球FPGA市场规模从55.85亿美元增至96.9亿美元,年均复合增长率为9.6%。 众多国际知名科技企业,如赛灵思、Lattice等,纷纷加大在 FPGA 研发和应用方…