
这篇博客里,我们会了解 LangGraph 是如何工作的。我们还会看到为什么需要它,graph、state、node 和 edge 分别是什么,tool 是怎么工作的、到底由谁调用,memory 和 human-in-the-loop 如何通过一个完整示例串起来,以及在真实世界中什么时候该用它。
我们会涵盖以下内容:
- 什么是 LangGraph?
- 为什么需要 LangGraph?
- LangGraph 里的 Graph 是什么?
- LangGraph 里的 State 是什么?
- Node 和 Edge
- 条件 Edge
- 一个完整示例
- Tool,以及到底由谁调用
- Memory 和持久化
- Human-in-the-loop
- 什么时候使用 LangGraph
我是 Amit Shekhar,Outcome School 创始人。我教过、带过许多开发者,他们的努力让他们拿到了高薪的技术岗位,也帮助许多科技公司解决了各自独特的难题,还创建了许多被顶级公司使用的开源库。我热衷于通过开源、博客和视频来分享知识。
我在 Outcome School 教授 AI 与机器学习。
我们开始吧。
什么是 LangGraph?
LangGraph 是一个框架,帮助我们构建由 LLM 驱动的应用,并把工作组织成一张步骤 graph。
在继续之前,我们先理解一个术语。LLM 是 Large Language Model,也就是大语言模型。ChatGPT 这类工具背后的 AI 模型就是 LLM。我们给它一些文本,它就回给我们一些文本。
现在,我们把这个名字拆开来看,让它更简单。
LangGraph = Lang + Graph
Lang 来自 language,因为我们处理的是语言模型。Graph 是一种把步骤连接起来的方式。所以,LangGraph 就是用结构化方式把语言模型相关步骤连接起来。
简单来说,LangGraph 让我们把一个 AI 应用描述成一组步骤,并控制哪个步骤运行、按什么顺序运行,以及接下来发生什么。
LangGraph 来自 LangChain 背后的同一个团队,并建立在 LangChain 的思路之上,在此基础上加入了 graph、loop 和 branching。我们有一篇详细博客讲 LangChain 是如何工作的,里面深入解释了这一点。
为什么需要 LangGraph?
学习它最好的方式,是看一个例子。
假设我们想构建一个简单的 AI 应用。我们把问题发给 LLM,它给我们一个答案。这很简单。为此我们不需要任何框架。
但真实应用没有这么简单。假设我们正在构建一个客服助手。这个助手必须做很多事。
首先,它必须读取用户消息。然后,它必须判断这个问题是账单问题,还是技术问题。之后,它必须搜索正确的文档。然后,它必须让 LLM 写一段回复。有时候,它还必须在发送之前请人类审批这段回复。
问题就在这里。这些步骤不是一条直线。应用必须做决策。它必须回到前面再试一次。它必须记住之前发生了什么。它必须暂停,等待人类。
如果我们只用普通的 if 和 else 条件来写这些逻辑,代码很快就会变得混乱。它会很难读,也很难修改。
所以,LangGraph 就派上用场了。
LangGraph 让我们把这些步骤和决策清楚地描述成一张 graph。然后它替我们运行这张 graph。它让我们的工作变得更轻松。
LangGraph 里的 Graph 是什么?
在进入 LangGraph 之前,我们必须知道 graph 是什么。
Graph 是一组由线连接起来的点。
简单来说,一张 graph 有两个东西。
- Node:这些是点。每个点都是一项工作。
- Edge:这些是线。每条线都把一个点连接到下一个点。
假设我们画一张小地图。我们有三个圆圈,分别叫 A、B 和 C。我们从 A 画一个箭头到 B,再从 B 画一个箭头到 C。这就是一张 graph。圆圈是 node。箭头是 edge。
我们可以把它画成下面这样:
+-----+ +-----+ +-----+
| A | -----> | B | -----> | C |
+-----+ +-----+ +-----+
node node node
edge edge
这里可以看到,A、B 和 C 是 node,也就是执行工作的方框。它们之间的箭头是 edge,用来告诉 graph 接下来该去哪里。Graph 从 A 开始,移动到 B,然后移动到 C。
再看一张简单的现实世界地图。我们从家出发,然后去办公室,然后再回家。家和办公室是 node。它们之间的路是 edge。
在 LangGraph 里,每个 node 做一些工作,每条 edge 告诉应用接下来去哪里。这是核心思想,其他所有东西都建立在它之上。
LangGraph 里的 State 是什么?
在构建 graph 之前,我们还必须理解另一个重要概念,叫 state。
State 是穿过整张 graph 的共享记忆。
简单来说,state 是一个信息盒子,每个 node 都可以从里面读取,也可以往里面写入。随着应用从一个 node 移动到下一个 node,state 会带着数据一起移动。
假设我们正在处理一个订单。State 可以保存用户消息、购物车里的商品,以及最终回复。Node 1 把用户消息放进 state。Node 2 读取这条消息,并把购物车商品放进 state。Node 3 读取所有内容,然后写入最终回复。
这样,node 之间不需要直接互相调用。它们只需要读写共享 state。State 是把整张 graph 粘在一起的胶水。
我们来看一个简单 state 的代码:
from typing import TypedDict
class State(TypedDict):
message: str
reply: str
这里,我们用 TypedDict 定义了一个 State。TypedDict 只是一个字典,我们在里面声明它会保存哪些值,以及这些值的类型。我们的 state 保存两样东西。message 是用户输入。reply 是我们要生成的答案。这就是会穿过整张 graph 的那个盒子。
Node 和 Edge
现在我们已经理解了 state,接下来学习 LangGraph 里的 node 和 edge。
Node 是一个 Python 函数,它接收当前 state,并返回对 state 的更新。
简单来说,node 就是一项工作。它读取 state,做一些事情,然后返回它想修改的那部分 state。
我们来看一个 node 的代码:
def write_reply(state: State):
user_message = state["message"]
answer = "Thanks for your message: " + user_message
return {"reply": answer}
这里,我们创建了一个名为 write_reply 的 node。它从 state 中读取 message。它构造一个简短回答。然后它返回一个字典,里面包含新的 reply。LangGraph 会接收这个返回值,并用它更新共享 state。这个 node 不会修改其他东西。它只更新自己返回的内容。
现在,我们来理解 edge。
Edge 把一个 node 连接到下一个 node,并告诉 graph 在一个 node 完成之后去哪里。
简单来说,edge 就是步骤之间的箭头。一个 node 完成之后,edge 决定下一个运行哪个 node。
每张 graph 里都有两个特殊点。START 是 graph 开始的地方。END 是 graph 停止的地方。我们把第一个 node 连接到 START,把最后一个 node 连接到 END。
条件 Edge
到目前为止,我们学到的是普通 edge,它总是去同一个下一个 node。但真实应用必须做决策。
所以,条件 edge 就出现了。
条件 edge 是一种根据当前 state 选择下一个 node 的 edge。
简单来说,条件 edge 就像路上的岔路口。根据 state 里的内容,graph 会选择一条路径或另一条路径。
假设用户发来一条消息。我们必须检查它是账单问题,还是技术问题。如果是账单问题,就去 billing node。如果是技术问题,就去 technical node。这个决策由条件 edge 做出。
我们可以把这个岔路画成下面这样:
+------------+
bill | billing |
-------> | node |
+---------+ / +------------+
| route | ----+
| message | \ +------------+
+---------+ -------> | technical |
not bill | node |
+------------+
这里可以看到,route message 这个步骤会查看 state,然后选择一条路径。如果消息里包含 bill 这个词,graph 就会去 billing node。否则,graph 会去 technical node。这就是条件 edge 如何根据 state 让 graph 分支。
我们来看一个条件 edge 函数的代码:
def route_message(state: State):
if "bill" in state["message"]:
return "billing"
return "technical"
这里,我们创建了一个名为 route_message 的函数。它从 state 中读取 message。如果消息里包含 bill 这个词,它就返回文本 billing。否则,它返回文本 technical。LangGraph 会读取这段返回文本,并把 graph 发送到匹配的 node。这样,graph 就可以向不同方向分支。
给你一个小提示
无论你在哪个技术领域工作,都应该熟悉这些主题:
- LLM
- RAG
- MCP
- Agent
- Fine-tuning
- Quantization
我们把这些内容放在了一个视频里:
AI Engineering Explained: LLM, RAG, MCP, Agent, Fine-Tuning, and Quantization
不用停下来现在看——先收藏,等有时间再看。未来的你会感谢现在的你。
现在,我们回到正题。
一个完整示例
现在,把所有内容串起来的最好方式,是从头到尾构建同一个账单示例。
回想一下我们的客服助手。它读取用户消息,判断这条消息是关于账单还是技术问题,然后用正确的团队身份回复。我们已经看过 state 和路由函数。现在,我们一步一步把完整 graph 组装起来。
首先,我们定义 state 和两个 node:
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
message: str
reply: str
def billing(state: State):
return {"reply": "This is the billing team. We will help you with your payment."}
def technical(state: State):
return {"reply": "This is the technical team. We will help you fix the issue."}
这里,我们定义了包含 message 和 reply 的 State。我们创建了两个 node。billing node 会写入来自账单团队的回复。technical node 会写入来自技术团队的回复。我们还导入了 StateGraph,也就是用来创建 graph 的 builder,同时导入了 START 和 END,它们是开始点和停止点。
然后,我们把路由函数拿回来:
def route_message(state: State):
if "bill" in state["message"]:
return "billing"
return "technical"
这里是我们前面见过的同一个 route_message 函数。它从 state 中读取 message。如果消息里包含 bill 这个词,它返回 billing。否则,它返回 technical。这个函数决定接下来运行哪个 node。
之后,我们构建 graph,并把各个部分连接起来:
builder = StateGraph(State)
builder.add_node("billing", billing)
builder.add_node("technical", technical)
builder.add_conditional_edges(START, route_message)
builder.add_edge("billing", END)
builder.add_edge("technical", END)
graph = builder.compile()
这里可以看到完整的连线。我们创建一个 StateGraph,并把 State 传给它。我们用 add_node 添加两个 node。然后,我们用 add_conditional_edges 从 START 添加一条条件 edge,它会调用 route_message 来选择下一个 node。我们从 billing 添加一条 edge 到 END,也从 technical 添加一条 edge 到 END,所以 graph 在回复之后就会停止。最后,我们调用 compile,把这段描述变成可以运行的 graph。
之后,我们用一条账单消息来运行 graph:
result = graph.invoke({"message": "I have a question about my bill"})
print(result["reply"])
这里,我们调用了 invoke,并传入初始 state,其中 message 是一条关于账单的消息。Graph 读取这条消息,条件 edge 把它发送到 billing node,node 写入回复,然后我们拿到最终 state。我们打印其中的 reply。
它会打印下面的内容:
This is the billing team. We will help you with your payment.
运行得很好。消息里有 bill 这个词,所以 graph 自己选择了 billing 路径。
现在,我们用另一条消息来运行 graph:
result = graph.invoke({"message": "My app is not working"})
print(result["reply"])
它会打印下面的内容:
This is the technical team. We will help you fix the issue.
这一次,消息里没有 bill 这个词,所以条件 edge 把 graph 发送到了 technical node。这就是我们一直在构建的同一个账单示例,现在已经从头到尾跑起来了。
我们可以把完整流程画成下面这样:
+------------+
bill | billing | ---> END
-------> | node |
+-------+ / +------------+
| START | ----->+
+-------+ \ +------------+
-------> | technical | ---> END
not bill | node |
+------------+
这里可以看到,graph 从 START 开始。条件 edge 读取 state 里的 message,并选择一条路径。如果消息里包含 bill,graph 就去 billing node。否则,它去 technical node。被选中的 node 会把 reply 写入 state,然后 graph 移动到 END。我们拿回来的最终 state 里,message 和 reply 都已经填好了。
如果你想学习如何构建这类 agent 应用——AI Agent、Agent Architecture、Orchestration and Routing——可以看看 Outcome School 的 AI 与机器学习课程,我们会从零开始构建一个 AI Coding Agent。
Tool,以及到底由谁调用
现在,该学习一个非常重要的概念了,叫 tool。这也是我们经常容易混淆的部分,所以必须仔细读。
首先,我们回忆一下 LLM 到底是什么。LLM 只接收文本,并返回文本。 它不能自己搜索网页。它不能读取我们的数据库。它不能发送邮件。它只能生成文字。
但真实应用需要真实动作。我们可能需要搜索网页、查询订单,或者查看天气。所以,tool 就出现了。
Tool 是一个普通函数,它会执行真实动作,比如搜索网页或读取数据库。
现在,关键点来了,我们必须把它说清楚。
LLM 不会调用 tool。LLM 只会建议使用哪个 tool。
简单来说,LLM 读取用户请求,然后说:“我们应该使用 search tool,输入应该是 weather in Delhi。”这就是 LLM 做的全部事情。它把这个建议作为文本返回。它不会运行任何东西。
我们可以把 LLM 的建议画成下面这样:
tool: search
input: weather in Delhi
这里可以看到,LLM 只是生成了一小段文本。它说出了 tool 的名字和输入。它没有运行 search。它只是给出了一个建议。
那么现在问题来了,谁真正调用 tool?答案是 agent。
简单来说,agent 是围绕 LLM 运行的代码。这里,LangGraph 就是那个 agent。它读取 LLM 给出的建议,调用真正的 tool 函数,拿到结果,然后把结果交回给 LLM。
我们用一个简单类比来理解。把 LLM 想成医生,把 agent 想成药剂师。医生看了病人,然后写处方。医生只是推荐药。医生不会把药交给病人。药剂师读取处方,真正把药给出去。同样,LLM 只是推荐 tool,而 agent 真正调用它。
我们一步一步看这个流程。
- 第 1 步: 用户提出问题。
- 第 2 步: LLM 读取问题,并推荐一个 tool 和一些输入。它不会运行 tool。
- 第 3 步: Agent 读取这个建议,并真正调用 tool。
- 第 4 步: Tool 运行并返回结果。
- 第 5 步: Agent 把结果交回给 LLM。
- 第 6 步: LLM 读取结果,并写出最终答案。
我们可以把这个流程画成下面这样:
user question
|
v
+-----------+
| LLM node | recommends a tool (but does not call it)
+-----------+
|
v
+-----------+
| agent | reads the recommendation
+-----------+
|
v
+-----------+
| tool node | actually calls the tool, gets the result
+-----------+
|
v the result goes back to the LLM node
+-----------+
| LLM node | reads the result and writes the final answer
+-----------+
这里可以看到清楚的分工。LLM node 只负责思考和推荐。Tool node 只负责执行真实动作。Agent 把两者连接起来。LLM 推荐,agent 调用。这是关键思想,我们必须一直记住。
在 LangGraph 里,这和我们前面学到的内容刚好吻合。LLM 是一个 node。Tool 是另一个 node。在 LLM node 之后,一条条件 edge 会检查一件简单的事:LLM 有没有推荐 tool?如果有,graph 就去 tool node,运行 tool,然后带着结果回到 LLM node。如果没有,graph 就带着最终答案去 END。
这就是为什么 LangGraph 非常适合用来构建 agent。它提供了一种清晰方式来运行“推荐、调用、回应”这个 loop。
这种模式,也就是 LLM 说出 tool 名称和输入、agent 负责运行它,叫 function calling。我们有一篇详细博客讲 LLM 中的 function calling 是如何工作的,从头到尾介绍了这件事。
Memory 和持久化
现在,我们来理解一个非常有用的功能,叫 memory。
LangGraph 里的 memory,意思是 graph 可以在多次运行之间记住 state。
简单来说,没有 memory 时,graph 一结束就会忘掉所有东西。有了 memory,graph 可以保存 state,并在之后从同一个地方继续。
假设我们正在构建一个聊天助手。用户说:“My name is Amit”。之后,用户问:“What is my name?”。为了让第二个问题能正常回答,助手必须记住第一条消息。这就是 memory 发挥作用的地方。
在 LangGraph 里,我们用一种叫 checkpointer 的东西来添加 memory。Checkpointer 是一个小帮手,会在每一步之后保存 state。当用户回来时,graph 会加载已保存的 state 并继续。
这样,我们的应用就可以进行长对话,并准确地从上次停下的地方接着走。State 不再丢失。它被持久化了,也就是被安全地存储起来。
Human-in-the-loop
现在,该学习另一个强大的功能了,叫 human-in-the-loop。
Human-in-the-loop 意味着 graph 可以暂停,等待人类检查或批准某一步,然后再继续。
简单来说,有时候我们不希望 AI 完全自主行动。我们希望先有人审查它的工作。
假设我们的助手写了一段给客户的回复,但这段回复涉及退款。我们不想自动发送退款。所以,graph 会暂停,人类审查这段回复,只有批准之后,graph 才继续。
因为 LangGraph 会用 checkpointer 保存 state,所以它可以停在任何 node 等待。人类检查 state、做出决定,然后 graph 从同一个点继续。这让重要工作流具备了控制和安全性。
如果你想深入学习 Agent 中的 tool use、Agent 中的 memory,以及 Multi-Agent Systems,我们会在 Outcome School 的 AI 与机器学习课程 里完整讲解。
什么时候使用 LangGraph
现在,我们已经理解了 LangGraph 是如何工作的。接下来理解什么时候必须使用它。
我把简单 LLM 调用和 LangGraph 的区别整理成表格,方便你根据自己的用例决定该用哪一个。
| 情况 | 简单 LLM 调用 | LangGraph |
|---|---|---|
| 一个问题,一个答案 | 最适合 | 不需要 |
| 多个顺序步骤 | 难管理 | 容易管理 |
| 决策和分支 | 用 if 和 else 会很乱 |
用条件 edge 很清楚 |
| 回头重试 | 困难 | 内置支持 |
| 调用 tool 或执行动作 | LLM 只能建议 | Agent 调用 tool |
| 记住过去的运行 | 需要手动处理 | Checkpointer 负责处理 |
| 暂停等待人类 | 非常困难 | 支持 human-in-the-loop |
这里可以清楚看到这个模式。对于一个问题、一个答案,普通 LLM 调用就够了。但当我们的应用有多个步骤、决策、loop、tool、memory 和人工检查时,LangGraph 会让事情更轻松。
所以,现在我们知道可以在哪里使用 LangGraph 了。
最后,我们用一个简单类比表快速回顾完整流程。它把每个 LangGraph 组件映射到现实世界中的角色,方便我们记住。
| LangGraph 组件 | 现实世界角色 |
|---|---|
| State | 每个人都会往里写的共享笔记本 |
| Node | 执行一项任务的工人 |
| Edge | 从一个工人到下一个工人的路径 |
| Conditional edge | 路上的岔路口 |
| Tool | 像搜索网页这样的真实动作 |
| LLM | 只推荐 tool 的顾问 |
| Agent | 真正调用 tool 的工人 |
| Checkpointer | 保存按钮 |
| Human-in-the-loop | 批准工作的经理 |
这里可以看到,每个技术组件都映射到了我们日常生活中已经熟悉的东西。State 是共享笔记本。Node 是工人。Edge 是路径。条件 edge 是岔路口。Tool 是真实动作。LLM 是只推荐 tool 的顾问,而 agent 是真正调用 tool 的工人。Checkpointer 是保存按钮。Human-in-the-loop 是负责批准的经理。
这就是 LangGraph 的工作方式。我们把 AI 应用描述成由 node 和 edge 构成的 graph,让共享 state 携带数据,用条件 edge 做决策,并用 checkpointer 实现 memory 和人工审批。我们还必须记住 tool 的关键点:LLM 只推荐使用哪个 tool,agent 才真正调用 tool。框架替我们运行 graph,于是我们就有了一种清晰而强大的方式,用非常简单的形式构建复杂 AI 应用。
准备 AI Engineering 面试:AI Engineering Interview Questions
今天就到这里。
谢谢
Amit Shekhar
Founder @ Outcome School
你可以在这里联系我:
关注 Outcome School:
订阅我们的通讯,把最新 AI 和机器学习博客直接送到你的邮箱。