尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

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

LangGraph实战:构建有状态AI智能体工作流,从链式到图式开发范式升级

LangGraph实战:构建有状态AI智能体工作流,从链式到图式开发范式升级 如果你正在尝试构建一个能自主决策、调用工具、并完成复杂任务的AI智能体却发现现有的框架要么过于简单只能做单轮问答要么过于复杂需要自己从头搭建状态机和流程控制那么LangGraph很可能就是你一直在寻找的那个“刚刚好”的解决方案。它不是一个全新的轮子而是对LangChain生态的一次关键性增强将智能体开发从“提示词工程”提升到了“有状态工作流”的维度。很多人误以为LangGraph只是LangChain的一个图形化插件或者一个可视化工具。这是一个典型的认知误区。LangGraph的核心价值在于它引入了一套基于有向图的编程范式让你能用清晰的代码定义智能体的“思考-行动-观察”循环、分支决策和长期记忆。这直接解决了传统链式调用在构建多步骤、带状态、可回溯的智能体时的无力感。本文将彻底拆解LangGraph。我不会只告诉你它是什么而是会聚焦于它解决了什么实际开发痛点并通过一个从零开始的代码实战带你构建一个能联网搜索、分析信息并生成报告的智能体。你会看到借助LangGraph你可以用极少的代码构建出过去需要大量胶水代码才能实现的复杂智能体逻辑。文章后半部分我们还会深入其与MCPModel Context Protocol等新兴协议的集成可能探讨如何让智能体能力边界进一步扩展。1. 为什么你需要关注LangGraph从“链”到“图”的范式升级在LangChain或类似框架中我们最熟悉的概念是“Chain”链。一个链将多个LLM调用或工具调用按顺序组合起来。这对于简单的问答、文本总结很有效。但当你需要构建一个能根据中间结果决定下一步做什么、能记住之前的对话、甚至能处理并行任务的智能体时链就显得力不从心了。传统链式开发的典型痛点状态管理困难你需要手动在函数之间传递和修改一个全局状态字典代码容易变得混乱。循环与分支逻辑复杂实现“如果模型输出包含A则执行步骤X否则执行步骤Y”这样的逻辑需要写很多if-else和循环控制代码。调试难度大当智能体执行路径不符合预期时很难直观地看到整个决策流程和状态变化轨迹。无法优雅处理“人类介入”在智能体运行中暂停并等待用户输入在链式结构中很难实现。LangGraph通过“图”Graph的概念解决了这些问题。在图论中节点Node代表一个执行单元如调用LLM、运行工具边Edge代表执行流的方向。LangGraph允许你显式定义状态使用一个强类型的State对象来管理整个工作流的所有数据。可视化流程你的代码逻辑直接对应一张可可视化的执行图调试和理解变得直观。内置循环与条件边通过conditional_edges和cycles轻松实现智能体核心的“ReAct”Reasoning and Acting模式。支持人工审批节点可以轻松地在流程中插入节点等待外部输入后再继续。简单来说LangGraph让你用声明式的方式定义智能体的“大脑”和“工作流程”而不仅仅是它的“技能”。这对于开发客服助手、数据分析智能体、自动化运维机器人等复杂应用至关重要。2. LangGraph核心概念拆解State, Node, Edge理解LangGraph最关键的是掌握三个核心概念State状态、Node节点和Edge边。我们用一个类比来理解构建智能体就像编写一个游戏剧本。State状态相当于游戏的“存档”。它记录了当前剧本进行到哪一步所有角色变量的当前信息是什么比如“用户问题”、“已收集的资料列表”、“最终答案草稿”。在LangGraph中State通常是一个Python字典或Pydantic模型在工作流的各个节点间传递和修改。Node节点相当于剧本中的“一场戏”。每一场戏有明确的动作比如“向LLM提问”、“调用搜索引擎API”、“解析结果”。在LangGraph中一个Node就是一个函数它接收当前的State执行一些操作调用LLM、工具等然后返回更新后的State。Edge边相当于剧本的“情节走向”。它决定了当前这场戏演完后下一场该演什么。边可以是固定的演完A必演B也可以是有条件的根据LLM的输出决定演B还是C。conditional_edges就是实现智能体自主决策的关键。此外还有一个重要的高级概念Checkpointer。它相当于游戏的“存档系统”能够将State持久化使得一个长对话或长任务可以在中断后从中间状态恢复这是实现智能体“长期记忆”的基础。为了更清晰地对比传统链式开发和LangGraph图式开发的区别我们来看下表特性维度传统链式开发 (如LCEL)LangGraph 图式开发状态管理隐式通过函数参数传递易混乱显式集中定义State对象清晰可控流程控制线性顺序复杂逻辑需手动编码图形化定义支持循环、分支、并行需手动调度可视化困难逻辑分散在代码中天然支持代码即流程图调试便利性困难需加日志跟踪流程容易可追踪每个节点的输入/输出状态适用场景简单、确定性的多步任务复杂、带状态、需决策的智能体工作流心智模型“管道”或“流水线”“状态机”或“工作流引擎”3. 环境准备与安装在开始实战之前我们需要准备好Python环境。LangGraph对Python版本有一定要求建议使用Python 3.8及以上版本。步骤1创建并激活虚拟环境强烈推荐为了避免包依赖冲突始终建议在虚拟环境中操作。# 创建虚拟环境 python -m venv langgraph-env # 激活虚拟环境 # 在 Windows 上 langgraph-env\Scripts\activate # 在 macOS/Linux 上 source langgraph-env/bin/activate步骤2安装核心库我们将安装langgraph以及langchain的核心包。同时为了后续的示例我们还需要安装langchain-openai来调用OpenAI的模型以及langchain-community来使用一些社区工具如网络搜索。pip install langgraph langchain-core langchain-openai langchain-community步骤3设置API密钥我们的智能体需要调用大模型。这里以OpenAI为例你需要准备一个有效的OPENAI_API_KEY。你可以将其设置为环境变量。# 在Linux/macOS的终端中 export OPENAI_API_KEY你的-api-key # 在Windows的PowerShell中 $env:OPENAI_API_KEY你的-api-key安全提醒切勿将API密钥直接硬编码在代码中提交到版本控制系统如Git。在生产环境中请使用安全的密钥管理服务。4. 构建你的第一个LangGraph智能体一个联网搜索分析助手现在让我们动手构建一个具备实用功能的智能体。这个智能体的目标是根据用户输入的问题自动决定是否需要联网搜索。如果需要则执行搜索并整合信息生成回答如果不需要则直接让LLM回答。我们将这个工作流命名为ResearchAgent。4.1 定义智能体的状态State首先我们需要定义智能体工作流中需要维护的所有数据。我们创建一个Pydantic模型来明确定义状态结构。# research_agent.py from typing import TypedDict, List, Optional, Literal from langgraph.graph import END # 定义状态结构 class AgentState(TypedDict): 智能体的状态定义 # 用户输入的问题 question: str # 是否需要搜索由‘路由节点’决定 needs_search: Optional[Literal[yes, no]] # 搜索得到的结果列表 search_results: List[str] # 智能体生成的最终答案 final_answer: str # 当前执行到了哪个节点用于调试和追踪 current_step: str我们使用TypedDict来获得更好的类型提示。状态中包含了从开始到结束所需的所有信息。4.2 创建节点Nodes节点是执行具体工作的函数。我们将创建三个节点路由节点router分析问题决定是否需要搜索。搜索节点web_searcher执行网络搜索并获取结果。回答节点answer_generator综合所有信息生成最终答案。# research_agent.py (续) from langchain_openai import ChatOpenAI from langchain_community.tools import TavilySearchResults from langchain_core.messages import HumanMessage, SystemMessage # 初始化LLM和工具 llm ChatOpenAI(modelgpt-4o-mini, temperature0) # 使用gpt-4o-mini成本较低 search_tool TavilySearchResults(max_results3) # 使用Tavily搜索工具需要其API KEY def router_node(state: AgentState) - AgentState: 路由节点判断问题是否需要联网搜索 print(f[路由节点] 正在分析问题: {state[question]}) # 构建提示词让LLM判断 prompt f 请判断以下用户问题是否需要通过**实时联网搜索**来获取最新、最准确的信息后才能回答。 仅当问题涉及实时新闻、股价、体育比赛结果、最新发布的科技产品参数、当前天气等非静态知识时才需要搜索。 对于历史事实、概念解释、代码编写等基于通用知识的问题则不需要搜索。 用户问题{state[question]} 请只回答“yes”或“no”。 messages [SystemMessage(content你是一个精准的路由判断助手。), HumanMessage(contentprompt)] response llm.invoke(messages) decision response.content.strip().lower() # 确保输出是‘yes’或‘no’ if decision not in [yes, no]: decision no # 默认不搜索 new_state state.copy() new_state[needs_search] decision new_state[current_step] router_node print(f[路由节点] 决策结果: {decision}) return new_state def web_searcher_node(state: AgentState) - AgentState: 搜索节点执行网络搜索 if state.get(needs_search) ! yes: # 如果不需要搜索直接返回原状态 new_state state.copy() new_state[search_results] [] new_state[current_step] web_searcher_node(skipped) return new_state print(f[搜索节点] 正在搜索: {state[question]}) try: # 调用搜索工具 results search_tool.invoke({query: state[question]}) # 提取文本信息 search_texts [result.get(content, ) for result in results] except Exception as e: print(f[搜索节点] 搜索出错: {e}) search_texts [f搜索过程中出现错误: {e}] new_state state.copy() new_state[search_results] search_texts new_state[current_step] web_searcher_node print(f[搜索节点] 获取到 {len(search_texts)} 条结果) return new_state def answer_generator_node(state: AgentState) - AgentState: 回答节点生成最终答案 print(f[回答节点] 正在生成最终答案...) # 准备上下文 question state[question] search_context if state.get(search_results): search_context \n以下是网络搜索到的相关信息\n \n---\n.join(state[search_results]) prompt f 请基于以下信息回答用户的问题。 用户问题{question} {search_context} 请生成一个友好、准确、信息完整的答案。 如果使用了搜索信息请在答案末尾简要说明信息来源。 messages [SystemMessage(content你是一个专业的问答助手。), HumanMessage(contentprompt)] response llm.invoke(messages) new_state state.copy() new_state[final_answer] response.content new_state[current_step] answer_generator_node return new_state4.3 定义边Edges并组合成图节点定义好了现在我们需要用边把它们连接起来并定义执行逻辑。# research_agent.py (续) from langgraph.graph import StateGraph, START # 创建一个图并指定状态类型 workflow StateGraph(AgentState) # 添加节点 workflow.add_node(router, router_node) workflow.add_node(search, web_searcher_node) workflow.add_node(answer, answer_generator_node) # 设置起始边从 START 到 router workflow.add_edge(START, router) # 设置条件边从 router 出来根据 needs_search 的值决定下一步 def decide_after_router(state: AgentState) - str: 路由后的决策函数 if state.get(needs_search) yes: return search # 需要搜索去搜索节点 else: return answer # 不需要搜索直接去回答节点 workflow.add_conditional_edges( router, decide_after_router, # 决策函数 { search: search, # 如果返回‘search’则跳转到‘search’节点 answer: answer # 如果返回‘answer’则跳转到‘answer’节点 } ) # 设置固定边从 search 节点出来后无论结果如何都去 answer 节点 workflow.add_edge(search, answer) # 设置终点answer 节点执行完毕后工作流结束 workflow.add_edge(answer, END) # 编译图得到可执行的应用 app workflow.compile()4.4 运行与测试智能体现在我们的智能体已经构建完成。让我们用两个不同性质的问题来测试它。# research_agent.py (续) if __name__ __main__: # 测试用例1需要搜索的问题实时信息 print( 测试1需要搜索的问题 ) test_state_1 { question: OpenAI今天发布了什么重要消息吗, needs_search: None, search_results: [], final_answer: , current_step: start } # 运行图 final_state_1 app.invoke(test_state_1) print(f\n最终答案\n{final_state_1[final_answer]}\n) print(f执行步骤{final_state_1[current_step]}) print(- * 50) # 测试用例2不需要搜索的问题静态知识 print(\n 测试2不需要搜索的问题 ) test_state_2 { question: 请用Python写一个快速排序算法的示例。, needs_search: None, search_results: [], final_answer: , current_step: start } final_state_2 app.invoke(test_state_2) print(f\n最终答案\n{final_state_2[final_answer][:500]}...\n) # 截取部分输出 print(f执行步骤{final_state_2[current_step]}) print(- * 50)预期执行流程对于问题1router_node会判断为‘yes’流程走向START - router - search - answer - END。对于问题2router_node会判断为‘no’流程走向START - router - answer - END。search节点被跳过。5. 进阶实战为智能体添加“长期记忆”与人工审核基础智能体已经能跑通但在实际应用中我们常常需要两个高级功能记忆和人工干预。LangGraph通过Checkpointer和Interrupt机制原生支持这些功能。5.1 使用Checkpointer实现对话记忆Checkpointer可以将智能体的状态State持久化到数据库或文件中当用户再次发起对话时可以加载之前的状态实现多轮对话的上下文记忆。下面是一个使用内存检查点的简化示例# research_agent_with_memory.py from langgraph.checkpoint.memory import MemorySaver from langgraph.graph import StateGraph, START, END # 1. 创建一个内存检查点生产环境可用数据库 memory MemorySaver() # 2. 在编译图时传入检查点 workflow StateGraph(AgentState, config_schema...) # config_schema用于线程ID workflow.add_node(...) # 添加节点同上例 # ... 添加边同上例 # 使用支持检查点的编译器 app_with_memory workflow.compile(checkpointermemory) # 3. 运行带有线程ID的对话 config {configurable: {thread_id: user_123}} # 每个用户或会话一个唯一thread_id # 第一轮对话 initial_state {question: 什么是LangGraph, ...} result1 app_with_memory.invoke(initial_state, configconfig) print(f第一轮答案: {result1[final_answer][:200]}) # 模拟第二轮对话基于上一轮的记忆状态 # 注意这里我们简单地将新问题放入状态实际中可能需要更复杂的合并逻辑 new_state_for_second_turn result1.copy() new_state_for_second_turn[question] 它和LangChain有什么区别 new_state_for_second_turn[final_answer] # 清空上一轮答案 result2 app_with_memory.invoke(new_state_for_second_turn, configconfig) print(f第二轮答案: {result2[final_answer][:200]})通过thread_id我们可以为不同的对话会话维护独立的状态流实现真正的有状态、多轮交互智能体。5.2 使用Interrupt实现人工审核节点在某些关键步骤例如智能体准备执行一个删除数据库的操作或者发送一封重要邮件我们可能需要暂停流程等待人工确认。LangGraph的interrupt机制让这变得简单。# research_agent_with_interrupt.py from langgraph.graph import StateGraph, START from langgraph.prebuilt import ToolNode import asyncio # 假设我们有一个发送邮件的工具 def send_email(to: str, subject: str, body: str) - str: # 模拟发送邮件 return f邮件已发送至 {to}主题{subject} # 创建一个需要人工审核的节点 def human_approval_node(state: AgentState) - AgentState: 人工审核节点这里会中断流程等待外部输入 print(f\n[人工审核] 智能体准备执行以下操作) print(f操作内容{state.get(pending_action)}) print(流程已暂停等待人工在外部确认...) # 在实际应用中这里会触发一个中断流程挂起。 # 开发者可以通过LangGraph的API如astream_events在外部监听中断事件 # 然后通过update_state注入人工决策例如 {approved: True}。 # 此处为演示我们模拟一个外部输入。 # 真实代码中这里会是一个 raise Interrupt 或类似机制。 # 模拟外部系统注入了批准信号 new_state state.copy() # 假设我们从某个通道如Webhook收到了批准信号 human_decision {approved: True, comment: 人工确认执行} new_state.update(human_decision) new_state[current_step] human_approval_node return new_state # 在图中插入审核节点 workflow StateGraph(AgentState) # ... 添加其他节点 workflow.add_node(human_approval, human_approval_node) # 在‘search’和‘answer’之间插入审核 workflow.add_edge(search, human_approval) workflow.add_edge(human_approval, answer) # ... 编译图 # 注意完整的中断处理需要结合LangGraph的异步流式API和特定的触发器配置以上是概念演示。通过这种方式你可以构建出安全、可控的智能体在关键决策点将控制权交还给人类。6. LangGraph与MCPModel Context Protocol的集成展望MCPModel Context Protocol是另一个近期备受关注的概念。你可以把它理解为大模型的“外挂硬盘”或“插件总线”标准。它旨在标准化大模型与外部工具、数据源如数据库、API、文件系统的连接方式。LangGraph与MCP的关系是互补而非竞争LangGraph负责智能体的**“大脑”和“工作流程”**即如何思考、决策、按步骤执行。MCP负责智能体的**“手”和“感官”**即如何以统一、安全的方式调用成千上万种不同的工具和访问数据。结合场景示例 你可以使用LangGraph来构建一个数据分析智能体的工作流State问题 - 解析意图 - 选择分析工具 - 执行分析 - 生成报告。而这个工作流中“选择分析工具”和“执行分析”的节点可以通过MCP协议动态地发现并调用连接在MCP Server上的各种数据库查询工具、图表生成工具等。目前LangGraph社区已经开始了与MCP的集成探索。未来的最佳实践可能是使用LangGraph编排高阶的、多步骤的智能体流程同时利用MCP来管理和接入低阶的、单一功能的工具。这能让智能体开发更模块化、更安全工具权限通过MCP统一管控、也更易扩展。7. 常见问题与排查思路在实际使用LangGraph时你可能会遇到以下典型问题问题现象可能原因排查方式解决方案app.invoke()报错提示状态字段缺失或类型错误1.State的TypedDict定义与实际传入/返回的字典键不匹配。2. 某个节点没有返回完整的State字典。1. 检查AgentState定义的所有字段是否在每个节点都被正确处理。2. 在每个节点函数开头和结尾打印state确认数据流。确保每个节点函数都返回一个包含所有AgentState键的字典。使用state.copy()并在其上修改是安全做法。条件边conditional_edges不生效总是走固定分支决策函数返回的值与add_conditional_edges中映射的键不匹配。打印决策函数的返回值确认其是‘search’、‘answer’这样的字符串且与映射键完全一致大小写敏感。仔细核对决策函数返回值与add_conditional_edges中dict的键名。使用常量或枚举来避免拼写错误。智能体陷入无限循环图中存在未正确终止的循环。例如从节点A到节点B又从节点B回到节点A且没有终止条件。使用workflow.get_graph().draw_mermaid()输出流程图可视化检查循环路径。确保每个循环路径都有明确的退出条件通过条件边指向END。对于ReAct模式通常设置最大迭代次数。调用工具如搜索时超时或报错1. 工具API密钥未设置或无效。2. 网络问题。3. 工具返回格式不符合预期。1. 检查相关环境变量如TAVILY_API_KEY。2. 用try...except包裹工具调用打印具体错误。3. 单独测试工具调用。配置正确的API密钥。为工具调用添加重试和超时机制。在节点中做好错误处理将错误信息放入State供后续节点处理。无法实现多轮对话记忆没有正确配置和使用Checkpointer。检查是否在compile()时传入了checkpointer参数以及每次调用invoke时是否使用了相同的config含thread_id。参考第5.1节正确初始化MemorySaver或SqliteSaver等检查点并确保会话ID一致。图结构复杂后代码难以维护所有节点和边定义在一个文件里逻辑耦合度高。-采用模块化设计将不同的节点函数放在不同的模块中将图的构建过程封装成工厂函数为复杂子图创建嵌套子图StateGraph可以作为另一个图的节点。8. 最佳实践与工程建议将LangGraph用于生产级智能体开发时遵循以下实践能让你事半功倍状态设计精益化State应只包含工作流必要的数据。避免将临时变量或大型对象如图片二进制流直接塞入State可以考虑存入外部存储如S3在State中只保留引用ID。节点职责单一化每个节点应只做一件事并把它做好。例如一个节点专门调用LLM另一个节点专门解析LLM的输出。这提高了可测试性和复用性。充分利用可视化在开发调试阶段多用workflow.get_graph().draw_mermaid()生成流程图。这能帮你快速理解逻辑是否正确也是向团队解释智能体行为的最佳文档。实现可观测性在生产环境中需要在关键节点记录日志、指标和追踪信息。可以创建一个装饰器来自动记录每个节点的输入、输出和耗时方便监控和故障排查。版本化与测试将智能体工作流图定义像代码一样进行版本控制。为复杂的图编写单元测试和集成测试模拟不同的输入状态验证执行路径和输出是否符合预期。安全边界对于能执行写操作如发邮件、改数据库的工具调用务必通过interrupt机制或严格的权限校验节点进行管控。永远不要相信LLM的输出是绝对安全的。性能考量对于耗时长的节点如大量文档检索考虑异步执行。对于高并发场景注意检查点存储如数据库可能成为瓶颈需要进行压测和优化。LangGraph代表了一种更工程化、更可控的智能体开发范式。它没有让智能体开发变得更简单而是让它变得更清晰、更可维护。当你需要构建超越简单问答的、具备复杂逻辑和状态管理的AI应用时LangGraph提供的这套基于图的编程模型是目前最值得深入学习和使用的工具之一。从今天这个联网搜索助手的例子开始尝试用它去设计一个属于你自己的、能够解决实际业务问题的智能体工作流吧。
返回列表