使用 Easysearch 打造企业内部知识问答系统

news/2024/9/23 19:26:51/文章来源:https://www.cnblogs.com/infinilabs/p/18331230

大家可能都有这样的经历,刚入职一家企业时,同事往往会给你分享一些文档资料,有可能是产品信息、规章制度等等。这些文档有的过于冗长,很难第一时间找到想要的内容。有的已经有了新版本,但员工使用的还是老版本。

基于这种背景,我们可以利用 Easysearch 加 LLM 实现一个内部知识的 QA 问答系统。这个系统将利用 LangChain 框架调用本地部署的大模型和 Easysearch,实现理解员工的提问,并基于最新的文档,给出精准答案。

开发框架


整个框架分为四个部分:

  • 数据源:数据可以有很多种,可以是非结构化的,比如 PDF、docx、txt 等。也可以是结构化的数据,甚至代码也行。在本次示例中,我们使用 PDF 的非结构化数据。
  • 大模型应用:应用与大模型交互,生成我们需要的答案。
  • 大模型:系统执行相关任务需要用到的大模型,可以有多个。
  • Q&A 场景:基于大模型为引擎的 QA 场景,使用 web 框架,构建一个交互界面。

数据准备

本次我们使用的资料是 "INFINI 产品安装手册.pdf" ,文档部分内容展示如下:

首先我们使用 LangChain 的 document_loaders 来加载文件。document_loaders 集成了数百种数据源格式,可以很方便的加载数据。我们的数据的 pdf 格式的,导入 PyPDFLoader 类来进行处理。代码如下:

import os# 导入 Document Loaders
from langchain_community.document_loaders import PyPDFLoader# Load Pdf
base_dir = '.\\easysearch' # 文档的存放目录
docs = []
for file in os.listdir(base_dir):file_path = os.path.join(base_dir, file)if file.endswith('.pdf'):loader = PyPDFLoader(file_path)documents.extend(loader.load())

上面的代码将 pdf 文件的内容存储在 docs 这个列表中,以便后续进行处理。

文本分割

一个文件的文本内容可能很大,无法适应许多模型的上下文窗口,也不利于检索和存储。因此,通常我们会将文本内容分割成更小的块,这将帮助我们在运行时只检索文档中最相关的部分。LangChain 提供了工具来进行处理文本分割,非常方便。
我们将把文档分割成 1000 个字符的块,每个块之间有 200 个重叠字符。这种重叠有助于减少将语句与相关的重要上下文分离的可能性。

# 2.将Documents切分成块
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=20)
chunked_documents = text_splitter.split_documents(docs)

上面的代码将 docs 的内容按 1000 字符大小进行切分,存储在 chunked_documents 中,以便后续进行处理。
注意,实际运行中,切分及重叠的大小,都会影响应用效果,需自行调试。

向量库 Easysearch

接下来,我们将这些文本块转换成向量的形式,并存储在一个向量数据库中。在本示例中,我们使用 mxbai-embed-large 模型来生成向量,然后将向量和原始内容存入 easysearch 。

本地部署模型,我使用的是 ollama ,大家可以使用自己喜欢的工具。

# 3. 定义embedding模型
from langchain_community.embeddings import OllamaEmbeddings
ollama_emb = OllamaEmbeddings(model="mxbai-embed-large",
)# 4. 定义 easysearch 集群的信息,以及存放向量的索引名称 infini
from langchain_community.vectorstores import EcloudESVectorStore
ES_URL = "https://192.168.56.3:9200"
USER = "admin"
PASSWORD = "e5ac1b537785ae27c187"
indexname = "infini"docsearch = EcloudESVectorStore.from_documents(chunked_documents,ollama_emb,es_url=ES_URL,user=USER,password=PASSWORD,index_name=indexname,verify_certs=False,
)

通过上面的步骤,我们成功将文本块转换成了向量,并存入到了 easysearch 集群的 infini 索引中。

我们看看 infini 索引内容是怎样的

text 字段存放了文本块的原始内容,vector 字段存放着对应的向量表示。

检索及生成答案

