LangGraph 核心概念全解笔记
一、LangGraph 是什么?
LangGraph 是 LangChain 团队官方推出的基于状态机的智能体 (Agent) 开发框架,它基于 LangChain 生态构建,专门解决了 LangChain 原生 LCEL 链式调用的核心短板,用来构建有状态、可循环、可持久化、支持复杂分支逻辑的 Agent 工作流。
它的核心设计思想是:以「状态」为核心,用「节点 + 边」的图结构编排工作流,天然支持 Agent 所需的「思考 - 行动 - 反思」循环逻辑,是目前 LangChain 生态中构建生产级 Agent 的官方标准方案。
关键补充:LangGraph 不是替代 LangChain,而是 LangChain 生态的补充。LangChain 提供 LLM、工具、向量库、文档加载器等原子组件,LangGraph 负责这些组件的复杂流程编排、状态管理和持久化,两者通常配合使用。
二、LangGraph 核心概念(逐点详解 + 实战示例)
1. State(状态:LangGraph 的灵魂)
State 是 LangGraph 最核心的概念,它是贯穿整个工作流的全局数据容器,工作流中所有节点的输入都来自 State,节点的输出都会更新 State,整个工作流的执行过程就是 State 不断更新的过程。
核心特性
- 强类型定义:通常用
TypedDict或 PydanticBaseModel定义,保证类型安全 - Reducer 机制:通过
Annotated绑定 reducer 函数,定义 State 字段的更新规则,避免手动处理数据合并 - 全链路共享:所有节点都可以读取 / 更新 State,是节点间通信的唯一载体
实战示例(你正在使用的写法)
from typing import TypedDict, Sequence, Annotated from langchain_core.messages import BaseMessage from langgraph.graph import add_messages # 定义State结构 class ReActState(TypedDict): # 消息列表:绑定add_messages reducer,自动实现消息追加,无需手动拼接列表 messages: Annotated[Sequence[BaseMessage], add_messages] loop_count: int # 防死循环计数器 user_id: str # 用户ID,绑定长期记忆 error: str | None # 错误信息,用于异常处理路由关键知识点
add_messages是 LangGraph 内置的最常用 reducer,专门处理消息列表的追加,自动去重、合并消息,是多轮对话的核心- 节点的返回值只需要包含 State 的子集,不需要返回完整的 State,LangGraph 会自动根据 reducer 规则合并到全局 State 中
- 你之前踩过的「HumanMessage 没有 tool_calls」的坑,本质就是 State 中 messages 列表的最后一条消息类型判断错误,属于 State 数据的处理问题
2. Node(节点:工作流的执行单元)
Node 是工作流中的具体执行逻辑单元,对应 Agent 中的一个动作(比如 LLM 思考、工具调用、文档检索、反思校验),本质是一个接收 State、返回 State 更新的纯函数。
节点的 3 种核心类型
| 节点类型 | 作用 | 示例 |
|---|---|---|
| 普通自定义节点 | 实现自定义业务逻辑 | LLM 思考节点、文档检索节点、反思校验节点 |
内置工具节点ToolNode | LangGraph 内置封装,专门处理 LLM 的工具调用 | 你代码中的ToolNode(tools),自动解析AIMessage中的tool_calls并执行工具 |
| 子图节点 | 把一个完整的 LangGraph 图作为节点嵌入到另一个图中 | 多智能体场景中,把单个 Agent 的工作流封装为子图 |
实战示例(你正在使用的写法)
from langchain_core.messages import AIMessage # 自定义节点:LLM思考节点 def llm_think(state: ReActState): """核心思考节点:加载记忆、调用LLM生成回答/工具调用""" messages = state["messages"] user_id = state["user_id"] error = None try: # 加载长期记忆 user_preference = store.get(("user_memory", user_id), "preference") if user_preference: messages = [HumanMessage(content=f'用户偏好:{user_preference.value}')] + messages # 调用LLM response = llm.invoke(messages) except Exception as e: response = AIMessage(content=f"请求失败:{str(e)}") error = str(e) # 返回State的更新,LangGraph自动合并 return { "messages": [response], "loop_count": state["loop_count"] + 1, "user_id": user_id, "error": error } # 内置工具节点 tool_executor = ToolNode(tools, handle_tool_errors=True)3. Edge(边:工作流的流程控制器)
Edge 是连接节点的「桥梁」,定义了工作流的执行顺序和分支逻辑,是 LangGraph 实现循环、条件判断、异常降级的核心。
边的 3 种核心类型
| 边类型 | 作用 | 语法 |
|---|---|---|
| 普通边 | 固定的执行顺序,上一个节点执行完,固定执行下一个节点 | builder.add_edge(START, "llm_think")、builder.add_edge("tool_executor", "llm_think") |
| 条件边 | 核心分支逻辑,根据当前 State 的数据,动态决定下一个执行的节点 | builder.add_conditional_edges("llm_think", should_continue, 路由映射) |
| 起止边 | 特殊的固定边,START代表工作流入口,END代表工作流结束 | builder.add_edge("llm_think", END) |
实战示例(你正在使用的写法)
from typing import Literal from langgraph.constants import START, END # 条件路由函数:接收State,返回下一个节点的名称 def should_continue(state: ReActState) -> Literal["llm_think", "backup_llm_think", "tool_executor", "end"]: # 优先处理异常:有错误则走备用LLM节点 if state.get("error"): if state["loop_count"] < 2: return "backup_llm_think" else: return "end" # 过滤出AI消息,避免HumanMessage没有tool_calls的报错 ai_messages = [msg for msg in state["messages"] if isinstance(msg, AIMessage)] if not ai_messages: return "llm_think" last_message = ai_messages[-1] # 正常流程判断:有工具调用则执行工具,否则结束 if not last_message.tool_calls or state["loop_count"] >= 5: return "end" return "tool_executor" # 构建图时绑定条件边 builder = StateGraph(ReActState) builder.add_node("llm_think", llm_think) builder.add_node("tool_executor", tool_executor) # 入口边 builder.add_edge(START, "llm_think") # 条件边:llm_think执行完后,根据should_continue的返回值路由 builder.add_conditional_edges( "llm_think", should_continue, # 路由映射:函数返回值 → 目标节点 { "backup_llm_think": "backup_llm_think", "tool_executor": "tool_executor", "end": END } ) # 普通边:工具执行完后,回到llm_think,实现ReAct循环 builder.add_edge("tool_executor", "llm_think")4. Checkpointer(检查点:持久化与会话恢复)
Checkpointer 是 LangGraph 内置的状态持久化组件,它会在工作流的每一步执行完成后,自动保存 State 的完整快照(Checkpoint),实现会话恢复、断点续跑、历史回溯。
核心能力
- 会话持久化:服务重启后,通过
thread_id恢复之前的对话状态,实现多轮对话不丢失 - 断点续跑:工作流执行中断后,从断点继续执行,无需从头开始
- 历史回溯:可以查看工作流每一步的 State 变化,方便调试和问题排查
- 时间旅行:支持回滚到历史任意一个检查点,重新执行工作流
常用实现
| 实现类 | 适用场景 | 特点 |
|---|---|---|
MemorySaver | 开发学习、本地测试 | 内存存储,零配置,重启数据丢失 |
RedisSaver | 生产环境、分布式部署 | Redis 持久化,重启不丢数据,支持多实例共享 |
PostgresSaver | 生产环境、企业级部署 | 数据库持久化,支持事务、数据备份 |
实战示例(你正在使用的写法)
from langgraph.checkpoint.redis import RedisSaver from langgraph.checkpoint.memory import MemorySaver # 1. 初始化持久化组件 checkpointer = RedisSaver("redis://localhost:6379/0") # 开发环境用MemorySaver零配置 # checkpointer = MemorySaver() # 2. 编译图时绑定checkpointer react_agent = builder.compile(checkpointer=checkpointer) # 3. 调用时通过thread_id绑定会话,实现持久化 config = {"configurable": {"thread_id": "session_001", "user_id": "user_001"}} # 同一个thread_id的调用,会自动恢复之前的State result = react_agent.invoke({"messages": [HumanMessage(content="你好")]}, config=config)5. Store(存储:跨会话长期记忆)
Store 是 LangGraph 内置的跨会话全局存储组件,和 Checkpointer 互补:
- Checkpointer:存储单会话内的工作流状态,生命周期和会话绑定
- Store:存储跨会话的全局数据,比如用户长期偏好、知识库元数据、全局配置,生命周期和用户 / 业务绑定
核心能力
- 键值对存储,支持命名空间(namespace),实现数据隔离
- 原生集成到 LangGraph 工作流中,节点内可以直接读写
- 支持 Redis、Postgres 等持久化实现
实战示例(你正在使用的写法)
from langgraph.store.redis import RedisStore # 初始化Store store = RedisStore.from_url("redis://localhost:6379/1") # 编译图时绑定store react_agent = builder.compile(checkpointer=checkpointer, store=store) # 节点内读写Store def llm_think(state: ReActState): user_id = state["user_id"] # 读取用户长期记忆 user_preference = store.get(("user_memory", user_id), "preference") # 写入用户长期记忆 store.put(("user_memory", user_id), "preference", "喜欢用摄氏度,偏好简洁回答") ...6. 其他核心概念
- Thread(会话):通过
thread_id唯一标识,对应一个独立的工作流执行实例,是 Checkpointer 隔离不同会话的核心标识。 - Compilation(编译):
builder.compile()把定义好的图结构,转换成可执行的运行时对象,同时绑定 Checkpointer、Store、中断配置等。 - Interrupt(中断):LangGraph 原生支持工作流执行中暂停,等待人工输入 / 审核后继续执行,适合需要人工介入的复杂 Agent 场景。
- Stream(流式输出):支持多种流式模式(
values、updates、messages),可以实时输出工作流的每一步执行结果,提升用户体验。
三、LangGraph vs LangChain 深度对比
3.1 核心差异总表
表格
| 对比维度 | LangChain | LangGraph |
|---|---|---|
| 核心设计范式 | 链式调用(LCEL),线性 DAG(有向无环图) | 状态机,图结构,支持有环图 |
| 流程控制能力 | 仅支持线性执行、简单分支,不支持循环 | 原生支持任意循环、多条件分支、子图嵌套、异常降级 |
| 状态管理 | 无内置全局状态,需要手动传递和管理上下文 | 内置全局 State,自动管理状态更新、合并、持久化 |
| 持久化能力 | 无原生持久化,需要自己实现会话存储 | 原生 Checkpointer 机制,一行代码实现会话持久化、断点续跑 |
| Agent 能力 | 仅支持简单的单轮工具调用,复杂 Agent 需要大量二次开发 | 原生适配 ReAct、Plan-Execute、多智能体等主流 Agent 范式,是 LangChain 官方 Agent 标准方案 |
| 可调试性 | 链式执行黑盒,难以回溯中间步骤 | 每一步都有 Checkpoint 快照,可完整回溯工作流的每一步状态变化 |
| 人工介入 | 无原生支持,需要自己实现中断逻辑 | 原生 Interrupt 机制,支持工作流暂停、人工介入、恢复执行 |
| 适用场景 | 简单线性任务、单轮对话、无状态一次性任务 | 复杂 Agent、多轮对话、有状态工作流、多智能体协作、需要人工介入的场景 |
| 学习曲线 | 低,简单链式调用上手快 | 中,需要理解状态机、图结构的核心概念,上限更高 |
3.2 关键差异详解
循环支持是核心分水岭LangChain 的 LCEL 是无环的线性链,天生无法实现 Agent 最核心的「思考→工具调用→再思考」的循环逻辑。而 LangGraph 基于状态机,天然支持循环,这也是 LangChain 官方推出 LangGraph 的核心原因 ——LCEL 根本不适合构建 Agent。
状态管理的本质区别LangChain 中,上下文需要在链的每个步骤手动传递,多轮对话的状态管理需要自己写代码实现;而 LangGraph 中,State 是全局共享的,所有节点都可以读取和更新,内置的 reducer 机制自动处理数据合并,开发者只需要关注业务逻辑。
生态定位的互补性LangGraph 不是替代 LangChain,而是扩展了 LangChain 的能力边界。LangChain 提供了海量的组件(LLM 集成、工具、向量库、文档加载器等),LangGraph 负责把这些组件编排成复杂、健壮的 Agent 工作流,两者是「原子组件」和「流程编排框架」的关系。
四、什么时候应该使用 LangGraph?
4.1 优先使用 LangGraph 的 7 大场景
构建任何类型的智能体 (Agent)只要你的场景需要 LLM 自主思考、调用工具、多步执行(比如 ReAct 工具调用 Agent、客服 Agent、代码执行 Agent),必须优先用 LangGraph。它原生支持 Agent 的循环逻辑,是 LangChain 官方的标准方案,比自己用 LCEL 封装要简单、健壮得多。
需要多轮对话、会话持久化的场景比如智能客服、个人知识库问答、陪伴式机器人,需要服务重启后用户的对话历史不丢失,LangGraph 的 Checkpointer 一行代码就能实现会话持久化,无需自己开发状态存储。
复杂的非线性工作流比如 RAG + 反思重写、文档审核→纠错→二次审核、多步骤分支判断、错误重试 / 降级兜底,这些场景用 LCEL 很难实现,用 LangGraph 的条件边、节点循环可以轻松搞定。
需要人工介入的场景比如合同审核 Agent 执行到关键步骤需要人工确认、代码生成 Agent 需要人工审核代码后再执行,LangGraph 的 Interrupt 原生支持工作流暂停和恢复,无需自己开发状态暂停机制。
多智能体协作场景比如产品经理 Agent + 开发 Agent + 测试 Agent 协作完成需求开发,LangGraph 的子图、多节点并行执行可以轻松实现多智能体的分工和协作。
需要高可观测性、可调试性的生产级应用生产环境中,你需要知道 Agent 每一步做了什么、为什么出错,LangGraph 的 Checkpoint 机制会保存每一步的完整状态,可以完整回溯执行过程,快速定位问题。
需要断点续跑的长任务场景比如长文档总结、批量数据处理、自动化报告生成,这些长任务如果中途中断,LangGraph 可以从断点继续执行,无需从头开始,节省时间和 Token 成本。
4.2 用 LangChain LCEL 就足够的场景
简单的线性单轮任务比如文本翻译、文案生成、单轮摘要、简单的单轮 RAG(提问→检索→生成回答),没有循环、没有多轮对话、没有分支逻辑,用 LCEL 一行代码就能实现,无需引入 LangGraph。
无状态的一次性任务执行一次就结束,不需要保存状态、不需要多轮对话,比如一次性的文档格式转换、数据清洗、单条数据的标签生成。
快速原型验证想快速验证一个想法的效果,用 LCEL 可以快速搭起一个最简原型,验证通过后,再用 LangGraph 重构为生产级的工作流。
五、LangGraph 最佳实践(结合你的踩坑经验)
State 设计优先先定义好 State 结构,再开发节点和边。State 只保留工作流必须的字段,避免冗余数据;复杂字段一定要绑定 reducer,避免手动处理数据合并出错。
优先用内置组件工具调用优先用内置的
ToolNode,消息管理优先用add_messagesreducer,持久化优先用官方的 Saver 实现,不要自己重复造轮子,避免踩坑。条件边一定要做边界校验条件路由函数中,一定要对 State 的数据做类型校验和空值判断,比如你之前踩过的「HumanMessage 没有 tool_calls」的坑,就是没有先过滤消息类型导致的。
开发用 MemorySaver,生产用 Redis/PostgresSaver开发阶段用
MemorySaver零配置快速迭代,上线生产环境切换到 Redis/PostgresSaver,保证数据持久化。节点职责单一一个节点只做一件事,比如「检索节点」只做文档检索,「生成节点」只做 LLM 调用,不要把多个逻辑写在一个节点里,方便调试和复用。
