第一章:核心认知与基础概念
1.1 LangGraph 的定位
- 本质 :Agent Server 的"操作系统内核"。它不关心具体模型或提示词,专门解决构建复杂 AI 应用时的底层工程难题:状态管理、流程编排、持久化、人工监督。
- 三大超能力 :
- 记忆大师:自动保持多轮对话上下文,支持跨会话记忆。
- 流程指挥官:将复杂任务拆解为可控的步骤(图结构)。
- 容错卫士:支持故障恢复、人工中断、生产级持久化。
1.2 核心概念区分
- 工作流(Workflow):流程固定、步骤预设(如客服工单处理)。
- 智能体(Agent):由 LLM 动态控制流程走向,灵活应对开放问题。
- LangGraph 的核心 :本质是构建工作流图(Graph),但可通过条件路由模拟智能体行为。
1.3 图计算三要素
- 节点(Node):处理步骤(函数)。
- 边(Edge):流转路径(固定或条件)。
- 状态(State):节点间共享的数据容器。
第二章:图构建核心实操
2.1 定义状态(State)与 Reducer(归约器)
知识点 :所有节点共享 State。
Annotated+operator.add实现列表追加/数值累加,而非覆盖。
python
from typing import TypedDict, Annotated
import operator
class OverallState(TypedDict):
# 列表使用 operator.add,每次更新会追加,而非替换
messages: Annotated[list, operator.add]
# 普通字段默认覆盖(替换)
user_name: str
# 数值使用 operator.add,实现累加
total_score: Annotated[int, operator.add]
2.2 定义节点与边(固定边 + 条件边)
知识点 :节点是接收 state 返回部分更新的函数。
START是入口,END是终止。条件边通过路由函数动态选择下一节点。
python
from langgraph.graph import StateGraph, START, END
# 1. 定义节点函数
def step_a(state: OverallState):
# 返回的字典会根据 Reducer 规则合并
return {"messages": ["A 节点执行"], "total_score": 10}
def step_b(state: OverallState):
return {"messages": ["B 节点执行"], "total_score": 20}
# 2. 构建图
builder = StateGraph(OverallState)
builder.add_node("step_a", step_a)
builder.add_node("step_b", step_b)
# 固定边:START -> A -> B
builder.add_edge(START, "step_a")
builder.add_edge("step_a", "step_b")
# 条件边:根据分数决定是否提前结束
def route_decision(state: OverallState) -> str:
if state.get("total_score", 0) > 100:
return "step_b" # 继续到 B
return END # 直接结束
builder.add_conditional_edges("step_a", route_decision)
# 3. 必须编译才能运行
graph = builder.compile()
2.3 高级状态管理
2.3.1 使用 Overwrite 绕过 Reducer
场景:重置聊天记录或强制覆盖列表。
python
from langgraph.types import Overwrite
def reset_node(state: OverallState):
# 强制覆盖 messages 列表,忽略 operator.add 的追加逻辑
return {"messages": Overwrite(["系统重置,历史已清空"])}
2.3.2 定义独立的输入/输出模式
场景:对外只接收用户问题,只返回最终答案;内部可存储敏感中间变量(不暴露给外部)。
python
# 外部只需传入这个
class InputState(TypedDict):
user_query: str
# 内部全量状态(包含输入 + 私有字段)
class PrivateState(InputState, TypedDict):
internal_id: str # 内部使用,不对外暴露
final_answer: str
# 对外只返回这个
class OutputState(TypedDict):
final_answer: str
builder = StateGraph(
state_schema=PrivateState, # 内部使用
input_schema=InputState, # 校验输入
output_schema=OutputState # 过滤输出
)
2.3.3 私有状态(节点间传递敏感数据)
知识点:不同节点返回的字段若未在总 State 中定义,仅在该链路中临时传递,不会污染全局输出。
第三章:工作流常见模式
3.1 模式概览
| 模式 | 特点 | 适用场景 |
|---|---|---|
| 提示链 | 线性流水线,前一步输出是下一步输入 | 内容创作(大纲→初稿→润色) |
| 并行化 | 多任务同时执行,最后汇总 | 多维度分析(市场、竞品、技术) |
| 路由 | 根据输入动态分流到专用处理器 | 智能客服(售前/售后/技术) |
| 协调者-工作者 | 运行时动态生成子任务并并行执行 | 文档拆分翻译、动态任务分配 |
| 评估器-优化器 | 循环生成→评估→改进,直到达标 | 代码质量迭代、内容优化 |
3.2 路由模式(智能分流)代码示例
核心:条件边返回字符串,直接映射到预定义分支节点。
python
def classify_intent(state: dict) -> str:
if "价格" in state["query"]:
return "sales_handler"
elif "报错" in state["query"]:
return "tech_handler"
return "default_handler"
builder.add_conditional_edges(
"classifier_node",
classify_intent,
["sales_handler", "tech_handler", "default_handler"]
)
3.3 协调者-工作者模式(动态并行)代码示例
核心 :条件边返回
Send对象列表,实现运行时动态生成 n 条并行任务。
python
from langgraph.types import Send
class State(TypedDict):
sections: list[str] # 协调者动态生成的章节列表
results: list[str]
def assign_workers(state: State):
# 为每个章节动态创建一个工作者任务
return [Send("worker_node", {"section": sec}) for sec in state["sections"]]
# 协调者节点后接条件边,动态发散到 worker_node
builder.add_conditional_edges("orchestrator", assign_workers, ["worker_node"])
第四章:持久化(记忆、检查点与人机交互)
4.1 Checkpointer(状态持久化)
知识点 :编译时必须传入
checkpointer,图才会在每个步骤后自动保存状态快照。
内存存储(开发测试)
python
from langgraph.checkpoint.memory import InMemorySaver
memory = InMemorySaver()
graph = builder.compile(checkpointer=memory)
PostgreSQL 存储(生产推荐)
python
# 需先安装: pip install langgraph-checkpoint-postgres
from langgraph.checkpoint.postgres import PostgresSaver
DB_URI = "postgresql://user:pass@host:5432/db"
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
checkpointer.setup() # 仅首次需要初始化建表
graph = builder.compile(checkpointer=checkpointer)
4.2 Thread(线程)与短期记忆
知识点 :通过
thread_id隔离不同会话。相同thread_id会自动加载历史状态,实现多轮记忆。
python
# 第一次对话(创建新线程)
config = {"configurable": {"thread_id": "user_123"}}
graph.invoke({"messages": ["我叫小明"]}, config)
# 第二次对话(程序重启后,相同 thread_id 自动恢复记忆)
result = graph.invoke({"messages": ["我叫什么名字?"]}, config)
print(result["messages"][-1]) # 输出:你叫小明
4.3 查看历史与时间旅行(Time Travel)
核心价值:定位错误节点,或修改历史状态后重放执行。
获取历史检查点
python
# 按时间倒序返回 StateSnapshot 列表
history = list(graph.get_state_history(config))
for snap in history:
print(f"检查点ID: {snap.config['configurable']['checkpoint_id']}")
print(f"下一步节点: {snap.next}") # 该时刻即将执行的节点
print(f"当时状态值: {snap.values}")
修改历史状态并从该点重放
python
# 假设 history[1] 是某一步的中间快照
old_snapshot = history[1]
# 修改该快照中的状态值(会生成新分支)
new_config = graph.update_state(
old_snapshot.config,
{"user_name": "修改后的名字"} # 覆盖那一刻的状态
)
# 从修改后的点继续执行(输入为 None,因为状态已载入)
final_result = graph.invoke(None, config=new_config)
4.4 人机交互(中断 Interrupt)
知识点 :节点内调用
interrupt()暂停执行,外部用Command(resume=...)恢复。必须配合checkpointer使用。
python
from langgraph.types import interrupt, Command
def approval_node(state: dict):
# 暂停执行,向外抛出提示,等待人工介入
user_input = interrupt("请确认是否转账?输入 yes/no")
if user_input == "yes":
return {"status": "approved"}
return {"status": "rejected"}
# 首次调用(会触发中断)
config = {"configurable": {"thread_id": "task_001"}}
result = graph.invoke({"task": "转账1000元"}, config)
print(result["__interrupt__"]) # 显示中断信息:"请确认是否转账?"
# 外部人工决策后恢复执行
final = graph.invoke(Command(resume="yes"), config)
print(final["status"]) # 输出:"approved"
4.5 跨会话持久化(Store 长期记忆)
知识点:Store 用于保存用户偏好、历史预订等跨线程数据,通过命名空间(Namespace)隔离。
python
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
# 编译时同时传入 checkpointer 和 store
graph = builder.compile(checkpointer=memory, store=store)
# 在节点中存取长期记忆
def save_preference(state, runtime, *, store):
user_id = runtime.context.get("user_id")
namespace = (user_id, "preferences")
# 存入
store.put(namespace, "key_001", {"favorite_food": "汉堡"})
# 读取
results = store.search(namespace)
| 功能模块 | 关键类/方法 | 必须记住的原则 |
|---|---|---|
| 状态合并 | Annotated[list, operator.add] |
默认覆盖,用 Reducer 实现追加/累加 |
| 节点 | add_node(name, func) |
函数返回 部分更新,无需返回完整 State |
| 条件路由 | add_conditional_edges(src, router, targets) |
路由器返回 节点名字符串 或 Send 列表 |
| 编译 | .compile(checkpointer=...) |
必须编译;持久化依赖 checkpointer |
| 会话隔离 | config={"configurable":{"thread_id":"x"}} |
相同 ID 自动恢复状态 |
| 中断 | interrupt(prompt) + Command(resume=...) |
必须配合 checkpointer,恢复时节点从头执行 |
| 时间旅行 | get_state_history + update_state |
修改历史快照后 invoke(None, new_config) 重放 |
