1 背景
知识库需求在各行各业中普遍存在,例如制造业中历史故障知识库、游戏社区平台的内容知识库、电商的商品推荐知识库和医疗健康领域的挂号推荐知识库系统等。传统知识库搜索系统基于关键字匹配,缺少对用户问题理解和答案二次处理能力。为保证推荐系统的实效性和准确性,需要大量的数据/算法/软件工程师的人力投入和包括硬件在内的物力投入。其次,为了进一步提高搜索准确率,如何引导用户搜索描述更加准确和充分利用用户行为优化搜索引擎也是常见的用户痛点。此外,如何根据企业知识库直接给出用户提问的答案也是众多企业中会遇见的技术瓶颈。
大语言模型(Large Language Model,LLM)是一种人工智能模型,旨在理解和生成人类语言。它们在大量的文本数据上进行训练,可以执行广泛的任务,包括文本总结、翻译、情感分析等等。近几年来,大语言模型的发展十分迅速,探索使用大语言模型,通过其对自然语言理解和生成的能力,揣摩用户意图,并对原始知识点进行汇总、整合,生成更贴切的答案。
2 应用
各行各业中有很多场景都需要基于企业知识库进行搜索和问答。
- 构建装备维护知识库和问答系统
使用历史维保记录和维修手册构建企业知识库,维修人员可依靠该知识库,快速地进行问题定位和维修。
- 构建 IT/HR 系统智能问答系统
使用企业内部 IT/HR 使用手册构建企业知识库,企业内部员工可通过该知识库快速解决在 IT/HR 上遇到的问题。
- 构建电商平台的搜索和问答系统
使用商品信息构建商品数据库,消费者可通过检索+问答的方式快速了解商品的详细信息。
- 构建游戏社区自动问答系统
使用游戏的信息(例如游戏介绍,游戏攻略等)构建社区知识库,可根据该知识库自动回复社区成员提供的问题。
- 构建智能客户聊天机器人系统
通过与呼叫中心/聊天机器人服务结合,可自动基于企业知识库就客户提出的问题进行聊天回复。
- 构建智能教育辅导系统
使用教材和题库构建不同教育阶段的知识库,模拟和辅助老师/家长对孩子进行教学。
为解决上述场景需求,可通过结合搜索和大语言模型的方式来实现。首先,可以利用企业自身积累的数据资产建立一个知识库。其次,对于特定的问答任务,可以使用搜索功能对知识库进行有效的召回,然后将召回的知识进行利用,增强大语言模型。通过这一方法,可以实现对问答任务的解决。
3 技术选型
3.1 需求描述
打造特定领域知识(Domain-specific Knowledge)问答系统,具体需求有:
- 通过自然语言问答的形式,和用户交互。
- 理解用户不同形式的问题,找到与之匹配的答案。可以对答案进行二次处理,比如将关联的多个知识点进行去重、汇总等。
- 支持上下文。有些问题可能比较复杂,或者原始知识不能覆盖,需要从历史会话中提取信息。
- 准确。不要出现似是而非或无意义的回答。
从大语言模型角度而言,上面的需求是在两阶段训练模式下,如图 1所示,面向下游场景进行适配的问题。基础模型(Foundation Model),面向特定领域不能直接应用,因为领域知识不在预训练的数据集中,比如:
- 较新的内容。同一个知识点不断变更:修改、删除、添加。如何反馈当前最新的最全面的知识。
- 未公开的、未联网的内容。
3.2 方案分析
基于 LLM 搭建问答系统的解决方案有以下几种:
(1)基于微调(Fine-Tuning)的技术方案。
(2)基于提示工程(Prompt Engineering)的技术方案,比如 Few-Shot 方式。
(3)与搜索结合的技术方案,使用基础模型对搜索结果加工。
3.2.1 基于微调
使用下游特定领域的知识对基础模型进行微调,改变神经网络中参数的权重。业界已经不少ChatGPT的平替方案都支持微调,比如:
-
清华大学于2023.03提出的ChatGLM支持中英双语,具有62亿参数,可以在消费级显卡上部署,INT4量化级别下最低只需要6GB显存。
-
Alpaca是在Meta提出的LLaMA 7B模型基础上微调的结果。原生的Alpaca对中文的支持并不好,不过已经业界也做了些扩充中文词表的开源方案。
微调方式比较适合特化的任务或风格,但也存在一些问题:
-
没有解决事实性问答可靠性的问题。
-
消耗的资源量虽然相对大模型预训练减少,但还是不容小觑的。比如Alpaca的微调,据作者介绍他们使用8个显存80GB A100,花费了3个小时。如果领域支持频繁更新,且需要较高的实时性,显然是无法满足要求的。
-
需要构建特定领域微调的训练语料,可以参考Dataset Engineering for LLM finetuning。如果想要获得较好的结果,高质量训练数据集的构建需要精心设计,开销也是不容忽视的。
微调的结果不一定符合预期。在ChatGLM-6B微调实践中可以发现,使用ADGEN数据集微调后,模型对“广告词生成”任务的确变好,但其他任务的回答均不如原始模型。
3.2.2 基于提示工程
将特定领域的知识作为输入消息提供给模型。类似于短期记忆,容量有限但是清晰。举个例子给 ChatGPT 发送请求,将特定的知识放在请求中,让ChatGPT对消息中蕴含的知识进行分析,并返回处理结果。
- 优势。正确性和精度高。
- 劣势。一次可以处理的文本量有限制,如果知识库较大,无论从可行性还是效率而言都是不合适的。
3.2.3 与搜索结合
基于微调和基于提示工程方式均存在缺陷,比如效率低下、数据不够精确、不能支持大规模数据量等问题。这里提出第三种方法,尝试克服这些困难,基本思想是:
- 使用传统搜索技术构建基础知识库查询。好处在于:
- 问答可控性更高一些。
- 无论是数据规模、查询效率、更新方式都可以满足常见知识库应用场景的需要。
- 技术栈成熟,探索风险低。
- 使用LLM作为用户和搜索系统件沟通的介质,发挥其强大的自然语言处理能力:
- 对用户请求进行纠错、提取关键点等预处理实现“理解”。
- 对输出结果在保证正确性的基础上二次加工,比如——概括、分析、推理等。
3.3 方案设计
整个方案设计由两部分组成,如下图所示:
(1)LLM
- 完成对用户问题的预处理。纠正语法错误,提取关键点,通过交互方式引导用户补充问题足够多的信息等。
- 对本地搜索系统的原始答案进行二次处理。比如内容过多,可以进行概括;也可以进行简单推理。
- 提供上下文交互的能力。一个常见的例子是 “比较”,比如游戏中贩售道具,倚天剑和屠龙刀。原始知识系统只会提供两件兵器的基础属性,但不会提供各属性的对比和总体评价。
(2)本地搜索系统
解决查询匹配的问题,在“Search: Query Matching via Lexical, Graph, and Embedding Methods”一文中介绍了三种基本方式:
- 基于词汇的搜索(Lexical-based search)
通过归一化、拼写纠错、扩展、翻译等方式对查询请求中的词进行替换。性能好、可控性强,尽管存在一些语义鸿沟问题,但仍被广泛的应用在现有的搜索引擎架构中。
- 基于图的搜索(Graph-based search)
以图的形式描述知识点以及相互间的关系,然后通过图搜索算法寻找与查询请求匹配的结果。这种方法可以通过考虑不同概念之间的关系来提高搜索结果的相关性。
- 基于嵌入的搜索(Embedding-based search)
将文字形式的查询请求,编码为数值向量的形式,体现潜在的关系。这种方法可以通过考虑查询和文档之间的语义相似性来提高搜索结果的相关性。
OpenAI推荐词嵌入方法。嵌入很容易实现,并且在问题中表现尤为出色,因为问题通常在词汇上不会与它们的答案重叠。
可以考虑将仅使用嵌入的搜索视为作为整个系统的起点。更好的搜索系统可能会结合多种搜索方法,以及特性,如受欢迎程度、最近性、用户历史记录、与先前搜索结果的冗余、点击率数据等。
同样,我们这里也选用基于嵌入的搜索方法实现本地搜索系统。
3.4 技术选型
通过方案分析,我们已经选取了LLM与搜索结合方法来构建知识问答系统。在方案设计部分,通过分析,我们选取了基于嵌入的搜索方法来构建本地搜索系统。接下来,针对选取的方案,确定具体使用的技术方案,包括整个框架的选取、LLM模型的选取、词向量(embedding)模型的选取等。
通过调研,最终我们选取了使用LangChain作为应用开发框架,LLM模型选用基于Llama2支持中文的模型,词向量模型选取智源人工智能研究院最新发布的bge-large-zh作为向量模型。
3.4.1 LangChain
LangChain 创建于2022年10月,是一个利用大语言模型的能力开发各种下游应用的开源框架,它的核心理念是为各种大语言模型应用实现通用的接口,简化大语言模型应用的开发难度,主要的模块示意图为:
-
Index:提供了各类文档导入、文本拆分、文本向量化存储和检索的接口,导入的文档类型除常见的 word、excel、PDF、txt 外,还包括 API 和数据库接口,向量化存储包括各类向量数据库,其中也包含 AWS 的 OpenSearch 搜索引擎。通过 Index 模块,非常容易处理各类型的外部数据,来提供给大模型进行推理。
-
Prompts:将用户输入和其他外部数据转化为适合大语言模型的提示词,包括提示词管理、提示词优化和提示词序列化等功能。通过调整提示词,可以让大语言模型执行各类任务,如文本生成文本(包括聊天、问答、摘要、报告等)、文本生成 SQL、文本生成代码等,另外还可以通过提示词让模型进行 few shot learning,目前对各任务的提示词最优实践在如火如荼的研究中,通过提示词不断探索大语言模型的能力边界,LangChain 提供了一个易用的提示词管理工具。
-
Models:提供了对各类大语言模型的管理和集成,除闭源的大语言模型 API 接口外,还提供对多个开源模型仓库中开源大语言模型的集成接口,以及在云上部署的大语言模型接口,如部署在 AWS SageMaker Endpoint 的大语言模型接口。
-
Memory:用来保存与模型交互时的上下文状态,是实现多轮对话的关键组件。
-
Chains:LangChain 的核心组件,能对上面的各组件组合在一起以完成特定的任务,如一个 chain 可以包含 prompt 模版、大语言模型及输出处理组件,来完成用户聊天功能。对各种不同的任务,LangChain 提供不同的 chain,如问答任务提供了 Question Answering Chain,文本摘要任务提供了 Summarization Chain,文本生成 SQL 任务提供了 SQL Chain,数学计算任务提供了 LLM Math Chain 等,同时可以自定义 Chain,Chain 组件提供了不同的模型推理模式,包括 stuff、map_reduce、refine、map-rerank 等,可以根据具体的任务需求,选择合适的 Chain 以及模型推理模式来完成任务。
-
Agents:LangChain 的高级功能,能根据用户的输入来决定调用那些工具,同时能组合一系列的 Chain 来完成复杂的任务,如提问:我的账号余额能买多少两黄金?Agents 通过 SQL chain 查询账号余额,通过调用网页查询接口的 LLM 查找实时黄金价格,通过调用 LLM Math 计算能买到的黄金数量完成最终的任务,这一系列的逻辑操作均可以在 Agents 中配置。
3.4.2 LLM模型
LLM模型选取了基于Llama2的中文模型。
LLaMA 2是Meta公司发布的一种大型语言模型(Large Language Model,LLM),它是LLaMA 1语言模型的后继版本。它具有商业友好的许可证,可以免费用于商业用途。LLaMA 2有3种不同的尺寸:7B、13B和70B。经过微调的LLMs称为Llama-2-Chat,针对对话用例进行了优化。Llama-2 相比 Llama-1 有不少技术层面的改进,从而带来了模型性能、推理效率以及安全性等方面的有效提升。具体而言,重要的改进有以下几点:
- 模型架构上使用 Group-Query-Attention (GQA) 来提高模型推理效率,语境长度从 2K 增加一倍到 4K。
- 预训练语料从 1.4T tokens 增加到 2T tokens。
- 在监督微调(SFT)阶段更加注重数据集质量,使用更少但质量更高的 SFT 数据相比使用百万量级的公开 SFT 数据,效果显著提升。
- 引入了三项安全训练技术 Supervised Safety Fine-Tuning、Safety RLHF、Safety Context Distillation 提升模型的安全性。
在 LLama 的训练语料中,中文占比较小,微调阶段也没有针对中文进行调优,所以当前 LLama-2-Chat 在中文问题上仍显不足。目前国内已经有多个社区和公司针对中文能力短板问题进行了语料补充与微调。我们选取了3个支持中文的模型进行了测试,测结果如下。其中,下载地址均为https://huggingface.co/加上模型名称,如ziqingyang/chinese-alpaca-2-13b · Hugging Face。
模型名称 | 效果 |
LinkSoul/Chinese-Llama-2-7b | 较差 |
FlagAlpha/Llama2-Chinese-13b-Chat | 一般 |
ziqingyang/chinese-alpaca-2-13b | 较好 |
根据测试效果,最终选取了ziqingyang/chinese-alpaca-2-13b作为LLM模型。
3.4.3 词向量模型
Embedding模型作为大语言模型(Large Language Model,LLM)的一个重要辅助,是很多LLM应用必不可少的部分。Embedding模型,简单来说,是一种能够将词、短语或整个句子转化为向量形式的技术。这些向量能够捕捉到语义的丰富含义,使计算机可以像处理数字一样来处理文本。在大语言模型时代,Embedding模型可以帮助大模型处理更长的上下文,也可以将大模型与私有数据结合。
但是,尽管开源的LLM很多,强大的embedding模型却很少,尤其是支持中文的可商用的开源embedding模型更少。而此次BAAI发布的BGE系列Embedding模型则对中文支持友好。BGE全称是BAAI General Embedding,即北京智源人工智能研究院通用Embedding模型,它可以将任意文本映射到低维的稠密向量,以用于检索、分类、聚类或语义匹配等任务,并可支持为大模型调用外部知识。
其下载地址为:BAAI/bge-large-zh · Hugging Face。
3.4.4 Langchain-Chatchat
在选取完成应用开发框架、LLM模型、词向量模型之后,就可以开始构建知识库问答系统了。这里,我们采用了一个开源的解决方案Langchain-Chatchat快速构建知识库问答系统。
Langchain-Chatchat一种利用Langchain 思想实现的基于本地知识库的问答应用,目标期望建立一套对中文场景与开源模型支持友好、可离线运行的知识库问答解决方案。
4 Langchain-Chatchat
4.1 功能
Langchain-Chatchat具有以下功能:
(1)使用FastChat提供开源LLM模型的API,以OpenAI API接口形式接入,提升LLM模型加载效果。
(2)使用Langchain中已有Chain的实现,便于后续接入不同类型Chain,并将对Agent接入开展测试。
(3)使用FastAPI提供API服务,全部接口可在FastAPI自动生成的docs中开展测试,且所有对话接口支持通过参数设置流式或非流式输出。
(4)使用Streamlit提供WebUI服务,可选是否基于API服务启动WebUI,增加会话管理,可以自定义会话主题并切换,且后续可支持不同形式输出内容的显示。
(5)项目中默认LLM模型改为THUDM/chatglm2-6b,默认Embedding模型改为moka-ai/m3e-base,文件加载方式与文段划分方式也有调整,后续将重新实现上下文扩充,并增加可选设置。
(6)项目中扩充了对不同类型向量库的支持,除支持FAISS向量库外,还提供Milvus, PGVector向量库的接入。
(7)项目中搜索引擎对话,除Bing搜索外,增加DuckDuckGo搜索选项,DuckDuckGo 搜索无需配置API Key,在可访问国外服务环境下可直接使用。
4.2 架构设计
流程如上图所示。
(1)把本地的一些文档( doc txt md csv json ...)先通过一系列处理(读取、分词)embedding模型编码成一定数量的高维向量(下图中1到6)。
(2)用户原本直接和LLM对话的文本也会通过embedding模型编码成高维向量(下图中8和9)。
(3)通过计算余弦相似度的方式(下图中10和7)来检索本地文档库中可能提供帮助的相关资料。
(4)再和原用户的问题文本结合(下图中11)。
(5)经过预先我们准备好的提示词模板Prompt Template组装成最后的Prompt提示词 (下图中12和13)。
(6)利用LLM的语义理解能力和知识问答能力,生成问题的答案(下图中14和15)。
这里,我们使用的LLM模型为前述的chinese-alpaca-2-13b模型,embedding模型bge-large-zh模型。
5 部署搭建
5.1 环境准备
5.1.1 硬件环境
如果使用llama2-13b的模型,若配置一张卡,建议使用的GPU显存至少为32G,否则需要配置多张卡,并且可用显存总和大于30G。
5.1.2 软件环境
操作系统使用Centos或Ubuntu都可以,因为最终用conda环境部署搭建。
使用下面命令创建conda环境。
conda create -n langchain-llama2 python=3.8 -y
conda activate langchain-llama2
5.2 模型准备
知识库问答系统搭建需要两个模型,一个是LLM模型,一个embedding模型。这里,我们需要下载这两个模型,并放到本地目录。直接从HuggingFace下载模型,下载命令如下:
git clone https://huggingface.co/ziqingyang/chinese-alpaca-2-13b
git clone https://huggingface.co/BAAI/bge-large-zh
5.3 项目下载
我们使用Langchain-Chatchat项目搭建知识库系统,需要先下载这个项目。
git clone https://github.com/chatchat-space/Langchain-Chatchat.git
5.4 依赖安装
cd Langchain-Chatchat
pip install -r requirements.txt
由于Langchain-Chatchat使用了FastChat,但是官方版本的FastChat在指定多卡设置时存在问题,因此使用另一版本的FastChat重新安装,安装步骤为:
git clone https://github.com/fan-chao/FastChat
cd FastChat
pip install -e ".[model_worker,webui]"
此时会卸载原有的FastChat并重新安装此版本。
5.5 参数配置
配置文件有2个,一个是model_config.py,另一个是server_config.py,都位于./configs路径下。
5.5.1 创建配置文件
复制模型相关参数配置模板文件configs/model_config.py.example存储至项目路径下./configs路径下,并重命名为 model_config.py。
复制服务相关参数配置模板文件configs/server_config.py.example存储至项目路径下./configs路径下,并重命名为server_config.py。
5.5.2 创建model_config.py文件
model配置文件主要用来配置embedding模型、LLM模型、向量数据库、prompt template等组件。其中,向量数据库使用默认的faiss向量库。
- embedding模型配置
- LLM模型配置
- prompt template配置
主要为Langchain设置prompt template,另外还需要设置一个system prompt。后者根据不同的LLM模型而不同。
prompt template的设置如下:
# 基于本地知识问答的提示词模版
PROMPT_TEMPLATE = """【已知信息】{context}
【问题】{question}"""
而system prompt对于使用ziqingyang/chinese-alpaca-2-13b时设置如下:
SYSTEM_PROMPT = "You are a helpful assistant. 你是一个乐于助人的助手。请你提供专业、有逻辑、内容真实、有价值的简洁回复。如果无法从中得到答案,请说 “根据已知信息无法回答该问题”,不允许在答案中添加编造成分,答案请使用中文。"
而当使用模型FlagAlpha/Llama2-Chinese-13b-Chat时设置如下:
SYSTEM_PROMPT = "You are a helpful assistant. 你是一个乐于助人的助手。请你提供专业、有逻辑、内容真实、有价值的简洁回复。如果无法从中得到答案,请说 “根据已知信息无法回答该问题”,不允许在答案中添加编造成分,答案请使用中文。"
5.5.3 创建server_config.py文件
server_config 里主要是该项目几个进程监听的端口的配置以及多GPU情况下的配置。直接用默认的即可。
如果使用多GPU或指定使用某个GPU,需要修改FSCHAT_MODEL_WORKERS中的gpus,如下图所示,其中num_gpus需要与gpus一致,max_gpu_memory可以设置为None。
5.6 初始化数据库
当前项目的知识库信息存储在数据库中,在正式运行项目之前请先初始化数据库:
python init_database.py --recreate-vs
5.7 启动
5.7.1 一键启动
运行下面命令 启动所有的组件
python startup.py --all-webui
5.7.2 依次启动
除了上面的一键启动 也可以依次单独启动下面的组件。
(1)启动LLM模型服务
python server/api.py
(2)启动API服务
python server/api.py
(3)启动Web UI服务
streamlit run webui.py
5.8 使用
所有服务组件启动完成之后,就可以通过访问http://127.0.0.1:8501/来使用知识库问答系统了。
在左侧可以选择对话模式,目前支持LLM对话和知识库问答。
5.8.1 LLM对话模式
如果使用LLM对话模式,可以直接输入对话内容,然后回车生成问题答案。
5.8.2 知识库问答模式
如果使用知识库问答模式,则需要先在知识库管理界面中,创建相应的知识库,并且上传添加文档,然后添加到向量库中。
之后,就可以使用知识库问答模式对话,先在左侧选择所使用的知识库,然后进行提问。如下图所示:
另外,可以看到当前的回答所引用的知识库中的内容。