需求简介
易束鲜花企业内部知识库如下:
本实战项目设计一个内部问答系统,基于这些内部知识,回答内部员工的提问。
在前面课程的基础上,需要安装的依赖包如下:
pip install docx2txt
pip install qdrant-client
pip install flask
初始化代码
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAIload_dotenv()
ai_model = os.getenv("OPENAI_MODEL")
# 实例化一个大模型工具
llm = ChatOpenAI(model_name=ai_model, temperature=0)from langchain_community.embeddings import HuggingFaceBgeEmbeddings
embedings = HuggingFaceBgeEmbeddings(model_name='./BAAI/bge-large-zh-v1.5', model_kwargs={'device': 'cuda'})import logging
logging.basicConfig()
logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)
这段代码实例化了一个deepseek的llm,bge-large-zh 的向量模型、日志组件
导入内部知识到向量数据库
# 加载Documents
base_dir = './OneFlower'
documents = []
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())elif file.endswith('.docx'):loader = Docx2txtLoader(file_path)documents.extend(loader.load())elif file.endswith('.txt'):loader = TextLoader(file_path)documents.extend(loader.load())# 2.Split 将Documents切分成块以便后续进行嵌入和向量存储
from langchain.text_splitter import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=10)
chunked_documents = text_splitter.split_documents(documents)from langchain_community.vectorstores import Qdrant
vectorstore = Qdrant.from_documents(documents=chunked_documents,embedding=embedings,location=":memory:",collection_name="my_documents",
)
内部知识在OneFlow文件夹中,包含了pdf文档、文本文档、word文档等格式,通过加载器加载到document中,然后使用分词器去分割,最后以内存的方式存入到Qdrant向量数据库中
构建查询的QA链
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain.chains import RetrievalQA# 实例化一个MultiQueryRetriever
retriever_from_llm = MultiQueryRetriever.from_llm(retriever=vectorstore.as_retriever(), llm=llm)# 实例化一个RetrievalQA链
qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever_from_llm)
MultiQueryRetriever 核心机制与技术优势
一、核心功能
-
多视角查询扩展
- 接收用户原始查询后,利用 LLM 自动生成多个语义相关但表达形式不同的子查询,例如针对模糊查询补充具体场景或同义词描述。
- 每个子查询独立执行向量数据库检索,合并结果并去重,形成更全面的文档集合。
-
动态适配场景
- 适用于用户输入模糊、语义范围广的场景(如开放性问题),通过多查询覆盖不同解读角度,降低因单一检索偏差导致的错误响应25。
二、技术实现原理
-
生成-检索-融合流程
- 生成阶段:LLM 根据原始查询生成 3-5 个变体问题,例如将“气候变化的影响”扩展为“全球变暖的经济后果”“碳排放对生态系统的破坏”等。
- 检索阶段:各子查询分别通过向量相似度计算从数据库召回 Top-K 文档。
- 融合阶段:合并所有文档并按相关性排序,去重后返回最终结果集。
-
性能优化特性
- 支持异步并发执行子查询检索,显著缩短整体响应时间2。
- 可配置生成查询数量、LLM 温度参数(
temperature
)以平衡生成多样性与相关性。
三、典型应用场景
-
模糊语义解析
- 当用户提问包含歧义术语(如“AI 的伦理问题”)时,自动生成“人工智能数据隐私风险”“机器学习算法偏见案例”等子查询,提升知识覆盖范围。
-
跨领域知识检索
- 在垂直领域(如医疗、法律)中,通过多查询映射专业术语与通用表述,解决术语差异导致的检索遗漏问题
RetrievalQA
组件解析
一、核心功能与定位
- 检索增强生成(RAG):将外部知识库检索与语言模型生成能力结合,通过“先检索后回答”机制提升问答准确性13。
- 适用场景:适用于需要结合结构化/非结构化数据(如文档、数据库)的问答系统,可解决大模型幻觉问题
启动服务器
# 5. Output 问答系统的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)
这里使用flask启动了一个服务,监听post请求,调用qa链,返回数据渲染到index.html
index.html文件内容如下:
<body><div class="container"><div class="header"><h1>易速鲜花内部问答系统</h1><img src="{{ url_for('static', filename='flower.png') }}" alt="flower logo" width="200"></div><form method="POST"><label for="question">Enter your question:</label><input type="text" id="question" name="question"><br><input type="submit" value="Submit"></form>{% if result is defined %}<h2>Answer</h2><p>{{ result.result }}</p>{% endif %}</div>
</body>
运行
输入查询的问题后,后台运行的输出如下