LangGraph 实战:把智能体从“串成链“升级为“画成图“
2026/8/29 14:30:42 网站建设 项目流程

这里写自定义目录标题

  • 欢迎使用Markdown编辑器
    • 一、Chain 式 Agent 的困境:为什么多轮任务总是"掉链子"
    • 二、核心转变:把工作流"画"成一张图
    • 三、一个完整的实战:3 小时搭出带记忆的客服助手
    • 生成一个适合你的列表
    • 创建一个表格
      • 设定内容居中、居左、居右
      • SmartyPants
    • 创建一个自定义列表
    • 如何创建一个注脚
    • 注释也是必不可少的
    • KaTeX数学公式
    • 新的甘特图功能,丰富你的文章
    • UML图表
    • 流程图
    • FLowchart流程图
    • 导出与导入
      • 导出
      • 导入

欢迎使用Markdown编辑器

你好! 这是你第一次使用# LangGraph 实战:把智能体从"串成链"升级为"画成图"

一、Chain 式 Agent 的困境:为什么多轮任务总是"掉链子"

如果你做过 Agent 开发,多半遇到过这样的场景:用户先问"我的耳机什么时候到",Agent 查了订单告诉你"已发货";接着用户追问"那能退吗",Agent 突然像失忆一样——“什么耳机?你谁?订单号呢?”。这种"聊着聊着就断片"的现象,几乎是所有用传统 Chain(链)方式构建的 Agent 的通病。

问题出在哪里?表面看是"记忆丢了",根子上却是架构不对。用 Chain 做 Agent,本质上是把一次调用串成一条直线:LLM 输出 → 决定调用哪个工具 → 拿到结果 → 再喂给 LLM。每一步的输入输出都是"一次性"的,状态只能靠手动拼进上下文,控制流只能靠写死的 if-else。一旦任务需要分支、循环、回退,或者中间结果需要"变道",这种线性结构就立刻捉襟见肘。

我曾在客服场景里被这个问题反复折磨:用户连续提问"查订单 → 查退货政策 → 推荐替代品",用 Chain 跑,第一轮还正常,第二轮就开始胡言乱语,第三轮直接报错。一开始我怀疑是模型不行,后来才意识到——问题不在模型,在架构。同一个 LLM,换一种编排方式,表现天差地别。

二、核心转变:把工作流"画"成一张图

LangGraph 给出的解决方案,是抛弃"一条路走到黑"的线性链,把 Agent 的工作流改造成一张有向图。在这张图里:

  • 状态(State)是贯穿全程的"共享黑板",通常是一个字典,存着对话历史、工具输出、下一步要做什么;
    • 节点(Node)是执行单元,本质就是函数——读状态、改状态;
    • 边(Edge)决定节点之间的流转关系;
    • 条件边(Conditional Edge)根据状态里的某个字段(比如"next_action")动态决定下一步是调工具还是直接回答。
      这个设计带来的最大好处,是把控制流从代码里抽离出来。你不再需要写一堆 if-else 去管理"下一步走哪",而是在图上直接画一条带条件的边;后期要调整流程,改个配置就行,不用重构整个 Agent。

更关键的是,这种图结构天然支持循环。Agent 调工具 → 工具返回结果 → Agent 继续决策 → 再调工具……直到完成任务。这在 Chain 里几乎没法优雅实现——你只能手动写个 while True,然后祈祷别死循环。而在图模型里,循环就是图上的一个环,是"一等公民"。

这里我还想补充一点自己的观察:把 Agent 从"链"升级为"图",表面上只是数据结构的变化,实质上是对"任务本质"认知的升级。链式思维假设任务是一条确定性的流水线,而图式思维承认任务是一张充满分支与回环的地图——后者显然更贴近真实世界的工作流。这也是为什么"把 AI 画成图,而不是串成链",正在成为 Agent 工程的主流范式。

三、一个完整的实战:3 小时搭出带记忆的客服助手

光讲概念没有说服力,我们用 LangGraph 完整搭一个带记忆的客服助手。环境版本:Python 3.12、langchain 0.3.x、langgraph 0.2.x。模型用 GPT-4o-mini,温度设为 0,尽量让它"照章办事"而不是自由发挥。

第一步:定义状态。客服助手需要记住"当前用户在问什么订单、查过哪些内容",所以状态里至少要包含对话历史、订单上下文和下一步动作:

