当前位置: 首页 > news >正文

基于LangChain框架搭建AI问答系统(附源码)

AI问答系统

      • 1. 背景知识
      • 2. 问答系统流程
      • 3. 知识问答系统相关组件
        • 3.1 文档加载器
        • 3.2 文档切割器
        • 3.3 嵌入模型包装器
        • 3.4 向量存储库
        • 3.5 模型包装器
        • 3.6 链组件
      • 4. 问答系统演示
        • 4.1 问答程序
        • 4.2 演示大模型回答效果
      • 5.问答系统代码

1. 背景知识

在人工智能技术飞速发展的今天,知识库问答系统已成为企业、教育、医疗等领域实现高效信息检索与智能交互的核心工具。传统问答系统往往依赖人工编写的规则或固定模板,难以应对复杂多变的业务场景和海量数据。而基于大语言模型(LLM)的智能问答系统,通过自然语言处理(NLP)技术,能够自动理解用户问题并从知识库中精准检索答案,显著提升了信息处理的效率与用户体验。

LangChain 作为当前最流行的框架之一,为开发者提供了构建端到端AI应用的强大工具链。它通过模块化设计,将大语言模型(如GPT、Llama等)、外部数据源(文档、数据库、API等)和智能代理(Agent)无缝集成,支持快速实现知识库问答、对话生成、自动化任务等复杂功能。相较于从零开发,LangChain大幅降低了技术门槛,使开发者能够专注于业务逻辑而非底层实现

问答系统:是一种基于人工智能和自然语言处理技术的智能工具,它允许用户通过自然语言提问,并从文档中提取相关信息来生成准确的回答。

无论是希望快速搭建原型的技术爱好者,还是需要为企业定制智能客服的开发者,本项目均能提供从理论到实践的完整指导。接下来,我们将从环境配置开始,逐步实现一个功能完备的AI知识库问答系统。

2. 问答系统流程

本项目旨在基于 PythonLangChain框架,构建一个可扩展的知识库问答系统,其核心目标包括:

  1. 支持多格式外部数据加载:从PDF、Word、CSV、excel等非结构化数据中提取知识,构建统一的知识库。
  2. 结合大语言模型的语义理解能力:通过向量检索(Embedding)和上下文增强技术,实现精准答案生成。

通过本项目,读者将掌握:

  • LangChain框架的核心组件(Document Loaders、Embeddings、Vector Stores、Chains)的使用方法;
  • 如何将本地或在线文档转化为可查询的知识库(向量库);
  • 如何结合LLM实现语义搜索与答案生成;

本项目模式
支持:支持加载多种类型数据(pdf、word、excel、md、json、yaml、csv、html等)
支持:多种大模型(deepseek、千帆、智普等)

流程图

在这里插入图片描述

基于上述流程图涉及到的功能点如下

功能点说明
文档加载器知识库多种格式数据加载
文档切割将大块文本切割为多个小文本,便于后续处理
模型嵌入包装器将文本转换为向量
向量库存储模型嵌入包装器文本转换的向量,同时支持文本相关度检索
大模型Deepseek、qianfan等大模型框架
chain链支持将向量库命中的文档传递给大模型的文档链

3. 知识问答系统相关组件

3.1 文档加载器