在这一步,我们会定义一个生成式大模型。然后创建一个 RetrievalQA 链,它是一个检索式问答模型,用于生成问题的答案。
在 RetrievalQA 链中有下面两大重要组成部分。

  • LLM 是大模型,负责回答问题。
  • retriever(vectorstore.as_retriever())负责根据用户的问题检索相关的信息。先是找最近似的“向量块”,再把”向量块“对应的“文档块”作为知识信息,和问题一起传递进入大模型。之所以要先检索,是因为从互联网信息训练而来的大模型不可能拥有一个私营企业的内部知识。
# 5. Retrieval 准备模型和Retrieval链
import logging
# MultiQueryRetriever工具
from langchain.retrievers.multi_query import MultiQueryRetriever
# RetrievalQA链
from langchain.chains import RetrievalQA# # 设置Logging
logging.basicConfig()
logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)# # 实例化一个大模型工具
from langchain_community.chat_models import ChatOllama
llm = ChatOllama(model="qwen2:latest")from langchain.prompts import PromptTemplate
my_template = PromptTemplate(input_variables=["question"],template="""You are an AI language model assistant. Your task isto generate 3 different versions of the given userquestion in Chinese to retrieve relevant documents from a vector  database.By generating multiple perspectives on the user question,your goal is to help the user overcome some of the limitationsof distance-based similarity search. Provide these alternativequestions separated by newlines. Original question: {question}""",
)# # 实例化一个MultiQueryRetriever
retriever_from_llm = MultiQueryRetriever.from_llm(retriever=docsearch.as_retriever(), llm=llm,prompt=my_template,include_original=True)# # 实例化一个RetrievalQA链
qa_chain = RetrievalQA.from_chain_type(llm,retriever=retriever_from_llm)

这里我们使用 ollama 在本地部署一个 qwen2 大模型,负责问题改写和生成答案。

启动 qwen2 大模型:ollama run qwen2

我们获取到用户问题后,先通过 MultiQueryRetriever 类调用大模型 qwen2 进行改写,生成 3 个同样语义的问题,然后再调用 easyearch 进行向量检索,搜索相关内容。

最后把所有相关内容,合并、去重后,与原始问题一起提交给大模型 qwen2,进行答案生成。

虽然这里使用的是向量检索,但实际上我们可以同时使用全文检索和向量检索。这也是使用 easysearch 作为检索库的优势之一。

前端展示

这一步我们创建一个 Flask 应用(需要安装 Flask 包)来接收用户的问题,并生成相应的答案,最后通过 index.html 对答案进行渲染和呈现。

在这个步骤中,我们使用了之前创建的 RetrievalQA 链来获取相关的文档和生成答案。然后,将这些信息返回给用户,显示在网页上。

# 6. Q&A系统的UI实现
from flask import Flask, request, render_template
app = Flask(__name__) # Flask APP@app.route('/', methods=['GET', 'POST'])
def home():if request.method == 'POST':# 接收用户输入作为问题question = request.form.get('question')# RetrievalQA链 - 读入问题,生成答案result = qa_chain({"query": question})# 把大模型的回答结果返回网页进行渲染return render_template('index.html', result=result)return render_template('index.html')if __name__ == "__main__":app.run(host='0.0.0.0',debug=True,port=5000)

效果演示

我们模仿用户进行提问。

Q&A 系统进行回答,回答速度取决于本地的计算资源。

内容校验,在原始文档内用 ctrl+F 搜索关键字 LOGGING_ES_ENDPOINT 得到如下内容。

嗯,回答的还不错,达到预期目的。如果还有其他要求,可修改 my_template 中的提示词或者替换成别的大模型也是可以的。

小结

通过这次示例,我们演示了如何基于 LangChain 和 easysearch 以及大模型,快速开发出一个内部知识问答系统。怎么样,是不是觉得整个流程特别简单易懂?

如有任何问题,请随时联系我,期待与您交流!

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

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

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

相关文章

Web系列-文件上传

