300 lines
10 KiB
Plaintext
300 lines
10 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# 14 LangGraph 概述\n",
|
||
"\n",
|
||
"## 学习目标\n",
|
||
"1. 理解为什么需要 LangGraph:复杂智能体流程的控制需求\n",
|
||
"2. 掌握 LangGraph 的核心概念:StateGraph、State、Node、Edge\n",
|
||
"3. 理解 LangGraph 与 LangChain 的关系和分工\n",
|
||
"4. 能够编写一个最简单的 LangGraph 状态图\n",
|
||
"5. 了解 LangGraph 的典型应用场景"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 1. 为什么需要 LangGraph\n",
|
||
"\n",
|
||
"前面我们用 LangChain 构建了链式应用和简单的工具调用智能体。但当智能体流程变得复杂时,会遇到一些问题:\n",
|
||
"\n",
|
||
"- **流程不可控**:标准 Agent 的黑盒决策难以调试和约束\n",
|
||
"- **循环和分支困难**:难以实现多轮循环、条件分支、人机协作\n",
|
||
"- **状态管理复杂**:多步骤之间的状态传递不清晰\n",
|
||
"- **缺乏持久化**:无法暂停、恢复或检查执行历史\n",
|
||
"\n",
|
||
"**LangGraph** 就是为了解决这些问题而设计的。它把智能体流程建模为一个**状态图(StateGraph)**,让开发者精确控制每个步骤。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 2. LangGraph 是什么\n",
|
||
"\n",
|
||
"LangGraph 是 LangChain 生态中的一个库,用于构建基于**状态图**的智能体应用。它的核心思想是:\n",
|
||
"\n",
|
||
"- 把应用看作一个图(Graph)\n",
|
||
"- 图中的每个节点(Node)是一个函数或操作\n",
|
||
"- 边(Edge)控制流程走向\n",
|
||
"- 状态(State)在节点之间传递\n",
|
||
"\n",
|
||
"LangGraph 基于 LangChain 的 Runnable 接口构建,因此可以无缝使用 LangChain 的模型、工具、Prompt 等组件。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3. LangGraph 与 LangChain 的关系\n",
|
||
"\n",
|
||
"| 对比项 | LangChain | LangGraph |\n",
|
||
"| --- | --- | --- |\n",
|
||
"| 核心抽象 | Chain / Agent | StateGraph |\n",
|
||
"| 流程控制 | 线性或简单循环 | 任意图结构、条件分支、循环 |\n",
|
||
"| 状态管理 | 隐式传递 | 显式 State 对象 |\n",
|
||
"| 适用场景 | 简单流水线、单次调用 | 复杂多智能体、多轮交互 |\n",
|
||
"| 关系 | 基础组件库 | 基于 LangChain 构建的流程编排层 |\n",
|
||
"\n",
|
||
"可以把 LangChain 理解为「零件库」,LangGraph 理解为「装配线控制系统」。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 4. 核心概念\n",
|
||
"\n",
|
||
"### 4.1 State(状态)\n",
|
||
"状态是整个图共享的数据结构。每个节点读取状态、修改状态,然后把状态传递给下一个节点。\n",
|
||
"\n",
|
||
"### 4.2 StateGraph(状态图)\n",
|
||
"状态图是 LangGraph 最核心的类。它负责定义节点、边和状态类型。\n",
|
||
"\n",
|
||
"### 4.3 Node(节点)\n",
|
||
"节点是图中的执行单元,通常是一个 Python 函数。节点接收当前状态,返回对状态的更新。\n",
|
||
"\n",
|
||
"### 4.4 Edge(边)\n",
|
||
"边定义节点之间的连接关系。LangGraph 支持:\n",
|
||
"- 普通边:固定从一个节点到另一个节点\n",
|
||
"- 条件边:根据状态决定下一个节点\n",
|
||
"- START / END:图的起点和终点"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 5. 第一个 LangGraph 程序\n",
|
||
"\n",
|
||
"下面构建一个最简单的图:两个节点 `node_a` 和 `node_b`,`node_a` 给状态加 1,`node_b` 再给状态乘 2。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from typing_extensions import TypedDict\n",
|
||
"from langgraph.graph import StateGraph, START, END\n",
|
||
"\n",
|
||
"# 1. 定义状态类型\n",
|
||
"class MyState(TypedDict):\n",
|
||
" \"\"\"图中的共享状态。\"\"\"\n",
|
||
" value: int\n",
|
||
"\n",
|
||
"# 2. 定义节点函数\n",
|
||
"def node_a(state: MyState):\n",
|
||
" \"\"\"把 value 加 1。\"\"\"\n",
|
||
" print(f'Node A 接收:{state[\"value\"]}')\n",
|
||
" return {'value': state['value'] + 1}\n",
|
||
"\n",
|
||
"def node_b(state: MyState):\n",
|
||
" \"\"\"把 value 乘 2。\"\"\"\n",
|
||
" print(f'Node B 接收:{state[\"value\"]}')\n",
|
||
" return {'value': state['value'] * 2}\n",
|
||
"\n",
|
||
"# 3. 构建状态图\n",
|
||
"builder = StateGraph(MyState)\n",
|
||
"builder.add_node('node_a', node_a)\n",
|
||
"builder.add_node('node_b', node_b)\n",
|
||
"\n",
|
||
"# 4. 添加边\n",
|
||
"builder.add_edge(START, 'node_a')\n",
|
||
"builder.add_edge('node_a', 'node_b')\n",
|
||
"builder.add_edge('node_b', END)\n",
|
||
"\n",
|
||
"# 5. 编译图\n",
|
||
"graph = builder.compile()\n",
|
||
"\n",
|
||
"# 6. 运行图\n",
|
||
"result = graph.invoke({'value': 3})\n",
|
||
"print(f'\\n最终结果:{result}')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 代码解释\n",
|
||
"\n",
|
||
"- `TypedDict` 定义状态结构,告诉 LangGraph 图中有哪些字段\n",
|
||
"- `StateGraph(MyState)` 创建状态图实例\n",
|
||
"- `add_node(name, func)` 添加节点\n",
|
||
"- `add_edge(START, 'node_a')` 设置从图起点到 node_a 的边\n",
|
||
"- `compile()` 编译图,生成可执行的 Runnable\n",
|
||
"- `invoke({'value': 3})` 运行图,传入初始状态\n",
|
||
"\n",
|
||
"这个例子的执行流程是:`START -> node_a(value=3 -> 4) -> node_b(value=4 -> 8) -> END`,最终结果是 8。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 6. LangGraph 执行流程可视化\n",
|
||
"\n",
|
||
"LangGraph 提供了 `get_graph()` 方法,可以查看图的结构。\n",
|
||
"\n",
|
||
"在线查看Mermaid 图:https://mermaid.live/edit\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# 打印图的节点和边\n",
|
||
"print(graph.get_graph().nodes)\n",
|
||
"print(graph.get_graph().edges)\n",
|
||
"\n",
|
||
"# 使用 mermaid 格式可视化(在支持 mermaid 的 Markdown 查看器中可显示)\n",
|
||
"print('\\nMermaid 图:')\n",
|
||
"print(graph.get_graph().draw_mermaid())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 7. 在 LangGraph 中使用 LangChain 组件\n",
|
||
"\n",
|
||
"LangGraph 的节点可以使用任何 LangChain 组件。下面是一个使用 LLM 和 Prompt 的节点示例。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"from langchain_core.prompts import ChatPromptTemplate\n",
|
||
"from langgraph.graph.message import add_messages\n",
|
||
"from dotenv import load_dotenv\n",
|
||
"\n",
|
||
"load_dotenv()\n",
|
||
"\n",
|
||
"\n",
|
||
"# 定义带消息历史的状态\n",
|
||
"class ChatState(TypedDict):\n",
|
||
" messages: list # 对话历史\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.7)\n",
|
||
"\n",
|
||
"def chat_node(state: ChatState):\n",
|
||
" \"\"\"调用 LLM 回复用户。\"\"\"\n",
|
||
" prompt = ChatPromptTemplate.from_messages([\n",
|
||
" ('system', '你是友好的 AI 助手。'),\n",
|
||
" *state['messages']\n",
|
||
" ])\n",
|
||
" response = (prompt | llm).invoke({})\n",
|
||
" return {'messages': [response]}\n",
|
||
"\n",
|
||
"builder = StateGraph(ChatState)\n",
|
||
"builder.add_node('chat', chat_node)\n",
|
||
"builder.add_edge(START, 'chat')\n",
|
||
"builder.add_edge('chat', END)\n",
|
||
"\n",
|
||
"chat_graph = builder.compile()\n",
|
||
"\n",
|
||
"result = chat_graph.invoke({\n",
|
||
" 'messages': [('user', '请用一句话介绍 LangGraph')]\n",
|
||
"})\n",
|
||
"print(result['messages'][-1].content)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 代码解释\n",
|
||
"\n",
|
||
"- `messages` 是列表类型,每个元素是 `(role, content)` 元组\n",
|
||
"- `ChatPromptTemplate.from_messages([...])` 中的 `*state['messages']` 把历史消息展开\n",
|
||
"- 节点返回 `{'messages': [response]}`,LangGraph 会自动合并到状态中\n",
|
||
"- 这里只是一个单节点图,后续课程会扩展到多轮对话和循环"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 8. LangGraph 的典型应用场景\n",
|
||
"\n",
|
||
"LangGraph 特别适合以下场景:\n",
|
||
"\n",
|
||
"| 场景 | 说明 |\n",
|
||
"| --- | --- |\n",
|
||
"| **多轮工具调用** | 在循环中反复调用工具,直到获得足够信息 |\n",
|
||
"| **人机协作(Human-in-the-loop)** | 在关键节点暂停,等待人类确认 |\n",
|
||
"| **多智能体系统** | 多个 Agent 通过图结构协作完成任务 |\n",
|
||
"| **复杂审批流程** | 根据条件分支决定流程走向 |\n",
|
||
"| **长期记忆** | 通过持久化状态实现跨会话记忆 |\n",
|
||
"\n",
|
||
"这些场景在后面几节课会逐一展开。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 9. 本节课练习\n",
|
||
"\n",
|
||
"1. 修改第一个 LangGraph 示例,增加第三个节点 `node_c`,实现 value = value - 2\n",
|
||
"2. 改变三个节点的连接顺序,观察最终结果如何变化\n",
|
||
"3. 在 ChatState 中增加一个 `topic` 字段,让 system prompt 根据 topic 动态变化\n",
|
||
"4. 尝试画出本节课第一个示例的状态图(START -> node_a -> node_b -> END)\n",
|
||
"5. 思考:LangGraph 与你之前学过的 LangChain Chain 相比,最大的优势是什么?"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": ".venv",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.14.4"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
}
|