fromtypingimportTypedDict,AnnotatedclassAgentState(TypedDict):messages:Annotated[list,add_messages]# 对话历史order_context:dict# 当前订单上下文next_action:str# 下一步动作```**第二步:定义工具。**客服需要三个工具:订单查询、退货政策查询、知识库搜索。在 LangChain 里用 @tool 装饰器定义即可,函数名和 docstring 会成为模型理解"这个工具是干嘛的"的依据。 ```pythonfromlangchain_core.toolsimporttool@tooldefquery_order(order_id:str)->str:"""根据订单号查询订单状态与物流信息"""returndb.get_order(order_id)@tooldefcheck_return_policy(category:str)->str:"""查询某个商品品类的退货政策"""returnpolicy_lookup[category]```**第三步:定义节点与条件边。**这是 LangGraph 的核心。我们设计三个节点:`agent`(LLM 决策)、`tools`(执行工具调用)、`respond`(直接回答)。agent 节点根据 LLM 的输出决定走哪条条件边: ```pythonfromlanggraph.graphimportStateGraph,ENDdefagent_node(state):# LLM 决定是调用工具还是直接回答result=llm_with_tools.invoke(state["messages"])ifresult.tool_calls:return{"messages":[result],"next_action":"tools"}return{"messages":[result],"next_action":"respond"}deftools_node(state):# 批量执行工具调用executed=[]forcallinstate["messages"][-1].tool_calls:executed.append(tool_executor.invoke(call))return{"messages":executed,"next_action":"agent"}graph=StateGraph(AgentState)graph.add_node("agent",agent_node)graph.add_node("tools",tools_node)graph.add_edge("tools","agent")# 工具执行完回到 agentgraph.add_conditional_edges("agent",lambdas:s["next_action"],{"tools":"tools","respond":END})graph.set_entry_point("agent")app=graph.compile()``` 注意 `graph.add_edge("tools","agent")` 和条件边的配合:**tools 永远回到 agent 继续决策**,agent 则根据 next_action 决定是再调工具还是结束。这就构成了一个天然的"思考-行动-观察"循环,而循环的出口由条件边动态控制,不会死锁。**第四步:挂上持久化记忆。**要让 Agent 在"多轮、跨会话"场景下不"失忆",可以把状态存储接入外部持久层(比如 Redis 或 SQLite),每次请求按会话 ID 恢复状态。这样即使用户隔天再回来,Agent 也能记住"这位用户上次问的是哪笔订单"。 这套实现下来,我的体会是:LangGraph 真正解决的,不只是"循环怎么写",更是"Agent 的每一步做了什么、为什么这么做"变得**可观测、可回溯**。节点、状态、边都显式可见,调试时一眼就能看出问题出在决策还是执行环节——这是 Chain 那种"黑盒流水线"完全做不到的。## 四、实战中踩过的坑与避坑建议在把 LangGraph 从 Demo 推向生产的过程中,有几个坑非常典型,值得单独记录。**坑一:把所有逻辑都塞进一个巨大的 agent 节点。**这样做的结果是退化成"带工具的高级 Chain",图的优势荡然无存。正确做法是让节点保持"小且专":一个节点只做一件事,把复杂性交给图结构去表达。**坑二:循环出口设计不清晰。**条件边的判断逻辑如果过于模糊,Agent 容易陷入"工具调用-失败-重试-再失败"的死循环。我的建议是:给节点加**最大轮次上限**,并在工具连续失败 N 次后强制走"抱歉,暂时无法处理"的分支,宁可降级也不能空转。**坑三:忽略状态里的敏感信息。**客服场景的订单上下文里可能包含地址、电话等隐私数据。状态在持久化时务必做脱敏,或者限制只保存完成任务所必需的最小字段。这既是合规要求,也能降低数据泄露的后果。**坑四:混用记忆与状态的概念。**在 LangGraph 里,"状态"是每次图执行的局部变量,而"记忆"是跨任务、跨会话的持久知识。不要把临时状态当长期记忆用,否则状态会越积越大、上下文越来越臃肿,最终拖垮性能和成本。## 五、从客服助手到更复杂的编排这个带记忆的客服助手只是一个起点。图的表达能力远不止于此:你可以在图上并行挂多个节点处理不同任务,可以用子图(Subgraph)把一个完整流程封装成可复用的"积木",还可以结合条件边实现"路由分流"——把问题按难度分给不同能力的模型。 事实上,LangGraph 这类"图编排"思想的普及,正在悄悄改变整个 Agent 工程的面貌:开发者从"串代码"转向"画流程",Agent 从"不可控的黑盒"走向"可观测的白盒"。对于想要把智能体真正用起来的团队来说,这可能是今年最值得投入的工程范式之一。**Markdown编辑器**所展示的欢迎页。如果你想学习如何使用Markdown编辑器,可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。## 新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:1.**全新的界面设计**,将会带来全新的写作体验;2.在创作中心设置你喜爱的代码高亮样式,Markdown**将代码片显示选择的高亮样式**进行展示;3.增加了**图片拖拽**功能,你可以将本地的图片直接拖拽到编辑区域直接展示;4.全新的**KaTeX数学公式**语法;5.增加了支持**甘特图的mermaid语法[^1]**功能;6.增加了**多屏幕编辑**Markdown文章功能;7.增加了**焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置**等功能,功能按钮位于编辑区域与预览区域中间;8.增加了**检查列表**功能。[^1]:[mermaid语法说明](https://mermaid.js.org/intro/)## 功能快捷键撤销:<kbd>Ctrl/Command</kbd>+<kbd>Z</kbd>重做:<kbd>Ctrl/Command</kbd>+<kbd>Y</kbd>加粗:<kbd>Ctrl/Command</kbd>+<kbd>B</kbd>斜体:<kbd>Ctrl/Command</kbd>+<kbd>I</kbd>标题:<kbd>Ctrl/Command</kbd>+<kbd>Shift</kbd>+<kbd>H</kbd>无序列表:<kbd>Ctrl/Command</kbd>+<kbd>Shift</kbd>+<kbd>U</kbd>有序列表:<kbd>Ctrl/Command</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd>检查列表:<kbd>Ctrl/Command</kbd>+<kbd>Shift</kbd>+<kbd>C</kbd>插入代码:<kbd>Ctrl/Command</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd>插入链接:<kbd>Ctrl/Command</kbd>+<kbd>Shift</kbd>+<kbd>L</kbd>插入图片:<kbd>Ctrl/Command</kbd>+<kbd>Shift</kbd>+<kbd>G</kbd>查找:<kbd>Ctrl/Command</kbd>+<kbd>F</kbd>替换:<kbd>Ctrl/Command</kbd>+<kbd>G</kbd>## 合理的创建标题,有助于目录的生成直接输入1<kbd>#</kbd>,并按下<kbd>space</kbd>后,将生成1级标题。输入2<kbd>#</kbd>,并按下<kbd>space</kbd>后,将生成2级标题。以此类推,我们支持6级标题。有助于使用`TOC`语法后生成一个完美的目录。## 如何改变文本的样式*强调文本*_强调文本_**加粗文本**__加粗文本__==标记文本==~~删除文本~~>引用文本 H~2~Ois是液体。2^10^运算结果是1024.## 插入链接与图片链接:[link](https://www.csdn.net/).图片:![Alt](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hdmF0YXIuY3Nkbi5uZXQvNy83L0IvMV9yYWxmX2h4MTYzY29tLmpwZw)带尺寸的图片:![Alt](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hdmF0YXIuY3Nkbi5uZXQvNy83L0IvMV9yYWxmX2h4MTYzY29tLmpwZw=30x30)居中的图片:![Alt](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hdmF0YXIuY3Nkbi5uZXQvNy83L0IvMV9yYWxmX2h4MTYzY29tLmpwZw#pic_center)居中并且带尺寸的图片:![Alt](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hdmF0YXIuY3Nkbi5uZXQvNy83L0IvMV9yYWxmX2h4MTYzY29tLmpwZw#pic_center =30x30)当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。## 如何插入一段漂亮的代码片[博客设置](https://mp.csdn.net/console/configBlog)页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 `代码片`.```javascript//An highlighted block var foo='bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants 是一个文本转换工具,主要功能是将普通的 ASCII 标点符号自动转换为更美观的印刷体标点符号。例如:

