1. LangGraph 介绍
本文是 LangGraph 系列的第 1 讲,目标是带你从 0 搭建一个能做四则运算的有状态智能体,理解图、节点、边和状态这几个核心概念,为后续 Memory、RAG、多代理等高级用法打下基础。
1.1 基本概述
LangGraph 是由 LangChain 团队开发的底层编排框架和运行时,旨在帮助开发者构建基于大型语言模型(LLM)的复杂、有状态、多主体应用。它将工作流表示为有向图(graph),提供更高的灵活性和控制能力,特别适合循环逻辑、状态管理以及多主体协作的场景(如智能代理、多代理工作流)。
适合读者:已具备基础Python / LangChain知识,想要实现“有状态、可循环、可调试”工作流的开发者。
本讲你将学会:
- 说清LangGraph的基本概念:图、节点、边、状态。
- 用Graph API从零构建一个带工具调用的有状态计算器智能体。
- 看懂START / END / 条件边在工作流中的作用,并能本地运行一个完整示例。
运行环境与版本:
- Python 3.10+
- 推荐:
pip install -U langgraph langchain-core(本文示例基于 LangGraph / LangChain v0.2+,消息类型从langchain_core.messages导入) - 可选:
pip install ipython用于可视化。模型默认使用DeepSeek,也可以替换为 OpenAI / 本地模型,需自行准备 API Key。
官方文档:langchain-ai.github.io/langgraph/
1.2 简单示例
首先安装 LangGraph:
pip install -U langgraph
# Requires Python 3.10+
创建一个简单的“Hello World”示例(可直接运行):
from langgraph.graph import StateGraph, MessagesState, START, END
def mock_llm(state: MessagesState):
return {"messages": [{"role": "ai", "content": "hello world"}]}
graph = StateGraph(MessagesState)
graph.add_node("mock_llm", mock_llm)
graph.add_edge(START, "mock_llm")
graph.add_edge("mock_llm", END)
graph = graph.compile()
graph.invoke({"messages": [{"role": "user", "content": "hi!"}]})
1.3 核心概念:图、节点、边、状态
图结构(Graph Structure)
LangGraph 将应用逻辑组织成一个有向图,其中:
- 节点(Nodes):代表具体的操作或计算步骤,可以是调用语言模型、执行函数或与外部工具交互等
- 边(Edges):定义节点之间的连接和执行顺序,支持普通边(直接连接)和条件边(基于条件动态选择下一步)
状态管理(State Management)
LangGraph 的核心特点是自动维护和管理状态
状态(State)是一个贯穿整个图的共享数据结构,记录了应用运行过程中的上下文信息
每个节点可以根据当前状态执行任务并更新状态,确保系统在多步骤或多主体交互中保持一致性
循环能力(Cyclical Workflows)
与传统的线性工作流(如 LangChain 的 LCEL)不同,LangGraph 支持循环逻辑,这使得它非常适合需要反复推理、决策或与用户交互的代理应用。例如,一个代理可以在循环中不断调用语言模型,直到达成目标。
1.4 核心优势
**持久执行:**内置支持状态的保存和恢复,便于错误恢复和长时间运行的任务
**人机交互:**支持“人在回路”(human-in-the-loop)功能,让人类在关键步骤参与决策
综合记忆:创建有状态的智能体,既有用于持续推理的短期记忆,又具有跨会话的长期记忆。
LangSmith调试:可视化跟踪执行路径、捕获状态转换并提供详细的运行时指标。
**灵活性:**开发者可以精细控制工作流的逻辑和状态更新,适应复杂的业务需求
**多主体协作:**允许多个代理协同工作,每个代理负责特定任务,通过图结构协调交互
1.5 使用场景
LangGraph 特别适用于以下场景:
**对话代理:**构建能够记住上下文、动态调整策略的智能聊天机器人
**多步骤任务:**处理需要分解为多个阶段的复杂问题,如研究、写作或数据分析
**多代理系统:**协调多个代理分工合作,比如一个负责搜索信息、另一个负责总结内容的系统
1.6 与 LangChain 的关系
- LangGraph 是 LangChain 生态的一部分,但它是独立于 LangChain 的一个模块
- LangChain 更擅长处理简单的线性任务链(DAG),而 LangGraph 专注于更复杂的循环和多主体场景
- 你可以单独使用 LangGraph,也可以结合 LangChain 的组件(如提示模板、工具接口)来增强功能
2. 快速入门
本快速入门指南演示了如何使用LangGraph Graph API构建一个“会算数”的简单智能体。
前置准备:Python 3.10+;pip install -U langgraph langchain-core,可选pip install ipython用于可视化。示例默认使用 DeepSeek 模型,如未配置可替换为本地/开源模型并调整init_chat_model。
本示例中将智能体定义为由节点和边组成的图,使用Graph API来驱动执行。
2.1 定义 tools 和 model
我们将使用 DeepSeek 模型,并定义加法、乘法和除法工具。
from langchain.tools import tool
from langchain.chat_models import init_chat_model
model = init_chat_model(
model="deepseek-chat",
model_provider="deepseek"
)
# Define tools
@tool
def multiply(a: int, b: int) -> int:
"""Multiply `a` and `b`.
Args:
a: First int
b: Second int
"""
return a * b
@tool
def add(a: int, b: int) -> int:
"""Adds `a` and `b`.
Args:
a: First int
b: Second int
"""
return a + b
@tool
def divide(a: int, b: int) -> float:
"""Divide `a` and `b`.
Args:
a: First int
b: Second int
"""
return a / b
# Augment the LLM with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)
小检查:此时你可以在 Python 里直接调用add(3, 4)、multiply(2, 5),确认工具函数本身工作正常,再继续后面的图构建。
2.2 定义 State(状态)
图的状态用于存储消息和 LLM 调用次数。
LangGraph 中的状态在智能体执行过程中始终存在。
from langchain_core.messages import AnyMessage
from typing_extensions import TypedDict, Annotated
import operator
class MessagesState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add]
llm_calls: int
这里有两个关键点:
messages:对话历史,是一个“不断追加”的列表;Annotated[..., operator.add]告诉 LangGraph 在每个节点执行完后,把新消息追加到旧消息后面,而不是整段替换。llm_calls:我们自己加的一个“计数器字段”,用来记录当前这条对话中 LLM 被调用了多少次,说明状态不仅能存消息,还能存任意业务相关信息。
2.3 定义模型节点(llm_call)
模型节点llm_call用于调用 LLM,并根据对话内容决定是否调用工具。
from langchain_core.messages import SystemMessage
def llm_call(state: dict):
"""LLM decides whether to call a tool or not"""
return {
"messages": [
model_with_tools.invoke(
[
SystemMessage(
content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
)
]
+ state["messages"]
)
],
"llm_calls": state.get('llm_calls', 0) + 1
}
小检查:你可以临时构造一个简单的state = {"messages": [], "llm_calls": 0}并调用一次llm_call(state),确认不会报错,帮助你在真正接入图之前先验证好这一节点的逻辑。
2.4 定义工具节点(tool_node)
工具节点tool_node用于真正执行工具调用并返回结果。
from langchain_core.messages import ToolMessage , HumanMessage
def tool_node(state: dict):
"""Performs the tool call"""
result = []
for tool_call in state["messages"][-1].tool_calls:
tool = tools_by_name[tool_call["name"]]
observation = tool.invoke(tool_call["args"])
result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
return {"messages": result}
2.5 定义结束逻辑(should_continue)
条件边函数用于根据 LLM 是否发出工具调用来路由到工具节点或终点。
from typing import Literal
from langgraph.graph import StateGraph, START, END
def should_continue(state: MessagesState) -> Literal["tool_node", END]:
"""Decide if we should continue the loop or stop based upon whether the LLM made a tool call"""
messages = state["messages"]
last_message = messages[-1]
# If the LLM makes a tool call, then perform an action
if last_message.tool_calls:
return"tool_node"
# Otherwise, we stop (reply to the user)
return END
补充说明:START:图的入口,首次调用从这里开始。END:图的出口,一旦路由到这里,本次执行就结束,结果返回给调用方。should_continue:就是“路由规则函数”,根据最后一条消息是否包含工具调用,决定下一步是继续走tool_node,还是直接结束。
2.6 构建并编译代理程序
使用StateGraph构建工作流图,并通过compile()方法进行编译:
# Build workflow
agent_builder = StateGraph(MessagesState)
# Add nodes
agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("tool_node", tool_node)
# Add edges to connect nodes
agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
"llm_call",
should_continue,
["tool_node", END]
)
agent_builder.add_edge("tool_node", "llm_call")
# Compile the agent
agent = agent_builder.compile()
# Show the agent
from IPython.display import Image, display
display(Image(agent.get_graph(xray=True).draw_mermaid_png()))
恭喜!您已使用 LangGraph Graph API 构建了您的第一个智能体。
运行本地服务
最后,我们把上面的工作流封装到一个main()函数里,便于直接通过python quickstart.py运行整个示例:
def main():
"""脚本入口:构建图、可选地展示结构,并执行一次示例调用。"""
# 可选:尝试展示工作流图结构(终端环境下失败会自动忽略)
try:
from IPython.display import Image, display # 延迟导入,避免缺少 IPython 时直接报错
img_bytes = agent.get_graph(xray=True).draw_mermaid_png()
print(f"[info] 已生成工作流图像(字节数: {len(img_bytes)}),在 Notebook 中可直接 display。")
# 在纯脚本环境中直接 display(Image(...)) 一般不会有可视化效果,这里仅提示用户
except Exception as e:
print(f"[warn] 跳过图像展示(可能未安装 IPython 或当前环境不支持图像显示):{e}")
# 执行一次示例调用
print("\n[info] 开始执行示例:'Add 3 and 4.'\n")
messages = [HumanMessage(content="Add 3 and 4.")]
result = agent.invoke({"messages": messages})
for m in result["messages"]:
m.pretty_print()
if __name__ == "__main__":
main()
执行结果(预期):
- 控制台提示生成工作流图(纯终端可忽略)。
- 示例调用 “Add 3 and 4.”,返回工具调用
add(3,4),最终回答 “The sum of 3 and 4 is 7。”
2.7 练习与扩展
建议你在本讲结束后尝试完成以下小练习,加深理解:
- 练习 1:新增一个减法工具
仿照
add/multiply定义subtract(a: int, b: int) -> int,并让 LLM 在需要做减法时自动选择这个工具。 - 练习 2:修改系统提示语
把
SystemMessage的内容改成“如遇到除零,请解释错误而不是直接调用工具”,观察 LLM 在输入 “divide 3 by 0” 时的行为是否符合预期。 - 练习 3:打印 LLM 调用次数
在
main()中打印result["llm_calls"],看看一次简单请求中 LLM 被调用了多少次,从而理解“循环 + 工具调用”的执行过程。
小提示:如果你把这三个练习都完成了,说明这一讲你已经不仅“看懂了代码”,而且真正掌握了 LangGraph 的基础用法,可以安心进入下一讲的 Memory 专题。
小结与下一讲预告
本讲完成了:
- 认识 LangGraph 的核心:节点、边、状态,用 Graph API 构建可循环的有状态计算器智能体。
- 理解工具调用在图中的位置:LLM 节点决定是否调用工具,工具节点执行后再回到 LLM。
- 拿到最小可跑通的示例,并了解如何生成可视化图(缺图形环境可跳过)。
下一讲(Memory 专题)将重点讲:
- LangGraph 的内存机制:短期记忆(线程内)与长期记忆(跨线程/跨会话)。
- 用代码实现短期记忆、长期记忆,演示多线程隔离与跨会话复用。
- 常见存储选项对比与示例:内存(MemorySaver / InMemoryStore)、SQLite、MySQL、Redis 等。
请准备:一个可用的数据库环境(SQLite 默认即可,或本地 MySQL/Redis 实例)与连接配置,方便直接实践下一讲。