1. 先搞清楚 LangChain、RAG 和 Agent 到底能帮你解决什么实际问题
如果你正在看大模型应用开发,大概率绕不开 LangChain、RAG 和 Agent 这几个词。但很多人一上来就被各种框架、概念和“企业级”教程搞晕了,不知道从哪里下手。
我建议先抛开那些复杂的术语,直接看核心:LangChain 是一个帮你连接大模型和外部工具、数据的框架;RAG 是让大模型能“查阅资料”来回答问题的技术;Agent 是让大模型能自主调用工具完成复杂任务的“智能体”。这三者组合起来,解决的就是“如何让通用大模型变成你业务里的专家”这个问题。
比如,你想做一个能回答公司内部知识库问题的客服机器人,或者一个能自动分析数据并生成报告的助手。纯靠大模型,它可能不知道你公司的内部规定,也无法执行“查数据库”“发邮件”这类动作。这时候,就需要 RAG 给它“喂”资料,用 Agent 给它“装”上手脚,而 LangChain 就是组装这些部件的工具箱和说明书。
所以,这个主题适合两类人:一是想快速把大模型能力接入自己业务的应用开发者;二是想深入理解现代 AI 应用架构的技术学习者。最值得关注的点不是某个框架多厉害,而是如何把“模型调用”、“知识检索”、“工具执行”这三件事稳定、高效地串联起来。下面我就按实际落地的顺序,带你拆解一遍。
2. 环境与工具准备:别在第一步就卡住
动手之前,先把环境理清楚。很多教程一上来就pip install langchain,然后报一堆版本冲突错误,信心直接减半。
我的建议是,先建立一个干净的、可复现的 Python 环境。用 Conda 或 venv 都行,目的是隔离项目依赖。Python 版本建议 3.9 或 3.10,这是目前大多数 AI 库兼容性最好的版本。
接下来是核心依赖。LangChain 是一个“元框架”,它本身不提供大模型,你需要额外安装模型提供商(如 OpenAI、智谱、月之暗面)的 SDK,或者本地模型运行库(如 Ollama、vLLM)。
# 1. 创建并激活虚拟环境(以 conda 为例) conda create -n langchain-demo python=3.10 conda activate langchain-demo # 2. 安装 LangChain 核心包(注意:通常安装 `langchain-community` 等子包) pip install langchain langchain-community langchain-core # 3. 安装你选择的大模型接口包 # 如果你用 OpenAI 的 API pip install openai # 如果你用智谱 AI 的 API pip install zhipuai # 如果你要运行本地模型,比如用 Ollama # 首先去 Ollama 官网下载并安装 Ollama,然后拉取模型 # ollama pull qwen2.5:7b # 再安装 LangChain 的 Ollama 集成包 pip install langchain-ollama除了这些,根据你要做的任务,可能还需要:
- 向量数据库:用于 RAG 存储和检索知识。轻量级起步可以用
ChromaDB(pip install chromadb) 或FAISS。 - 文档加载器:用来读取你的知识文件(PDF、Word、TXT)。
pip install pypdf python-docx等。 - Embedding 模型:把文本转换成向量。可以用 OpenAI 的
text-embedding-3-small,或者本地模型如BAAI/bge-small-zh-v1.5,需要安装sentence-transformers。
关键一步:验证基础环境。不要急着写复杂应用,先确保你能成功调用一次大模型。
# 一个极简的验证脚本 (以 OpenAI API 为例,你需要有自己的 API Key) import os from langchain_openai import ChatOpenAI os.environ["OPENAI_API_KEY"] = "你的-api-key" # 务必替换,并从环境变量管理更安全 llm = ChatOpenAI(model="gpt-3.5-turbo") response = llm.invoke("你好,请用一句话介绍你自己。") print(response.content)如果这一步能成功输出,说明你的网络、API 密钥和基础库都没问题。如果报错,优先检查:1) API Key 是否正确且有效;2) 网络是否能访问对应服务;3) 库版本是否兼容(有时需要指定稍旧版本)。
3. 从零构建一个最简单的 RAG 流程:理解核心链条
RAG 听起来高大上,但核心流程就四步:加载文档 -> 切分文本 -> 向量化存储 -> 检索增强生成。我们用一个最简单的本地知识库问答来走通它。
假设你有一个company_rules.txt的文本文件,里面写着公司的请假规定。目标是让大模型能基于这个文件回答问题。
3.1 第一步:文档加载与处理
from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # 1. 加载文档 loader = TextLoader("./company_rules.txt") documents = loader.load() # 2. 切分文本(这是关键,直接影响检索效果) text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每个文本块的最大字符数 chunk_overlap=50, # 块之间的重叠字符,避免上下文断裂 separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] # 按此优先级分割 ) splits = text_splitter.split_documents(documents) print(f"原始文档被切分为 {len(splits)} 个片段。")为什么 chunk_size 和 overlap 重要?如果 chunk 太大,检索出的内容可能包含无关信息,干扰模型;如果太小,可能丢失关键上下文。overlap 能保证关键信息(如一个定义跨越了两段)不被切断。通常从 500-1000 字符开始调整。
3.2 第二步:向量化与存储
from langchain_community.embeddings import OllamaEmbeddings # 使用本地模型生成向量 from langchain_community.vectorstores import Chroma # 3. 选择 Embedding 模型(这里用本地 Ollama 模型,无需 API Key) embeddings = OllamaEmbeddings(model="nomic-embed-text") # 4. 创建向量数据库并存储 vectorstore = Chroma.from_documents( documents=splits, embedding=embeddings, persist_directory="./chroma_db" # 向量数据库保存到本地目录 ) vectorstore.persist() # 持久化保存这里选择了 Chroma 作为向量数据库,它将文本片段和对应的向量存储在本地./chroma_db目录。下次启动可以直接加载,无需重新计算向量。
3.3 第三步:检索与生成
from langchain.chains import RetrievalQA from langchain_community.llms import Ollama # 使用本地 LLM # 5. 加载本地大模型(例如 Qwen2.5) llm = Ollama(model="qwen2.5:7b") # 6. 创建检索链 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", # 最简单的方式,将所有检索到的上下文塞给模型 retriever=vectorstore.as_retriever(search_kwargs={"k": 3}), # 检索最相关的3个片段 return_source_documents=True # 返回参考来源,便于调试 ) # 7. 提问 question = "请问公司年假有多少天?" result = qa_chain.invoke({"query": question}) print(f"答案:{result['result']}") print(f"参考来源:{result['source_documents']}")这个链条的工作流程是:你的问题 -> 被转换为向量 -> 在向量库中搜索最相似的文本片段(k=3)-> 将这些片段作为“参考资料”和问题一起提交给大模型 -> 模型生成最终答案。
第一次跑通后,务必验证:答案是否准确?检索到的来源片段是否真的相关?如果答案胡编乱造,问题可能出在:1) 检索的 k 值太小或太大;2) 文本切分不合理,导致检索不到关键信息;3) 本地模型能力不足,无法理解上下文。
4. 深入 Agent 开发:让模型学会“使用工具”
RAG 解决了“知识”问题,Agent 要解决“行动”问题。一个简单的 Agent 由三部分组成:大脑(LLM)、工具(Tools)、执行引擎(Agent Executor)。
假设我们要做一个能查询天气和计算数学的智能体。
4.1 第一步:定义工具
工具本质上是一个能被模型调用的函数,需要清晰的描述供模型理解。
from langchain.agents import tool import requests import math @tool def get_weather(city: str) -> str: """根据城市名称查询实时天气。输入应为城市名,如‘北京’。””” # 这里使用一个模拟的天气API,真实场景替换为真实API # 注意:避免使用任何需要特殊网络配置的服务 try: # 模拟返回 return f"{city}的天气是晴天,25摄氏度。" except Exception as e: return f"查询{city}天气失败:{e}" @tool def calculate(expression: str) -> str: """计算一个数学表达式的值。输入应为字符串表达式,如‘3 + 5 * 2’。””” try: # 使用 eval 有安全风险,仅作演示。生产环境应用安全计算库。 result = eval(expression, {"__builtins__": None}, {"math": math}) return f"{expression} = {result}" except Exception as e: return f"计算表达式‘{expression}’时出错:{e}"工具定义的关键:函数文档字符串"""..."""非常重要!模型就是靠这个描述来决定什么时候、如何调用这个工具。描述要准确、简洁,说明输入格式和功能。
4.2 第二步:创建 Agent 并运行
from langchain.agents import create_react_agent, AgentExecutor from langchain import hub from langchain_community.llms import Ollama # 加载模型 llm = Ollama(model="qwen2.5:7b") # 获取一个预设的提示词模板(包含ReAct框架的思考-行动-观察循环) prompt = hub.pull("hwchase17/react") # 创建 Agent tools = [get_weather, calculate] agent = create_react_agent(llm, tools, prompt) # 创建执行器 agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, # 开启详细日志,可以看到模型的“思考过程” handle_parsing_errors=True # 处理模型输出解析错误 ) # 运行 Agent result = agent_executor.invoke({ "input": "先计算一下 (15 + 7) * 3 等于多少,然后告诉我北京的天气怎么样。" }) print(result["output"])当verbose=True时,你会在控制台看到类似下面的输出,这是理解 Agent 工作原理的关键:
> Entering new AgentExecutor chain... 我需要按顺序完成两个任务:先计算数学表达式,再查询天气。 我应该使用计算工具。 Action: calculate Action Input: (15 + 7) * 3 Observation: (15 + 7) * 3 = 66 现在我需要查询北京的天气。 Action: get_weather Action Input: 北京 Observation: 北京的天气是晴天,25摄氏度。 我有最终答案了。 > Finished chain. 最终答案:计算结果是66,北京的天气是晴天,25摄氏度。这就是 Agent 的核心:模型会“思考”(Chain of Thought)需要做什么,选择工具(Action),获取结果(Observation),然后决定下一步,直到完成任务或达到步数限制。
5. 项目实战:构建一个企业级问答助手的关键考量
把 RAG 和 Agent 组合起来,就能构建更强大的应用。比如一个内部问答助手,既能查知识库(RAG),又能调用内部 API 帮你订会议室(Agent)。
5.1 架构设计要点
不要一上来就写代码,先画个简单的数据流图:
- 用户提问-> 2.意图识别(是查知识还是执行操作?)-> 3A.知识类:走 RAG 流程 -> 4A.生成答案。
- -> 3B.操作类:走 Agent 流程,选择工具 -> 4B.执行并返回结果。
这个“路由”逻辑,可以用一个简单的分类器(Prompt 判断),或者用 LangChain 的RouterChain来实现。
5.2 性能与稳定性优化
当项目从 Demo 走向“企业级”,以下问题必须考虑:
- 检索优化:
- 多路召回:不要只依赖向量检索。可以结合关键词检索(如 BM25),提高召回率。
- 重排序:向量检索返回前 10 个结果,再用一个更精细的模型(或规则)对这 10 个结果重排序,选出最相关的 3 个给 LLM。
- 元数据过滤:给文档片段加标签(如“部门=财务”、“年份=2023”),检索时先过滤部门,再查相似度。
- Agent 稳定性:
- 工具描述:工具的描述必须极度精准,避免模型误解。输入/输出格式要明确。
- 错误处理:在
AgentExecutor中设置max_iterations(最大执行步数,防止死循环),并做好工具调用异常的捕获和反馈。 - 验证输出:对于关键操作(如发邮件、修改数据),可以设计“确认”步骤,让 Agent 先输出计划,用户确认后再执行。
- 生产化部署:
- 异步处理:对于耗时的 RAG 检索或工具调用,使用异步框架(如 FastAPI +
asyncio)避免阻塞。 - 缓存:对常见的查询结果进行缓存,特别是 Embedding 和 LLM 的响应,能极大降低成本、提升速度。
- 日志与监控:记录每一次用户查询、检索到的内容、模型回复、工具调用记录。这是排查问题和优化效果的生命线。
- 异步处理:对于耗时的 RAG 检索或工具调用,使用异步框架(如 FastAPI +
5.3 一个结合 RAG 和 Agent 的简化示例
from langchain.agents import AgentExecutor, create_react_agent from langchain import hub from langchain_community.vectorstores import Chroma from langchain_community.embeddings import OllamaEmbeddings from langchain_community.llms import Ollama from langchain.chains import RetrievalQA # 初始化组件 llm = Ollama(model="qwen2.5:7b") embeddings = OllamaEmbeddings(model="nomic-embed-text") vectorstore = Chroma(persist_directory="./chroma_db", embedding_function=embeddings) rag_chain = RetrievalQA.from_chain_type(llm=llm, retriever=vectorstore.as_retriever()) # 定义工具:RAG查询也作为一个工具 @tool def query_company_knowledge(question: str) -> str: """查询公司内部知识库。输入是一个关于公司政策、产品、流程的问题。””” return rag_chain.invoke({"query": question})["result"] # 假设还有其他工具,如 book_meeting_room tools = [query_company_knowledge, book_meeting_room] # book_meeting_room 需要你自行实现 # 创建智能体 prompt = hub.pull("hwchase17/react") agent = create_react_agent(llm, tools, prompt) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True) # 运行:智能体会自己判断该用知识库工具还是预订工具 result = agent_executor.invoke({ "input": "我们公司今年的年假政策有什么变化?另外,帮我预订明天下午2点的大会议室。" })6. 常见问题排查与进阶学习方向
6.1 踩坑记录:你可能会遇到这些问题
- LangChain 调用速度慢:
- 网络延迟:如果使用云端 API,网络是首要因素。考虑使用国内节点或本地模型。
- 工具调用开销:Agent 每步思考都要调用一次 LLM,步数越多越慢。优化工具描述,让模型更快做对决策。
- 向量检索慢:知识库文档太多。考虑使用更高效的向量索引(如 HNSW),或引入前置过滤。
- RAG 答案不准,胡编乱造:
- 检索不到:检查文本切分(chunk)是否合理。尝试调整
chunk_size和chunk_overlap。检查 Embedding 模型是否适合你的语种(中文问题用中文 Embedding 模型)。 - 检索到但模型忽略:在 Prompt 中加强指令,如“请严格依据提供的上下文回答,如果上下文没有相关信息,请直接说‘不知道’。”。
- 模型能力不足:如果上下文很长很复杂,小模型可能无法有效理解。尝试换更强模型,或使用
map_reduce、refine等更复杂的链类型来处理长上下文。
- 检索不到:检查文本切分(chunk)是否合理。尝试调整
- Agent 死循环或调用错误工具:
- 工具描述不清:重新打磨工具的函数文档,确保无歧义。
- Prompt 引导不够:在给 Agent 的系统提示词中,明确其角色和约束,例如“你是一个谨慎的助手,在执行修改类操作前必须向我确认”。
- 设置最大迭代次数:
AgentExecutor(max_iterations=5)。
6.2 如何选择 LangChain、LangGraph 和 Dify 等框架?
- LangChain:高度灵活的程序化框架。你需要写代码,但能控制每一个细节。适合需要深度定制、复杂逻辑、与现有系统紧密集成的项目。学习曲线较陡。
- LangGraph:基于 LangChain,用于构建有状态、多步骤的复杂工作流。如果你的 Agent 需要循环、分支、并行执行(像一个流程图),LangGraph 更合适。可以理解为 LangChain 的进阶版。
- Dify、FastGPT 等:低代码/无代码平台。通过图形界面配置工作流、知识库和 Agent。优势是开发速度快,适合快速原型、简单应用或非技术背景者。劣势是灵活性受限,深度定制困难。
选择建议:如果你是开发者,想真正掌握技术并构建复杂应用,从LangChain 开始学起。理解了底层原理,再用 Dify 这类平台会知其所以然。如果只是快速实现一个简单需求,Dify 是更快的选择。
6.3 持续学习路线
- 夯实基础:彻底吃透 LangChain 的LCEL(LangChain Expression Language)来声明式地组合链,这是现代 LangChain 的核心。
- 深入原理:学习RAG 的进阶技术,如 HyDE(生成假设文档再检索)、Self-RAG、RAG-Fusion(多查询检索融合)。
- 掌握高级 Agent 模式:研究ReAct、Plan-and-Execute、Multi-Agent 协作等模式。了解Tool Calling与Function Calling的异同(前者是 LangChain 抽象,后者是 OpenAI 等模型的原生能力,现在通常用后者)。
- 关注工程化:学习如何用FastAPI封装服务,用Celery或Dramatiq处理异步任务,用PostgreSQL或Redis管理会话和缓存。
- 跟进生态:关注LangSmith(LangChain 官方的调试、监控平台)、LangGraph等官方工具的发展。
最后一点建议:不要被“企业级”这个词吓到,也不要追求一开始就做出完美的系统。从把一个 PDF 问答做通开始,再到加入一个计算器工具,逐步迭代。过程中遇到的每一个报错和不如预期的结果,都是最宝贵的学习材料。先跑起来,再跑得好,最后跑得稳。