LangChain实战:从RAG到Agent的完整开发指南与避坑经验 📅 2026/7/21 12:40:38 1. 先搞清楚 LangChain、Agent 和 RAG 到底能帮你解决什么如果你刚接触大模型应用开发看到 LangChain、Agent、RAG 这些词第一反应可能是“概念好多从哪开始”。别急着去背定义先想清楚它们各自解决的核心问题。LangChain不是一个具体的 AI 模型而是一个框架。它的核心价值是把调用大模型、处理数据、管理对话历史、连接外部工具这些零散的步骤变成一条清晰、可复用的“链”Chain。简单说它让你不用从零开始写一堆胶水代码就能快速搭建一个能理解上下文、能查资料、能执行任务的应用。RAG检索增强生成解决的是大模型的“知识截止”和“胡说八道”问题。大模型训练数据有截止日期不知道最新信息也记不住你公司的内部文档。RAG 的思路是用户提问时先从你的知识库比如一堆 PDF、网页里找到最相关的几段内容然后把“问题”和“找到的资料”一起喂给大模型让它基于这些资料生成答案。这样答案既准确又有依据。Agent智能体是让大模型有了“手和脚”。一个普通的问答链你问它答流程就结束了。但 Agent 可以理解你的复杂目标比如“帮我分析一下上个月的销售数据做个总结报告”然后自己决定先调用哪个工具查数据库、再调用哪个工具做图表、最后调用哪个工具生成文本。它像一个有自主规划能力的“大脑”能串联起多个步骤。所以一个典型的实战项目流程是用LangChain搭建框架用RAG给模型注入你的专属知识再用Agent赋予模型调用工具、自主决策的能力。最终做出一个能理解你业务、能处理复杂任务的应用。2. 环境准备别在依赖版本上踩第一个坑动手之前环境是最大的拦路虎。很多人卡在第一步就是因为 Python 版本、包冲突。我建议用一个干净的虚拟环境开始。2.1 创建并激活虚拟环境这是避免未来包冲突的最佳实践。在命令行中执行# 创建名为 langchain-env 的虚拟环境 python -m venv langchain-env # 激活环境 (Windows) langchain-env\Scripts\activate # 激活环境 (macOS/Linux) source langchain-env/bin/activate激活后命令行提示符前会出现(langchain-env)表示你正在这个独立环境中操作。2.2 安装核心依赖现在安装 LangChain 和 OpenAI或其他大模型的包。注意LangChain 是一个“元框架”它本身不提供模型能力需要连接具体的模型提供商。pip install langchain langchain-openai这里安装的是langchain-openai这个官方集成包它包含了调用 OpenAI API 的便捷方式。如果你打算用其他模型比如通义千问、DeepSeek需要安装对应的集成包如langchain-qianwen。2.3 准备你的 API Key你需要一个能调用大模型的 API Key。以 OpenAI 为例其他厂商类似去官网注册获取。千万不要把 Key 硬编码在代码里然后上传到公开仓库。最安全的方式是设置为环境变量。在命令行中临时设置重启终端会失效# Windows (cmd) set OPENAI_API_KEY你的sk-xxx密钥 # Windows (PowerShell) $env:OPENAI_API_KEY你的sk-xxx密钥 # macOS/Linux export OPENAI_API_KEY你的sk-xxx密钥对于长期项目我建议使用.env文件配合python-dotenv库来管理。pip install python-dotenv在项目根目录创建.env文件内容为OPENAI_API_KEY你的sk-xxx密钥然后在代码开头加载from dotenv import load_dotenv load_dotenv() # 这会读取 .env 文件中的变量到环境变量3. 从零到一构建你的第一个 RAG 问答链我们先不碰复杂的 Agent从最核心的 RAG 流程走一遍。目标是让模型能回答关于你提供的文档内容。3.1 准备知识库文档在项目目录下创建一个docs文件夹放一些测试用的文本文件.txt或 PDF。例如创建一个company_intro.txt里面写一段你虚构的公司介绍。3.2 代码实现加载、切分、向量化、检索、生成创建一个simple_rag.py文件跟着以下步骤写代码第一步导入必要的模块from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA import os # 如果你用了 .env 文件确保已执行 load_dotenv()第二步加载和切分文档大模型有上下文长度限制不能把整本书塞进去。我们需要把长文档切成有重叠的小块chunks这样检索时才能精准定位。# 加载文档 loader TextLoader(./docs/company_intro.txt) documents loader.load() # 初始化文本分割器 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个块大约500字符 chunk_overlap50 # 块之间重叠50字符避免语义被切断 ) docs text_splitter.split_documents(documents) print(f原始文档被切分成 {len(docs)} 个小块。)第三步向量化并存入向量数据库这是 RAG 的“检索”核心。我们把文本块转换成数学向量Embedding存入一个能快速进行相似度搜索的数据库。# 初始化嵌入模型用于生成向量 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) # 创建向量数据库这里用轻量级的 Chroma数据存在本地 vectorstore Chroma.from_documents( documentsdocs, embeddingembeddings, persist_directory./chroma_db # 向量数据库存储路径 ) # 持久化到磁盘下次可以直接加载无需重新向量化 vectorstore.persist()第四步创建检索器与问答链检索器负责从向量库中找到最相关的文本块。问答链则将“问题相关文本”组合发送给大模型生成最终答案。# 从向量库创建检索器 retriever vectorstore.as_retriever(search_kwargs{k: 3}) # 检索最相关的3个块 # 初始化大语言模型 llm ChatOpenAI(modelgpt-3.5-turbo) # 创建检索式问答链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 最常用的类型将检索到的所有内容“塞”进提示词 retrieverretriever, return_source_documentsTrue # 返回参考来源便于调试 )第五步提问并查看结果# 提问 query “我们公司的主要业务是什么” result qa_chain.invoke({query: query}) print(问题, query) print(答案, result[result]) print(\n--- 参考来源 ---) for i, doc in enumerate(result[source_documents]): print(f[来源{i1}]: {doc.page_content[:200]}...) # 打印前200字符运行这个脚本你应该能看到模型基于你的company_intro.txt生成的答案以及它参考了哪几个文本块。这就完成了一个最基础的 RAG 流程。3.3 关键参数与避坑点chunk_size 和 chunk_overlap这是 RAG 效果的“命门”。chunk_size太大检索不精准太小语义不完整。chunk_overlap能防止关键信息被切碎。对于普通文本500-1000 的chunk_size和 50-100 的overlap是不错的起点。Embedding 模型text-embedding-3-small性价比高。如果对精度要求极高可以考虑text-embedding-3-large但向量维度会变大存储和检索成本增加。检索数量 (k)search_kwargs{“k”: 3}表示取最相关的 3 个块。k 太小可能信息不足k 太大可能引入噪声并增加 token 消耗。通常 3-5 是个安全范围。chain_type“stuff”这是最简单的方式把所有检索到的内容拼接后一次性发给模型。如果检索内容总长度可能超过模型上下文限制需要考虑“map_reduce”或“refine”等更复杂但能处理长文档的类型。4. 升级为智能体 (Agent)让模型学会使用工具现在你的模型能“读”你的文档了。接下来我们让它不仅能“读”还能“做”——比如查完资料后再帮你写封邮件。4.1 理解 Agent 的核心组件一个 Agent 通常由三部分组成LLM做决策的“大脑”。Tools它能调用的“手和脚”比如搜索、计算、查数据库、调用 API。AgentExecutor运行智能体的“发动机”负责管理工具调用、解析 LLM 输出、处理错误等。4.2 实战创建一个能查资料并写总结的智能体假设我们有一个需求用户输入一个技术名词比如“RAG”智能体先通过 RAG 从我们知识库查资料然后基于查到的资料用另一个工具生成一份简单的介绍邮件。第一步定义两个工具知识库查询工具复用之前的 RAG 链。邮件撰写工具一个模拟的函数。from langchain.agents import Tool, AgentExecutor, create_react_agent from langchain import hub # 用于拉取预设的提示词 # 工具1知识库查询工具 rag_tool Tool( nameCompany_Knowledge_Base, funcqa_chain.invoke, # 直接使用之前建好的 qa_chain description当需要查询关于公司业务、产品、政策等内部信息时使用此工具。输入应是一个明确的问题。 ) # 工具2邮件撰写工具模拟 def write_email(subject, body): 一个模拟的邮件撰写函数。在实际项目中这里会调用真正的邮件API。 email_template f 主题{subject} 正文 {body} 此邮件由AI助手生成。 return email_template email_tool Tool( nameEmail_Drafting, funclambda inputs: write_email(inputs[“subject”], inputs[“body”]), description根据提供的主题和正文草稿生成一封格式完整的邮件。输入应该是一个包含‘subject’和‘body’键的字典。 )第二步创建智能体并运行我们使用 ReAct 框架这是一种让模型“思考-行动-观察”的经典 Agent 模式。# 拉取一个预设好的 ReAct 提示词模板 prompt hub.pull(hwchase17/react) # 创建智能体 agent create_react_agent(llm, [rag_tool, email_tool], prompt) # 创建执行器 agent_executor AgentExecutor(agentagent, tools[rag_tool, email_tool], verboseTrue, handle_parsing_errorsTrue) # 给智能体一个复杂任务 result agent_executor.invoke({ “input”: “请先查阅知识库了解我们公司的主打产品是什么然后以此为内容起草一封向客户介绍该产品的邮件主题设为‘新产品介绍’。 }) print(result[“output”])运行这段代码并观察verboseTrue模式下控制台的输出。你会看到智能体类似这样的思考过程Thought:我需要先查公司产品信息。Action:调用Company_Knowledge_Base工具输入“公司的主打产品是什么”。Observation:工具返回产品信息。Thought:现在我有了产品信息可以起草邮件了。Action:调用Email_Drafting工具输入主题和正文。...最终完成。4.3 Agent 开发中的关键经验工具描述 (description) 至关重要这是 LLM 决定是否调用、如何调用工具的主要依据。描述要清晰、具体说明工具的用途和输入格式。处理解析错误handle_parsing_errorsTrue这个参数很重要因为 LLM 的输出可能偶尔不符合工具调用的格式这个参数能防止整个流程因小错误而崩溃。控制成本与时长Agent 可能会陷入“思考-行动”循环。通过设置max_iterations和max_execution_time参数来限制执行时间避免无限循环消耗 API 费用。从简单开始先用 1-2 个工具测试智能体的决策逻辑是否正常再逐步增加工具复杂度。5. 项目实战深化处理真实场景中的挑战把 Demo 跑通只是第一步。要投入实际使用以下几个问题是绕不开的。5.1 上下文过长与 LangChain 的应对策略当你的知识库文档非常多、非常长时会面临两个问题检索阶段海量向量搜索慢。生成阶段检索出的多个相关块加起来长度可能超出模型上下文窗口。应对策略索引优化使用专业的向量数据库如 Pinecone, Weaviate它们支持高效的近似最近邻搜索比本地 Chroma 更适合大规模数据。分级检索先用一个快速的、粗粒度的检索器如基于关键词缩小范围再用精确的向量检索器在缩小后的集合里查找。Chain Type 选择“map_reduce”: 将每个检索到的文档块单独发送给 LLM 生成摘要Map再将所有摘要组合起来生成最终答案Reduce。适合处理大量文档。“refine”: 迭代处理文档块用后一个块的答案去 refine 前一个块的答案。通常质量更高但调用 LLM 次数多速度慢。“stuff”: 就是我们之前用的简单直接但受限于上下文长度。5.2 RAG 效果优化重排序 (Re-ranking)向量检索找到的 Top-K 个块是按“向量相似度”排名的。但“语义相似”不一定等于“最相关”。重排序技术使用一个更精细的通常也更耗资源的模型对初步检索结果进行二次排序把最可能包含答案的块排到最前面。# 示例使用 Cohere 的重排序模型需要 Cohere API Key from langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import CohereRerank compressor CohereRerank(cohere_api_keyos.getenv(“COHERE_API_KEY”), top_n3) compression_retriever ContextualCompressionRetriever( base_compressorcompressor, base_retrievervectorstore.as_retriever(search_kwargs{“k”: 10}) # 先取10个 ) # 然后将 compression_retriever 用于 qa_chain重排序能显著提升答案质量尤其是对于复杂问题但会增加延迟和成本。它属于“优化”步骤建议在基础 RAG 流程稳定后再引入。5.3 Agent 的复杂编排与 LangGraph当你的智能体需要处理多步骤、有状态、带循环或分支判断的复杂工作流时基础的AgentExecutor可能不够直观。这就是LangGraph的用武之地。你可以把 LangGraph 理解为一个为 LangChain 设计的可视化工作流编排器。它用“图”的概念来定义节点步骤和边流转条件非常适合构建复杂的 Agent 逻辑。一个简单对比LangChain Agent适合线性的“思考-行动”序列。LangGraph适合“先做A根据结果决定走B还是C然后循环直到条件满足”这类有状态、带分支或循环的流程。对于大多数入门和中级项目基础的 LangChain Agent 足够使用。当你需要清晰管理复杂流程状态时再考虑 LangGraph。6. 部署与持续迭代的考量本地开发完成想要分享或投入使用你需要考虑部署。6.1 模型选择云端 API 与本地部署云端 API (如 OpenAI, Anthropic)上手最快无需担心硬件模型能力强且稳定。但会产生持续费用且有数据出境合规风险对于敏感数据。本地/私有化部署 (如 Ollama 跑 Llama, Qwen)数据最安全长期成本可能更低。但需要较强的 GPU 硬件且开源模型的综合能力通常弱于顶级闭源模型需要更多调优。建议原型验证和早期开发用云端 API快速验证想法。待流程跑通、效果确认后如果对数据和成本有要求再评估本地化部署。6.2 应用封装从脚本到服务一个 Python 脚本只能你自己用。要给别人用需要封装成服务。Web API (FastAPI/Flask)最通用的方式。将你的 RAG 链或 Agent 封装成 HTTP 接口。前端网页、移动 App、其他系统都能调用。from fastapi import FastAPI app FastAPI() app.post(“/ask”) async def ask_question(query: str): result qa_chain.invoke({“query”: query}) return {“answer”: result[“result”]}聊天界面 (Gradio/Streamlit)最快的演示和轻量级使用方式。几行代码就能生成一个带界面的 Web 应用适合内部工具或 demo 展示。6.3 监控与日志一旦服务上线必须要有监控。记录每一次问答保存用户问题、检索到的源文档、模型答案、token 消耗、响应时间。这是优化和排查问题的唯一依据。监控成本特别是使用按 token 计费的 API 时设置用量告警。评估效果定期抽样检查答案质量可以结合人工评估或设计一些自动化评估指标如答案与源文档的相关性。6.4 常见故障排查清单当你的应用出问题时按这个顺序查API 密钥与网络Key 是否过期、是否设置正确网络是否能通输入数据用户的问题是否为空格式是否正确知识库文档是否成功加载和向量化检查chroma_db目录是否有文件检索阶段向量检索是否返回了结果返回的源文档和问题相关吗如果不相关检查 Embedding 模型和 chunk 大小。生成阶段LLM 是否收到了正确的提示词包含问题和检索内容可以打印出最终发送给 LLM 的提示词来检查。Agent 决策如果 Agent 不调用工具检查工具描述是否清晰。如果调用错误工具检查工具描述的区分度。我个人更建议在项目初期就把日志系统做简单点但一定要有。把关键步骤的输入输出记录下来绝大多数问题都能通过日志快速定位。不要把时间浪费在反复“猜”为什么模型没给出预期结果上。