从0到1用LangChain搭建RAG知识库与AI Agent实战指南 先问自己一个问题你在 B 站收藏夹里躺了多少个“AI Agent 教程”我猜不少。但真正跟着做下来、能讲清 RAG 原理、能写出 Agent 代码的人可能没几个。不是大家不努力而是 AI Agent 这条学习路径实在太散了。今天看一个概念视频明天刷一篇 LangChain 笔记后天又看到有人在讲 LangGraph知识永远是碎片化的。尤其当你真正动手时会发现文档加载、向量化、检索、Agent 工具调用、记忆管理……每一步都藏着大量的坑没有人帮你把整条链路串起来学半年也还是一知半解。本文就是一套从 0 到 1 的系统化实操笔记围绕 RAG 与智能代理展开以 LangChain 为主线把“概念 → 环境 → 原理 → 代码 → 排错 → 工程实践”完整走一遍。无论是零基础想入门 AI 应用开发还是已经接触过 LangChain 但没跑通完整项目这篇文章都值得你跟着做一遍。1. 背景与核心概念AI Agent、RAG 与 LangChain 到底是什么1.1 从大模型聊起为什么需要 RAG 和 Agent大语言模型LLM很强但你一定有这种体验问它“我们公司内部的报销流程是什么”它答不上来问它“帮我分析一下这个 Excel 表格”它也无能为力。这是因为大模型的知识停留在训练数据的截止日期之前它不知道你公司内部的私有文档也看不到你本地的实时数据更不具备调用外部系统操作的能力。于是出现了两类非常关键的解决方案RAG检索增强生成Retrieval-Augmented Generation把外部知识先放进向量数据库用户提问时先检索最相关的片段再把片段拼进 Prompt 里让大模型基于这些材料作答。Agent智能代理让大模型具备“思考 行动”的能力它可以调用工具、访问 API、操作数据库根据任务目标自主决策下一步动作。两者的关系并不冲突。RAG 解决的是“知识不足”的问题Agent 解决的是“能力边界”的问题实际项目中它们经常组合使用也就是常说的 Agentic RAG。1.2 LangChain 和 LangGraph 分别扮演什么角色很多初学者会把 LangChain 和 LangGraph 搞混这里做一个简单的区分。LangChain 是一套面向大模型应用的开发框架它把各种组件模型、提示词、向量库、工具、记忆、输出解析器标准化、模块化让你可以用比较少的代码组装出一条 AI 应用流水线。LangGraph 是 LangChain 生态中面向 Agent 编排的底层框架。你可以把它理解成“用图结构来定义 Agent 的状态流转”节点和节点之间通过边连接每个节点执行一个动作状态在节点之间传递。它适合构建复杂的、需要循环和多分支决策的 Agent 系统。如果你只是构建一个简单的 RAG 问答系统LangChain 就够了如果你要构建一个复杂的多工具、带状态管理的 AgentLangGraph 是更合适的选择。1.3 这篇文章能带你完成什么我把它拆成三个递进的目标理解 RAG 的核心流程文档加载 → 拆分 → 向量化 → 检索 → 生成。用 LangChain 从零搭建一个 RAG 知识库问答系统。用 LangChain Agent 构建一个能调用多个工具的智能代理。每一部分都会给完整代码、运行方式和避坑说明。2. 环境准备与工具选型2.1 基础环境要求本文演示以 Python 作为开发语言建议按以下环境准备依赖项建议版本/工具操作系统Windows / macOS / Linux 均可Python3.9 及以上包管理工具pip 或 poetry大模型接口OpenAI API兼容接口或本地 Ollama向量数据库Chroma轻量适合学习IDEVS Code 或 PyCharm 均可版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。不同版本的 LangChain API 可能存在细微差别如果你使用的是较新的 0.3.x 版本下面代码基本兼容。2.2 安装 LangChain 及相关依赖先创建虚拟环境再安装依赖# 创建虚拟环境Windows 下执行 venv\Scripts\activate python -m venv langchain-demo source langchain-demo/bin/activate # 安装核心依赖 pip install langchain langchain-openai langchain-community langchainhub chromadb # 文档处理与网络请求 pip install pypdf requests tiktoken # 如果使用 dotenv 管理环境变量 pip install python-dotenv这里简单说明一下各个包的作用langchainLangChain 核心框架提供链式调用、工具、Agent 等基础能力。langchain-openaiOpenAI 模型封装支持 ChatGPT 和 Embedding 接口。langchain-community社区维护的加载器、向量库、工具等集成。chromadb轻量级向量数据库本地运行适合学习和原型验证。pypdf用于加载 PDF 文档。tiktokenOpenAI 的 token 计算工具用于在文档拆分时估算 token 长度。2.3 管理 API Key 与环境变量在项目根目录下创建一个.env文件内容如下OPENAI_API_KEY你的_API_Key # 如果你使用国内兼容接口可以修改 base_url # OPENAI_BASE_URLhttps://api.xxx.com/v1在代码中通过如下方式加载import os from dotenv import load_dotenv load_dotenv() api_key os.getenv(OPENAI_API_KEY)如果你没有 OpenAI Key也可以用 Ollama 跑本地模型后面在第 6 节会给出替换方案。3. RAG 核心原理拆解从文档到知识库的五步闭环在写代码之前一定要把 RAG 的流程在脑子里过一遍。很多初学者代码能跑通但换了一个场景就不会用了原因就是没理解流程。3.1 RAG 的五个核心步骤用一个表格来展示整体流程步骤做什么常用组件1. 文档加载读取本地文件PDF、Word、TXT或在线网页TextLoader、PyPDFLoader2. 文档拆分把长文档拆成适当大小的 chunk避免超出模型上下文RecursiveCharacterTextSplitter3. 向量化把每个 chunk 转成向量EmbeddingOpenAIEmbeddings4. 存储与检索把向量存入向量库用户提问时做相似度检索Chroma、FAISS5. 生成回答把检索到的内容作为上下文拼入 Prompt交给大模型生成答案ChatOpenAI Prompt3.2 为什么不能直接把整篇文档丢给大模型原因有两个上下文长度限制GPT-4 等模型虽然有较长的上下文窗口但企业内部知识库动辄几百 MB根本无法全部放入。检索成本与精度文档越长无关信息越多大模型的回答越容易“跑偏”。RAG 的优势在于只把和最相关的内容找出来针对性回答既省 token 又提升准确率。3.3 拆分Chunking为什么是最容易踩坑的环节拆分过大导致一个 chunk 里混杂多个主题检索精度下降拆分过小导致上下文碎片化模型缺少整体理解。常见的拆分参数包括chunk_size每个块的最大长度字符数或 token 数。chunk_overlap相邻块之间的重叠长度避免在边界处截断语义。实际项目中chunk_size 建议从 500 到 1000 字符开始调试chunk_overlap 设置为 10% 到 20% 左右。具体数值要结合你的文档类型调整没有一个万能值。3.4 检索后为什么要重排Rerank向量检索的结果通常只是“单词/语义相似”不一定是“真正满足用户意图”。比如用户问“合同中关于违约金的条款”单纯向量检索可能把包含“合同”“违约”字样的其他段落也捞出来影响回答质量。高级 RAG 方案中会在向量检索之后增加一个重排模型对候选段落重新打分排序保留最相关的 3-5 段。国内大厂做 RAG 知识库时重排几乎是标配。学习阶段可以先不加重排但在知识库指标那一节你会看到重排对“命中率”和“准确率”两个指标影响很大。3.5 知识库指标怎么看初学 RAG 时很多人只关注“回答得对不对”但在工程上我们需要更细的指标来衡量知识库效果召回率Recall检索出的相关文档数 / 实际相关文档总数衡量“有没有漏掉关键内容”。准确率Precision检索出的相关文档数 / 检索出的总文档数衡量“有没有把无关内容捞进来”。命中率Hit Rate用户提问后正确答案是否出现在检索返回的前 N 条中。忠实度Faithfulness模型回答是否基于检索到的文档而不是模型自己臆想。如何理解这些指标简单来说召回率低说明拆分或索引有问题准确率低说明检索策略或重排不够忠实度低说明 Prompt 约束不足。排错时可以按这个思路逐层定位。4. 实战一用 LangChain 从零搭建 RAG 知识库问答系统下面进入代码环节。我们以一份本地 txt 文档和一个 PDF 文档为例构建一个简单的本地知识库问答系统。4.1 项目结构建议先创建如下目录结构langchain-demo/ ├── .env ├── requirements.txt ├── docs/ │ └── xxx公司员工手册.txt ├── rag_demo.py └── agent_demo.pydocs目录放你自己的测试文档本文用一份员工手册作为示例。4.2 文档加载支持 TXT 和 PDF先来看文档加载代码。LangChain 提供了很多加载器我们这里演示最常见的两种。# 文件路径rag_demo.py第一部分文档加载 from langchain_community.document_loaders import TextLoader, PyPDFLoader # 加载 TXT 文件 def load_txt(path): loader TextLoader(path, encodingutf-8) docs loader.load() return docs # 加载 PDF 文件 def load_pdf(path): loader PyPDFLoader(path) docs loader.load() return docsloader.load()返回的是一个 Document 对象列表每个 Document 包含page_content页面内容和metadata元数据如来源文件、页码等。如果你要加载 Word 文档可以使用Docx2txtLoader如果要加载网页可以用WebBaseLoader。原理是一样的都是把不同来源的内容统一成 Document 结构。4.3 文档拆分控制 chunk 大小与重叠# 文件路径rag_demo.py第二部分文档拆分 from langchain.text_splitter import RecursiveCharacterTextSplitter def split_docs(docs, chunk_size500, chunk_overlap50): text_splitter RecursiveCharacterTextSplitter( chunk_sizechunk_size, chunk_overlapchunk_overlap, separators[\n\n, \n, 。, , , , ], length_functionlen, ) chunks text_splitter.split_documents(docs) return chunks这里重点解释separators参数。它的作用是指定拆分的优先级顺序。RecursiveCharacterTextSplitter会先尝试用第一个分隔符双换行拆分如果拆分后的块还是太长再尝试第二个分隔符单换行以此类推。我建议把中文标点。也加入分隔符列表这样句子就不会被硬生生截断更符合中文文档的语义完整性。4.4 向量化并写入 Chroma 向量库# 文件路径rag_demo.py第三部分向量化与存储 from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma # 指定持久化目录 PERSIST_DIR ./chroma_db def build_vectorstore(chunks): embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directoryPERSIST_DIR, ) return vectorstore这里有几个点需要说明OpenAIEmbeddings会把每个 chunk 转成一个向量数组默认模型是 text-embedding-3-small性价比高适合入门。Chroma.from_documents会一次性把文档写入本地向量库并指定持久化目录。第二次运行如果目录已存在会重复写入。实际项目中建议先判断目录是否存在避免重复入库。如果你想使用本地向量库 FAISS写法也很类似from langchain_community.vectorstores import FAISS vectorstore FAISS.from_documents( documentschunks, embeddingembeddings, )两者在后面的检索接口上基本一致可以根据需要切换。4.5 创建检索器# 文件路径rag_demo.py第四部分检索器 retriever vectorstore.as_retriever( search_typesimilarity, # 相似度检索 search_kwargs{k: 4} # 返回最相关的 4 个块 )search_type还可以设置为mmr这是最大边际相关性检索可以在相关性和多样性之间做平衡。如果一个问题可能涉及多个不同角度的内容mmr会比similarity更合适。4.6 组装 RAG 生成链路接下来就是最关键的组装环节。LangChain 0.3 版本推荐使用 LCELLangChain Expression Language来组装链路。# 文件路径rag_demo.py第五部分组装 RAG 链路 from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough def build_rag_chain(retriever): # 1. 定义 Prompt 模板 prompt ChatPromptTemplate.from_template( 你是一个企业知识库问答助手。请基于以下上下文内容回答用户问题。 上下文 {context} 用户问题 {question} 要求 1. 如果上下文中没有相关信息请明确回答“知识库中未找到相关内容”不要编造。 2. 使用中文回答回答要简洁准确。 ) # 2. 初始化大模型 llm ChatOpenAI(modelgpt-4o-mini, temperature0.1) # 3. 定义“格式化上下文文档”的函数 def format_docs(docs): return \n\n.join([doc.page_content for doc in docs]) # 4. 组装 LCEL 链路 rag_chain ( { context: retriever | format_docs, question: RunnablePassthrough(), } | prompt | llm | StrOutputParser() ) return rag_chain这条链路的执行逻辑可以这样理解用户输入一个question。retriever根据问题检索向量库得到相关的 docs。format_docs把 docs 拼接成一段文本作为 context。RunnablePassthrough()把用户的 question 原样传递。context 和 question 一起填入 prompt 模板。大模型生成回答StrOutputParser把输出解析成纯文本。4.7 完整运行代码把以上几段合并就得到完整的 RAG 演示脚本。为了方便你复制运行我合并成一份# 文件路径rag_demo.py import os from dotenv import load_dotenv from langchain_community.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import Chroma from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough load_dotenv() PERSIST_DIR ./chroma_db DOC_PATH ./docs/xxx公司员工手册.txt def main(): # 1. 加载文档 loader TextLoader(DOC_PATH, encodingutf-8) docs loader.load() # 2. 拆分文档 text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , ], ) chunks text_splitter.split_documents(docs) # 3. 向量化并入库生产环境建议先判断目录是否存在 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) if os.path.exists(PERSIST_DIR): vectorstore Chroma( embedding_functionembeddings, persist_directoryPERSIST_DIR, ) else: vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directoryPERSIST_DIR, ) # 4. 创建检索器 retriever vectorstore.as_retriever( search_typesimilarity, search_kwargs{k: 4}, ) # 5. 定义 Prompt prompt ChatPromptTemplate.from_template( 你是一个企业知识库问答助手。请基于以下上下文内容回答用户问题。 上下文 {context} 用户问题 {question} 要求 1. 如果上下文中没有相关信息请明确回答“知识库中未找到相关内容”不要编造。 2. 使用中文回答回答要简洁准确。 ) llm ChatOpenAI(modelgpt-4o-mini, temperature0.1) def format_docs(docs): return \n\n.join([doc.page_content for doc in docs]) # 6. 组装链路 rag_chain ( { context: retriever | format_docs, question: RunnablePassthrough(), } | prompt | llm | StrOutputParser() ) # 7. 问答循环 while True: question input(请输入问题输入 exit 退出) if question.strip().lower() exit: break result rag_chain.invoke(question) print(\n回答, result) print(- * 50) if __name__ __main__: main()运行方式python rag_demo.py首次运行会提示输入问题示例如下请输入问题输入 exit 退出员工的年假制度是什么 回答根据员工手册员工入职满一年后享有带薪年假具体天数根据工龄确定...注意第一次运行如果chroma_db目录不存在会先做文档向量化这一步会请求 Embedding 接口耗时取决于文档大小。5. 实战二用 LangChain Agent 构建智能代理RAG 只是一个被动问答的组件。接下来我们让模型升级为 Agent它能调用工具、自主决策比如查天气、做计算、读取数据库甚至调用搜索引擎。5.1 Agent 的核心组成一个标准的 LangChain Agent 由三部分组成工具ToolsAgent 可以调用的外部函数比如search、calculator、database_query。大模型LLM负责理解用户意图、选择工具、解析工具结果。循环LoopAgent 不是一次调用就结束它可能需要“调用工具 → 看结果 → 再决定下一步”地循环多次直到得到最终答案。使用tool装饰器可以将普通函数转换为 LangChain 工具。5.2 编写两个自定义工具# 文件路径agent_demo.py第一部分定义工具 from langchain_core.tools import tool import datetime tool def get_current_time(): 获取当前日期和时间当用户询问今天几号、现在几点时使用。 now datetime.datetime.now() return f当前时间是{now.strftime(%Y-%m-%d %H:%M:%S)} tool def calculate_expression(expression: str) - str: 计算数学表达式例如 12 * 8 100。注意只接受安全的四则运算和括号。 # 注意生产环境不要使用 eval这里仅做学习演示 try: result eval(expression) return f计算结果{result} except Exception as e: return f计算失败{str(e)}工具函数的docstring非常重要因为大模型是根据 docstring 来判断“什么时候该调用这个工具”的。docstring 写得不清晰Agent 就会在错误的时候调用错误工具。5.3 使用 create_tool_calling_agent 构建 AgentLangChain 0.3 推荐使用create_tool_calling_agent配合AgentExecutor来创建 Agent。# 文件路径agent_demo.py第二部分构建 Agent from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.prompts import ChatPromptTemplate def main(): # 1. 准备工具列表 tools [get_current_time, calculate_expression] # 2. 初始化大模型 llm ChatOpenAI(modelgpt-4o-mini, temperature0) # 3. Agent 专用的 Prompt prompt ChatPromptTemplate.from_messages( [ (system, 你是一个智能助手可以根据用户问题调用合适的工具。), (human, {input}), (placeholder, {agent_scratchpad}), ] ) # 4. 创建 Agent agent create_tool_calling_agent(llm, tools, prompt) # 5. 使用 AgentExecutor 执行 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 打印执行过程便于观察 Agent 的思考过程 max_iterations5, # 防止死循环 handle_parsing_errorsTrue, # 容错 ) # 6. 测试 while True: user_input input(请输入任务输入 exit 退出) if user_input.strip().lower() exit: break response agent_executor.invoke({input: user_input}) print(\n最终回答, response[output]) print(- * 50)5.4 运行与观察 Agent 的思考过程运行python agent_demo.py当我们输入“现在几点了帮我算一下 24 * 365 等于多少”时verboseTrue会打印出完整执行过程你就能看到 Agent 是如何先调用get_current_time再调用calculate_expression最后汇总答案的。这正是 Agent 和普通 LLM 调用的最大区别Agent 有“工具选择”和“结果反馈”的闭环过程。5.5 Agent 结合 RAGAgentic RAG 的简单形态当你把第 4 节的 RAG 链路也封装成一个工具时Agent 就同时具备了“知识问答”和“工具调用”的能力tool def knowledge_base_search(query: str) - str: 当用户询问公司制度、员工手册、产品文档等内部知识时使用此工具搜索知识库。 # 这里实际上调用 RAG 链路 return rag_chain.invoke(query)然后把这个工具加入tools列表。这样用户问“员工年假几天”模型会先检索知识库问“今天几号”模型会调用时间工具。这种组合就是目前企业落地 AI 助手最流行的形态之一。6. 常见问题与排查思路6.1 安装依赖后仍然报 ModuleNotFoundError问题现象常见原因解决思路No module named langchain_openai没有安装 langchain-openai 包执行 pip install langchain-openaiNo module named langchain_community没有安装 community 包执行 pip install langchain-community版本冲突导致 API 变化各包版本不兼容统一升级到同版本pip install -U langchain langchain-openai langchain-community6.2 向量库检索结果不相关这是 RAG 最常见的坑按照下面顺序排查检查文档拆分粒度chunk 是否过大或过小尝试调整chunk_size。检查 Embedding 模型中文场景下OpenAI 的 text-embedding-3-small 效果尚可但如果知识库是垂直领域建议后续测试中文专用的 Embedding 模型。检查文档内容质量PDF 扫描件没有 OCR 处理加载进来就是乱码检索必然失败。增加重排在检索后加 Rerank 模型。查看指标计算召回率和命中率确定问题出在检索还是生成阶段。6.3 Agent 不调用工具或一直调用同一个工具问题现象常见原因解决思路模型自己编造答案而不调用工具Prompt 没有明确说明“必须使用工具”在 system prompt 中增加“如果需要查询实时信息必须调用工具”工具调用后循环不停止工具返回结果不清晰模型无法判断精简工具返回值并使用 max_iterations 限制次数模型调用了不存在的工具工具描述不准确或版本不匹配检查工具 name 和 docstring不要出现歧义6.4 API 调用超时或限流OpenAI 等接口不稳定或本地网络环境较差时可以增加超时和重试配置llm ChatOpenAI( modelgpt-4o-mini, temperature0, request_timeout60, max_retries3, )如果你的网络环境无法直接访问 OpenAI也可以改用本地 Ollama 模型代码需要调整如下from langchain_ollama import ChatOllama, OllamaEmbeddings llm ChatOllama(modelqwen2.5:7b, temperature0) embeddings OllamaEmbeddings(modelnomic-embed-text)这里需要先安装 Ollama并提前下载好对应模型。本地模型的好处是数据不出内网适合私有化部署场景。7. 最佳实践与工程建议7.1 拆分策略要结合文档结构不要把所有文档都套用一个chunk_size。产品手册、合同、规章制度它们的语义单元完全不同。建议在拆分之前先分析文档结构在章节标题处增加分隔再按结构拆分。不要偷懒。7.2 构建知识库时一定要做数据清洗很多团队把原始文件直接扔给加载器结果知识库越做越乱。去除页眉页脚、页码。去除表格中的重复表头。PDF 扫描件要做 OCR。统一编码为 UTF-8。数据清洗是 RAG 项目里最枯燥但最值得投入的部分。脏数据进库检索质量一定差后面做再多优化都很难挽救。7.3 知识库指标要量化不要“感觉回答还行”。搭建知识库时建议准备一份标准测试集包括 100-200 条问题标注正确答案对应的文档片段。每次改动拆分策略、索引方式或重排模型后跑一遍测试集对比召回率和命中率。否则你完全不知道自己改动是变好了还是变坏了。7.4 Agent 工具要最小化、职责单一一个工具只做一件事。如果你写了一个process_all函数内部又调数据库又调 API大模型很难判断什么时候该调用它。工具命名要直接docstring 要写清使用场景和参数含义。7.5 生产环境必须关注的安全问题不要在代码中硬编码 API Key使用环境变量或密钥管理服务。对用户输入做长度限制和内容过滤防止 Prompt 注入。Agent 执行的工具函数要严格校验输入。比如上面的calculate_expression使用了eval这在生产环境是绝对不安全的建议用安全表达式解析库替代。涉及数据库、删除、修改等操作Agent 要受限执行最小权限原则并且所有操作留日志。7.6 及时跟进版本变动LangChain 的 API 变化速度很快0.2 到 0.3 都有不少破坏性变更。建议你在项目的requirements.txt中固定版本例如langchain0.3.7 langchain-openai0.2.5 langchain-community0.3.7固定版本后团队协作和线上部署才不会出现“本地能跑服务器报错”的问题。当然具体版本号需要你安装时确认一下不要盲目套用。8. 从 RAG 到 Agent 的下一步学习路线如果你已经跑通了本文的代码说明你已经有能力独立基于 LangChain 构建一个 AI 应用了。接下来可以按下面的顺序继续深入深入学习 LangGraph掌握 State、Node、Edge 的概念尝试用 LangGraph 重写本文的 Agent观察两者编排方式的差异。完善 RAG 项目增加重排模型、关键词混合检索、多路召回把知识库质量指标做起来。增加对话记忆在 RAG 问答中加入历史对话管理让多轮问答有连贯性。尝试多模态 RAG除了文本加入图片、表格的解析与检索让知识库覆盖更多类型的数据。阅读开源项目源码例如 LangChain 官方案例、Dify 的 RAG 模块看成熟项目是如何组织代码的。最后想说的是AI Agent 和 RAG 的核心其实不是某个框架而是你如何拆解问题、设计流程。框架会变这个能力不会。希望这篇文章能帮你把基础打牢少走一些弯路。如果文中的代码或思路对你有用建议收藏备用也欢迎在评论区聊聊你在实践中遇到的坑。