ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LangChain与LangGraph:从线性链到状态图的AI应用开发演进

LangChain与LangGraph:从线性链到状态图的AI应用开发演进 大家好我是专注于AI应用开发的技术博主。在探索大模型应用落地的过程中你是否曾被 LangChain 和 LangGraph 这两个名字相似、功能又有所重叠的框架搞得一头雾水它们到底是什么关系是升级版还是并列关系在构建AI应用时又该如何选择本文将为你彻底理清 LangChain 与 LangGraph 的从属、区别与核心适用场景。通过动画讲解般的拆解思路结合代码示例让你在5分钟内建立起清晰的概念图谱。无论你是零基础的初学者还是已有一定经验的开发者都能轻松掌握并为你的下一个AI应用项目做出正确的技术选型。1. 核心概念它们分别是什么在深入关系之前我们必须先明确两个框架各自的定义和核心使命。1.1 LangChain大模型应用的“脚手架”与“粘合剂”你可以把 LangChain 想象成一个功能强大的工具箱或脚手架。它的主要目标是简化构建基于大语言模型LLM的应用程序的过程。它解决了什么问题早期直接调用大模型API如 OpenAI GPT开发应用时开发者面临诸多挑战上下文管理如何将超长的对话历史或文档有效地喂给模型工具调用如何让模型不仅能聊天还能执行代码、查询数据库、调用API数据交互如何让模型读取本地文件、网页内容或数据库信息流程编排如何将调用模型、处理输入、解析输出、执行工具等多个步骤串联起来LangChain 通过提供一系列模块化组件如 Models, Prompts, Indexes, Chains, Agents和高级接口将上述复杂功能封装成易于使用的模块让开发者能像搭积木一样快速构建应用。一个简单的 LangChain “链”Chain示例# 文件simple_chain.py # 这是一个使用LangChain构建的简单问答链 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) # 2. 定义提示词模板 prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的技术翻译助手。), (user, 请将以下英文技术术语翻译成中文{term}) ]) # 3. 构建链输入 - 提示词 - 模型 - 输出解析 chain prompt | llm | StrOutputParser() # 4. 调用链 result chain.invoke({term: Neural Network}) print(result) # 输出神经网络这个例子展示了 LangChain 的核心抽象之一Chain它把多个步骤提示词填充、模型调用、输出解析组合成一个可执行单元。1.2 LangGraph复杂、有状态工作流的“流程图”与“调度器”LangGraph 是构建在 LangChain 之上的一个专门库。你可以把它看作是 LangChain 这个工具箱里用于绘制和运行复杂流程图的高级工具。它解决了什么问题当你的应用逻辑不再是简单的线性链A-B-C而是包含循环、分支、并行、持久化状态时基础的Chain就显得力不从心。例如一个支持多轮对话、能根据用户反馈回溯或跳转的客服机器人。一个自主执行多步骤任务搜索、分析、撰写、审核的智能体Agent。一个需要持续跟踪会话状态和中间结果的审批流程。LangGraph 引入了图Graph的概念。它将应用中的每个步骤定义为一个节点Node步骤之间的流转路径定义为边Edge。它特别擅长管理有状态Stateful的、可能循环的执行过程。核心比喻LangChain像是提供了砖块、水泥、钢筋Models, Prompts, Tools。LangGraph则是专门用来设计并建造带有复杂管道系统循环、条件分支和记忆房间状态持久化的建筑蓝图和施工管理系统。2. 关系辨析从属、互补与演进理解了各自是什么它们的关系就一目了然了。2.1 从属关系LangGraph 是 LangChain 生态的“高级成员”这是最关键的一点LangGraph 是 LangChain 框架的一部分但它是一个相对独立、专注于解决特定问题的库。在安装上它通常是langchain包的一个子集或独立包如langgraph。在功能上它深度依赖 LangChain 的核心组件如 Models、Tools、Runnables。你需要先用 LangChain 定义好你的LLM、工具和提示词然后才能用 LangGraph 来编排它们。在定位上LangGraph 不是来取代 LangChain 的Chain而是来补充和增强它处理Chain难以应对的复杂场景。2.2 核心区别线性链 vs. 状态图我们可以通过一个对比表格来清晰区分特性LangChain (Chain)LangGraph (Graph)核心抽象链Chain图Graph流程结构线性或少量分支。通常是预定义的顺序执行。任意复杂结构。支持循环、条件分支、并行、嵌套子图。状态管理隐式或无状态。每次调用相对独立状态通过上下文传递或外部管理。显式且有状态。内置State对象在整个图执行过程中持久化并传递数据。控制流有限。主要通过RunnableBranch等实现简单分支。强大。基于边的条件逻辑conditional_edge决定下一个节点轻松实现循环END指向START。适用场景问答系统、文档总结、简单提取、一次性转换任务。多轮对话代理、复杂决策工作流、多步骤任务执行、需回溯的流程。复杂度低到中。易于理解和上手。中到高。需要设计节点和边但表达能力极强。2.3 演进关系从 Chain 到 GraphLangGraph 的出现代表了 LangChain 生态对更复杂应用场景的回应。早期 LangChain 的Agent实现其实已经包含了类似图的循环执行逻辑但不够直观和灵活。LangGraph 将这种模式抽象成第一公民first-class citizen提供了更规范、更强大、更可视化的方式来构建智能体和复杂工作流。简单说当你觉得用 Chain 拼接起来很别扭、需要写很多胶水代码来处理循环和状态时就该考虑使用 LangGraph 了。3. 环境准备与安装在开始代码实战前我们需要设置好开发环境。本文示例将使用 Python。3.1 基础环境要求Python 版本建议 3.8 及以上。包管理工具使用pip。大模型访问需要一个可用的 LLM API 密钥如 OpenAI, Anthropic, 或本地部署的模型。本文以 OpenAI 为例。IDE任何你喜欢的代码编辑器VS Code, PyCharm 等。3.2 安装依赖我们将安装langchain核心包、用于连接 OpenAI 的langchain-openai、以及langgraph。同时为了更好的开发体验可以安装langchain-cli可选。打开终端执行以下命令# 创建并进入项目目录可选 mkdir langchain-langgraph-demo cd langchain-langgraph-demo # 创建虚拟环境推荐 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Mac/Linux: source venv/bin/activate # 安装核心依赖 pip install langchain langchain-openai langgraph # 安装可选依赖用于本地模型或工具 # pip install langchain-community3.3 设置 API 密钥在代码中直接硬编码密钥是不安全的。推荐使用环境变量。在终端中设置临时# Linux/Mac export OPENAI_API_KEYyour-api-key-here # Windows (Command Prompt) set OPENAI_API_KEYyour-api-key-here # Windows (PowerShell) $env:OPENAI_API_KEYyour-api-key-here在 Python 代码中读取import os from langchain_openai import ChatOpenAI # 从环境变量读取 api_key os.getenv(OPENAI_API_KEY) if not api_key: raise ValueError(请设置 OPENAI_API_KEY 环境变量) llm ChatOpenAI(api_keyapi_key, modelgpt-3.5-turbo)4. 实战对比分别用 Chain 和 Graph 实现对话让我们通过一个具体的例子来感受区别。任务构建一个对话助手它能回答问题并在用户说“告诉我更多”时提供关于上一个话题的更多详细信息。4.1 使用 LangChain Chain 实现略显笨拙用基础的Chain来实现这个“循环”逻辑我们需要在外部手动管理状态对话历史。# 文件chain_conversation.py from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain.memory import ConversationBufferMemory # 初始化模型和内存 llm ChatOpenAI(modelgpt-3.5-turbo) memory ConversationBufferMemory(return_messagesTrue, memory_keychat_history) output_parser StrOutputParser() # 定义提示词模板 prompt_template ChatPromptTemplate.from_messages([ (system, 你是一个友好的助手。根据对话历史回答用户问题。如果用户说‘告诉我更多’请对上一个回答进行扩展和补充。), (placeholder, {chat_history}), # 这里依赖外部传入的历史 (user, {input}) ]) # 构建链 chain prompt_template | llm | output_parser # 模拟对话循环 def chat_with_chain(): print(助手你好我是你的助手。输入‘退出’来结束对话。) chat_history [] while True: user_input input(\n你) if user_input.lower() 退出: print(助手再见) break # 准备链的输入需要手动拼接历史 context {input: user_input, chat_history: \n.join([f{role}: {msg} for role, msg in chat_history])} # 调用链 response chain.invoke(context) print(f助手{response}) # 手动更新历史 chat_history.append((用户, user_input)) chat_history.append((助手, response)) if __name__ __main__: chat_with_chain()痛点分析状态外置对话历史chat_history需要在链的外部chat_with_chain函数中手动维护和格式化。逻辑混合判断用户是否说“告诉我更多”的逻辑被硬编码在系统提示词里模型可能不理解或执行不准确。控制流局限整个流程的“循环”是由外部的while循环驱动的而不是链本身的特性。链本身只是一次性转换。4.2 使用 LangGraph 实现清晰优雅现在我们用 LangGraph 来重构。我们将“回答问题”和“提供更多细节”定义为两个不同的节点并通过条件边来控制流程。# 文件graph_conversation.py from typing import TypedDict, Annotated, Literal import operator from langgraph.graph import StateGraph, END from langgraph.graph.message import add_messages from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # 1. 定义状态结构 class State(TypedDict): # 消息历史LangGraph 提供了专门的注解来处理 messages: Annotated[list, add_messages] # 上一个话题用于“告诉我更多”的场景 last_topic: str # 2. 初始化模型和提示词 llm ChatOpenAI(modelgpt-3.5-turbo) # 节点A普通回答 def answer_node(state: State): prompt ChatPromptTemplate.from_messages([ (system, 你是一个友好的助手。请直接回答用户的问题。), (placeholder, {messages}), (user, {input}) ]) # 获取最新的用户消息 last_message state[messages][-1].content if state[messages] else chain prompt | llm response chain.invoke({messages: state[messages], input: last_message}) # 更新状态添加助手回复并记录话题 return { messages: [response], # add_messages 注解会自动追加到列表 last_topic: last_message # 记录用户的问题作为上一个话题 } # 节点B扩展上一个回答 def elaborate_node(state: State): prompt ChatPromptTemplate.from_messages([ (system, 用户想了解更多关于上一个话题的信息。请对以下话题进行详细扩展和补充说明。), (user, 话题是{topic}) ]) chain prompt | llm response chain.invoke({topic: state[last_topic]}) return {messages: [response]} # 3. 路由函数决定下一个节点 def route_after_answer(state: State) - Literal[elaborate, __end__]: # 检查用户最新的输入 last_user_msg state[messages][-1].content.lower() if state[messages] else if 告诉我更多 in last_user_msg or more in last_user_msg: return elaborate # 前往扩展节点 else: return __end__ # 结束本轮对话 # 4. 构建图 workflow StateGraph(State) # 添加节点 workflow.add_node(answer, answer_node) workflow.add_node(elaborate, elaborate_node) # 设置入口点 workflow.set_entry_point(answer) # 添加条件边从 answer 节点出来后根据路由函数决定去向 workflow.add_conditional_edges( answer, route_after_answer, { elaborate: elaborate, # 如果返回 elaborate跳转到 elaborate 节点 __end__: END # 如果返回 __end__结束 } ) # 从 elaborate 节点出来后直接结束 workflow.add_edge(elaborate, END) # 编译图 app workflow.compile() # 5. 运行图 from IPython.display import Image, display try: # 可视化图结构需要安装 graphviz display(Image(app.get_graph().draw_mermaid_png())) except: print(无法显示图形但图已构建成功。) # 模拟对话 print( 开始 LangGraph 对话 ) initial_state {messages: [(user, 什么是机器学习)], last_topic: } result app.invoke(initial_state) print(f助手回答{result[messages][-1].content}) # 用户要求更多 new_state { messages: result[messages] [(user, 告诉我更多)], # 添加新消息 last_topic: result.get(last_topic, ) } result2 app.invoke(new_state) print(f助手扩展{result2[messages][-1].content})优势分析状态内化所有状态对话历史、上一个话题都定义在State对象中并在节点间自动传递和更新。逻辑分离“普通回答”和“扩展回答”是两个独立的节点职责单一易于测试和维护。显式控制流route_after_answer函数和add_conditional_edges清晰地定义了业务逻辑如果用户要求更多就循环到elaborate节点否则结束。这比在提示词里描述逻辑要可靠得多。可视化app.get_graph().draw_mermaid_png()可以生成流程图直观展示应用逻辑对调试和团队沟通极其有利。5. 核心适用场景与选择指南通过上面的对比我们可以总结出各自的“主场”。5.1 优先选择 LangChain Chain 的场景简单的线性任务文档加载-分割-向量化-检索-问答。这种管道式操作用LCEL(LangChain Expression Language) 写成的链非常简洁。快速原型验证当你需要快速测试一个想法比如“用这个提示词和模型能不能完成摘要”一个简单的PromptTemplate | LLM链几分钟就能搭好。无状态或状态简单的应用每次请求都是独立的或者状态可以通过简单参数传递。作为 LangGraph 的“零件”在 LangGraph 中每个节点内部的功能往往就是由一个或多个 LangChain Chain 来实现的。5.2 优先选择 LangGraph 的场景构建复杂的智能体Agent这是 LangGraph 的“杀手级”应用。智能体需要循环执行“思考-行动-观察”的步骤直到任务完成这天然是一个图结构。多轮、有状态的对话系统对话状态用户意图、已填写槽位、历史需要在整个会话中持久化和流转。业务流程自动化例如一个订单处理流程接收订单-检查库存- (有货)创建物流单/ (无货)通知采购-发送确认。其中的分支和节点非常适合用图来定义。需要清晰可视化的工作流当你需要向非技术人员如产品经理解释应用逻辑时一张自动生成的流程图比代码更有说服力。涉及循环和回溯的任务例如一个代码生成助手如果生成的代码有错误可以回溯到“分析错误”节点然后重新进入“生成代码”节点。选择流程图开始 | v 你的应用流程是简单的、线性的吗 -- 是 -- 使用 LangChain Chain |否 v 你的应用需要处理循环、分支、或有复杂的状态吗 -- 是 -- 使用 LangGraph |否 v 从 LangChain Chain 开始随着复杂度增长自然过渡到 LangGraph。6. 常见问题与排查思路在实际使用中你可能会遇到以下典型问题问题现象可能原因排查思路与解决方案ImportError或ModuleNotFoundError1. 包未正确安装。2. 包名或导入路径在新版本中已更改。1. 使用 pip listAPI 密钥错误或模型调用失败1. 环境变量未设置或设置错误。2. 网络问题或 API 服务不可用。3. 模型名称拼写错误或额度不足。1. 在代码中打印os.getenv(“OPENAI_API_KEY”)的前几位确认。2. 尝试用curl或直接requests调用 API 端点测试连通性。3. 登录对应平台检查额度和模型可用性。LangGraph 图编译或运行时报错1.State结构定义与节点返回值不匹配。2. 边Edge指向不存在的节点。3. 节点函数没有返回有效的状态更新字典。1. 仔细核对State的TypedDict定义确保节点返回的字典键名与之匹配。2. 使用app.get_graph().print()打印图结构检查节点和边名称。3. 确保每个节点函数都返回一个字典用于更新状态。智能体陷入死循环1. 结束条件END设置不当。2. 路由逻辑有误导致在两个节点间无限跳转。1. 在 LangGraph 中确保有明确的路径通向END。2. 在路由函数中添加日志或打印语句调试其返回值。3. 为循环设置最大迭代次数例如在状态中维护一个step_count并在路由函数中检查。提示词效果不佳1. 提示词指令不清晰。2. 未提供足够的上下文或示例。3. 系统提示词与用户消息角色混淆。1. 使用ChatPromptTemplate.from_messages清晰区分system,user,assistant,placeholder等角色。2. 遵循最佳实践指令明确、上下文相关、示例具体Few-shot。3. 在 LangChain 生态中可以利用hub.pull()拉取经过社区验证的优质提示词。7. 最佳实践与工程建议将 LangChain/LangGraph 用于生产级项目时请考虑以下建议7.1 项目结构与代码组织分离配置与逻辑将模型配置、API密钥、提示词模板等放在配置文件如config.yaml或环境变量中不要硬编码在业务逻辑里。模块化节点在 LangGraph 中将每个节点Node的实现放在独立的函数或类方法中保持功能单一便于单元测试。使用类型提示为State和节点函数参数添加详细的类型提示如TypedDict,Annotated这能极大提升代码可读性和 IDE 支持。7.2 可观察性与调试启用 LangSmithLangSmith 是 LangChain 官方的调试和监控平台。通过设置环境变量LANGCHAIN_TRACING_V2true和LANGCHAIN_API_KEY可以自动记录每次链和图的调用详情包括输入、输出、中间步骤和耗时是排查问题的利器。日志记录在关键的节点函数、路由函数中添加日志记录状态的变化和决策过程。可视化图定期使用app.get_graph().draw_mermaid_png()导出当前工作流的图片作为文档的一部分。7.3 性能与稳定性缓存对于昂贵的操作如模型调用、向量检索利用 LangChain 内置的缓存如InMemoryCache,SQLiteCache或集成 Redis 等外部缓存避免重复计算。超时与重试为模型调用和外部工具调用配置合理的超时时间和重试策略增强应用的鲁棒性。可以使用tenacity库或 LangChain 的RunnableWithRetry。流式输出对于需要长时间运行的链或图优先支持流式输出Streaming通过chain.stream()或app.stream()逐步返回结果提升用户体验。7.4 生产环境部署状态持久化LangGraph 的State默认在内存中。在生产环境中你需要将其持久化到数据库如 PostgreSQL, Redis。可以通过实现自定义的CheckpointSaver来做到这一点。版本管理对提示词、图的结构、节点逻辑进行版本控制。任何更改都应经过测试并考虑蓝绿部署等策略以平滑升级。权限与安全如果图中有调用外部工具或 API 的节点务必实施严格的权限检查和输入验证防止越权操作或注入攻击。8. 总结与学习路线通过本文的“动画式”拆解相信你已经清晰地理解了 LangChain 与 LangGraph 的关系LangChain 是构建LLM应用的综合性基础框架而 LangGraph 是其生态中专门用于编排复杂、有状态工作流的高级库。它们不是二选一的关系而是相辅相成。你的学习路线可以这样规划入门阶段从 LangChain 开始。掌握Models,Prompts,Chains,Agents这些核心概念用LCEL编写简单的链。完成一个文档问答或总结的小项目。进阶阶段当你的链变得复杂需要处理分支或循环时引入 LangGraph。学习如何定义State、创建Node和Edge构建一个带条件逻辑的智能体。精通阶段深入 LangGraph 的高级特性如持久化检查点Checkpointer、并行执行、子图Subgraph以及如何与LangServe结合快速部署为 API 服务。记住技术选型的核心是匹配场景。对于大多数初创想法一个简单的 LangChain Chain 足以快速验证。当业务逻辑变得复杂和动态时LangGraph 提供的结构化和可视化能力将成为你不可或缺的利器。现在就选择一个你感兴趣的场景动手搭建你的第一个 LangGraph 工作流吧。如果在实践中遇到任何问题欢迎在评论区交流讨论。
返回列表