Web系列-文件上传 做题思路 前端限制了上传文件的后缀,可以在前端修改代码或者bp抓包,再上传符合前端要求的文件类型,抓包后进行修改。 如果是php的环境,可以利用.user.ini,是一个局部配置文件,可以通过配置选项使每个php文件头或文件尾都进行文件包含 .user.ini利用需要…

【ollama】手把手教你布置本地大语言模型 以及各种常见用途#如何加载guff模型到ollama #如何更改ollama目录

ollama介绍 Ollama 是一个开源框架,专为在本地机器上便捷部署和运行大型语言模型(LLM)而设计。 以下是其主要特点和功能概述:简化部署:Ollama 目标在于简化在 Docker 容器中部署大型语言模型的过程,使得非专业用户也能方便地管理和运行这些复杂的模型。轻量级与可扩展:作…

SPONGE常用教程0:软件安装教程

课程准备阶段,介绍最简明安装流程,安装过程中如果遇到其他问题,请移步官方教程。第三方软件只提供个人安装心得。 软件安装环境默认为linux。 软件支持 SPONGE(Simulation Package tOward Next GEneration molecular modelling)是由北京大学高毅勤课题组开发的分子动力学模…

使用高速收发器进行数据传输(一)

本来想做一个这样的项目,但是简单地使用这个方法传递数据实在是没意义; 我希望最后以万兆网来实现这点; 目前事实上只是按照UG476的要求给IP核数据和取数即可,并不困难;

虚拟机:GCC共享库在连接时的搜索位置和优选次序

假设有两个相同的共享库,一个在标准的共享库搜索目录(/lib/i386-linux-gnu), 一个在非标准目录(/home/charles/tmp):在/home/charles/tmp下有个测试程序main.c, 调用共享库里的函数。 用如下的命令编译: 用ldd看一下link的共享库:可以看出,虽然我们指定了 要使用 …

mysql导出csv文件中文乱码解决方案

确认csv文件导出编码格式,如果已经知道了 ->从文本/csv导出 ->选择文件原始格式 ->转换保存即可 如果不知道是什么编码可以通过记事本或者 nop++打开查看文件编码格式 一般导出和保存的编码格式为:utf8,gb2312,ANSI

SmartSQL:一款方便、快捷的数据库文档查询、生成工具

SmartSQL ⚡ 一款方便、快捷的数据库文档查询、生成工具 致力于成为帮助企业快速实现数字化转型的元数据管理工具 🚩 项目介绍SmartSQL 是一款方便、快捷的数据库文档查询、导出工具!从最初仅支持SqlServer数据库、CHM文档格式开始,通过不断地探索开发、集思广益和不断改进…

Django-APP及项目入门

1. APP定义:Django中功能的细分,每个APP有独立的数据库、表结构、HTML模版、CSS。创建APP python manage.py startapp app01重要文件介绍 views.py:常用文件,urls中的函数常常在此处定义。 models.py:常用文件,对数据库进行操作。2. 项目入门确保app也注册(settings.py)…

7.22 ~ 7.28

原来模拟赛就是一个不断挂分的过程啊7.22 上午听学长讲课。 不过这次讲的还是挺快的。可能因为都是数学? 然后打了打前几天的板子,改完了前几天的题,赛后总结就先咕了 下午依然是模拟赛。 T1 T2 都是签到题,但题面出了一点小问题:T1 没有规定 \(a_i\) 的正负; T2 没有说明…

Label Smoothing

简单的说,Label Smoothing就是把one-hot向量从[0,0,1,0,0,0,...,0]变成[0.01,0.01,0.8,0.01,0.01,0.01,...,0.01],用公式表示,就是其中,k是类别数量,a是一个较小的数.这样做的目的是为了缓解模型过于武断的问题,增强模型的泛化能力,预防过拟合等等.但是也会带来一些问题,如增加…

Android 8.0 源码分析 (四) Activity 启动

链接:https://juejin.cn/post/6844903983442558989 前言 我们熟知一般 Android 工程师都是在应用层上���发,不会涉及系统源码,但是如果你想往底层发展,或者深入插件化、Framework 系统层等开发工作,如果不了解 Android 源码可是不行的,那么接下来我基于自己的理解跟学…