LangChain实战:三步构建企业级智能问答系统,附完整代码

📅 2026/7/9 4:03:29
LangChain实战:三步构建企业级智能问答系统,附完整代码
引言随着大语言模型LLM的普及开发者不再满足于简单的对话补全而是希望将 LLM 与外部数据、工具以及复杂业务逻辑相结合构建真正落地的 AI 应用。LangChain 正是为此而生的开源框架它提供了一系列标准化的组件和链式调用能力帮助开发者高效地组合模型、数据检索、记忆、代理等模块。本文将从实际需求出发带你深入理解 LangChain 的核心概念并通过一个完整的、可运行的代码示例从零开始构建一个基于私有 PDF 文档的智能问答系统。读完本文你将能够掌握 LangChain 中模型、提示、链、检索、记忆等核心抽象学会使用 LangChain 加载并处理私有文档实现一个带记忆的多轮对话问答机器人了解常见问题与最佳实践无论你是刚接触 LangChain 的新手还是希望系统梳理概念的开发者这篇实战指南都能为你提供清晰的路线图。核心概念LangChain 的六脉神剑在动手写代码前我们需要先理解 LangChain 的六大基础组件它们是构建一切应用的基石。1. 模型ModelsLangChain 封装了两种主要模型LLM纯文本补全和聊天模型Chat Models如gpt-3.5-turbo。它们都通过统一的接口调用方便替换。例如from langchain.chat_models import ChatOpenAI llm ChatOpenAI(model_namegpt-3.5-turbo, temperature0)2. 提示Prompts提示管理是 LLM 应用的关键。LangChain 提供了PromptTemplate、ChatPromptTemplate等工具支持变量插值、Few-shot 示例以及消息角色system、human、ai的组合。from langchain.prompts import ChatPromptTemplate template ChatPromptTemplate.from_messages([ (system, 你是一个友好的AI助手), (human, {user_input}) ])3. 链Chains链是 LangChain 的核心思想它将多个组件串联起来形成一个处理管道。比如最简单的LLMChain就是把提示模板和模型组合起来。更复杂的还有RetrievalQA、ConversationalRetrievalChain等这些封装好的链大大降低了开发门槛。4. 检索Retrieval为了让 LLM 能够回答非公开知识我们需要将文档切片、向量化并存入向量数据库。用户提问时先检索相关文档片段再与问题一起交给模型回答。这一流程常被称为RAGRetrieval-Augmented Generation。LangChain 提供了各种文档加载器、文本分割器、嵌入模型接口和向量数据库集成。5. 记忆Memory默认情况下LLM 是无状态的。LangChain 的Memory组件可以保存对话历史实现多轮对话能力。常见的记忆类型有ConversationBufferMemory全量缓存、ConversationSummaryMemory摘要记忆等。6. 代理Agents代理将 LLM 作为“大脑”能够自主决定使用哪些工具、按什么顺序执行最终完成复杂任务。本文以 RAG 为主代理部分可视为进阶内容。理清这些组件后我们开始实战。实战示例私有 PDF 智能问答系统我们以一个典型场景为例公司内部有许多产品使用手册PDF 格式希望搭建一个智能问答机器人员工可以用自然语言提问机器人能基于手册内容给出精准回答并支持多轮对话。环境准备确保已安装 Python 3.9并安装以下依赖pip install langchain openai chromadb pypdf tiktoken streamlit我们需要一个 OpenAI 的 API Key请将其设置为环境变量OPENAI_API_KEY。步骤一加载并处理文档首先将 PDF 加载为文本然后进行分块。分块的原因有两个向量模型通常有 token 上限小块文本检索时更精准。# 1. 文档加载 from langchain.document_loaders import PyPDFLoader loader PyPDFLoader(path/to/your/product_manual.pdf) documents loader.load() # 每页作为一个 Document 对象 print(f文档页数: {len(documents)}) # 2. 文本分割 from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每块最大字符数 chunk_overlap50, # 块之间重叠字符数避免在语义边界切断 separators[\n\n, \n, 。, , , , , ] ) chunks text_splitter.split_documents(documents) print(f分割后的文本块数量: {len(chunks)})注意separators列表定义了分割优先级先从两个换行段落开始如果没有则用单个换行再逐级下降。这能保留更好的语义结构。步骤二创建向量数据库将文本块转化为向量并存储到 Chroma一个轻量级本地向量数据库中。# 3. 嵌入与向量存储 from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma embeddings OpenAIEmbeddings() # 指定持久化目录避免每次运行都重新计算嵌入 persist_directory ./chroma_db vectordb Chroma.from_documents( documentschunks, embeddingembeddings, persist_directorypersist_directory ) vectordb.persist() # 持久化到磁盘 print(向量数据库创建完成)后续再次使用时可以直接加载已有数据库vectordb Chroma( persist_directorypersist_directory, embedding_functionembeddings )步骤三构建对话型检索链我们使用ConversationalRetrievalChain一步到位它内部整合了问题改写基于对话历史生成独立问题、文档检索、上下文整合和答案生成。from langchain.chat_models import ChatOpenAI from langchain.chains import ConversationalRetrievalChain from langchain.memory import ConversationBufferMemory # 初始化语言模型 llm ChatOpenAI( model_namegpt-3.5-turbo, temperature0.1, # 降低随机性保证回答精确 max_tokens512 ) # 创建记忆组件用于存储对话历史 memory ConversationBufferMemory( memory_keychat_history, # 链内部会使用这个key从记忆读取历史 return_messagesTrue, # 以消息对象列表形式返回 output_keyanswer # 指定输出存储的键 ) # 构建对话检索链 qa_chain ConversationalRetrievalChain.from_llm( llmllm, retrievervectordb.as_retriever(search_kwargs{k: 4}), # 每次检索返回4个相关块 memorymemory, verboseFalse # 设为True可查看内部运行细节 ) print(对话检索链创建成功开始对话吧)步骤四测试对话# 模拟用户提问 print(第一轮) response qa_chain({question: 如何重置设备的网络设置}) print(fAI: {response[answer]}\n) print(第二轮跟随上下文) response qa_chain({question: 对刚才提到的步骤有没有更详细说明}) print(fAI: {response[answer]}\n) print(第三轮) response qa_chain({question: 如果重置后仍无法连接怎么办}) print(fAI: {response[answer]}\n)运行以上代码你将看到一个能够记住“刚才提到的步骤”的问答系统。记忆组件会自动将对话历史加入提示使得模型可以正确理解上下文。完整可运行代码下面将所有步骤整合为一个完整的 Python 脚本qa_bot.py你只需修改 PDF 路径即可运行import os from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.chat_models import ChatOpenAI from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationalRetrievalChain # 1. 加载文档 pdf_path ./user_manual.pdf # 请替换为你的PDF路径 loader PyPDFLoader(pdf_path) docs loader.load() # 2. 分割文本 splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , , ] ) chunks splitter.split_documents(docs) # 3. 向量化并存储 embeddings OpenAIEmbeddings() vectordb Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_manual_db ) vectordb.persist() # 4. 初始化 LLM 和记忆 llm ChatOpenAI(model_namegpt-3.5-turbo, temperature0.1) memory ConversationBufferMemory( memory_keychat_history, return_messagesTrue, output_keyanswer ) # 5. 构建对话检索链 qa ConversationalRetrievalChain.from_llm( llmllm, retrievervectordb.as_retriever(search_kwargs{k: 4}), memorymemory ) # 6. 命令行交互循环 print(智能问答机器人已启动输入退出结束对话。) while True: user_input input(\n用户: ) if user_input.lower() in [退出, exit, quit]: print(再见) break try: result qa({question: user_input}) print(fAI: {result[answer]}) except Exception as e: print(f发生错误: {e})运行后即可在命令行进行多轮对话。常见问题 注意事项1. Token 超限怎么办当对话历史越来越长加上检索到的文档块提示可能会超出模型的上下文长度。解决方案限制检索返回数量k值调小使用ConversationSummaryMemory替代全量缓存自动生成摘要启用 token 计数对历史进行截断选择更大上下文窗口的模型如 gpt-3.5-turbo-16k2. 回答质量不理想常见原因及优化方向文档切割不合理块太大检索不准块太小丢失上下文。建议chunk_size500~1000overlap50~100为初始值根据实际文档粒度调整。检索结果相关性低可以在检索时增加相似度阈值过滤或使用带有元数据的筛选条件。提示模板可定制通过from_llm的condense_question_prompt和combine_docs_chain_kwargs传入自定义提示引导模型更好地利用上下文。3. 持久化与成本嵌入计算会消耗 API 费用如果文档不变应持久化向量数据库避免重复计算。Chroma 默认使用内存模式指定persist_directory后才会存盘。在本地频繁测试时可以先用较小的文档集验证流程。4. 向量数据库选择Chroma 适合原型和小规模应用。生产环境可考虑FAISS本地速度快Pinecone、Weaviate、Qdrant等云原生向量数据库LangChain 对它们都有良好支持。5. 安全性切勿将 API Key 硬编码在代码中使用环境变量或密钥管理服务。对于面向最终用户的产品注意控制数据访问权限防止检索到未授权文档。总结本文从零开始详细拆解了 LangChain 构建 AI 应用的全过程。我们从核心概念入手理解了模型、提示、链、检索和记忆的职责随后通过一个完整的 PDF 问答项目展示了从文档加载、分割、向量化到构建带记忆检索链的每个环节。所有代码均可直接运行希望能为你开启 LangChain 实战之旅提供坚实基础。LangChain 的威力远不止于此它还支持代理、工具调用、回调系统等高级特性。但万变不离其宗理解这六脉神剑的组合方式你就能轻松驾驭更复杂的场景。有什么问题欢迎在评论区交流一起探索大语言模型应用的无限可能。