首页 分享 LangChain实战课—“易速鲜花”本地部署

LangChain实战课—“易速鲜花”本地部署

来源:花匠小妙招 时间:2025-09-01 10:40

此项目为初步了解LangChian作为一个基于大语言模型的应用开发框架,其功能的强大。用于深入学习LangChain(包括每一个组件)之前。

项目及实现框架

项目名称:“易速鲜花”内部员工知识库问答系统。

项目介绍:“易速鲜花”作为一个大型在线鲜花销售平台,有自己的业务流程和规范,也拥有针对员工的SOP手册。新员工入职培训时,会分享相关的信息。但是,这些信息分散于内部网和HR部门目录各处,有时不便查询;有时因为文档过于冗长,员工无法第一时间找到想要的内容;有时公司政策已更新,但是员工手头的文档还是旧版内容。

基于上述需求,我们将开发一套基于各种内部知识手册的 “Doc-QA” 系统。这个系统将充分利用LangChain框架,处理从员工手册中产生的各种问题。这个问答系统能够理解员工的问题,并基于最新的员工手册,给出精准的答案。

开发框架:整个框架分为三个部分:

数据源(Data Sources):数据可以有很多种,包括PDF在内的非结构化的数据(Unstructured Data)、SQL在内的结构化的数据(Structured Data),以及Python、Java之类的代码(Code)。在这个示例中,我们聚焦于对非结构化数据的处理。 大模型应用(Application,即LLM App):以大模型为逻辑引擎,生成我们所需要的回答。 用例(Use-Cases):大模型生成的回答可以构建出QA/聊天机器人等系统。

实现机制:大模型应用作为“服务器”,根据用例在数据源中找到答案并返回给用户。

核心实现机制: 这个项目的核心实现机制是下图所示的数据处理管道(Pipeline)。

在管道的每一步中,LangChain都提供了相关工具,这就是LangChain的强大之处。

具体流程是:

加载文件(Loading):文档加载器把Documents 加载为以LangChain能够读取的形式。 切分文件(Splitting):文本分割器把Documents 切分为指定大小的分割,我把它们称为“文档块”或者“文档片”。 嵌入及存储(Storage):将上一步中分割好的“文档块”以“嵌入”(Embedding)的形式存储到向量数据库(Vector DB)中,形成一个个的“嵌入片”。 检索(Retrieval):应用程序从存储中检索分割后的文档(例如通过比较余弦相似度,找到与输入问题类似的嵌入片)。 返回结果(Output):把问题和相似的嵌入片传递给语言模型(LLM),使用包含问题和检索到的分割的提示生成答案

前三步为准备数据源,第四步是将用户提出的问题同样切分等操作得到一个向量,再与数据源中的向量数据库通过余弦相似度等找出类似的问题答案。【这些都是数据分析的知识】

接下来将具体讲解上面的五步操作。

项目结构:

 易速鲜花内部员工知识库问答系统     │ DocQA.py     │     ├─OneFlower     │     易速鲜花员工手册.pdf     │     易速鲜花运营指南.docx     │     花语大全.txt     │     ├─static     │     flower.png     │     └─templates             index.html

1. 加载文件

首先要准备文件,这里先给你提供样例文件:下载OneFlower中的三个文件。

我们首先用langchain_community中的document_loaders来加载各种格式的文本文件;在这一步中,我们从pdf、word和txt文件中加载文本并将这些文本存储在一个列表中。(可能还需要安装PyPDF、Docx2txt等库,根据报错安装即可)

代码如下:

 # 1.loading: 文档加载器把Documents 加载为以LangChain能够读取的形式。  import os  from langchain_community.document_loaders import PyPDFLoader,Docx2txtLoader,TextLoader  ​  # 加载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. 切分文件

我们已经得到了文本信息(存储在documents数组中),接下来我们就需要将文本切分成更小的块,以便于进行嵌入和向量存储。

相关工具:LangChain中的RecursiveCharacterTextSplitter

代码如下:

 # 2.Splitting 文本分割器把Documents 切分为指定大小的分割,我把它们称为“文档块”或者“文档片”。  from langchain.text_splitter import RecursiveCharacterTextSplitter  ​  text_splitter = RecursiveCharacterTextSplitter(chunk_size=200,chunk_overlap=10)  chunk_documents = text_splitter.split_documents(documents)

说明:chunk_size参数为切分的文档块chunk的最大长度,这里设定200。chunk_overlap参数为相邻两个chunk之间的重叠token数量,保证文本语义的连贯性。

3. 嵌入及存储

数据源的最后一步,我们将这些分割后的文本转换成嵌入的形式,并将其存储在一个向量数据库中。

相关工具:

嵌入工具:OpenAIEmbeddings(OpenAI的Embedding Model) 向量数据库:Qdrant(需安装库qdrant-client)

