LangGraph 入门

前面几章我们用 while 循环手写多轮对话与 ReAct(第 6~8 章),流程藏在代码里。一旦叠加"多轮状态、工具循环、会话恢复、危险操作人工审批"这些需求,手写分支会越来越散。LangGraph 是 LangChain 官方的智能体编排框架:把运行过程画成一张"状态图"——节点是处理函数、边是流转规则,循环、状态合并、持久化、人工介入全部由框架托管。本章先装好环境、跑通一个最小图,感受它的写法。

安装与环境变量

基于 Python 3.10+。模型客户端沿用全书约定,从三个环境变量读取配置(示例模型 deepseek-chat 可换成任意 OpenAI 兼容模型):

pip install langgraph langchain-openai
import os
from langchain_openai import ChatOpenAI

# 读取 LLM_API_KEY / LLM_BASE_URL / LLM_MODEL(同前面章节)
model = ChatOpenAI(
    model=os.getenv("LLM_MODEL", "deepseek-chat"),
    api_key=os.getenv("LLM_API_KEY"),
    base_url=os.getenv("LLM_BASE_URL"),
)

最小图:两个节点一条边

把"写初稿 → 润色"拆成两个节点,节点就是普通 Python 函数:

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):            # 状态:贯穿全图的"共享黑板"
    topic: str
    essay: str

def draft(state):                  # 节点 1:写初稿,返回部分更新
    reply = model.invoke(f"用 80 字介绍:{state['topic']}")
    return {"essay": reply.content}

def polish(state):                 # 节点 2:润色
    reply = model.invoke(f"把下面文字改通顺:\n{state['essay']}")
    return {"essay": reply.content}

builder = StateGraph(State)                   # 1. 用状态类型建图
builder.add_node("draft", draft)              # 2. 注册节点
builder.add_node("polish", polish)
builder.add_edge(START, "draft")              # 3. 连边:入口→写稿
builder.add_edge("draft", "polish")           #    写稿→润色
builder.add_edge("polish", END)               #    润色→出口
graph = builder.compile()                     # 4. 编译成可调用对象

result = graph.invoke({"topic": "什么是大模型"})
print(result["essay"])
# 输出:一段润色后的介绍文字(内容由模型生成,每次可能不同)

要点:节点函数签名统一是 f(state) -> dict,收到的是完整状态,返回的是"要改动哪些字段"的部分字典,框架自动合并后再交给下一个节点。执行顺序完全由边决定,draft 一定先于 polish。

四个核心名词

  • State:用 TypedDict 声明的状态结构,所有节点共享读写(下一章重点)。
  • 节点 node:一个处理步骤,本质是普通函数。
  • 边 edge:节点间的流转;条件边按返回值选择下一步去哪。
  • compile():把定义好的图编译为可运行对象,之后可 invoke/stream。

与手写循环对比

需求手写循环(第 6~8 章)LangGraph
运行流程隐式写在 while 里显式节点+边,可读可画
历史消息自己维护 messages 列表状态字段+Reducer 自动累积
循环退出手动 break条件边决定去留
会话恢复自己落库再读回checkpointer 按 thread_id 恢复
人工把关手写 if 拦截interrupt() 挂起,批准后继续

一句话:手写方案适合一两个工具的简单循环;当"循环 + 状态 + 持久化 + 人工介入"同时出现时,把它们变成图的显式要素,代码反而更短、更好维护。

何时用 LangGraph

推荐在以下场景使用:需要多轮工具调用循环(第 18 章)、需要恢复历史会话(第 20 章)、需要危险操作审批(第 19 章)、需要流式输出(第 21 章)、需要把多个子流程组合并行(第 22 章)。只调一次模型、无状态、无工具的简单问答,用第 2~3 章的直接调用即可,不必上框架。

16~22 章内容地图

主题关键 API
16入门与最小图StateGraph、add_node、add_edge、compile、invoke
17状态、Reducer 与条件边TypedDict、add_messages、add_conditional_edges
18用图写 ReActbind_tools、ToolNode
19人工审批interrupt、Command
20持久化与会话checkpointer、thread_id
21流式输出stream、stream_mode
22子图与并行Send、编译子图当节点

常见问题

  • 编译好的图能复用吗?能。builder.compile() 只需一次,之后可反复 invoke/stream,多次调用互不影响。
  • 节点能访问全局变量或读写文件吗?可以,但状态字段应尽量只放可序列化数据(字符串、数字、列表、字典),为后续接 checkpointer 做准备。
  • 节点返回的键没在 State 里定义会怎样?该键会被忽略(部分版本会给出告警),写代码时让返回键与 TypedDict 字段保持一致。
  • 忘了填必填字段就 invoke?框架会报缺字段错误,按 TypedDict 逐项提供输入即可。

小结:LangGraph 用"状态图"显式描述智能体流程——add_node 注册函数、add_edge 连流转、条件边实现分支循环、compile() 编译后 invoke 执行;循环、状态、持久化、人工介入都变成图的零件,接下来几章逐个拆开讲解。

笔记加载中…