AI如何助力电商卖家制作爆款短视频?从创意到生产解析
2026-07-29 3431662
2026-07-29 0
活动预告
主题:《Easysearch 结合大模型实现 RAG》;搜索客社区 Meetup 线上直播活动第1期 | 2024,将于【7月31日】举行
下面进入正文
不少人刚进入一家企业时,都有过同事分享文档资料的经历,其中可能包含产品信息、规章制度等内容。有些文档篇幅太长,想要的信息很难立刻找到;还有些文档虽然已有新版本,员工使用的却仍是老版本。
让系统理解员工提问并依据最新文档给出精准答案,是这一背景下内部知识 QA 问答系统的目标。其实现方式是组合 Easysearch 和 LLM,并由 LangChain 框架调用本地部署的大模型及 Easysearch。
开发框架
完整框架由四个部分组成:
数据源:数据来源可以非常多样,既包括 PDF、docx、txt 等非结构化数据,也可以是结构化数据,甚至能够使用代码。本次示例选用的是 PDF 非结构化数据。
大模型应用:通过应用与大模型进行交互,得到我们需要的答案。
大模型:系统可使用一个或多个大模型执行相关任务。
Q&A 场景:以大模型作为 QA 场景的引擎,再通过 web 框架搭建交互界面。
数据准备
下面展示 “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 链中有下面两大重要组成部分。
LLM 是大模型,负责回答问题。
私营企业的内部知识不可能被基于互联网信息训练的大模型直接掌握,因此必须先进行检索。用户提出问题后,retriever(vectorstore.as_retriever())先定位最近似的“向量块”,再取出该“向量块”对应的“文档块”,将其作为知识信息连同问题传入大模型。
# 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 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}""",)# # 实例化一个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)
面向广大搜索领域从业者,这一更丰富、更便捷的学习交流平台属于“搜索人自己的社区” 。
喜如果喜欢我们的内容,就点“在看”分享给小伙伴哦