注意:

处理OpenAI的模型,还可以使用其他的嵌入模型,如Doubao-embedding-large等 LangChain中支持很多向量数据库,比如Pinecone、Chroma和Qdrant,有些是收费的,有些则是开源的。Qdrant是开源向量数据库。 Qdrant.from_documents返回的是一个Qdrant类的实例,这个实例代表了一个向量数据库。这个函数是创建一个向量数据库并且根据参数存储在指定位置(location=":memory:"表示存储在内存中)。可以根据这个实例访问这个向量数据库。

代码如下:

使用OpenAI模型:

 # 3.Store 将分割嵌入并存储在矢量数据库Qdrant中  from langchain_community.vectorstores import Qdrant  from langchain.embeddings import OpenAIEmbeddings  ​  vecto_rstore = Qdrant.from_documents(      documents=chunked_documents, # 以分块的文档      embedding=OpenAIEmbeddings(), # 用OpenAI的Embedding Model做嵌入      location=":memory:",  # 存储在内存中      collection_name="my_documents", # 指定collection_name  )

2. 使用豆包模型:

使用豆包模型就有些复杂,首先你需要在[火山方舟管理控制台 (volcengine.com)](https://console.volcengine.com/ark/region:ark+cn-beijing/endpoint?config=%7B%7D)新创建一个Doubao-embedding-large或Doubao-embedding的接入点,然后在API调用中获取其base_url和model,接着创建对应的环境变量(当然可以直接定义); 安装包`volcengine-python-sdk`:pip install volcengine-python-sdk; 定义一个DoubaoEmbeddings类(目前还没弄明白实现原理),然后做嵌入使用这个类

 # 3.Storage:将上一步中分割好的“文档块”以“嵌入”(Embedding)的形式存储到向量数据库(Vector DB)中,形成一个个的“嵌入片”。  from typing import Dict, List, Any  from langchain.embeddings.base import Embeddings  from langchain.pydantic_v1 import BaseModel  from volcenginesdkarkruntime import Ark  ​  class DoubaoEmbeddings(BaseModel, Embeddings):      client: Ark = None      api_key: str = ""      model: str  ​      def __init__(self, **data: Any):          super().__init__(**data)          if self.api_key == "":              self.api_key = os.environ["ARK_API_KEY"]          self.client = Ark(              base_url=os.environ.get("EMBEDDING_BASE_URL"),              api_key=self.api_key         )  ​      def embed_query(self, text: str) -> List[float]:          """         生成输入文本的 embedding.         Args:             texts (str): 要生成 embedding 的文本.         Return:             embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.         """          embeddings = self.client.embeddings.create(model=self.model, input=text)          return embeddings.data[0].embedding  ​      def embed_documents(self, texts: List[str]) -> List[List[float]]:          return [self.embed_query(text) for text in texts]  ​      class Config:          arbitrary_types_allowed = True  ​  from langchain_community.vectorstores import Qdrant  ​  vector_store = Qdrant.from_documents(      documents=chunk_documents,  # 以分块的文档      embedding=DoubaoEmbeddings(          model=os.environ.get("EMBEDDING_MODELEND"),     ),   # 用豆包的Embedding Model做嵌入      location=":memory:",    # 存储在内存中      collection_name="my_document",  # 指定collection_name  )

4. 检索

检索器

相关工具:MultiQueryRetriever工具、RetrievalQA链

此工具用于从向量存储(vector_store)中检索与查询相关的多个文档。

检索器即retriever(vector_store.as_retriever()),将向量存储转化为检索器,然后使用MultiQueryRetriever利用大型语言模型的能力来创建一个多查询检索器,这个检索器可以处理和优化多个查询,从而提高检索的效果和效率。

最后使用LangChain下的RetrievalQA建立“一条链QA”,它的作用将用户与查询并返回形成“一条链”。之后通过RetrievalQA.from_chain_type函数返回的对象传入字典{“query”:问题}就可以使用了。

 # 4.Retrieval:应用程序从存储中检索分割后的文档(例如通过比较余弦相似度,找到与输入问题类似的嵌入片).  import logging  from langchain_openai import ChatOpenAI  from langchain.retrievers.multi_query import MultiQueryRetriever  from langchain.chains import RetrievalQA  ​  # 设置Logging  logging.basicConfig()  logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)  ​  # 实例化一个大模型工具 豆包  chat = ChatOpenAI(      api_key = os.environ.get("ARK_API_KEY"),      base_url = os.environ.get("BASE_URL"),      model = os.environ.get("LLM_MODELEND"),      temperature = 0.8,      max_tokens = 600,  )  # 实例化一个MultiQueryRetriever  retriever_from_llm = MultiQueryRetriever.from_llm(retriever=vector_store.as_retriever(), llm=chat)  # 实例化一个RetrievalQA链  qa_chain=  RetrievalQA.from_chain_type(chat,retriever=retriever_from_llm)

注意:logging的作用是对查询建立日志;可以去掉【但还是不要去掉】

5. 返回结果并可视化

可视化用一个flask建立一个网页,然后通过输入问题向服务端请求,之后返回结果到页面即可。

 # 5.Output:把问题和相似的嵌入片传递给语言模型(LLM),使用包含问题和检索到的分割的提示生成答案。  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)

html代码可根据你的需要进行更改,以下是样例(注意html放入template文件夹中):

 <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><br>              <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>

最终代码

 # 1.loading 文档加载器把Documents 加载为以LangChain能够读取的形式。  import os  from langchain_community.document_loaders import PyPDFLoader, Docx2txtLoader, TextLoader  ​  # 加载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.Splitting 文本分割器把Documents 切分为指定大小的分割,我把它们称为“文档块”或者“文档片”。  from langchain.text_splitter import RecursiveCharacterTextSplitter  ​  text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=10)  chunk_documents = text_splitter.split_documents(documents)  ​  # 3.Storage:将上一步中分割好的“文档块”以“嵌入”(Embedding)的形式存储到向量数据库(Vector DB)中,形成一个个的“嵌入片”。  from typing import Dict, List, Any  from langchain.embeddings.base import Embeddings  from pydantic.v1 import BaseModel  from volcenginesdkarkruntime import Ark  ​  class DoubaoEmbeddings(BaseModel, Embeddings):      client: Ark = None      api_key: str = ""      model: str  ​      def __init__(self, **data: Any):          super().__init__(**data)          if self.api_key == "":              self.api_key = os.environ["ARK_API_KEY"]          self.client = Ark(              base_url=os.environ.get("EMBEDDING_BASE_URL"),              api_key=self.api_key         )  ​      def embed_query(self, text: str) -> List[float]:          """         生成输入文本的 embedding.         Args:             texts (str): 要生成 embedding 的文本.         Return:             embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.         """          embeddings = self.client.embeddings.create(model=self.model, input=text)          return embeddings.data[0].embedding  ​      def embed_documents(self, texts: List[str]) -> List[List[float]]:          return [self.embed_query(text) for text in texts]  ​      class Config:          arbitrary_types_allowed = True  ​  from langchain_community.vectorstores import Qdrant  ​  vector_store = Qdrant.from_documents(      documents=chunk_documents,  # 以分块的文档      embedding=DoubaoEmbeddings(          model=os.environ.get("EMBEDDING_MODELEND"),     ),  # 用豆包的Embedding Model做嵌入      location=":memory:",  # 存储在指定路径      collection_name="my_document",  # 指定collection_name  )  ​  ​  ​  # 4.Retrieval:应用程序从存储中检索分割后的文档(例如通过比较余弦相似度,找到与输入问题类似的嵌入片).  import logging  from langchain_openai import ChatOpenAI  from langchain.retrievers.multi_query import MultiQueryRetriever  from langchain.chains import RetrievalQA  ​  # 设置Logging  logging.basicConfig()  logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)  ​  # 实例化一个大模型工具 豆包  chat = ChatOpenAI(      api_key = os.environ.get("ARK_API_KEY"),      base_url = os.environ.get("BASE_URL"),      model = os.environ.get("LLM_MODELEND"),      temperature = 0.8,      max_tokens = 600,  )  # 实例化一个MultiQueryRetriever  retriever_from_llm = MultiQueryRetriever.from_llm(retriever=vector_store.as_retriever(), llm=chat)  # 实例化一个RetrievalQA链  qa_chain=  RetrievalQA.from_chain_type(chat,retriever=retriever_from_llm)  ​  # 5.Output:把问题和相似的嵌入片传递给语言模型(LLM),使用包含问题和检索到的分割的提示生成答案。  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)

相关知识

18|CAMEL:通过角色扮演脑暴一个鲜花营销方案
LangChain实战课笔记05 思维链与思维树
梅花易数3D实战案例
本地SEO优化实战案例分析
06|链(上):写一篇完美鲜花推文?用SequencialChain链接不同的组件
搜索引擎营销实战教程(SEO/SEM)(附微课视频)
【30岁程序员失业】转行大模型还来得及吗?全面解析与职业转型建议
搜索引擎营销实战教程(SEO/SEM)(微课版 第2版)
DeepSeek超全使用攻略(实战版)
Thinkphp5.0实战教程

网址: LangChain实战课—“易速鲜花”本地部署 https://www.huajiangbk.com/newsview2289813.html

所属分类:花卉
上一篇: 花语造句
下一篇: 【C语言

推荐分享