LangGraph 入门:第一个智能代理
理解 LangGraph 状态图、节点编排和 Checkpoint 持久化。
LangGraph 入门:搭建第一个智能代理
为什么从 ReAct 升级到 LangGraph
LangChain 的 ReAct 循环(Think → Act → Observe)在简单场景下够用,但一旦需要条件分支、循环控制、多角色协作,它的线性结构就显得力不从心。LangGraph 用图结构定义 Agent 执行流程,让复杂 Agent 的设计和调试都清晰很多。
核心概念
StateGraph = 状态 + 节点 + 边
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
# 1. 定义状态
class SearchState(TypedDict):
query: str
results: List[str]
refined: bool
# 2. 创建图
graph = StateGraph(SearchState)
# 3. 添加节点
def search(state: SearchState) -> SearchState:
results = search_engine(state["query"])
return {"results": results}
def refine(state: SearchState) -> SearchState:
better_query = rewrite_query(state["query"])
return {"query": better_query, "refined": True}
graph.add_node("search", search)
graph.add_node("refine", refine)
# 4. 添加条件边
def check_results(state: SearchState) -> str:
if not state["results"] and not state["refined"]:
return "refine" # 结果为空则优化搜索
return END # 有结果则结束
graph.add_conditional_edges("search", check_results)
graph.add_edge("refine", "search")
graph.set_entry_point("search")
# 5. 编译
app = graph.compile()
状态驱动
LangGraph 的核心设计理念:节点读取状态 → 处理 → 更新状态 → 条件边决定下一个节点。状态是整个图的"共享内存",每个节点可以读取和写入。
关键点:
- 状态类型通过
TypedDict定义,类型安全 - 节点函数接收当前状态,返回要更新的字段(不是完整状态)
- 条件函数返回字符串,匹配边的命名
节点(Node)
节点可以是:
- 普通函数:同步处理,适合数据转换、API 调用
- Async 函数:异步处理,适合 LLM 调用
- Runnable:LangChain 的可运行对象
边(Edge)
- 普通边:无条件从一个节点到另一个节点
- 条件边:根据条件函数的返回值决定目标节点
- 入口边:指定起始节点
首次调试经验
LangGraph 的调试不像普通 Python 函数那样简单——状态在节点间传递,很难直观看到中间结果。解决方法是开启 LangGraph 的 debug 模式:
app = graph.compile(debug=True)
这个模式会在每次节点执行后打印状态变化,对理解执行流程帮助很大。
另一个实用技巧:在节点函数中打印关键状态字段,也就是"手动插桩",简单但有效。
使用场景
LangGraph 适合的典型场景:
- 多步骤问答:理解问题 → 检索知识 → 生成回答 → 验证回答
- 条件分支 Agent:根据中间结果决定下一步策略
- 循环执行:错误重试、迭代优化
- 人机协作:AI 处理→人工确认→继续执行
总结
LangGraph 把 Agent 从"一个怎么都调不好的提示词"变成了"一个可设计、可调试的图执行引擎"。虽然入门门槛比 ReAct 高一些,但对于生产级的 Agent 应用来说,这个投入是值得的。