首页
看点啥
插画图片
首页 看点啥 使用 Easysearch 构建企业内部知识问答系统 | 征文系列

使用 Easysearch 构建企业内部知识问答系统 | 征文系列

2026-07-29 0


使用 Easysearch 打造企业内部知识问答系统 | 征文系列

活动预告



主题:《Easysearch 结合大模型实现 RAG》;搜索客社区 Meetup 线上直播活动第1期 | 2024,将于【7月31日】举行


下面进入正文



不少人刚进入一家企业时,都有过同事分享文档资料的经历,其中可能包含产品信息、规章制度等内容。有些文档篇幅太长,想要的信息很难立刻找到;还有些文档虽然已有新版本,员工使用的却仍是老版本。


让系统理解员工提问并依据最新文档给出精准答案,是这一背景下内部知识 QA 问答系统的目标。其实现方式是组合 Easysearch 和 LLM,并由 LangChain 框架调用本地部署的大模型及 Easysearch。


开发框架



完整框架由四个部分组成:


数据准备


下面展示 “INFINI 产品安装手册.pdf” 的部分内容,该文档是本次采用的资料:



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

import os
# 导入 Document Loadersfrom langchain_community.document_loaders import PyPDFLoader
# Load Pdfbase_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 RecursiveCharacterTextSplittertext_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 OllamaEmbeddingsollama_emb = OllamaEmbeddings(    model="mxbai-embed-large",)
# 4. 定义 easysearch 集群的信息,以及存放向量的索引名称 infinifrom langchain_community.vectorstores import EcloudESVectorStoreES_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 链中有下面两大重要组成部分。


# 5. Retrieval 准备模型和Retrieval链import logging# MultiQueryRetriever工具from langchain.retrievers.multi_query import MultiQueryRetriever# RetrievalQA链from langchain.chains import RetrievalQA
# # 设置Logginglogging.basicConfig()logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)
# # 实例化一个大模型工具from langchain_community.chat_models import ChatOllamallm = ChatOllama(model="qwen2:latest")
from langchain.prompts import PromptTemplatemy_template = PromptTemplate(    input_variables=["question"],    template="""You are an AI language model assistant. Your task is    to generate 3 different versions of the given user    question 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 limitations    of distance-based similarity search. Provide these alternative    questions separated by newlines. Original question: {question}""",)
# # 实例化一个MultiQueryRetrieverretriever_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_templateapp = 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 与大模型,迅速开发一个内部知识问答系统。整个流程是不是显得特别简单易懂?


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




正文结束





首期征文活动,由 INFINI Labs 带来!


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


点击 图片 查看活动详情!


嗨,一起来互动吧!

喜欢本文么?欢迎留下你的评论!

如果您撰写了搜索领域技术相关文章,欢迎投给长期征稿的搜索客 公众号,与大家一起进步! 添加微信searchkit-org即可投稿:


招聘信息

Job board






为伯乐和千里马牵线搭桥,是社区招聘栏目设置的目的:一方面让企业找到所需人才,另一方面帮助社区的小伙伴获得心仪职位。企业有招聘需求或社区小伙伴正在求职时,可以联系微信 searchkit-org 提交招聘需求,并发布个人简历信息。

搜索客公众号 (SearchKit)

面向广大搜索领域从业者,这一更丰富、更便捷的学习交流平台属于“搜索人自己的社区” 。


如果喜欢我们的内容,就点“在看”分享给小伙伴哦

喜欢(0)

上一篇

德勤(Deloitte)的 AI 战略规划,AI产品及各业务线AI应用

下一篇

4.2K star!告别抓狂的SQL,这个项目真牛!

猜你喜欢