原始符号转换后说明
"引号"“引号”直引号变弯引号
'单引号'‘单引号’直单引号变弯单引号
--两个连字符变短破折号
---三个连字符变长破折号
...三个点变省略号

创建一个自定义列表

Markdown
Text-to-HTMLconversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。1

注释也是必不可少的

Markdown将文本转换为HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb NΓ(n)=(n1)!nN是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.Γ(z)=0tz1etdt.

你可以找到更多关于的信息LaTeX数学表达式here.

新的甘特图功能,丰富你的文章

2014-01-072014-01-092014-01-112014-01-132014-01-152014-01-172014-01-192014-01-21已完成进行中计划一计划二现有任务Adding GANTT diagram functionality to mermaid
  • 关于甘特图语法,参考 这儿,

UML图表

可以使用UML图表进行渲染,例如下面产生的一个序列图:

王五李四张三王五李四张三李四想了很长时间, 文字太长了不适合放在一行.你好!李四, 最近怎么样?你最近怎么样,王五?我很好,谢谢!我很好,谢谢!打量着王五...很好... 王五, 你怎么样?
  • 关于UML图表语法,参考 这儿,

流程图

链接

长方形

圆角长方形

菱形

  • 关于Mermaid语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart.js的流程图语法:

Created with Raphaël 2.3.0开始我的操作确认?结束yesno
  • 关于Flowchart流程图语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到文章导出,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. 注脚的解释 ↩︎

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询