
如果你正在学习大模型应用开发一定绕不开 LangChain 和 LangGraph 这两个名字。它们频繁出现在各种教程和项目里但很多开发者尤其是刚入门的同学常常会感到困惑它们到底是什么关系我该先学哪个为什么有时候用 LangChain有时候又要用 LangGraph一个常见的误解是把它们当作两个独立的、需要二选一的框架。实际上这种理解会让你在构建复杂应用时走弯路。LangGraph 并不是 LangChain 的替代品而是一个关键的、用于解决特定难题的“增强组件”。简单来说LangGraph 是 LangChain 生态中专门用于构建有状态、多步骤、可循环的智能体Agent应用的核心库。这篇文章将帮你彻底理清它们的关系。我会用一个简单的比喻开始如果把构建大模型应用比作造车那么 LangChain 提供了发动机、轮胎、方向盘等所有标准零件和组装手册Chain而 LangGraph 则提供了设计复杂传动系统和控制逻辑如自动变速箱、四驱系统的专用工具箱。前者让你能快速造出一台能跑的车后者让你能造出适应复杂路况的越野车或赛车。接下来我们将从概念、原理到代码一步步拆解让你不仅明白“是什么”更清楚“什么时候用”以及“怎么用”。1. 核心关系从“链条”到“图”的演进要理解 LangChain 和 LangGraph首先要抓住它们各自解决的核心问题。LangChain 的核心是“链Chain”。它的设计初衷是简化大模型应用的开发把调用大模型、处理输入输出、连接工具如搜索、数据库等步骤封装成一个个可复用的模块然后像搭积木一样把它们“链”起来。例如一个经典的RetrievalQA链就内部集成了文档加载、文本分割、向量化检索、提示词组装、大模型调用等一系列步骤。对于大多数线性的、确定性的任务问答、总结、翻译Chain 非常高效。然而现实世界中的很多任务并非一条直线。比如你让一个智能体帮你订机票它需要先理解你的需求对话。可能要去搜索航班信息调用工具。根据结果向你确认时间或舱位返回对话。如果你不满意它需要重新搜索循环。最终确认并执行预订调用另一个工具。这个过程充满了分支、循环和状态依赖上一步的结果影响下一步的决策。用一条固定的“链”很难优雅地描述这种逻辑。这就是LangGraph 要解决的问题。LangGraph 的核心是“图Graph”。它允许你将应用逻辑定义为一个由节点Node和边Edge组成的有向图。每个节点可以是一个工具调用、一次LLM对话或者任何处理函数边则定义了节点之间的流转条件。更重要的是Graph 维护着整个流程的“状态State”每个节点都可以读取和修改这个全局状态从而轻松实现多轮对话、循环执行、条件分支等复杂控制流。所以关系总结如下LangChain 是基础框架和组件库提供了与各种大模型、向量数据库、工具集成的标准化接口以及构建简单线性流程的“链”。LangGraph 是高级流程编排引擎基于 LangChain 的组件提供了构建复杂、有状态、非线性工作流的图模型。它通常与 LangChain 的Agent概念紧密结合用于构建强大的智能体。你可以只用 LangChain 来构建应用。但当你的应用需要智能体、复杂决策或循环时你就需要引入 LangGraph 来增强 LangChain。它们不是竞争关系而是互补与增强。2. 关键概念对比Chain vs. Graph vs. Agent为了避免混淆我们通过一个表格来直观对比几个核心概念概念所属框架核心思想适用场景状态管理类比ChainLangChain线性管道。将多个模块按固定顺序串联执行。摘要、翻译、简单问答、格式转换等确定性、单次执行的任务。无内置全局状态靠节点间传递输入输出。工厂的流水线。零件从A工位到B工位再到C工位顺序固定。GraphLangGraph有向图。由节点和边组成支持循环、条件分支。智能体、多轮对话、需要根据中间结果动态调整路径的复杂任务。有强大的全局状态State管理节点共享和修改状态。城市的交通路网。车辆数据可以根据路况条件选择不同路线甚至绕回原路循环。AgentLangChain (由Graph实现)自主决策者。基于LLM能够理解目标动态选择使用哪个工具并持续执行直到完成。任何需要自主规划、调用工具、处理不确定性的任务如数据分析、自动化客服。早期Agent实现状态管理较弱现代Agent多基于LangGraph构建拥有完整状态。自动驾驶汽车。感知环境用户输入规划路径思考操作方向盘/油门调用工具最终到达目的地。一个重要的认知升级在 LangChain 的最新体系中功能强大的 Agent 通常是使用 LangGraph 构建的。LangGraph提供了StateGraph等核心类成为创建复杂 Agent 的推荐方式。所以当你学习用 LangGraph 构建应用时本质上就是在学习构建新一代的、更强大的智能体。3. 环境准备与安装理解了概念我们开始动手。首先确保你的 Python 环境推荐 3.8和包管理工具如 pip已经就绪。安装 LangChain 和 LangGraphLangGraph 通常与 LangChain 协同安装。建议安装较新的版本以获取完整功能。# 安装 LangChain 的核心包和社区常用工具包 pip install langchain langchain-community # 安装 LangGraph pip install langgraph # 为了示例运行我们还需要一个大模型。这里使用 OpenAI 的模型需要安装其 SDK 并准备 API Key。 pip install openai重要提示使用 OpenAI 需要有效的 API Key。请将其设置为环境变量不要在代码中硬编码。# 在 Linux/Mac 的终端中 export OPENAI_API_KEY你的-api-key # 在 Windows 的 CMD 中 set OPENAI_API_KEY你的-api-key # 在 Windows PowerShell 中 $env:OPENAI_API_KEY你的-api-key如果你没有 OpenAI API Key也可以使用 LangChain 集成的其他开源模型如通过 Ollama 本地部署但配置步骤会稍复杂。本文为简化流程使用 OpenAI GPT-3.5-turbo 进行演示。4. 从 LangChain Chain 开始一个简单示例我们先看一个典型的 LangChain Chain 如何工作。这个例子实现一个简单的“翻译然后总结”的线性流程。# 文件simple_chain_demo.py from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 1. 初始化模型 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) # 2. 定义第一个提示词模板翻译 translation_prompt ChatPromptTemplate.from_template( 请将以下英文文本翻译成地道的中文{text} ) # 3. 定义第二个提示词模板总结 summary_prompt ChatPromptTemplate.from_template( 请用一句话总结以下中文文本的核心内容{chinese_text} ) # 4. 构建链使用管道操作符 | 将组件串联起来 # 这是 LangChain 表达式语言 (LCEL) 的写法非常简洁 translation_chain translation_prompt | llm | StrOutputParser() summary_chain summary_prompt | llm | StrOutputParser() # 将两个链再组合成一个顺序链 combined_chain translation_chain | summary_chain # 5. 调用链 input_text Large language models are transforming how we build software, enabling more natural interactions and automating complex tasks. result combined_chain.invoke({text: input_text}) print(原文, input_text) print(\n翻译并总结的结果, result)代码解读线性流程代码清晰地定义了翻译 - 总结这个固定顺序。无状态translation_chain的输出直接作为summary_chain的输入chinese_text。两个步骤之间除了传递文本没有其他共享信息。LCEL 语法|操作符是 LangChain 表达式语言的核心它让链的组装像 Unix 管道一样直观。运行这个脚本你会得到类似“大语言模型正在通过实现更自然的交互和自动化复杂任务来改变软件开发方式”的总结。这个 Chain 完美解决了线性任务。5. 引入 LangGraph构建一个循环决策智能体现在我们面对一个更复杂的场景一个数字猜测游戏智能体。用户心中想一个1-100的数字智能体来猜。智能体可以做出猜测。根据用户的反馈“大了”、“小了”、“对了”决定下一步。如果没猜对更新知识范围继续猜直到猜对为止。这个流程明显包含循环和基于状态的决策是 LangGraph 的用武之地。# 文件number_guessing_agent.py from typing import TypedDict, Literal from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate import json # --- 第1步定义状态State--- # 使用 TypedDict 清晰定义整个流程需要共享和修改的数据结构 class AgentState(TypedDict): # 游戏状态进行中、成功、失败 game_status: Literal[playing, success, failed] # 当前猜测的数字 current_guess: int # 已知的最小可能值 low: int # 已知的最大可能值 high: int # 用户上一轮的反馈 feedback: str # 猜测历史 guess_history: list[int] # 与用户的对话记录可选用于复杂对话 messages: list # --- 第2步定义节点Nodes函数 --- def guess_number(state: AgentState): 智能体做出猜测的节点 print(f[Agent] 思考中... 已知范围: {state[low]} ~ {state[high]}) # 简单的二分法策略取中间值 guess (state[low] state[high]) // 2 print(f[Agent] 我猜是{guess}) # 更新状态 new_state state.copy() new_state[current_guess] guess new_state[guess_history].append(guess) new_state[game_status] playing # 可以在这里添加调用LLM进行更复杂策略的代码 return new_state def process_feedback(state: AgentState): 处理用户反馈并更新范围的节点 feedback state[feedback].lower() guess state[current_guess] low state[low] high state[high] new_state state.copy() if 大 in feedback or high in feedback: # 猜大了更新上限 new_state[high] guess - 1 print(f[System] 反馈‘大了’更新范围至: {new_state[low]} ~ {new_state[high]}) elif 小 in feedback or low in feedback: # 猜小了更新下限 new_state[low] guess 1 print(f[System] 反馈‘小了’更新范围至: {new_state[low]} ~ {new_state[high]}) elif 对 in feedback or correct in feedback: # 猜对了结束游戏 new_state[game_status] success print(f[System] 恭喜你猜对了数字就是 {guess}。) return new_state else: print(f[System] 无法理解的反馈: {feedback}。请说‘大了’、‘小了’或‘对了’。) # 对于无效反馈可以不更新范围让智能体再猜一次 # 检查是否还有可能的值 if new_state[low] new_state[high]: new_state[game_status] failed print([System] 游戏出错可能你记错了数字) return new_state # --- 第3步定义条件边Conditional Edges--- def should_continue(state: AgentState) - Literal[guess_again, __end__]: 根据游戏状态决定下一步是继续猜还是结束 if state[game_status] in [success, failed]: return END # 特殊节点表示图结束 else: return guess_again # 返回下一个要执行的节点名 # --- 第4步构建图Graph--- # 初始化图构建器并指定状态结构 workflow StateGraph(AgentState) # 添加节点 workflow.add_node(make_guess, guess_number) # 节点1做猜测 workflow.add_node(process_fb, process_feedback) # 节点2处理反馈 # 设置入口点 workflow.set_entry_point(make_guess) # 添加边从“做猜测”到“处理反馈”是固定路径 workflow.add_edge(make_guess, process_fb) # 添加条件边从“处理反馈”出来后根据状态决定下一步 workflow.add_conditional_edges( process_fb, # 源节点 should_continue, # 路由函数返回下一个节点名 { guess_again: make_guess, # 如果返回guess_again则跳回make_guess END: END, # 如果返回END则结束 } ) # 编译图得到一个可执行的应用 app workflow.compile() # --- 第5步运行智能体 --- print( 数字猜测游戏开始 ) print(请在心中想一个1-100的整数。) # 初始化状态 initial_state: AgentState { game_status: playing, current_guess: 0, low: 1, high: 100, feedback: , guess_history: [], messages: [] } # 运行图 try: for step, state in app.stream(initial_state, stream_modevalues): node_name list(step.keys())[0] # 获取当前执行的节点名 print(f\n--- 步骤完成: {node_name} ---) # 如果游戏还在进行且刚执行完“做猜测”节点则等待用户输入 if node_name make_guess and state[game_status] playing: user_fb input(你的反馈是大了/小了/对了: ) # 将用户反馈更新到状态中以便下一个节点使用 state[feedback] user_fb # 注意这里为了简化我们手动更新状态并继续流。 # 更优雅的方式是将用户输入也设计成一个节点。 except KeyboardInterrupt: print(\n游戏被用户终止。) except Exception as e: print(f运行出错: {e})代码深度解读状态State是核心我们定义了AgentState这个强类型字典。图中的所有节点都接收并返回这个状态对象从而实现了信息的持久化和共享。这是与 Chain 最根本的区别。节点Node是功能单元guess_number和process_feedback是两个节点函数它们只关心自己那部分逻辑通过读写state来协作。边Edge定义流程add_edge定义了固定路径猜完后必须处理反馈。add_conditional_edges定义了动态路径处理完反馈后由should_continue函数根据game_status决定是循环回去再猜还是结束。图Graph是编排器StateGraph将节点和边组装起来compile()方法将其编译成可执行的app。流式执行app.stream()允许我们逐步执行并观察状态变化这对于调试复杂智能体至关重要。这个例子虽然逻辑简单但完整展示了 LangGraph 构建有状态、可循环应用的核心模式。你可以看到智能体的“记忆”当前范围、历史记录被完美地维护在状态中。6. 运行效果与进阶思考运行上面的number_guessing_agent.py你会与智能体进行交互。它通常能在7次猜测内猜中你的数字这正是二分查找算法的威力。 数字猜测游戏开始 请在心中想一个1-100的整数。 --- 步骤完成: make_guess --- [Agent] 思考中... 已知范围: 1 ~ 100 [Agent] 我猜是50 你的反馈是大了/小了/对了: 小了 --- 步骤完成: process_fb --- [System] 反馈‘小了’更新范围至: 51 ~ 100 --- 步骤完成: make_guess --- [Agent] 思考中... 已知范围: 51 ~ 100 [Agent] 我猜是75 你的反馈是大了/小了/对了: 大了 --- 步骤完成: process_fb --- [System] 反馈‘大了’更新范围至: 51 ~ 74 ... 直到猜对从这个示例延伸出去一个真正的、基于LLM的智能体应该如何构建上面的智能体策略二分法是我们硬编码的。一个更“智能”的Agent应该由LLM来驱动决策。我们可以改造guess_number节点# 进阶版让LLM来决定猜测策略 def guess_number_with_llm(state: AgentState): llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) prompt ChatPromptTemplate.from_messages([ (system, 你是一个数字猜测游戏高手。已知数字范围在{low}到{high}之间之前的猜测历史是{history}。请根据游戏策略给出下一个最应该猜测的数字。只返回这个数字不要有任何其他解释。), ]) chain prompt | llm | StrOutputParser() # 调用LLM获取猜测 guess_str chain.invoke({ low: state[low], high: state[high], history: state[guess_history] }) try: guess int(guess_str.strip()) except: # 如果LLM输出不规范回退到二分法 guess (state[low] state[high]) // 2 print(f[LLM Agent] 我猜是{guess}) new_state state.copy() new_state[current_guess] guess new_state[guess_history].append(guess) return new_state在这个进阶版中LLM 成为了决策大脑。你可以通过设计不同的提示词让智能体拥有不同的“性格”和策略。这就是 LangGraph 的强大之处它将复杂的流程控制图与强大的认知能力LLM节点结合了起来。7. 常见问题与排查思路在学习和使用 LangChain 与 LangGraph 时你可能会遇到以下典型问题问题现象可能原因排查方式解决方案ImportError或ModuleNotFoundError1. 包未安装。2. 包版本不兼容。3. 导入路径在新版本中已更改。1.pip list | grep langchain检查版本。2. 查看官方文档对应版本的导入方式。1. 使用pip install -U更新。2. 检查代码中的导入语句是否过时如从langchain.llms改为langchain_openai。Chain 或 Graph 执行无输出或报错1. API Key 未设置或无效。2. 网络问题导致无法访问模型服务。3. 提示词格式错误模型无法理解。4. 状态结构定义与节点读写不匹配。1. 打印或检查环境变量。2. 尝试一个最简单的llm.invoke(“hello”)测试连通性。3. 仔细检查提示词模板中的变量名是否与传入字典的键匹配。4. 在节点函数中打印state检查数据流。1. 正确设置环境变量。2. 使用try...except捕获网络异常。3. 使用 LangChain 的PromptTemplate或ChatPromptTemplate规范构建提示词。4. 确保TypedDict的定义和节点中存取的键完全一致。Graph 陷入无限循环条件边conditional_edges的逻辑有误始终无法满足结束条件。1. 在should_continue类函数中添加详细日志。2. 使用app.stream(stream_mode”updates”)观察每个步骤后状态的具体变化。1. 仔细检查结束条件如game_status “success”。2. 确保至少有一条边能通向END节点。3. 考虑设置最大循环次数在状态中添加step_count并在条件中判断。无法理解 LangGraph 的状态流对“有状态”和“节点共享数据”的概念不清晰。1. 重读本文第5节的代码注释。2. 在纸上画出节点和边标注每个节点输入/输出的状态字段。3. 运行官方最简单的示例如TwoAgentDebate。1. 记住每个节点函数都接收完整的当前状态并返回一个完整的新状态或修改部分。2. LangGraph 内部会合并这些更新。理解state.copy()和直接修改state的区别推荐返回新对象。构建的 Agent 效果很差1. 提示词设计不佳。2. 工具定义不清晰或不好用。3. 图的结构工作流不符合任务逻辑。1. 单独测试每个LLM节点的输出。2. 单独测试每个工具函数。3. 简化图先让一个最小闭环跑通。1. 学习提示词工程最佳实践给LLM清晰的指令、上下文和格式要求。2. 为工具编写详细的描述确保LLM能正确理解其功能。3. 参考 ReAct、Plan-and-Execute 等经典 Agent 架构来设计你的图。8. 最佳实践与工程建议当你准备将 LangChain 和 LangGraph 用于实际项目时请遵循以下建议从简单开始逐步复杂化不要一开始就设计庞大的图。先用 LangChain Chain 解决线性问题。当遇到需要“循环”或“基于结果选择不同路径”时再考虑引入 LangGraph。先构建一个包含2-3个节点的最小可行图MVP确保状态流正确再添加更多功能。精心设计状态State结构使用TypedDict或Pydantic BaseModel来明确定义状态这有利于类型检查和代码维护。将状态划分为不同的“命名空间”例如agent_stateuser_sessionconversation_history 使结构更清晰。只将必要的共享数据放在状态里避免状态过于庞大。节点函数保持纯净与可测试每个节点函数应尽量只做一件事并且功能明确。避免在节点函数内部进行复杂的条件分支分支逻辑应该通过图的“边”来体现。编写单元测试来单独测试每个节点函数确保其输入输出符合预期。利用可视化工具调试LangGraph 提供了可视化图结构的功能。在开发过程中利用它来检查你的流程设计是否正确。# 显示图的结构 from IPython.display import Image, display try: display(Image(app.get_graph().draw_mermaid_png())) except: # 如果无法生成图片至少打印文本结构 print(app.get_graph().draw_ascii())为生产环境做好准备密钥管理永远不要将 API Key 硬编码在代码中。使用环境变量或专业的密钥管理服务。错误处理与重试网络调用和模型服务可能不稳定。为 LLM 调用和工具调用添加重试机制和超时设置。日志与监控记录每个节点的输入、输出和耗时这对于排查问题和优化性能至关重要。考虑集成像 LangSmith 这样的 LangChain 官方监控平台。流式输出对于需要长时间运行的 Agent使用app.stream()并向客户端流式返回中间结果提升用户体验。理解成本与延迟每个 LLM 节点调用都会产生成本和延迟。优化你的图避免不必要的 LLM 调用例如能用确定性逻辑判断的就不要交给 LLM。对于复杂 Agent可以考虑“规划-执行”模式先让一个 LLM 节点制定详细计划再由多个工具节点执行减少中间决策的 LLM 调用次数。选择 LangChain 还是 LangGraph从来都不是一个二选一的问题。LangChain 是你的工具箱和材料库而 LangGraph 是你用来组装复杂机械智能体的精密机床和设计图。对于大多数应用如果你需要快速构建一个数据提取、格式转换、简单问答的管道LangChain Chain 是你的最佳选择。它简单、直接、高效。如果你需要构建一个能够与用户进行多轮对话、自主调用工具、在复杂任务中规划并执行步骤的智能体那么 LangGraph 是你必须掌握的利器。它提供了描述这种复杂性的最佳抽象。建议的学习路径是先扎实掌握 LangChain 的核心概念Model, Prompt, Chain, Agent 基础然后当你想构建真正“智能”的、非线性的应用时深入学习和实践 LangGraph。记住LangGraph 的学习曲线更陡峭但它所开启的可能性也大得多——从自动化工作流到复杂的游戏 AI其核心模式都是一致的用图来编排状态用LLM来驱动决策。现在你可以回到你的项目中重新审视你的需求它是一条清晰的流水线还是一张需要动态导航的地图答案会指引你选择正确的工具。