ARTICLE DETAIL

资讯详情

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

LangGraph从入门到实战:用状态图掌控Agent流程

LangGraph从入门到实战:用状态图掌控Agent流程 你有没有遇到过这种情况用 LangChain 搭了一个 Agent第一轮调用模型、调用工具都正常但一旦进入多轮任务Agent 就像失忆了一样忘了自己刚才筛过哪些条件同一个工具被重复调用三次甚至在一个循环里出不来。你试着在 Chain 里加 if-else却发现链条越长越难维护。我第一次遇到这个问题时第一反应是模型不够聪明后来才发现问题根本不在模型而在流程结构。LangGraph 之所以值得花时间学不是因为它比 LangChain 更“高级”而是它终于把 Agent 的执行过程从一条线变成了一张图。这个转变听起来不大但它实际改变了处理复杂 Agent 的方式。只要流程还是一条固定链条遇到分支、循环、人工确认、多轮记忆恢复这些问题就会非常别扭而当你把它当成一张图来设计每个节点的输入输出都变得清晰状态由全局数据统一管理条件边负责决定下一步去哪。今天这篇不是要把所有 API 都讲一遍而是想顺着“从入门到项目实战”这条线把真正决定你能不能把它用起来的几个关键点拆开。如果你刚搜到 LangGraph正在纠结它和 LangChain 的区别或者已经被网上各种教程淹没那你应该在这里停下来先把框架搞清楚。1. 为什么 LangChain 解决不了流程控制LangGraph 才把“图”还给了 Agent1.1 LangChain 擅长的是链式调用不是可控循环最早理解 LangChain 的人都会把它当成一个编排框架。提示词模板、模型调用、输出解析、检索、工具调用可以像流水线一样串起来。对于顺序固定的任务比如“用户问题 - 检索 - 拼提示词 - 调用模型 - 输出”它确实很顺手。但 Agent 类任务不是这种线性结构。Agent 需要先判断“要不要调用工具”调用完工具后可能要把工具结果反馈给模型再决定下一步是继续还是结束。这个过程天然是一个循环而且循环次数不是写死的完全取决于中间结果。在 Chain 里模拟这个逻辑通常只能靠外层 Python while 循环去包住整条链或者写一堆 ConditionalChain。短任务还能忍任务一长代码里到处是分支判断整个流程的可读性会迅速下降。你很难一眼看出这个 Agent 到底有多少种结束方式什么情况下会进入死循环每一步依赖哪个字段这时问题不在代码风格而在抽象层级。Chain 的抽象是“串联”它没有把“节点”和“边”作为第一公民。而 LangGraph 把这些变成了核心概念。1.2 LangGraph 的核心抽象State、Node、EdgeLangGraph 的模型其实很朴素就是把流程画成图。图里有三样东西State全局共享的数据结构相当于整个流程的“内存”。每个节点都能读它也能返回需要更新的字段。Node一个函数。这个函数可以调用大模型、执行 Python 逻辑、调工具也可以调用另一个子图。Edge节点之间的连接。普通边表示“执行完 A 一定去 B”条件边表示“根据当前 State 决定去 B 还是 C”。你可以把 LangGraph 理解成把一张流程图变成可执行的程序。每个节点负责一件事节点之间通过边连接运行时的所有信息都放在 State 里。这个设计比 Chain 更接近真实工作流因为真实业务流程本来就有分支、有循环、有异常回退。值得注意的是LangGraph 并不要求你一定用 LangChain 的组件。节点可以是纯 Python 函数State 也可以是任意可序列化结构。图只是一个调度框架真正干活的是节点函数。这意味着学习成本可以拆开先学图本身再学怎么把 LangChain 的模型调用放进去。1.3 LangGraph 和 LangChain 不是二选一而是互补很多人搜“langgraph和langchain的区别”容易把两者放在对立面。实际上LangGraph 更像是 LangChain 生态里针对“复杂 Agent 状态管理”提出的解决方案。它可以继续使用 LangChain 的 ChatModels、Retriever、DocumentLoader 这些组件也可以完全脱离。我的判断是如果你的流程是固定顺序用 LangChain 的 Chain 或直接写函数调用就够了如果流程里存在“根据结果决定下一步”的循环或需要暂停等待人工输入LangGraph 会更合适。它不是取代 LangChain而是在你需要更精细控制流程时补上那块拼图。学习的时候别把它们拆开学最好的姿势是想清楚你要解决的是“串联任务”还是“图状状态流”。2. 从零跑通一张图先别急着抄项目把最小可运行流程吃透2.1 安装与最简工程骨架网上很多 LangGraph 教程一上来就贴一个客服 Agent节点七八个工具五六个新手看完容易产生两个感觉第一这框架真复杂第二完全不知道从哪里开始。我建议你先忘掉那些花哨项目只跑一个最简图。安装很简单pip install langgraph如果你打算复用 LangChain 的模型封装可以再装对应的包比如langchain-openai或langchain-anthropic。但这里先不引入模型只用普通函数这样更容易理解 LangGraph 自己的执行逻辑。一个最简工程通常包含四部分定义 State 结构。编写节点函数。用 StateGraph 把节点和边连起来。编译并运行。2.2 节点函数如何读取和修改 StateLangGraph 的节点函数约定非常关键它接收当前 State返回一个字典字典里的字段会被合并到 State 中。下面是最常见写法from typing import TypedDict class State(TypedDict): messages: list[str] step: int def node_a(state: State): return { messages: state[messages] [A 节点处理过], step: state[step] 1, }这里有几个重点不要直接修改state里的列表再返回应该返回一个新字典。LangGraph 的状态更新默认是“增量合并”的。返回的字段必须存在于 State 定义中。如果返回一个 State 里没有的键虽然可能不会立即报错但后续节点读取时容易出问题。如果节点不需要更新某些字段只返回需要改的字段即可不需要把整个 State 原样返回。很多人第一次跑图时遇到“状态没变”的问题十有八九是节点函数没有return或者返回的键名写错了。这类问题排查方式很简单在节点函数入口打日志打印一下接收到的 State再在出口打印返回的字典一眼就能看出哪一个字段断了。2.3 第一次使用 Graph 编译并运行有了节点函数就可以建图了from langgraph.graph import StateGraph, START, END builder StateGraph(State) builder.add_node(a, node_a) builder.add_edge(START, a) builder.add_edge(a, END) graph builder.compile() result graph.invoke({messages: [], step: 0}) print(result)START和END是特殊节点表示整个图从哪里开始、在哪里结束。compile()会做检查并返回一个可调用的对象。你可以直接invoke()传入初始状态也可以把它接成 HTTP 服务。这个最小流程虽然没有任何“智能”但它把 LangGraph 的执行机制暴露得很清楚从 START 进入节点 aa 更新 State然后走到 END返回最终 State。后面所有复杂能力条件边、循环、子图、并行都是基于这个基础模型加出来的。先把这个流程跑通再开始折腾其他高级功能比一开始就复制大型项目要稳得多。3. 真正的入门分水岭条件路由、循环检测与并行分支3.1 conditional_edge从一个判断函数开始当流程需要“根据当前状态决定下一步去哪”时普通边就不够用了。这时要用条件边add_conditional_edge。最常见的场景是Agent 调用模型后判断它是否想调用工具。如果需要就进入工具节点如果不需要就直接结束。def route_after_llm(state: State): if state.get(need_tool): return tool return end builder.add_node(agent, agent_node) builder.add_node(tool, tool_node) builder.add_conditional_edge( agent, route_after_llm, { tool: tool, end: END, }, )条件边由三部分组成源节点执行完哪个节点后做判断。路由函数接收 State返回一个字符串 key。路径映射把 key 映射到目标节点。这个设计最妙的地方是图结构依然是静态的、可理解的。你在path_map里能看到所有分支去向而不是在函数内部偷偷改流程。LangGraph 的官方文档管这个机制叫 conditional edges网上一些深度教程会把conditional_edge单独拉出来讲因为它确实是 LangGraph 新手容易看懵的地方。我建议你写路由函数时只做一件事判断并返回一个字符串。不要在里面调用模型、写文件、调外部服务那样会让整个图的行为变得非常难追踪。判断逻辑越单纯后续出问题时越好排查。3.2 循环不是 bug而是 Agent 的决策能力LangGraph 的图是允许出现环路的。这跟很多传统工作流引擎默认“必须是无环图”不一样。循环意味着你可以让 Agent 反复调用工具直到满足某个退出条件。举个例子一个数据分析 Agent第一轮先生成 SQL然后执行 SQL发现结果不对就再生成一条新的 SQL再执行直到查询结果符合预期。这种“反思—执行—再反思”的循环在 Chain 里要写递归或 while 循环非常难受在 LangGraph 里只需要让两个节点之间形成回边。但循环能力越强越需要安全阀。常见做法是在 State 里加一个计数器每轮循环 1路由函数里判断超过 N 次就强制结束。否则一旦模型一直认为“需要继续调用工具”你的应用就会被拖进死循环烧 token 不说用户还会看到无响应。如果遇到“图一直不退出”的情况我建议按这个顺序排查先看路由函数里的结束分支是否可达。再看 State 中用于判断的字段是否每轮都正确更新。再看是否存在多个节点之间的成环路径比如 A-B-A但 B 到 A 的条件始终成立。最后看有没有设置 recursion_limit 之类的限制。千万不要一上来就认为是大模型的问题。很多时候是路由函数里用了某个没有更新的状态字段导致判断条件永远不改变。3.3 子图把复杂流程封装成可复用模块随着图越来越大把所有节点都放在同一层会重新变得难维护。LangGraph 允许你把一个编译好的子图当成一个节点放回父图里。子图的好处是可以独立测试。我通常会把业务流程拆成几块输入清洗子图、Agent 调度子图、后处理子图。每块子图只负责自己的内部状态通过输入输出映射与父图通信。这样当整体流程出问题时可以先单独调用子图快速定位是哪一个环节的问题。子图的写法没有太多新概念你只需要在父图里添加一个节点该节点的执行函数就是子图对象的.invoke()。不过需要注意 State 字段的映射父图的字段名和子图的字段名不一定完全一致需要额外处理。如果你刚开始学不要急着用子图。先在一个图里把所有逻辑写明白等节点数量达到十几个、或者发现某些节点组合可以被复用到多个项目时再抽子图。过早拆分会增加阅读成本。3.4 并行分支什么时候用什么时候别用并行分支是指从一个节点同时连接到多个节点多个节点可以并发执行。LangGraph 对这种场景有原生支持但你得想清楚这几个节点之间是否真的没有依赖关系比如你要针对一段文本同时做关键词提取、情感分析、实体识别这三个任务互不影响那就可以并行。但如果一个节点的输入依赖另一个节点的输出就不能并行。并行分支会让性能提升但也会带来两个麻烦。第一State 的并发写入需要小心。多个节点同时返回更新同一个字段时最终结果取决于 reducers 的合并策略这可能不是你预期的。第二调试难度增加。并发环境下日志顺序会乱定位问题更难。我的建议是小规模验证时先全部串行跑通再根据瓶颈决定是否并行。不要为了炫技一上来就并行否则只会徒增排查成本。LangGraph 执行上的并发能力是有价值的但真正的收益通常出现在模型调用耗时较长的场景中。4. 状态管理是 LangGraph 的命门长期记忆、Checkpoint 与 State 修改4.1 节点里修改 State 的正确方式和坑状态管理是整个 LangGraph 最容易被轻视、却又决定成败的部分。很多教程讲条件边、讲子图却不讲清楚 State 到底怎么更新结果新手一写就错。先记住一条规则节点函数里的state参数是当前状态的快照你不应该直接修改它。正确做法是返回一个字典LangGraph 会把这个字典作为增量更新应用到全局状态。比如def node_b(state: State): # 错误 # state[step] 1 # return state # 正确 return {step: state[step] 1}如果需要把多个值追加到一个列表里还可以给 State 字段配置 reducer。LangGraph 的 State 字段支持 reducers比如用operator.add实现列表拼接这样每次更新不再覆盖原值而是自动合并。这是官方文档一个值得反复读的细节。还有人会遇到从图外部修改状态的需求LangGraph 提供了update_state方法。这种能力在“人工审核后改状态”的场景非常有用比如暂停流程等待人工确认审核通过后调用update_state修改某个字段再告诉图继续执行。4.2 短期状态与长期记忆记忆到底存在哪搜索 LangGraph 时“长期记忆”是一个高频关键词。很多人期待框架自带长期记忆其实需要先把“记忆”分清楚。图内 State 是单次运行的短期记忆。它存在于一次invoke过程当中调用结束就没了。如果你要做一个多轮对话 Agent用户第一轮说“我叫张三”第二轮问“我叫什么”单靠图内 State 是记不住的因为第二次invoke是一个全新开始。要让 Agent 具备长期记忆通常有两条路使用 checkpointer 保存每次执行的状态快照。这样同一个对话线程的多次调用可以恢复之前的 State。LangGraph 的 checkpointer 机制就是为了这个目的。把需要长期记住的信息持久化到外部存储比如数据库、向量库或文件。节点每次执行时主动读取和更新这部分外部记忆。更准确地说LangGraph 提供的是“状态持久化”能力而不是“语义长期记忆”。如果你要的是让 Agent 记住用户的偏好那么工程上还是要靠根据用户ID加载记忆、在节点中写回记忆。框架负责流程记忆内容还是要你自己管理。4.3 失败恢复与断点续跑没有 Checkpoint 就不算生产级如果只是本地学习不配 checkpointer 也没问题。但一旦把 LangGraph 放到真实项目里比如一个长时间运行的工作流中间调用模型失败、工具超时、甚至进程重启如果没有 Checkpoint整个流程就得从头再来。Checkpoint 的原理并不复杂图在执行到每个节点之前或之后会把当前 State 保存到一个存储后端。你可以选择内存存储也可以接 Redis、Postgres 等。除了保证流程可恢复它还有一个附带价值支持断点续跑。结合前面说的“人工审核”场景你可以让图在某个节点前暂停把控制权交给人等人工处理完再从暂停的地方继续执行。这在自动化流程里非常重要因为并不是所有决策都适合完全交给模型。LangGraph 官方把这种模式称为interrupt实际用起来非常像“设置一个断点暂停然后恢复”。初次接触可能会觉得有点绕但它解决的问题非常实际把人和机器放在一条可控的流程里而不是让机器一条路走到黑。如果你要长期使用 LangGraph我建议从一开始就考虑接入 checkpointer而不是等项目快上线了再补。因为一旦中间状态变得复杂中途改造的成本会高很多。5. 聊几个搜索时高频出现的问题文档、可视化、Rust 版本5.1 官方文档和中文手册怎么看很多人一开始会去找“langgraph官方手册中文”或“langgraph菜鸟教程”但我的建议是官方文档永远是第一优先中文教程作为辅助。LangGraph 这类框架迭代速度很快中文教程往往基于某个历史版本里面有些 API 可能已经不推荐使用。如果你照着老教程写代码可能会报错或行为不一致。更稳妥的做法是先看官方文档里的核心概念再找最新版本的入门示例最后用中文教程辅助理解“为什么”而不是“怎么做”。另外官方文档的 API 参考非常值钱。比如你想确认add_conditional_edge最新的参数顺序或者某个 reducer 该怎么配置直接查 API 参考比在搜索引擎里找碎片信息更快。5.2 LangGraph 节点流程能不能用 ECharts 可视化“echarts 与 langgraph 能否实现节点可视化”这个问题经常出现在想做 Agent 流程展示的人身上。答案是能但不是 LangGraph 直接生成的。LangGraph 编译后的图结构本身包含节点和边你可以通过相关方法把图结构导出来拿到一份节点列表和边列表。然后把它转成 ECharts graph 类型需要的nodes和links字段再丢给 ECharts 渲染。但要注意这里可视化的是“流程图结构”不是“执行过程的实时状态”。如果你想让用户看到每一步执行到哪个节点、耗时多少、State 变成了什么需要自己在节点函数里埋点记录或者利用 debug 回调把每一步事件推送出来。图结构和运行时 trace 是两回事别混在一起。如果你的需求只是给技术方案画一张清楚的状态图用 ECharts 完全足够。如果要做完整的链路追踪还需要结合日志系统和监控系统ECharts 只是展示层。5.3 有没有 Rust 版本会不会有性能问题有朋友会搜“langgraph 是否有rust 版本”大概是因为觉得 Python 执行效率不够。从当前公开信息来看LangGraph 官方主线还是以 Python 和 TypeScript 生态为主没有听说官方推出 Rust 版本。社区里或许有一些借鉴图思想的项目但成熟度和生态完整性通常还无法和官方版本相比。至于性能我的看法是LangGraph 作为编排层它的主要开销在于状态传递和节点调度但这些相比大模型调用、外部工具请求的耗时通常可以忽略不计。真正影响性能的地方在节点内部比如你在大模型输出解析上用了低效逻辑或者在工具调用里重复请求而不是图引擎本身。所以如果项目里 Python 本身不是瓶颈不必纠结有没有 Rust 版本。如果你确实遇到了极高性能要求优先做节点函数的性能优化或者减少不必要的序列化而不是把编排框架换掉。5.4 从 LangChain 项目迁移到 LangGraph 的三种路径很多人不是从零开始而是已有 LangChain 项目想迁到 LangGraph。到底要不要迁移怎么迁移我的建议分三种情况项目是固定顺序的链式调用没有循环和复杂分支那就不需要迁移。强行换成 Graph 只会增加理解成本。项目已经用到了 AgentExecutor并且你在代码里尝试过手动控制循环、管理消息历史说明你已经在碰 LangGraph 想解决的问题。这时候可以把 Agent 的主循环抽成一个 StateGraph把原来的工具函数、模型调用保留下来逐步迁移。新项目或者还不稳定的小项目建议直接用 LangGraph 搭骨架。即使暂时用不到复杂功能但图的表达能力更强后续加分支、加状态恢复都会自然很多。迁移的关键不是重写代码而是先画图。把当前 Agent 的执行流程用节点和边画下来标出哪些地方有循环、哪些地方需要人工干预然后再对照 LangGraph 的 API 实现。没有这张图你很难判断迁移后到底改进了什么。6. 从入门到项目实战的七天路线以及我给你的省略版6.1 一个稳妥的七天学习节奏但不用真的机械执行项目标题里提到的“七天从小白到大神”其实更适合理解成一个“有节奏的学习计划”而不是真的七天速成。真正能七天从零到有一定实战能力的学习节奏我建议这样切第 1 天掌握 StateGraph 最小流程把节点、边、State 三个概念跑明白。第 2 天重点研究条件路由和循环。自己写一个 2 节点循环在 State 里设置退出条件。第 3 天从单个图拆到子图再用并行分支改善一个简单任务的耗时。第 4 天研究 checkpointer做一个多轮对话状态恢复的例子。第 5 天写一个带工具调用的 Agent能在循环里根据模型输出决定是否调用工具。第 6 天加入人工审核节点用 interrupt/恢复机制模拟人在环流程。第 7 天把整个流程日志、错误重试、持久化补上做一个可部署的最小项目。但实际情况往往是你不需要把 7 天全部走完可能只需要解决一个具体问题。比如你要给现有 Agent 加一个“自动重试”的循环那你只需要学条件路由和循环就够了。把“按项目倒推学习路径”作为原则比按计划机械打卡更重要。6.2 实战示例一个人工审核节点的工作流我强烈建议你做一个带人工环节的小项目因为它能让你同时用上条件边、状态暂停和恢复是 LangGraph 相对其他编排框架最有区分度的能力。场景可以设计成内容审核先用模型对一段文本做风险初筛。如果风险分低于阈值直接自动放行如果风险分较高则进入人工审核队列流程暂停。审核员在外部系统处理完后再通过update_state更新审核结果并让流程继续执行决定是高风险拦截还是正常发布。这个示例的关键点有两个用条件边把低风险文本导向自动通过节点高风险文本导向人工审核节点。在人工审核节点前设置断点让图暂停等待外部输入。你可以暂时不接数据库先只在内存里模拟判断跑通后再把审核结果落库。这个小项目一旦跑通你对 LangGraph 的理解会明显上一个台阶因为你会真正理解“状态可暂停、可恢复”意味着什么。6.3 工程化前必须补的四块拼图如果只是做实验把图跑通就算完。但要拿到项目里用至少还要补四块东西日志与可观测性。每个节点的进入、退出、耗时、状态变化都要有记录。否则一个流程走完出了问题你根本不知道它经过了哪条路径。错误处理与重试。模型调用会超时工具会报错外部 API 会波动。你要决定哪些错误可以重试哪些错误要直接终止哪些需要退回人工处理。权限与安全。不要让 Agent 可以无限调用任意工具。工具列表、调用范围、输出长度都要有控制。尤其在有外部输入的场景要警惕提示词注入。测试与评估。每次改动都可能影响流程走向。准备一组小样本用例覆盖正常路径、分支路径、异常路径每次改完代码都跑一遍比靠肉眼观察稳得多。这四个部分不是 LangGraph 特有的但 LangGraph 把流程集中在一张图上之后做这些事情反而更方便。因为每一步的状态变化都是可追踪的你可以在统一的位置埋点。6.4 适用边界什么项目不建议用 LangGraph最后必须说清楚边界。LangGraph 很强大但不是所有 Agent 项目都适合用。我见过一些人一个简单的单轮问答系统也非要套一个 StateGraph结果代码量翻倍性能没有提升维护还变麻烦。这种场景直接用函数调用或 LangChain Chain 就足够了。同样纯 RAG 管线如果没有分支、没有循环、没有人工介入也没必要引入图。LangGraph 真正值得用的场景通常满足以下至少一条流程中存在循环且循环次数取决于运行时状态。需要根据模型或工具的中间结果做条件分支。需要暂停流程等待人工审核或外部输入。需要跨多次调用的状态持久化或失败后恢复现场。流程复杂度已经高到“画一张图”比“读一堆 if-else”更清晰。如果这些条件都不满足直接写普通代码可能才是更好选择。技术选型最忌讳为了“用了新框架”而强行引入复杂度毕竟图带来的可控性只有在你真正需要控制分支和状态时才体现得出来。我自己第一次在 LangGraph 里把一个死循环用条件边切断时最大感受不是框架神奇而是流程一旦画成图很多原本藏在代码里的问题会变得非常可见。你在哪里进入循环、凭什么条件退出、哪一个状态字段没有更新全部暴露在结构里。这大概就是 LangGraph 真正值得长期关注的原因它不是帮你省掉思考而是把思考沉淀成一张可执行、可恢复、可视化的图。如果你也在折腾 Agent先别急着抄项目试着先画出你自己的第一张状态图。
返回列表