尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LangGraph实战指南:用状态图编排可控的Agent流程

LangGraph实战指南:用状态图编排可控的Agent流程 LangGraph不是又一个模型调用库它是把Agent应用流程画成状态图、再按图执行的编排框架。简单说过去你用普通Python函数一步步把LLM、工具、文本处理串起来现在你把每个处理步骤拆成“节点”用“边”控制它们怎么流转包括分支、循环、并行和子流程。这套思路适合已经写过几轮LLM调用、开始觉得代码难以维护的人也适合想把RAG、工具调用、多轮记忆整合到一个可控流程里的开发者。最值得先了解的不是它有哪些API而是它背后的状态机设计每个节点只做一件事状态集中管理分支和循环都变成图上的显式路线。下面按“先搞清关系→搭最小环境→吃透核心机制→跑一个能落地的Agent→排查问题→梳理学习路径”的顺序拆一遍。内容偏工程实践不会只讲概念。1. 先搞清楚LangGraph在LangChain生态里解决什么问题1.1 LangChain和LangGraph的分工不同LangChain本质上是一个组件集合封装了模型调用、Prompt模板、输出解析、向量数据库、文档加载、工具调用这些高频动作。LangGraph则往上走了一层它关心的是“这些组件按什么顺序执行、在什么条件下跳转、中间状态怎么保存”。可以这样理解LangChain负责把单个零件做好LangGraph负责把整条流水线装配起来。很多人会问LangChain是不是过时了。这个问题其实不太准。LangChain作为组件库依然有用很多LangGraph节点内部还是会用到LangChain的模型封装和消息结构。LangGraph并不是替代LangChain而是在LangChain之上或旁边提供流程编排能力。如果你的项目只是单次问答用LangChain链就够了一旦出现多轮工具调用、条件分支、退出循环直接写链式代码会越来越难维护这时候才需要LangGraph。1.2 LangGraph的能力边界它不负责模型只负责流程LangGraph本身不会替你调用大模型也不会决定用哪个模型。它提供的是状态管理和执行引擎。所谓状态就是一个被图里所有节点共享的字典对象。每个节点读取当前状态计算后返回需要更新的字段LangGraph再把更新合并回状态里然后根据边决定下一步执行哪个节点。这意味着图里的节点可以是任意函数里面可以做LLM调用、普通计算、数据库查询、HTTP请求、文件读写、工具调用。LangGraph只保证执行顺序和状态一致不限制你在节点里做什么。这点很重要。很多人一开始以为LangGraph会自带Agent决策能力实际上它只提供“框架”真正让Agent聪明的还是模型、Prompt、工具和你的流程设计。1.3 MCP在中间扮演什么角色MCP是一个开放协议目标是让LLM应用能够以统一方式发现和调用外部工具、数据源。它解决的不是流程控制而是工具接入标准化问题。一个MCP Server把某个工具封装成标准协议Agent通过协议去调用不必给每个工具单独写一套集成代码。所以LangGraph和MCP不是二选一的关系。LangGraph里可以写一个节点这个节点去调用某个MCP Server暴露的工具也可以让LangChain工具管理器去封装MCP工具。真正的流程控制仍然在LangGraph的图里。了解这个关系之后学习路径会清楚很多先学图结构再学怎么把外部能力接进节点。2. 环境准备与最小LangGraph应用2.1 建议的Python环境和依赖先准备Python环境常见要求是Python 3.10及以上。用虚拟环境跑比较省心避免和系统Python混在一起。依赖方面至少需要langgraph如果计划接入大模型还需要对应的模型SDK比如langchain-openai或者直接用openai库。安装命令很简单pip install langgraph langchain-openai如果你的机器网络下载慢换成国内镜像源是常规操作。安装完成后建议先跑一下版本确认python -c import langgraph; print(langgraph.__version__)能正常输出版本号说明环境基本可用了。后面如果代码里某个API找不到先确认你安装的版本是否比较新不要一上来就怀疑代码写错了。2.2 最小案例节点、State和图LangGraph的核心API围绕三类对象State、节点函数、图。State用TypedDict定义表示整个流程共享的数据结构。节点函数接收当前state返回一个字段更新字典。图中通过add_node注册节点通过add_edge定义节点之间的连线。下面是一个最简单可运行的例子from typing import TypedDict from langgraph.graph import StateGraph, START, END class State(TypedDict): input_text: str output_text: str def process_start(state: State) - dict: return {output_text: state[input_text].upper()} # 创建图 graph StateGraph(State) graph.add_node(process, process_start) # 连线 graph.add_edge(START, process) graph.add_edge(process, END) # 编译 app graph.compile() # 调用 result app.invoke({input_text: hello langgraph}) print(result)这个例子做了三件事定义状态、注册一个处理节点、让流程从START进入节点再结束。执行结果是一个字典包含input_text和output_text两个字段。先跑通这个最小案例后面加分支、循环和外部调用时才不会被状态更新问题干扰。2.3 为什么先跑最小案例而不是直接上复杂Demo很多人学LangGraph时第一件事就是找一个带Agent、工具调用、向量检索的完整Demo来跑。这个思路能让你快速看到效果但一旦报错你很难判断是环境问题、状态字段问题、还是模型调用问题。我更建议把第一次测试拆成三步先确认环境再跑最小案例最后才往里面加模型和工具。最小案例的价值在于验证三件事依赖能正常导入、图能正常编译、invoke能正常返回。只要这三件事成立后续绝大部分问题都能定位在业务逻辑和参数上。实测中很多“为什么模型没被调用”“为什么分支没走对”的问题最后都回到最基础的图结构和state字段上。3. 核心机制节点、条件路由、循环、子图与并行分支3.1 节点函数怎么写更清晰节点函数是LangGraph的基本执行单元。它接收当前state返回需要更新的字段。这里有一个很容易踩的坑返回的内容代表“对状态的更新”而不是“完整的新状态”。你可以只返回要改的字段LangGraph会做合并。def call_model(state: State) - dict: return {messages: state[messages] [model reply]} def tool_node(state: State) - dict: return {messages: state[messages] [tool result]}节点里不要写太多东西。一个节点只做一件事比如“调用模型”“检索文档”“调用工具”“汇总结果”。因为LangGraph的优势就是让你用图的方式观察每个环节节点里塞太多逻辑图就退化成普通函数链了。3.2 conditional_edge条件路由怎么玩条件路由是LangGraph最常见的进阶功能。它解决的问题是下一步不一定固定需要根据当前状态判断走哪个节点。实现方式是注册一个路由函数这个函数读取state返回某个节点名或节点key。from typing import Literal def route_after_think(state: State) - Literal[need_tool, need_answer]: if state.get(need_tool): return need_tool return need_answer graph.add_conditional_edges( think_node, route_after_think, { need_tool: tool_node, need_answer: final_node, }, )这里第二参数是路由函数第三参数是路由结果到节点名的映射。注意映射的key必须和路由函数返回的字符串完全一致否则会报找不到节点。条件路由的意义在于它把if-else从代码里提出来变成图上可见的一条判断边。调试时只要看状态里哪些字段影响路由函数就能还原决策路径。很多教程里专门拆开讲conditional_edge确实值得重点练一遍因为它是Agent能否灵活决策的关键。3.3 循环Agent为什么能反复调用工具循环是LangGraph区别于普通链式调用的关键能力。典型场景是Agent循环模型判断需要调用工具→执行工具节点→回到模型节点继续判断→直到模型给出最终答案。用图表示就是从某个节点画一条边回到前面的节点形成一个环。# 简单示意工具节点执行完回到模型节点 graph.add_edge(tool_node, model_node)光有环还不够必须考虑退出条件。否则模型一直判断“还需要工具”流程就会卡死。LangGraph本身有递归深度限制。通过invoke参数可以传recursion_limit也可以在自己维护的计数器中控制最大轮数result app.invoke( {input_text: 帮我查一下天气然后回答}, config{recursion_limit: 10} )更稳妥的做法是在循环中维护一个步骤计数达到上限后强制进入最终输出节点。这里不要急着调大递归上限因为卡死通常不是上限不够而是退出条件没有设计好。3.4 子图、并行分支与状态合并当流程越来越长可以把一部分逻辑抽成子图。子图本质是一个可以被整体当作节点来执行的小图。适合用来封装“检索生成”“多轮对话”这类可复用流程。LangGraph官方文档和不少示例都支持这种组合方式。并行分支则适合“同时处理多个相对独立的子任务”。从同一个节点分出多条边到不同节点这些节点会并行执行最后再合并到一个节点。并行分支的坑在于状态合并。多个节点同时往state里同一个字段写值可能出现互相覆盖或行为不确定。建议让不同并行分支更新不同字段最后用一个合并节点汇总。并行很诱人但不要一开始就上。先跑单条任务确认每个分支单独执行都正确再验证并发下的状态合并。很多看似“功能不支持”的问题实际上是并行分支之间在互相覆盖返回值。3.5 核心参数与判断标准在学习和调参阶段我会关注这几个点recursion_limit控制整条链路最多执行多少步防止死循环。并发参数不同后端可能有不同并发配置先小并发验证。checkpointer是否保存会话状态决定多轮对话是否记忆。debug开关是否输出详细日志。判断流程图跑得对不对不是只看最终结果。更有效的指标是每个节点的输入输出是否符合预期、路由函数走到了哪条分支、循环结束在第几步、状态里最终保留了哪些字段。把这些观察点记录下来排查问题会快很多。4. 把一个真正可用的Agent跑起来记忆、RAG、MCP4.1 多轮对话记忆和checkpointerLangGraph的state默认只在一次invoke内有效。要让多轮对话记住历史需要给图配置checkpointer。checkpointer是LangGraph里用于保存和恢复状态快照的组件。本地学习时可以用内存型实现进程一重启就没了生产环境需要换成文件存储或数据库存储。配置方式一般是在compile时传入checkpointerfrom langgraph.checkpoint.memory import MemorySaver checkpointer MemorySaver() app graph.compile(checkpointercheckpointer) # 多轮调用时传入同一个thread_id app.invoke( {input_text: 你好}, config{configurable: {thread_id: session-1}} )多轮对话的关键是thread_id。同一个thread_id下后面调用能读到之前保存的状态。如果你没有传thread_id每次调用会被当成新会话记忆自然不生效。遇到“怎么没有记住刚才的话”时第一时间检查的就是这个。4.2 把RAG检索作为一个独立节点RAG在LangGraph里可以很自然地拆成多个节点用户输入→向量化→检索→组装上下文→生成回答。检索作为一个独立节点的好处是你可以单独替换向量库、单独调试召回结果甚至可以在检索后加一个“是否需要重新提问”的判断节点。一个常见的误区是把检索和生成写在一个节点里。短期看省事但当你需要观察检索结果、调整Prompt、或者增加多轮检索时就会后悔。LangGraph的价值就是让这些环节之间可以插入判断和循环你只有把它们拆开才能用上这种能力。4.3 通过MCP接入外部工具MCP的价值在工具数量多、工具类型杂的时候最明显。传统做法是给每个工具写一套专用调用代码MCP把工具接入变成标准化握手Agent通过MCP协议发现工具有哪些、看描述、用统一格式传参数、再接收结果。在LangGraph图里MCP工具通常不是图的顶层概念而是被封装在一个工具调用节点里的执行能力。流程大概是在外部启动或配置一个MCP Server它暴露工具的调用入口。在LangGraph应用里配置MCP客户端让Agent能发现工具。在工具节点里根据模型返回的工具调用指令执行具体工具。把工具结果作为新消息写回state回到模型节点继续判断。这里的细节不少但先把握住核心MCP负责“工具怎么暴露、怎么调用”LangGraph负责“什么时候调用、调用失败后怎么走、结果回到哪里”。两者结合才能构成完整的Agent工具调用闭环。4.4 MCP和Agent Skill到底有什么区别这个问题热度很高。简单说MCP解决的是工具接入的协议问题是一个“接口层”Skill或者叫Agent Skill、技能包解决的是任务执行模板问题是一个“能力层”。Skill通常包含这个技能适用什么场景、需要哪些提示词、固定流程是什么、可能调用哪些工具、输出怎么整理。它关注的是“怎么把一个复杂任务拆成步骤并稳定复现”。MCP Server只是这个流程里可被调用的其中一个工具来源。两者可以配合Skill定义任务怎么做MCP Server提供Task里需要的工具。如果一个人只装了MCP Server但没有定义任何Skill模型仍然可以按工具调用的方式去用它如果一个人只写Skill不通过MCP接入工具他用普通函数调用也能实现。所以它们不是同一个层级的东西不要混为一谈。4.5 怎么验证Agent真的可用一个Agent项目能跑起来不代表可用。我建议用一组验收用例来判断普通问答不调用工具能否直接回答。工具调用问题需要查数据能否正确选择工具并传参。多轮对话前一轮结果是否影响下一轮。失败处理工具返回错误或超时流程能否降级。长流程超过10步时是否稳定、是否出现状态漂移。验收时不只看最终答案还要看日志和中间状态。把这组用例跑完基本就知道这个Agent离“能交付”还差多远。5. 开发调试与排查链路5.1 观察图的执行过程LangGraph给了状态、节点、边这些概念调试时就要用好它们。最简单的做法是在节点函数里打印当前state的关键字段或者把中间结果写入日志。如果图比较复杂可以输出图的Mermaid结构直观确认边的走向。还有不少项目会接入可观测性工具把每次调用的节点执行序列和token消耗记录下来适合后期做性能分析。学习阶段不用追求完整链路至少保证两点能看每个节点的输入输出能看路由函数实际返回了哪个分支。有了这两点绝大多数流程问题都能定位。5.2 常见报错和排查顺序我把LangGraph初学者最容易遇到的问题整理成一张表现象优先排查点补充建议启动或导入报错Python版本、依赖版本、安装环境用虚拟环境重装依赖确认langgraph版本invoke后没有任何输出图是否编译成功、输入state字段是否齐全先跑最小案例排除环境问题报找不到节点节点名拼写、conditional_edges映射key是否一致用映射字典比对函数返回值分支没走预期路线路由函数读取的字段是否被更新在路由函数里打印state模型调用失败API key、模型名、上下文长度、网络先单独测试模型SDK调用流程长时间不结束退出条件、recursion_limit把递归上限调小先暴露问题工具没有被调用工具描述是否清晰、参数Schema是否匹配用最简工具先验证并行结果丢失多个分支写同一个state字段给每个分支独立字段最后合并排查顺序我一般是这样先看现象再看输入再看日志再看代码逻辑最后才怀疑框架本身。很多时候看起来像是框架的问题实际是state字段没传对、路由key写错或者模型返回格式不符合预期。5.3 从Demo到生产要注意的边界本地Demo跑通之后直接拿去生产会遇到另外一层问题持久化内存型checkpointer不能用于生产需要换数据库或对象存储。超时模型、HTTP工具、长流程都可能有超时需要单独设置。重试工具调用失败后的重试策略要明确否则会出现重复写入。并发批量和多用户并发时资源占用会明显上升先压测。日志要有能追踪单次完整链路的结构化日志。这些不是LangGraph本身能帮你解决的需要在使用它的应用层去设计。如果只是学习和实验内存方式完全够用如果是上线服务这些问题必须在第一天就想清楚。6. 学习路线从入门到能自己画流程6.1 分阶段突破LangGraph学起来最忌讳一上来就啃全部概念。我建议按下面顺序推进最小案例理解state、节点、边、invoke。条件路由用一个二选一分支练手。循环实现一个简化版Agent让模型决定是否调用工具。子图和并行把检索、生成拆成子流程。加记忆用checkpointer实现多轮对话。接真实工具从普通HTTP接口开始再到MCP Server。每一步都保留一个可运行的最小项目不要急着把所有功能堆在一起。我见过不少人一天之内把所有Demo都跑了一遍但换一个新需求仍然不会设计图结构就是因为缺少分阶段的独立思考。6.2 常见误区第一个误区是把LangGraph当成普通流水线把所有节点都设计成“从上往下执行一次”。这样你用不到条件路由和循环也无法体现LangGraph的价值。设计图之前先想清楚你的业务有没有分支节点、有没有需要反复执行的环节、有没有需要并行的子任务。第二个误区是混淆了流程和工具接入。MCP能解决工具接入标准化但它不能替你设计Agent的决策链。LangGraph是编排引擎MCP是工具来源之一LangChain是组件库三者的边界要先分清。第三个误区是报错后乱改参数。例如循环卡住第一反应是调大recursion_limit内容不对第一反应是换模型。实际上大部分问题要回到state、路由和工具返回格式上排查。先把日志和状态输出打开再决定改哪里。6.3 接下来研究什么如果前面这些都已经掌握可以继续往这几个方向深入多Agent协作多个图或子图之间如何通信、如何分派任务。人工确认环节在关键节点插入人工审批适合生产流程。结构化输出让模型返回规范JSON并和state字段绑定。流式输出面向交互场景逐步返回模型生成结果。可观测性把节点执行序列、耗时、token消耗统一记录下来。这些方向在官方文档和社区示例里都有对应场景。学习时不要只盯着新的API更要理解每个模式是为了解决什么业务问题。LangGraph本身就是一个流程设计的表达工具能力上限取决于你对业务的分拆能力和对状态流转的理解。我个人的建议是不管你看的是哪种形式的教程最后一定要自己动手画一张跟你业务相关的流程图出来。画不出来就说明还没真正掌握。LangGraph最值得投入的时间不在API记忆上而在“把模糊需求拆成图结构”这件事上。先跑通单节点再一步一步加条件、加循环、加记忆、加工具这个过程本身就是最快速的入门路线。
返回列表