​ 在 LangChain大语言模型(LLM)应用 中,文档加载器(Loader 的作用是 从 PDF、CSV、txt、excel等 文件中提取文本内容,并将其转换为 LLM 可处理的格式(如字符串、列表或结构化数据),以便后续进行 文本分割(Text Splitting)、嵌入(Embedding)、问答(QA)或总结(Summarization) 等任务。

工具名称使用场景
PdfReaderPyPDF2中操作pdf工具
TextLoader加载txt文本文件
CSVLoader加载CSV格式的文件
UnstructuredExcelLoader加载excel格式文件
JSONLoader加载json格式文件
UnstructuredMarkdownLoader加载MD格式文件

我们的文档系统支持加载多种数据格式,比如pdf、txt、csv、excel, 这里加载文本后获取的数据有两种格式

  1. 一种是返回原始的文本列表 list[Document]
  2. 一种是统一转换为文本格式(个人发现:使用非结构化的文本数据,向量库的检索的准确率更高,模型回答效果更好)

下面列举上述文本加载的python代码(代码很多但是超级简单

  • 加载并转换为文档
import osfrom PyPDF2 import PdfReader
from langchain_community.document_loaders import TextLoader, CSVLoader, UnstructuredExcelLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document# 文本转换为 list[Document]:对于pdf、txt非结构化数据处理
def textSplitForDocs(content: str) -> list[Document]:"""将文本内容进行切割,返回切割后的文本列表使用 langchain_text_splitters 库进行切割Args:content (str): 待切割的文本内容Returns:list[str]: 切割后的文本列表"""# 初始化递归字符分割器 (每个文档库100字、每个文档块可以允许重复10个字)# 重叠字符数:为了分割文字同时不破化其语义完整性splitter = RecursiveCharacterTextSplitter(chunk_size=100,      # 每个文档块的最大字符数chunk_overlap=10     # 相邻文档块之间的重叠字符数)# 将文本分割成多个 Document 对象docs = splitter.create_documents([content])return docs  #PdfReader 加载器 加载pdf文件
def loadPyPdf2Loader(pdf_path: str) -> list[Document]:"""从本地路径加载 PyPDF2 并返回 Document 列表使用 PyPDF2 库进行加载Args:pdf_path (str): PDF 的本地路径(如 "path/to/your/pdf.pdf")Returns:list[Document]: 包含文本内容和元数据的 Document 列表"""#入参 pdf文档路径 加载完成padReader = PdfReader(pdf_path)raw_text = ''# 遍历 PDF 的每一页for page in padReader.pages:#提取文本内存(目前不考虑图片相关资源)text = page.extract_text()#拼接成长文本if text:raw_text += text#长文本分割并转换为Document列表        return textSplitForDocs(raw_text)#TextLoader 加载器 加载txt文件
def loadTextLoader(text_path: str) -> list[Document]:"""从本地路径加载txt文件:param text_path: 文件路径:return: 文本信息"""#校验文件路径if not os.path.exists(text_path):raise FileNotFoundError(f"输入文件不存在: {text_path}")#文件路径、编码方式(中文需要指定,否则会乱码)   创建加载器 load = TextLoader(text_path, encoding="utf-8")# 加载文本文件 直接会返回document列表 文件内容按自然段落或换行符分割成文档列表# 不完全符合我们要求,故此处还是拼接文本,在调用方式按照我们要求分隔文本docs = load.load()raw_text = ''for doc in docs:text = doc.page_contentif text:raw_text += text#长文本分割并转换为Document列表         return textSplitForDocs(raw_text)#CSVLoader 加载器 加载csv文件(结构化数据直接load 即可获取Document列表)
def loadCSVLoader(cvs_path: str) -> list[Document]:"""加载CSV格式文件:param cvs_path:  csv文件路径:return: 获取到的文本信息"""csvLoader = CSVLoader(cvs_path, encoding="utf-8")docs = csvLoader.load()return docs#UnstructuredExcelLoader 加载器 加载excel文件(结构化数据直接load 即可获取Document列表)
def loadExclLoader(excl_path: str) -> list[Document]:"""加载excel文件:param excl_path: 文件路径:return: excel中文本信息"""loader = UnstructuredExcelLoader(excl_path, encoding="utf-8")docs = loader.load()return docs##### 其他格式文档加载待补充  
  • 加载并转换为纯文本格式
#逻辑与上述加载文本转换为文档列表大体一致,主要添加了将数据提取为长文本并分割
import osfrom PyPDF2 import PdfReader
from langchain_community.document_loaders import TextLoader, CSVLoader, UnstructuredExcelLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Documentdef loadPyPdf2Loader(pdf_path: str) -> list[str]:"""从本地路径加载 PyPDF2 并返回 字符串结婚 列表使用 PyPDF2 库进行加载Args:pdf_path (str): PDF 的本地路径(如 "path/to/your/pdf.pdf")Returns:list[str]: 包含文本内容列表"""padReader = PdfReader(pdf_path)raw_text = ''for page in padReader.pages:text = page.extract_text()if text:raw_text += textreturn textSplitter(raw_text)def loadTextLoader(text_path: str) -> list[str]:"""从本地路径加载txt文件:param text_path: 文件路径:return: 文本信息"""#校验文件路径if not os.path.exists(text_path):raise FileNotFoundError(f"输入文件不存在: {text_path}")load = TextLoader(text_path, encoding="utf-8")docs = load.load()raw_text = ''for doc in docs:text = doc.page_contentif text:raw_text += textreturn textSplitter(raw_text)def loadCSVLoader(cvs_path: str) -> list[str]:"""加载CSV格式文件:param cvs_path:  csv文件路径:return: 获取到的文本信息"""csvLoader = CSVLoader(cvs_path, encoding="utf-8")docs = csvLoader.load()raw_text = ''for doc in docs:text = doc.page_contentif text:raw_text += textreturn textSplitter(raw_text)def loadExclLoader(excl_path: str) -> list[str]:"""加载excel文件:param excl_path: 文件路径:return: excel中文本信息"""try:loader = UnstructuredExcelLoader(excl_path, encoding="utf-8")docs = loader.load()  # 在这里卡住说明是加载器内部问题except Exception as e:print(f"加载失败: {str(e)}")raiseraw_text = ''for doc in docs:text = doc.page_contentif text:raw_text += textreturn textSplitter(raw_text)
3.2 文档切割器

​ 在大语言模型(LLM)应用 中,文档切割器(Text Splitter) 的核心作用是 将长文本拆分成更小的、符合模型输入限制的片段(chunks),同时尽可能保留语义完整性。它是连接 原始文档LLM 处理单元 的关键工具,尤其在处理长文档(如 PDF、书籍、报告)时必不可少。

类名功能描述核心参数适用场景
CharacterTextSplitter按固定字符数或分隔符(如换行符、空格)切割文本。- chunk_size: 最大块大小(字符数) - chunk_overlap: 块间重叠字符数 - separator: 分隔符(默认 \n\n简单文本切割,无需语义结构(如日志、纯文本)。
RecursiveCharacterTextSplitter递归尝试多种分隔符(如段落、句子、空格),优先保留语义边界。- chunk_size: 最大块大小 - chunk_overlap: 块间重叠 - separators: 分隔符优先级列表(默认 ["\n\n", "\n", " ", ""]通用文本切割(如文章、书籍、网页内容)。
MarkdownHeaderTextSplitter按 Markdown 标题层级(如 ###)切割文本,保留章节结构。- headers_to_split_on: 标题元组列表(如 [("#", "Header 1"), ("##", "Header 2")]Markdown 文档(如技术文档、笔记)。
HTMLSectionSplitter按 HTML 标签(如 <h1><p>)切割文本,保留 HTML 结构。- tag_names: 标签名列表(如 ["h1", "p"]) - attributes_to_keep: 保留的属性(如 ["class"]HTML 文档(如网页、报告)。
TokenTextSplitterToken 数量(而非字符数)切割文本,适合需要精确控制 Token 的场景(如 GPT 模型)。- chunk_size: 最大 Token 数 - model_name: 用于分词的模型名(如 "gpt2"需要与 LLM Token 限制对齐的场景(如 OpenAI API)。
LanguageSplitter自然语言边界(如句子、段落)切割,支持多语言(需指定语言模型)。- chunk_size: 最大块大小 - language: 语言代码(如 "en""zh") - model_name: 分词模型名多语言文本切割(如中文、英文混合文档)。

如果上述返回的是纯文本,则需要长文本转换为小的满负荷模型输入限制的片段,文档分割器就派上用场了。

from langchain_text_splitters import RecursiveCharacterTextSplitterdef textSplitter(content: str) -> list[str]:"""将文本内容进行切割,返回切割后的文本列表使用 langchain_text_splitters 库进行切割Args:content (str): 待切割的文本内容Returns:list[str]: 切割后的文本列表"""splitter = RecursiveCharacterTextSplitter(chunk_size=100,      # 每个文档块的最大字符数chunk_overlap=10     # 相邻文档块之间的重叠字符数)# chunk_size:每个文档块的最大字符数  chunk_overlap:相邻文档块之间的重叠字符数splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=10)# 文档分割texts = splitter.split_text(content)return texts
3.3 嵌入模型包装器

​ 嵌入模型包装器是自然语言处理(NLP)框架中的核心组件,其核心作用是将 文本数据转换为浮点数值向量(Embedding),从而可以分析文本的相似度。后续将其存储在向量库中,便于后续的搜索使用等。

类名功能描述核心参数
OpenAIEmbeddings调用 OpenAI 或 Azure OpenAI 的嵌入模型(如 text-embedding-ada-002),将文本转换为高维向量。- model: 模型名称(如 text-embedding-ada-002) - api_key: OpenAI API 密钥 - inputs: 输入文本(字符串或字符串列表)
QianfanEmbeddingsEndpoint百度千帆平台的嵌入模型包装器,支持多种嵌入模型,提供稳定的 API 接口。- endpoint: 千帆平台 API 地址 - qianfan_ak: 千帆平台 Access Key - qianfan_sk: 千帆平台 Secret Key - model: 模型名称(如 qianfan-embedding-model
ZhipuAIEmbeddings智谱 AI 的嵌入模型包装器,用于生成文本的嵌入向量,支持参数配置和错误处理。- model: 模型名称(如 zhipuai-embedding-model) - batch_size: 批量处理大小 - max_retries: API 调用最大重试次数
BaichuanTextEmbeddings百川智能开发的中文文本嵌入模型,专注中文语义理解,生成高维度向量。- model: 模型名称(如 baichuan-text-embedding) - max_tokens: 最大处理 token 数(如 512) - dimension: 输出向量维度(如 1024)

如下是我整合了千帆、智普、百川三个平台的模型嵌入包装器(为啥没有openAI 因为需要🪜)其他国产大模型的嵌入模型包装器我没有找到对应的demo ,参考文档:langchain嵌入模型包装器

import os
from pathlib import Pathfrom dotenv import load_dotenv
from langchain_community.embeddings import BaichuanTextEmbeddings, QianfanEmbeddingsEndpoint, ZhipuAIEmbeddings
from langchain_core.embeddings import Embeddings
from langchain_openai import  OpenAIEmbeddings#支持百川大模型、千帆大模型、智普AI模型
def getEmbeeding(modelName: str) -> Embeddings:"""获取嵌入模型包装器Args:modelName (str): 嵌入模型名称Returns:Embeddings: 嵌入模型对象"""#加载配置信息 (安全) #大模型相关key存储在resource/.env BASE_DIR = Path(__file__).parent.parentload_dotenv(dotenv_path=BASE_DIR / "resource" / ".env")if modelName == "baichuan":# 百川大模型#1.获取对应的apikeybai_chuan_api_key = os.getenv("BAI_CHUAN_API_KEY")#2.创建百川嵌入模型包装器return BaichuanTextEmbeddings(baichuan_api_key=bai_chuan_api_key)elif modelName == "qianfan":# 千帆大模型(文心一言)#1.获取千帆ak、skqianfan_ak = os.getenv("QIANFAN_AK")qianfan_sk = os.getenv("QIANFAN_SK")#2.创建千帆的嵌入模型包装器return QianfanEmbeddingsEndpoint(qianfan_ak=qianfan_ak,qianfan_sk=qianfan_sk)elif modelName == "zhipu":# 智普AI模型#1. 获取智普apikeyzhipu_api_key = os.getenv("zhipu-api-key")#2. 创建智普的嵌入模型包装器return ZhipuAIEmbeddings(model="embedding-3",api_key=zhipu_api_key)elif modelName == "openai":# openai大模型 TODO 没有open_ai 的keyreturn OpenAIEmbeddings()else:return None

资源添加resource/.env

#百川大模型 apiKey(注册申请)
BAI_CHUAN_API_KEY=sk-XXXXX#智普AI的api-key
zhipu-api-key=fxxx#千帆大模型
QIANFAN_AK=xxx
QIANFAN_SK=xxxx#openai
OPEN_AI_KEY=xxxxx
3.4 向量存储库

向量存储库(Vector Store)是专门用于存储、索引和检索高维向量数据的数据库系统,支持存储向量。从而支持相似性搜索语义理解能力多模态支持等。

  1. 高效存储高维向量:支持海量高维向量的压缩存储,例如文本、图像、音频等非结构化数据经嵌入模型转换后的向量。
  2. 相似性搜索:通过近似最近邻(ANN)算法(如HNSW、IVF-PQ、LSH)快速查找与查询向量最相似的向量集合,而非传统数据库的精确匹配。
  3. 语义理解能力:基于向量间的距离度量(如余弦相似度、欧氏距离),实现基于语义的搜索,而非关键词匹配。
  4. 多模态支持:可处理文本、图像、音频等多种数据类型的向量表示,支持跨模态检索。
  5. 可扩展性:设计用于处理大规模数据,支持分布式部署和水平扩展。
类名功能描述核心参数
Milvus开源的分布式向量数据库,支持多种索引类型(如HNSW、IVF_PQ),适用于大规模向量相似性搜索。- dim:向量维度 - index_type:索引类型(如IVF_FLATHNSW) - metric_type:距离度量方式(如L2IP
FAISSFacebook AI Research开发的开源库,针对相似性搜索优化,支持GPU加速。- dim:向量维度 - M(HNSW参数):每个节点的最大连接数 - efConstruction(HNSW参数):构建索引时的搜索范围
Pinecone全托管的向量数据库服务,提供高性能的向量搜索,支持实时更新和水平扩展。- dimension:向量维度 - metric:距离度量方式(如cosineeuclidean) - pod_type:计算资源类型(如s1.x1
Weaviate开源的向量数据库,结合语义搜索与图形数据库特性,支持自动schema推断和丰富的GraphQL API。- vectorizer:嵌入模型配置(如text2vec-contextionary) - distance:距离度量方式(如cosine
Chroma开源的、AI本地的嵌入式向量数据库,支持查询、过滤、密度估计等多种功能。- 支持多种嵌入模型(如BERTCLIP) - 提供Python API,易于集成到AI应用中
Qdrant开源的向量相似性搜索引擎和数据库,提供生产就绪的服务和易于使用的API。- dim:向量维度 - distance:距离度量方式(如cosineeuclidean) - hnsw_m:HNSW参数,每个节点的最大连接数
Elasticsearch + pgvector传统数据库添加的向量搜索功能,支持SQL查询和向量检索的混合搜索。- dim:向量维度 - distance:距离度量方式(如l2inner_product
Annoy轻量级开源库,适合大型数据集的近似最近邻搜索,特点是构建索引速度快且占用空间小。- f:向量维度 - metric:距离度量方式(如angulareuclidean) - n_trees:树的数量
HNSWlib实现HNSW算法的库,支持高效的近似最近邻搜索。- dim:向量维度 - space:距离度量方式(如cosinel2) - M:每个节点的最大连接数

这里我使用的是FAISS向量库,存储嵌入模型包装器(该向量库对于数字类型查询不太理想,准确度较低,对于文字相关搜索精确度挺高,后续看演示吧)

保存向量库数据

def saveFAISSVector(indexPath: str) -> None:"""加载外部数据并将其存储到向量库中:param indexPath: 向量库路径"""# 加载pdf文件pdf_texts = loadPyPdf2Loader("doc_data/member.pdf")# 加载文本文件txt_texts = loadTextLoader("doc_data/crm_info.txt")# 加载CSV格式文件csv_texts = loadCSVLoader("doc_data/cust_info.csv")# 加载Excel格式文件excel_texts = loadExclLoader("doc_data/dms.xlsx")# 3. 合并 PDF 和 TXT 的文档列表texts = pdf_texts + txt_texts + csv_texts + excel_texts# 3.使用嵌入模型包装器,将文档转换嵌入向量embeddings = getEmbeeding(embeeding_model)# vectors = embeddings.embed_documents(texts)# 4. 创建向量数据库并与嵌入模型连接,# 将文本转换为向量,并保存到向量数据库中docSearch = FAISS.from_texts(texts, embeddings)# 持久化向量库docSearch.save_local(indexPath)print("向量库保存成功!")

加载向量库 用于查询使用

def loadFAISSVector(indexPath: str) -> FAISS:"""加载 FAISS 向量库:param index: 向量库路径:return: FAISS 对象"""return FAISS.load_local(indexPath, getEmbeeding(embeeding_model),allow_dangerous_deserialization=True)

文档检索

我们从向量库中加载相关向量后,需要从向量库中进行检索,并将检索出来的数据(document 列表)作为背景信息传递给大模型

 # 5.查询数据从向量库# query是自然语言查询条件docs = docSearch.similarity_search(query, k=6)print("命中的文档数:", len(docs))
3.5 模型包装器

模型包装器(Model Wrappers)是 LangChain 的核心组件之一,其作用是为大语言模型提供一层抽象接口,封装模型的调用、输入输出处理以及配置管理等功能。

类名作用功能用法
ChatOpenAILangChain 中用于与 OpenAI 聊天模型交互的核心类,提供多种方法来调用和管理对话- 核心方法: - invoke():同步调用模型,获取完整响应。 - stream():流式响应,适合逐步显示结果的场景。 - generate():批量生成,同时处理多个用户输入,返回包含元数据的完整响应对象。 - bind_tools():绑定工具调用,将函数调用能力绑定到当前模型。 - with_structured_output():结构化输出,强制模型返回结构化数据。 - with_fallbacks():失败回退,设置模型调用失败时的备用模型。 - 配置相关方法: - 模型参数设置,如 model(模型名称)、temperature(随机性控制)、max_tokens(最大输出长度)等。 - 异步方法: - 所有核心方法都有对应的异步版本,如 ainvoke()astream() 等。 - 使用示例: - 同步调用:response = chat.invoke("你好!") - 流式处理:for chunk in chat.stream("请写一首关于春天的诗"): print(chunk.content, end="", flush=True) - 批量生成:result = chat.generate([[HumanMessage(content="2+2等于多少?")]])
QianfanChatEndpoint百度千帆平台提供的聊天模型端点,支持多轮对话和历史消息记录- 多轮对话:维护对话上下文,支持连续交互。 - 历史消息记录:记录对话历史,便于追溯和复用。 - 应用场景:聊天机器人、客服系统、智能问答等需要对话交互的场景。 - 使用方式:在千帆平台中配置模型参数,通过API调用实现对话功能。
ChatDeepSeek(假设类名,基于DeepSeek模型)封装DeepSeek大语言模型的调用接口,提供文本生成、语义理解、代码生成等功能- 文本生成:支持文章、故事、诗歌创作,营销文案生成等。 - 自然语言理解:语义解析、情感分析、意图识别、实体提取。 - 编程辅助:代码生成、补全、调试建议,API文档生成。 - 数据可视化:生成流程图、折线图、柱状图等图表。 - 使用方式:通过官方网站或API调用,输入提示语(Prompt)获取输出。
#目前支持 deepseek、qianfan、zhipu
def getLLM(modelName: str) -> BaseChatModel:"""获取大模型对象Args:modelName (str): 模型名称Returns:BaseChatModel: 模型对象"""#加载配置信息 (安全)BASE_DIR = Path(__file__).parent.parent.parentload_dotenv(dotenv_path=BASE_DIR / "resource" / ".env")if modelName == "deepseek":# deepseek大模型api_key = os.getenv("DEEPSEEK_API_KEY")return ChatDeepSeek(model="deepseek-chat",temperature=0,max_tokens=None,timeout=None,max_retries=2,openai_api_key=api_key,)elif modelName == "qianfan":# 千帆大模型app_id = os.getenv("QIANFAN_APPID")access_token = os.getenv("QIANFAN_TOKEN")return QianfanChatEndpoint(model="ERNIE-Tiny-8K",temperature=0.2,timeout=30,app_id=app_id,access_token=access_token)elif modelName == "zhipu":# 智普AI模型api_key = os.getenv("zhipu-api-key")# 初始化一个 ChatOpenAI 对象(即一个 LLM 模型接口)return ChatOpenAI(temperature=0.95,  # 控制生成文本的随机性(0=确定性强,1=随机性强)model="glm-4-air-250414",  # 指定模型名称(这里是智谱 GLM-4 的某个版本)openai_api_key=api_key,  # 你的 API 密钥(需提前定义变量 api_key)openai_api_base="https://open.bigmodel.cn/api/paas/v4/"  # 智谱 AI 提供的 API 基础地址)elif modelName == "openai":# openai大模型 TODO 没有open_ai 的keyreturn ChatOpenAI()else:return None
3.6 链组件

​ 在 LangChain 中,链(Chain) 是核心抽象概念之一,它代表一个将多个组件(如大语言模型LLM、提示词模板prompt、工具调用toool、其他链等)按特定逻辑组合起来的可执行流程。链的设计使得复杂任务可以分解为可复用的模块,并通过组合这些模块实现灵活的功能扩展。下面列举几个常用链

  • 基础链(Basic Chains)

简单任务的基础组件。

链类型核心作用典型适用场景
LLMChain直接调用 LLM 完成单步文本生成或问答。单轮问答、提示词测试、简单文本生成。
SequentialChain按顺序执行多个链(如 Chain1 → Chain2),支持线性流程。多步骤任务(如数据清洗 → 分析 → 报告生成)。
SimpleSequentialChain简化版的顺序链,固定输入输出结构。标准化线性流程(如固定格式的文档处理)。
  • 2. RAG 链(Retrieval-Augmented Generation Chains)

通过检索实时更新的外部知识库(如新闻、数据库、API),将最新信息作为上下文输入大模型,生成准确回答。

链类型核心作用典型适用场景
Stuff Documents Chain合并输入:将多个文档拼接成一个长文本,直接传给 LLM 处理。短文档问答(文档总长度 < LLM max_tokens)、简单信息提取。
Map-Reduce Documents Chain分治处理: 1. Map:对每个文档单独处理(如生成摘要、提取关键信息); 2. Reduce:合并所有处理结果后传给 LLM 生成最终输出。长文档总结、多文档信息聚合(如新闻汇总、产品评论分析)。
Refine Documents Chain迭代优化: 1. 生成初步回答; 2. 基于所有文档逐步优化回答(多次交互)。复杂问题优化(如法律条文分析、科研文献综述)、需要多轮修正的高精度任务。
Map-Rerank Chain生成-排序: 1. Map:批量生成多个候选结果(如答案、摘要、选项); 2. Rerank:按评分标准(如相关性、准确性)对候选结果排序,选择最优解。问答系统(多答案选择)、搜索结果优化、文本摘要质量提升、推荐系统候选筛选。
  • 3. 代理链(Agent Chains)

通过工具扩展 LLM 能力,实现自动化。

链类型核心作用典型适用场景
Zero-Shot Agent通过自然语言描述工具,自主选择工具完成任务。简单自动化任务(如“查询天气”“计算数学题”)。
ReAct Agent结合推理(Reasoning)和行动(Action),支持多步决策。复杂逻辑任务(如“规划旅行路线”“诊断系统故障”)。
Conversational Agent支持对话历史记忆,实现多轮上下文交互。聊天机器人、客服系统、个人助手。
  • **4. 高级推理链(Advanced Reasoning Chains) **

针对特定场景优化(如知识图谱、辩论)。

链类型核心作用典型适用场景
GraphQA Chain基于知识图谱进行关系推理和问答。结构化知识查询(如“XX 和 XX 的关系是什么?”)。
Debate Chain通过多 LLM 角色辩论优化回答质量。高质量内容生成(如论文写作、创意策划)。
  • 多模态链(Multimodal Chains)

支持非文本数据(图像、音频)与 LLM 交互。

链类型核心作用典型适用场景
Vision-Language Chain处理图像和文本混合输入(如 OCR + LLM 描述图像)。图像分析、图表解读、视觉问答。
Audio-Language Chain处理音频和文本混合输入(如语音转文字 + LLM 总结)。语音助手、会议纪要生成、音频内容分析。

我们的问答系统,需要将向量库使用RAG代理增强,对文本进行代理增强。实现了stuff链(文档问答链)代码如下

stuff链(文档问答链)

def qa_stuff(docs: list[Document], query: str):"""创建一个基于 Stuff 策略的问答链,将多个文档合并后传给 LLM 回答用户问题。Args:docs (list[Document]): 文档列表,每个文档包含文本内容和元数据。query (str): 用户提出的查询问题。Returns:str: LLM 生成的回答结果。"""# 1. 定义系统提示模板(System Prompt)#    - 指导模型如何利用提供的文档回答问题#    - 强调“不知道就说明不知道”,避免编造答案system_template = "使用以下背景信息来回答用户的问题。如果你不知道答案,只需说明不知道,不要编造答案。{context}"# 2. 构建完整的提示模板(Prompt Template)#    - 包含系统消息(System Message)和用户消息(Human Message)messages = [# 系统消息:设置模型行为规则SystemMessagePromptTemplate.from_template(system_template),# 用户消息:包含实际查询问题HumanMessagePromptTemplate.from_template("{question}"),]# 3. 创建聊天提示模板(ChatPromptTemplate)#    - 将消息列表转换为 LangChain 可识别的提示格式chat_prompt = ChatPromptTemplate.from_messages(messages)# 4. 创建 Stuff 文档链#    - 使用自定义的聊天提示模板#    - 指定 LLM 模型(这里调用 getLLM 函数获取 "deepseek" 模型)chain = create_stuff_documents_chain(llm=getLLM("deepseek"),  # 获取 LLM 模型实例prompt=chat_prompt       # 使用上面定义的聊天提示模板)# 5. 执行链式调用#    - 输入参数:#       - context: 要合并的文档列表(会自动拼接)#       - question: 用户查询问题result = chain.invoke({"context": docs,  # 文档上下文(会自动转换为字符串)"question": query # 用户问题})# 6. 返回结果return result

至此,langchain的所有核心组件讲完,同时我们问答系统的所有流程也编写完成!下面让我们进入演示环节。

4. 问答系统演示

4.1 问答程序

调用我们上面章节的相关代码,我们便编写完了一个基于知识库的AI智能问答系统。流程如下

def qa_system(query: str) -> None:"""基于向量检索和LLM的问答系统主流程:1. 将数据保存到FAISS向量库(若不存在则创建)2. 从本地加载向量库3. 执行相似度检索获取相关文档4. 使用Stuff链将文档和问题传给LLM生成答案Args:query (str): 用户输入的自然语言查询问题Returns:None (结果直接打印,如需返回可修改为return result)"""# 1. 保存/更新数据到FAISS向量库#    - 如果向量库已存在则直接使用,不存在则创建新索引#    - faiss_index_name 是全局常量,指定索引存储路径saveFAISSVector(faiss_index_name)# 2. 从本地加载FAISS向量库#    - 返回的docSearch是已初始化的向量检索器#    - 内部包含嵌入模型(embedding model)和FAISS索引docSearch = loadFAISSVector(faiss_index_name)# 3. 执行相似度检索#    - 参数说明:#       - query: 用户查询文本#       - k=6: 返回最相似的6个文档(可根据需求调整)#    - 返回的docs是Document对象列表,包含文本内容和元数据docs = docSearch.similarity_search(query, k=6)print("命中的文档数:", len(docs))  # 调试信息:实际检索到的文档数量# 4. 调用Stuff链处理文档并生成答案#    - qa_stuff函数实现:#      1) 将所有文档内容合并为单个字符串#      2) 添加系统提示词指导LLM回答#      3) 调用LLM生成最终答案result = qa_stuff(docs, query)# 5. 输出最终结果print("最终答案:", result)#启动程序
if __name__ == "__main__":#用户输入提问query = input("你想要问些什么?")#问答qa_system(query)
4.2 演示大模型回答效果

知识库和向量库

图中是我的建立的知识库以及向量库。

pdf_qa_system.py 是将所有数据转换为文档存入向量 (针对数字类型的问答不准确)

pdf_qa_system_text.py 是将所有数据转换为长文本分割成多个文档存入向量 (各个维度查询准确度都很高)
在这里插入图片描述
命中知识库的回答

​ 首先在【3.1 文档加载器】加载了不同类型的文档知识,例如加载了:csv格式的客户数据:

客户id客户姓名客户类型营业执照地址锁定状态
1000002007塔德伊·波加查经销商91588888MAAK96L889北京市石景山区八角游乐园锁定

可以针对上述数据任何维度进行问答。问答效果如下:

在这里插入图片描述
在这里插入图片描述

不命中的效果

在这里插入图片描述

5.问答系统代码

链接: 代码原文件地址

项目目录结构
lang_chain_qa/
└── doc_data/ 知识库资源 (目前是空自行补充)
├── faiss_index/ 向量库持久化文件(文档类型)
├── faiss_text_index/ 向量库持久化文件(文本类型)
├── crm_info.txt 资源
├── cust_info.csv 资源
├── dms.xlsx 资源
├── mathPix.md 资源
├── member.pdf 资源
├── pdf_qa_system.py 文档类型数据知识问答
├── pdf_qa_system_text.py 文本类型数据知识问答
└── rerank_prompt.py

至此,我们一步一步的手写了一份知识库问答系统,如有问题欢迎指正。原创不易,对你有帮助还请一键三连。

http://www.dtcms.com/a/356838.html

相关文章:

  • 将2D基础模型(如SAM/SAM2)生成的2D语义掩码通过几何一致性约束映射到3D高斯点云
  • android 不同分辨图片放错对应文件夹会怎样?
  • Python 编码与加密全解析:从字符编码到 RSA 签名验证
  • (笔记)Android ANR检测机制深度分析
  • 【微知】如何撤销一个git的commit?以及撤销的3种方式?
  • 多代理系统架构:Supervisor 与 Swarm 架构详解
  • Java面试-MySQL事务
  • Word文档怎么打印?Word打印技巧?【图文详解】单面/双面/指定页面/逆序等Word打印选项
  • 微信小程序中蓝牙打印机中文编码处理:使用iconv-lite库
  • Java 大视界 -- Java 大数据在智能安防入侵检测系统中的多模态数据融合与检测精度提升(405)
  • 将数据赋值到多个文档里,并将多个word放入压缩包并下载
  • Elasticsearch 9.X 使用推理 API 进行语义搜索
  • JAVA 请求第三方接口,将JSON数据转为对象
  • 微软正在公开测试其首个完全自主训练的大语言模型——MAI-1-preview
  • week5-[二维数组]翻转
  • 【性能优化】Unity 渲染优化全解析:Draw Call、Batch、SetPass 与批处理技术
  • 整理python接口自动化相关——10、自动考虑点(待续)
  • 动态规划--Day02--爬楼梯--2466. 统计构造好字符串的方案数,2533. 好二进制字符串的数量,2266. 统计打字方案数
  • 匠心传承,古韵新生——记木雕名家龙巍的艺术人生
  • v-model与v-bind区别
  • 吴恩达机器学习作业五:神经网络正向传播
  • Python Imaging Library (PIL) 全面指南:PIL基础入门-图像合成与处理技巧
  • 基于 Python asyncio 和币安 WebSocket 打造高频加密货币预警机器人
  • TypeScript: Reflect.ownKeys 操作(针对 Symbol)
  • Lenovo C225 一体机拆机维修教程
  • 2025牛客暑期多校训练营4 G Ghost in the Parentheses 题解记录
  • LoRA三种不同训练流程在配置和保存权重的差异(64)
  • 《Shell 大道:筑基篇(下)—— 流控筑根基,数据任驱驰》
  • shell学习笔记-实战:创建、运行与变量操作
  • Python Imaging Library (PIL) 全面指南:PIL基础入门-构建简易图像编辑器