ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

LangChain 1.3实战:从RAG到LangGraph Agent开发全指南

LangChain 1.3实战:从RAG到LangGraph Agent开发全指南 1. 为什么 LangChain 1.3 值得重新学一遍如果你最近搜过 LangChain 的资料大概率会有一个感觉网上教程要么停留在 0.1/0.2 版本要么直接跳到 LangGraph中间断层非常严重。这个断层不是错觉而是 LangChain 在过去两年里完成了一次底层重构。0.x 时代的Chain和Agent设计到了 1.x 已经被大幅简化以前需要十几个依赖包才能跑通的 RAG 链路现在只需要一条pip install langchain加几个核心模块而 Agent 的编排逻辑则被完整移交给了 LangGraph。也就是说你现在从旧教程学到的很多 API很可能在新版本里已经废弃了。这也是我写这篇文章的原因。我们要聊的不是LangChain 又更新了什么小版本而是从 2025 年后 LangChain 进入 1.x 稳定期以来它的开发范式到底发生了哪些变化以及作为一个普通开发者你该怎么用最短时间把入门到代码实战这件事跑通。在动手之前先给出我对 LangChain 1.3 的核心判断LangChain 1.x 不再是一个什么都能干的框架平台而是一套面向大模型应用开发的标准组件库。它不负责 AI 推理本身也不负责模型训练它负责的是把模型、工具、数据、状态流编排成一个可稳定运行的应用这件事。 换句话说LangChain 是胶水不是引擎。这篇文章会沿着一条完整的实战路径展开先讲清楚基础概念和常见误区然后搭建环境再用一个最小 RAG 项目和一个 Agent 项目带你体验 LangChain 1.3 的完整开发流程。最后给出排错清单和工程建议方便你直接迁移到实际项目中。如果你是下面这几类读者这篇文章最适合你只写过几段prompt调用想系统了解 LangChain 怎么组织代码的开发者被 LangGraph、Agent、MCP 这几个概念绕晕想搞清它们之间关系的人从 0.x 时代的老教程入门发现代码跑不起来想切换到 1.x 新写法的开发者。2. LangChain 基础概念框架边界与核心组件2.1 LangChain 到底解决什么问题在没有 LangChain 之前开发一个大模型应用其实也能做# 不使用框架的最小实现 import openai client openai.OpenAI() resp client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个专业助手。}, {role: user, content: 请总结这段文本……} ] ) print(resp.choices[0].message.content)这段代码很简单但它只解决了调用一次模型的问题。一旦你的应用需要连续对话、从文档库检索、调用外部工具、处理中间状态、追踪每一次模型调用的耗时和 token 成本事情就开始变得不可控。你需要自己管理对话历史、自己处理向量化与存储、自己写工具循环、自己设计异常重试。LangChain 的核心价值就是把这一段自己写逻辑变成了组装模块场景没有 LangChain 时要做的工作使用 LangChain 后对话记忆自己维护 messages 列表拼接历史ChatMessageHistory直接管理RAG 检索自己封装向量化 向量库查询加载器、分割器、向量库接口统一工具调用自己写 while 循环让模型反复选择Agent 编排器自动完成耗时追踪手动记录每次 API 调用回调系统统一收集一句话概括LangChain 解决的是大模型应用工程化的问题而不是大模型本身的问题。2.2 LangChain 与 LangGraph 的区别这是热搜里出现频率最高的问题之一也是新手最容易踩坑的地方。LangChain 和 LangGraph 不是同一个层面的东西LangChain面向应用开发者的工具集。包括模型封装、Prompt 模板、输出解析器、向量存储接口、文档加载器、文本分割器等。你可以用它快速搭出 RAG、问答、总结等应用。LangGraph面向复杂状态流的编排引擎。它把一次 AI 应用执行看作一张图图中的节点是要执行的动作比如调用模型、调用工具、查数据库边是状态转移。它更擅长做 Agent、多步骤工作流、人机协同等需要精细控制流程的场景。在 LangChain 1.x 体系里两者是配合关系LangChain 零件库模型、工具、解析器、向量库 LangGraph 总装线节点、状态、条件分支、循环所以当你看到LangChain 过时了吗这个问题时准确理解是LangChain 作为框架并没有过时过时的是 0.x 时代那种用 Chain 堆逻辑的写法新的官方建议是复杂流程用 LangGraph 编排LangChain 负责提供底层组件。2.3 Agent 与 Skill、Tool 的关系Agent智能体是 LangChain 里最容易被误解的概念。Agent 不是什么黑魔法模型而是一个由大模型驱动决策的控制循环。它接收一个任务自己判断我需要调用哪个工具调用之后结果满足要求了吗不够就继续调用直到任务完成。在 LangChain 1.x 的语境下几个概念要分清Tool工具可以被模型调用的函数。比如查询天气执行 SQL搜索网页。它是对外能力的抽象。Skill技能一组相关工具和提示词的组合。比如数据分析技能可能包含 SQL 工具、Python 执行工具、报表生成工具。它更偏向业务粒度的复用。Agent智能体使用这些工具完成任务的决策主体。它知道自己有哪些工具可选也知道当前任务的目标。初学者最容易犯的错误是把能调用工具等同于有智能。实际上 Agent 的能力上限由三件事决定底层模型的推理能力、工具的可靠性、以及你对状态流的控制能力。LangChain 1.x 的 Agent 设计理念就是尽量把控制权交还给开发者而不是让模型自由发挥。2.4 Prompt、RAG 与 MCP 的定位这部分是 2025 年后 LangChain 生态最热的三件事值得单独说明Prompt 工程最轻量级的应用开发方式。它不引入外部数据完全靠提示词设计约束模型行为。适合需求简单、不涉及私有数据的场景。RAG检索增强生成给模型外挂一个知识库。回答问题时先从库里检索相关内容拼进上下文再让模型生成回答。这是目前企业落地大模型应用最常见的技术路线。MCPModel Context Protocol统一模型如何接入外部工具和数据源的协议。它和 LangChain 的关系是互补而非竞争LangChain 提供的是 Python 开发框架MCP 提供的是标准化的工具接入协议。LangChain 1.x 已经支持通过 MCP 适配器连接 MCP 服务器这也是很多面试题里会问的方向。3. 环境准备与版本选型这部分我们直接进入实操。3.1 版本选型建议写这篇文章时LangChain 1.x 已经进入稳定期。给你的选型建议是新项目一律使用langchain1.0的版本不要再安装langchain-community全家桶按需安装子包Agent 编排优先使用langgraph而不是 0.x 时代的AgentExecutor向量库根据项目实际选型本地演示可以用Chroma。注意不同子包的版本更新非常快下面的安装命令只保证在当前时间点可用。实际安装时请以 PyPI 上的最新稳定版本为准不要死磕某一个固定版本号。本文重点演示的是 1.x 的通用开发思路。3.2 安装依赖推荐使用 Python 3.11 或 3.12 的虚拟环境避免系统级环境污染。# 创建并激活虚拟环境Windows/Linux/macOS 通用思路 python -m venv langchain-demo source langchain-demo/bin/activate # Windows 下使用 langchain-demo\Scripts\activate # 安装核心依赖 pip install --upgrade pip pip install langchain pip install langchain-openai pip install langchain-community pip install langgraph # RAG 演示环境依赖 pip install chromadb pip install pypdf pip install tiktoken # 如果需要查看版本信息 pip show langchain langchain-openai langgraph依赖说明langchain-openai官方维护的 OpenAI 模型适配包如果你用的是其他模型厂商就换成对应的langchain-*适配包。langgraphAgent 编排和复杂流程控制必装。chromadb本地向量数据库适合学习和小规模原型。pypdf用来加载 PDF 文档做 RAG 演示时需要。3.3 环境变量配置在项目根目录创建.env文件OPENAI_API_KEYsk-你的密钥 OPENAI_BASE_URLhttps://api.openai.com/v1如果你使用的是国内兼容 OpenAI 接口的模型服务把OPENAI_BASE_URL改成你实际的服务地址即可。不要在生产代码里硬编码密钥尽量通过环境变量或密钥管理服务注入。4. 核心流程拆解一个最小 LangChain 应用是怎么跑起来的在写完整项目之前先用一个最小示例理解 LangChain 1.x 的核心开发流程。4.1 最小调用Model 封装LangChain 1.x 不再像 0.x 那样要求你理解LLM和ChatModel的复杂继承体系。你用ChatOpenAI就能完成绝大多数对话场景# 文件路径: demo_01_basic.py from langchain_openai import ChatOpenAI # 创建模型实例 llm ChatOpenAI( modelgpt-4o-mini, temperature0.7 ) # 直接调用 resp llm.invoke(用一句话解释什么是 LangChain) print(resp.content)关键点invoke是 1.x 的统一调用入口。无论是模型、链还是 Agent都实现了这个接口。ChatOpenAI返回的是一个AIMessage对象取内容时需要.content。如果你需要多轮对话直接传messages列表而不是自己拼接字符串。4.2 带 Prompt 模板与输出解析实际项目中很少直接裸调模型。更常见的写法是Prompt 模板 模型 输出解析器用管道符组合成一条链。# 文件路径: demo_02_prompt_chain.py from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 1. 定义提示词模板 prompt ChatPromptTemplate.from_messages([ (system, 你是资深 {field} 工程师回答要专业、简洁。), (human, {question}) ]) # 2. 定义模型 llm ChatOpenAI(modelgpt-4o-mini, temperature0.3) # 3. 定义输出解析器 parser StrOutputParser() # 4. 用 | 符号组装成链这是 LCEL 核心语法 chain prompt | llm | parser # 5. 调用 result chain.invoke({ field: Python, question: 请解释 Python 的 GIL 是什么以及它对多线程的影响。 }) print(result)这个例子体现了 LangChain 1.x 最重要的编程范式LCELLangChain Expression Language。LCEL 的核心思想是每个组件都实现Runnable接口然后通过|管道符组合。左边组件的输出自动变成右边组件的输入。它的好处是代码可读性高一条链的完整流程一眼就能看清天然支持流式输出、异步调用、批量处理可以方便地插入回调、日志和重试逻辑。很多新手第一次看到prompt | llm | parser会觉得奇怪以为只是语法糖。其实 LCEL 背后是一整套 Runnable 协议它是理解 LangChain 1.x 的关键。4.3 核心流程总结一个标准 LangChain 应用的开发流程可以拆成五步确定输入输出用户输入什么最终想要什么格式的结果。组装 Prompt把系统提示、用户输入、外部上下文组织成模型可理解的 messages。选择模型根据任务类型、成本、延迟选择模型。补充检索或工具如果需要外部知识接 RAG如果需要操作外部系统接 Tool。编排与验证简单场景用 LCEL复杂场景用 LangGraph最后验证输出质量和延迟。这五步是整个 LangChain 开发的基本功。后面的实战项目都会围绕这个框架展开。5. 实战一基于 LangChain 1.3 搭建 RAG 问答系统RAG 是 LangChain 最经典的应用场景。我们用一个本地 PDF 文档问答作为实战项目它足够小能完整展示文档加载、切分、向量化、检索、生成全链路。5.1 项目结构langchain-rag-demo/ ├── .env ├── data/ │ └── langchain-intro.pdf # 你本地的知识库文档 ├── rag_demo.py # 主程序 └── requirements.txt在data/目录下放任意一份 PDF 文档即可。我这里使用一份关于 LangChain 的介绍文档作为示例。5.2 完整实现# 文件路径: rag_demo.py import os from dotenv import load_dotenv # 加载 .env 文件 load_dotenv() from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_chroma import Chroma from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser def build_vectorstore(): 加载文档并构建向量库返回 retriever. # 1. 加载 PDF 文档 loader PyPDFLoader(data/langchain-intro.pdf) docs loader.load() print(f加载了 {len(docs)} 页文档) # 2. 文本切分 text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , ., ] ) chunks text_splitter.split_documents(docs) print(f切分为 {len(chunks)} 个文本块) # 3. 向量化并存储到 Chroma embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db ) # 4. 获取检索器返回 Top-K4 retriever vectorstore.as_retriever(search_kwargs{k: 4}) return retriever def create_rag_chain(retriever): 构建 RAG 链路. # 1. 提示词模板要求模型基于提供的上下文回答 prompt ChatPromptTemplate.from_messages([ (system, 你是一个严谨的技术文档助手。只能根据提供的上下文回答如果上下文中没有相关信息就明确说文档中未找到相关答案不要编造。), (human, 上下文内容\n{context}\n\n用户问题{question}) ]) llm ChatOpenAI(modelgpt-4o-mini, temperature0.2) parser StrOutputParser() # 2. 定义一个格式化上下文的函数把检索结果拼成字符串 def format_docs(docs): return \n\n.join(doc.page_content for doc in docs) # 3. 使用 LCEL 组装 RAG 链路 # retriever - format_docs - prompt - llm - parser chain ( { context: retriever | format_docs, question: lambda x: x[question] } | prompt | llm | parser ) return chain if __name__ __main__: # 首次运行会构建向量库之后可以复用 retriever build_vectorstore() rag_chain create_rag_chain(retriever) # 测试问答 while True: question input(请输入问题输入 q 退出) if question.lower() q: break answer rag_chain.invoke({question: question}) print(\n回答, answer) print(- * 50)5.3 代码逻辑说明这段代码里有几个关键设计需要理解文本切分参数。chunk_size500表示每块最多 500 个字符chunk_overlap50表示相邻块之间重叠 50 个字符。重叠的目的是避免在切分处丢失语义信息。中英文混排场景下在separators里加入中文标点符号会更有效。format_docs 函数。从向量库检索出来的结果是一个Document列表每个 Document 有page_content和metadata。这里把page_content拼接成字符串作为上下文注入 Prompt。为什么用|把它接在retriever后面因为 LCEL 支持自定义函数作为 Runnable函数接收上一个组件的输出返回下一个组件需要的格式。检索参数设置。search_kwargs{k: 4}表示返回最相似的 4 个文本块。k 值太大会导致上下文冗长、模型注意力分散k 值太小可能检索不到关键信息。实际项目中需要根据文档长度和模型上下文窗口调试。5.4 运行结果验证python rag_demo.py预期输出效果类似加载了 10 页文档 切分为 28 个文本块 请输入问题输入 q 退出什么是 LCEL 回答根据文档内容LCEL 是 LangChain Expression Language 的缩写是一种用于组合多个组件如 Prompt 模板、模型、输出解析器的声明式语法使用竖线|操作符将这些组件串联成一个可执行的链…… 请输入问题文档里没有提到的内容呢 回答文档中未找到相关答案。如何判断系统是否工作正常第一次运行会看到加载和切分日志说明文档读取成功问题能被正常回答说明向量检索和生成链路已经打通问一个文档里没有的内容模型能拒绝回答说明系统没有被幻觉带偏。如果回答内容完全和文档无关大概率是检索失效先检查 Chroma 目录是否成功生成再检查 k 值是否过小。6. 实战二基于 LangGraph 构建带任务规划的 Agent第二个项目是 Agent。网上关于 Agent 的讨论很多但真正能帮忙跑通一个带任务规划的 Agent 项目的教程其实不多。这一节我们用 LangGraph 实现一个能自主规划并调用工具完成任务的 Agent。6.1 为什么用 LangGraph 而不是旧版 AgentExecutor在 LangChain 0.x 时代initialize_agent一键创建 Agent 的方式很受欢迎但它有一个问题Agent 的决策过程像一个黑盒你很难干预它现在准备做什么。当任务复杂、工具变多之后排查问题会非常痛苦。LangGraph 的定位是可控的 Agent 运行时。你可以明确地定义这个 Agent 有哪些状态模型在哪里做决策工具调用失败后怎么办什么条件下结束循环。它把不可控的循环变成了可以看到每一步的图执行。6.2 LangGraph 核心概念使用 LangGraph 前先建立三个基本概念State全局状态对象。它贯穿整个图每个节点都可以读取和修改它。比如messages是常见的状态字段用来保存整个对话历史。Node图中的节点就是一个 Python 函数。它接收当前状态处理后返回新的状态更新。Edge节点之间的连接。分为普通边和条件边。条件边根据当前状态决定下一步走向哪个节点这是实现模型决策的关键机制。6.3 完整示例带任务规划的 Agent下面的示例实现了一个简单但完整的 Agent用户提出任务Agent 自动判断是否调用工具调用工具后把结果交给模型继续推理直到认为任务完成。# 文件路径: agent_demo.py import os from dotenv import load_dotenv load_dotenv() from typing import TypedDict, Annotated, Literal from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage, SystemMessage from langchain_core.tools import tool from langgraph.graph import StateGraph, END from langgraph.prebuilt import ToolNode # ---------- 1. 定义工具 ---------- tool def add(a: int, b: int) - int: 计算两个整数的和。 return a b tool def multiply(a: int, b: int) - int: 计算两个整数的乘积。 return a * b tool def get_weather(city: str) - str: 获取指定城市的当前天气概况模拟数据。 weather_map { 北京: 晴25 度, 上海: 多云27 度, 广州: 小雨30 度, } return weather_map.get(city, 暂无该城市天气数据) tools [add, multiply, get_weather] # ---------- 2. 定义状态 ---------- class AgentState(TypedDict): messages: Annotated[list, 对话历史] next: str # 记录下一步动作类型 # ---------- 3. 定义模型节点 ---------- llm ChatOpenAI(modelgpt-4o-mini, temperature0) # 让模型知道可用工具 llm_with_tools llm.bind_tools(tools) def agent_node(state: AgentState): 模型决策节点判断是直接回答还是调用工具. messages state[messages] # 调用模型模型可能返回 tool_calls也可能直接返回文本 response llm_with_tools.invoke(messages) return {messages: [response]} # ---------- 4. 定义条件路由 ---------- def router(state: AgentState) - Literal[tools, __end__]: 根据模型输出判断下一步有工具调用就去 tools 节点否则结束. last_message state[messages][-1] if hasattr(last_message, tool_calls) and last_message.tool_calls: return tools return __end__ # ---------- 5. 组装图 ---------- builder StateGraph(AgentState) # 添加节点 builder.add_node(agent, agent_node) builder.add_node(tools, ToolNode(tools)) # 设置入口 builder.set_entry_point(agent) # agent 节点之后走条件路由 builder.add_conditional_edges( agent, router, { tools: tools, __end__: END } ) # 工具节点结束后回到 agent 继续决策 builder.add_edge(tools, agent) # 编译图 graph builder.compile() # ---------- 6. 调用 Agent ---------- def run_agent(user_input: str): system_msg SystemMessage(content你是一个乐于助人的助手。如果用户的请求涉及工具请先用工具计算再根据工具结果回答。) result graph.invoke({ messages: [system_msg, HumanMessage(contentuser_input)] }) # 返回最终回复 return result[messages][-1].content if __name__ __main__: # 测试1需要拆解乘法任务 print(run_agent(请计算 (3 5) * 2 的结果)) # 测试2查询天气 print(run_agent(上海今天天气怎么样)) # 测试3纯文本对话 print(run_agent(你好请介绍一下你自己。))6.4 代码逻辑与任务规划机制解析这段代码虽然不长但它已经把 Agent 的任务规划能力完整展示出来了。所谓任务规划本质上是模型在每一步做出下一步动作的决策当用户问请计算 (3 5) * 2 的结果模型首先理解这是一个算术问题它可以调用add和multiply两个工具第一次调用agent节点时模型输出tool_calls里面包含工具名和参数但模型并不会真的执行工具路由判断存在tool_calls于是把控制权交给tools节点tools节点执行真实函数把结果包装成ToolMessage追加到messages控制权回到agent节点模型看到工具返回结果后继续推理输出最终答案这一次模型没有tool_calls路由走向END流程结束。这就是 LangGraph 对任务规划能力的典型实现用条件边模拟循环用状态对象保存中间结果让模型成为每一步的决策者。6.5 运行效果与验证python agent_demo.py预期输出根据计算(3 5) * 2 的结果是 16。 上海今天多云27 度。 你好我是一个乐于助人的助手可以帮你回答问题、执行计算、查询天气等。有什么可以帮你的验证重点测试 1 能正确执行多步工具调用后续调用没有使用上一轮的错误结果说明状态管理正确测试 2 能从get_weather返回的模拟数据中提取城市天气说明工具结果成功注入了上下文测试 3 能正常对话说明条件路由在无工具调用场景下能正常结束流程。如果想看每一步的中间状态可以给graph.invoke加上debug: True参数LangGraph 会打印每个节点的输入输出这是排查 Agent 问题最直接的手段。7. LangChain 与 LangGraph 常见问题与排查方法在实际开发中新手最先遇到的技术问题往往不是架构设计而是各种看起来莫名其妙的环境和运行问题。下面是一份基于 LangChain 1.x 常见踩坑点整理的排查表问题现象可能原因排查方式解决方案安装时依赖冲突旧版 langchain 0.x 残留包冲突pip listgrep langchain 查看残留包ChatOpenAI导入失败缺少langchain-openai子包查看报错信息中的缺失模块pip install langchain-openai调用模型报 401/403API Key 错误或环境变量未加载检查.env文件是否被读取打印环境变量确认.env路径正确使用python-dotenv加载调用模型报超时网络不通或代理设置异常用 curl 测试模型 API 连通性确认接口地址正确配置合规网络环境中文文档检索效果差文本切分时中文标点被切断打印切分后的 chunk 内容在 separators 中加入中文标点调整 chunk_sizeChroma 数据重复重复执行脚本导致旧数据残留查看chroma_db目录内容删除本地chroma_db目录后重新构建Agent 不调用工具直接回答模型没有正确绑定工具打印llm_with_tools绑定的工具列表确认bind_tools已经调用工具描述是否清晰Agent 无限循环调用工具缺少终止条件或工具返回异常设置 debug 模式观察节点流转在条件路由中增加最大步数限制或检查工具异常处理工具参数解析错误模型输出的工具参数与函数签名不匹配检查工具函数签名和 docstring给工具函数写清晰的 docstring 和类型注解LCEL 链调用时报RunnableSequence错误组件之间输入输出格式不匹配检查管道中各组件期望的输入格式在链中插入自定义函数转换格式7.1 排查思路的通用原则先看链路不要只看报错。LangChain 报错信息可能很冗长优先定位是哪个组件抛出的异常。可以用chain.with_config({callbacks: [...]})添加回调打印中间变量。先跑最小示例。遇到问题后把链路缩减到模型调用这一层确认模型、密钥、网络没有问题再逐步加回 Prompt、检索、工具。版本不一致是万恶之源。升级依赖后如果代码跑不通先检查是否 0.x 和 1.x 的 API 混用。比如langchain.chains.LLMChain在 1.x 中已经不推荐直接使用新代码应该用 LCEL。Agent 问题先看tool_calls再往下查。如果模型输出里根本没有tool_calls说明问题出在模型理解和工具描述上而不是后续节点。8. 生产环境中的最佳实践与工程建议很多教程停在能跑通这一层但真实项目里跑通只代表开始。这一节我们把 LangChain 应用从 Demo 提升到工程级别聊一聊真正值得投入精力的地方。8.1 项目结构设计按组件而非页面组织代码不要把代码全部堆在一个文件里。一个可维护的 LangChain 项目建议这样分层project/ ├── app/ │ ├── chains/ # 各业务链 │ │ ├── rag_chain.py │ │ └── agent_graph.py │ ├── tools/ # 自定义工具集 │ ├── prompts/ # Prompt 模板 │ ├── models/ # 模型实例配置 │ ├── services/ # 业务服务层 │ └── main.py # 入口 ├── config/ │ ├── settings.py # 配置读取 │ └── .env ├── data/ # 文档数据 ├── tests/ # 单元测试 └── requirements.txt这样设计的核心好处是Prompt、模型、工具都在独立模块中修改任何一个组件不需要牵连其他部分。8.2 配置管理不要把密钥写进代码严格遵守最小权限原则。生产环境的 API Key 应该放在密钥管理服务中开发环境用.env文件但必须进.gitignore。配置项按环境区分可以用 pydantic-settings 或类似工具统一管理。# 文件路径: config/settings.py from pydantic_settings import BaseSettings class Settings(BaseSettings): openai_api_key: str openai_base_url: str https://api.openai.com/v1 model_name: str gpt-4o-mini embedding_model: str text-embedding-3-small vectorstore_dir: str ./chroma_db chunk_size: int 500 chunk_overlap: int 50 retriever_k: int 4 class Config: env_file .env settings Settings()8.3 可观测性记录每次调用的全链路信息LangChain 提供了回调系统你可以监听每个组件的开始、结束和错误事件。生产环境中建议至少记录每次调用的耗时和 token 消耗输入输出摘要检索出的文档 ID 和相关性得分Agent 每一步的工具调用记录。下面是一个简单的回调示例# 文件路径: observability.py from langchain_core.callbacks import BaseCallbackHandler class LoggingCallbackHandler(BaseCallbackHandler): def on_llm_start(self, serialized, prompts, **kwargs): print(f[LLM 开始] prompts{prompts}) def on_llm_end(self, response, **kwargs): print(f[LLM 结束] output{response.generations[0][0].text[:50]}) def on_tool_start(self, serialized, input_str, **kwargs): print(f[工具 开始] tool{serialized.get(name)}, input{input_str}) def on_tool_end(self, output, **kwargs): print(f[工具 结束] output{output})然后在调用链时传入from langchain_core.callbacks import CallbackManager callback_manager CallbackManager([LoggingCallbackHandler()]) result chain.invoke({question: ...}, config{callbacks: callback_manager})8.4 安全边界LLM 应用必须做的几件事大模型应用的安全和传统 Web 应用不完全一样除了常规的鉴权和防注入还要特别关注Prompt 注入防护。外部输入可能包含恶意指令不要让用户输入直接覆盖系统提示词。在工程上对系统消息和用户消息做严格隔离必要时对用户输入做敏感词过滤。工具权限最小化。给 Agent 绑定的工具只授予完成业务所需的最小权限。比如查询数据库的工具只能用只读账号不能给 drop 权限。输出内容审核。模型生成的输出需要经过合规过滤可以在链的末尾增加一个审核节点。调用频率限制。防止用户通过你的应用大量消耗模型 token需要做配额控制。8.5 性能与成本优化缓存对重复问题做语义缓存。LangChain 内置了InMemoryCache或RedisCache对高频问题非常有效。模型分级简单任务用gpt-4o-mini这类低成本模型复杂任务才上旗舰模型。一个应用可以同时配置多个模型实例按路由分发。检索优化RAG 的延迟瓶颈往往在向量检索。如果检索结果量大考虑使用MultiVectorRetriever或先做粗排再做精排。流式输出使用.stream()方法而不是.invoke()可以显著改善用户等待体验。9. 总结与后续学习方向这篇文章从 LangChain 1.x 的框架定位讲起梳理了 LangChain、LangGraph、Agent、Skill、MCP 这几个关键概念的关系然后通过一个最小 LCEL 示例让你理解新版本的核心编程范式接着用两个完整项目分别演示了 RAG 问答系统和基于 LangGraph 的 Agent 任务规划。最后给出了排查清单和工程建议。你真正应该带走的不是代码本身而是三个判断LangChain 1.x 是稳定期框架。过去那种两个月不看就跟不上的情况已经过去1.x 的核心 API 设计LCEL、invoke、组件化趋于稳定值得投入学习。RAG 是入门 LangChain 的最短路径。它链路完整、见效快、不需要复杂的编排知识适合作为第一个动手项目。复杂 Agent 请直接学 LangGraph。不要花时间研究 0.x 时代的 AgentExecutor 写法那是已经被官方边缘化的旧模式。LangGraph 的状态图思维不只适用于 Agent也适用于所有需要流程控制的大模型应用。下一步的实践建议按顺序做把上面的 RAG 项目换成本领域的技术文档试试文档质量对回答效果的影响给 Agent 增加一个你工作中真正需要的工具比如查数据库、调内部 API在项目里加上回调日志和简单的 token 统计开始培养可观测性意识学习 LangGraph 的checkpoint机制给你的 Agent 加上多轮记忆。最后补充一点网上关于 LangChain 过时的讨论非常多但绝大多数是标题党。框架可以换代但用组件编排大模型应用这套工程思想不会过期。真正值得你长期投入的是理解模型应用的分层架构、接口抽象和状态流控制——这些能力换任何框架都适用。
返回列表