LangGraph 深度解析:定义、功能、原理与实践
-
- [LangGraph 深度解析:定义、功能、原理与实践](#LangGraph 深度解析:定义、功能、原理与实践)
-
- [**一、什么是 LangGraph?**](#一、什么是 LangGraph?)
- [**二、LangGraph 核心功能**](#二、LangGraph 核心功能)
-
- [**1. 图结构流程定义**](#1. 图结构流程定义)
- [**2. 循环与迭代支持**](#2. 循环与迭代支持)
- [**3. 多代理协作**](#3. 多代理协作)
- [**4. 与 LangChain 生态集成**](#4. 与 LangChain 生态集成)
- [**5. 可视化与调试**](#5. 可视化与调试)
- [**三、LangGraph 底层实现原理**](#三、LangGraph 底层实现原理)
-
- [**1. 核心架构:状态机(State Machine)**](#1. 核心架构:状态机(State Machine))
- [**2. 图执行引擎**](#2. 图执行引擎)
- [**3. 关键技术细节**](#3. 关键技术细节)
- [**四、使用 LangGraph 构建复杂工作流:完整示例**](#四、使用 LangGraph 构建复杂工作流:完整示例)
-
- **场景描述**
- [**步骤 1:安装依赖**](#步骤 1:安装依赖)
- [**步骤 2:完整代码实现**](#步骤 2:完整代码实现)
- **五、代码解析与执行结果**
- **六、总结**
LangGraph 深度解析:定义、功能、原理与实践
一、什么是 LangGraph?
LangGraph 是 LangChain 生态 中用于构建复杂、有状态、多步骤 AI 工作流 的框架,核心特点是支持图结构(Graph) 定义流程,原生支持循环(Cycles) 、分支(Branches) 、多代理协作(Multi-Agent Collaboration),并能与 LLM、工具(Tools)、记忆(Memory)无缝集成。
它解决了传统链式调用(如 LangChain SequentialChain)难以处理的非线性流程(如迭代优化、条件跳转、并行任务),适用于构建 Agent、对话系统、数据处理流水线等复杂场景。
二、LangGraph 核心功能
LangGraph 的功能围绕"图结构工作流"展开,核心能力包括:
1. 图结构流程定义
- 节点(Nodes):代表流程中的独立步骤(如 LLM 调用、工具执行、数据处理),可同步或异步执行。
- 边(Edges) :定义节点间的流转逻辑,分为:
- 普通边(Normal Edge) :固定从一个节点到另一个节点(如
A → B)。 - 条件边(Conditional Edge):根据运行时状态动态决定下一个节点(如"若问题类型为'技术问题'则进入节点 C,否则进入节点 D")。
- 普通边(Normal Edge) :固定从一个节点到另一个节点(如
- 状态(State):贯穿全流程的共享数据对象,节点可读取/更新状态(类似"上下文")。
2. 循环与迭代支持
原生支持循环逻辑(如 Agent 反复调用工具直到完成任务),通过"指向自身的边"实现(如节点 A 执行后根据状态决定是否回到 A 重新执行)。
3. 多代理协作
允许定义多个"代理节点"(每个节点可包含一个 Agent),支持并行或串行协作(如"Agent A 收集需求 → Agent B 设计方案 → Agent C 评审")。
4. 与 LangChain 生态集成
无缝对接 LangChain 组件:
- LLM(如 GPT、Claude)、Prompt Templates、Tools(如搜索引擎、计算器);
- 记忆模块(Memory)、检索器(Retriever);
- 链路追踪(LangSmith)。
5. 可视化与调试
支持导出流程图(如 Mermaid 格式),并提供运行时状态追踪,便于调试复杂流程。
三、LangGraph 底层实现原理
LangGraph 的核心是**"状态机 + 有向图"** 模型,底层通过 Python 异步编程和状态管理实现灵活流转。
1. 核心架构:状态机(State Machine)
- 状态(State) :用 Python
TypedDict或dataclass定义,包含所有流程共享的键值对(如{"step": "collect_info", "user_input": "...", "solution": None})。 - 节点(Nodes):Python 函数,接收当前状态,返回更新后的状态(不可变更新,避免副作用)。
- 边(Edges):决定节点执行顺序,条件边通过 Python 函数评估状态,返回下一个节点名称。
2. 图执行引擎
- 编译阶段:将用户定义的图(节点+边)编译为可执行的有限状态机(FSM)。
- 运行阶段 :
- 初始化状态,从"入口节点"开始执行;
- 节点执行后更新状态,根据边规则跳转到下一节点;
- 遇到循环边时,重复执行直至满足退出条件;
- 支持异步节点(如 LLM 调用),通过
async/await实现并发。
3. 关键技术细节
- 状态不可变性:节点返回新状态对象(而非修改原状态),避免并发冲突。
- 条件边评估 :条件函数接收当前状态,返回目标节点名称(如
lambda state: "tool_node" if state["need_tool"] else "llm_node")。 - 循环控制:通过"最大迭代次数"防止无限循环(默认配置)。
四、使用 LangGraph 构建复杂工作流:完整示例
以下以"智能客服工作流 "为例,构建一个包含问题分类、信息收集、解决方案生成、人工介入的复杂流程,涉及循环(信息不足时重新收集)和条件分支(不同类型问题走不同流程)。
场景描述
用户输入问题 → 分类问题类型(技术问题/投诉/咨询)→ 收集必要信息(若信息不足则循环收集)→ 生成解决方案(技术问题调用工具,投诉转人工)→ 输出结果。
步骤 1:安装依赖
bash
pip install langgraph langchain openai python-dotenv # 核心依赖
# 可选:安装可视化工具
pip install graphviz
步骤 2:完整代码实现
python
import os
from typing import TypedDict, Literal, Annotated
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from dotenv import load_dotenv
load_dotenv() # 加载环境变量(需配置 OPENAI_API_KEY)
# ----------------------
# 1. 定义状态(State)
# ----------------------
class CustomerServiceState(TypedDict):
"""客服工作流共享状态"""
user_input: str # 用户原始输入
problem_type: Literal["technical", "complaint", "inquiry", "unknown"] # 问题类型
collected_info: dict # 收集的信息(如设备型号、问题描述)
solution: str | None # 最终解决方案
need_human: bool # 是否需要人工介入
messages: Annotated[list, lambda x,y: x + y] # 对话历史(累加)
# ----------------------
# 2. 定义工具(Tools):模拟技术问题查询
# ----------------------
@tool
def search_tech_docs(query: str) -> str:
"""模拟查询技术文档库"""
tech_docs = {
"登录失败": "尝试重置密码或检查网络连接,步骤:1. 点击'忘记密码';2. 验证邮箱;3. 设置新密码。",
"页面卡顿": "清除浏览器缓存(Ctrl+Shift+Del),或尝试更换浏览器(推荐 Chrome)。"
}
return tech_docs.get(query, "未找到相关文档,请联系技术支持。")
tools = [search_tech_docs]
tool_node = ToolNode(tools) # LangGraph 预构建的工具节点
# ----------------------
# 3. 初始化 LLM(模拟大模型调用)
# ----------------------
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
llm_with_tools = llm.bind_tools(tools) # 绑定工具的 LLM
# ----------------------
# 4. 定义节点(Nodes):工作流步骤
# ----------------------
def classify_problem(state: CustomerServiceState) -> CustomerServiceState:
"""节点 1:分类问题类型"""
prompt = f"""用户问题:{state['user_input']}
分类为:technical(技术问题)、complaint(投诉)、inquiry(咨询)、unknown(未知),仅返回类型名称。"""
response = llm.invoke([HumanMessage(content=prompt)]).content.strip().lower()
# 确保类型合法
valid_types = ["technical", "complaint", "inquiry", "unknown"]
problem_type = response if response in valid_types else "unknown"
return {**state, "problem_type": problem_type, "messages": [SystemMessage(content=f"问题分类为:{problem_type}")]}
def collect_info(state: CustomerServiceState) -> CustomerServiceState:
"""节点 2:收集必要信息(循环执行直到信息足够)"""
# 根据问题类型确定需要收集的信息
required_info = {
"technical": ["设备型号", "错误代码", "复现步骤"],
"complaint": ["订单号", "投诉原因", "期望解决方案"],
"inquiry": ["咨询主题", "具体疑问"]
}.get(state["problem_type"], [])
# 模拟信息收集(实际场景可调用表单或对话)
collected = state.get("collected_info", {})
if len(collected) < len(required_info):
# 假设用户补充了信息(实际中需交互,这里模拟)
collected.update({k: f"模拟_{k}_值" for k in required_info[:len(collected)+1]})
return {**state, "collected_info": collected, "messages": [SystemMessage(content=f"已收集信息:{collected}")]}
def generate_solution(state: CustomerServiceState) -> CustomerServiceState:
"""节点 3:生成解决方案(调用工具或转人工)"""
if state["problem_type"] == "technical":
# 技术问题:调用工具查询文档
query = state["collected_info"].get("错误代码", state["user_input"])
tool_response = tool_node.invoke({"messages": [HumanMessage(content=query)]})
solution = tool_response["messages"][-1].content
need_human = False
elif state["problem_type"] == "complaint":
# 投诉:转人工
solution = "您的投诉已记录,人工客服将在 24 小时内联系您。"
need_human = True
else:
# 咨询:LLM 直接回答
prompt = f"""用户咨询:{state['user_input']},收集的信息:{state['collected_info']},请给出简洁回答。"""
solution = llm.invoke([HumanMessage(content=prompt)]).content
need_human = False
return {**state, "solution": solution, "need_human": need_human}
def human_handoff(state: CustomerServiceState) -> CustomerServiceState:
"""节点 4:人工介入处理"""
return {**state, "solution": "人工客服已接手,正在处理中...", "messages": [SystemMessage(content="转人工成功")]}
def output_result(state: CustomerServiceState) -> CustomerServiceState:
"""节点 5:输出最终结果"""
return {**state, "messages": [SystemMessage(content=f"最终结果:{state['solution']}")]}
# ----------------------
# 5. 定义边(Edges):流转逻辑
# ----------------------
def route_after_collect(state: CustomerServiceState) -> Literal["generate_solution", "collect_info"]:
"""收集信息后判断是否继续收集"""
required_info = {
"technical": ["设备型号", "错误代码", "复现步骤"],
"complaint": ["订单号", "投诉原因", "期望解决方案"],
"inquiry": ["咨询主题", "具体疑问"]
}.get(state["problem_type"], [])
# 若收集的信息不完整,则继续收集
if len(state["collected_info"]) < len(required_info):
return "collect_info"
return "generate_solution"
def route_after_generate(state: CustomerServiceState) -> Literal["human_handoff", "output_result"]:
"""生成方案后判断是否转人工"""
return "human_handoff" if state["need_human"] else "output_result"
# ----------------------
# 6. 构建图(Graph)
# ----------------------
workflow = StateGraph(CustomerServiceState)
# 添加节点
workflow.add_node("classify", classify_problem) # 分类问题
workflow.add_node("collect", collect_info) # 收集信息
workflow.add_node("generate", generate_solution) # 生成方案
workflow.add_node("human", human_handoff) # 人工介入
workflow.add_node("output", output_result) # 输出结果
workflow.add_node("tools", tool_node) # 工具节点(技术问题调用)
# 添加边(流转逻辑)
workflow.set_entry_point("classify") # 入口节点:分类问题
workflow.add_edge("classify", "collect") # 分类后进入收集信息
workflow.add_conditional_edges( # 收集信息后条件分支
"collect",
route_after_collect,
{"collect_info": "collect", "generate_solution": "generate"}
)
workflow.add_conditional_edges( # 生成方案后条件分支
"generate",
route_after_generate,
{"human_handoff": "human", "output_result": "output"}
)
workflow.add_edge("human", "output") # 人工介入后输出结果
workflow.add_edge("output", END) # 输出后结束
# 编译图为可执行工作流
app = workflow.compile()
# ----------------------
# 7. 运行工作流(示例)
# ----------------------
def run_customer_service(user_input: str):
"""运行客服工作流"""
initial_state: CustomerServiceState = {
"user_input": user_input,
"problem_type": "unknown",
"collected_info": {},
"solution": None,
"need_human": False,
"messages": []
}
# 执行工作流
result = app.invoke(initial_state)
print(f"用户问题:{user_input}")
print(f"问题类型:{result['problem_type']}")
print(f"收集信息:{result['collected_info']}")
print(f"解决方案:{result['solution']}")
print("="*50)
# 测试用例
if __name__ == "__main__":
# 测试 1:技术问题(需调用工具)
run_customer_service("登录时提示错误代码 500,设备型号是 iPhone 13")
# 测试 2:投诉(需转人工)
run_customer_service("我昨天买的订单 #123 商品破损,要求退款并赔偿")
# 测试 3:咨询(直接回答)
run_customer_service("如何修改账户绑定的手机号?")
五、代码解析与执行结果
核心流程
- 分类问题 :LLM 将用户输入分类为
technical/complaint/inquiry。 - 收集信息:根据问题类型收集必要信息(如技术问题的"设备型号""错误代码"),信息不足时循环收集。
- 生成方案 :
- 技术问题:调用
search_tech_docs工具查询文档; - 投诉:标记为需人工介入;
- 咨询:LLM 直接生成回答。
- 技术问题:调用
- 人工介入/输出结果:投诉转人工,其他情况直接输出方案。
执行结果示例
用户问题:登录时提示错误代码 500,设备型号是 iPhone 13
问题类型:technical
收集信息:{'设备型号': '模拟_设备型号_值', '错误代码': '模拟_错误代码_值', '复现步骤': '模拟_复现步骤_值'}
解决方案:尝试重置密码或检查网络连接,步骤:1. 点击'忘记密码';2. 验证邮箱;3. 设置新密码。
==================================================
六、总结
LangGraph 通过图结构+状态机模型,为大模型工程师提供了构建复杂 AI 工作流的强大工具。其核心优势在于:
- 灵活性:支持循环、分支、并行,突破线性链式调用的限制;
- 可维护性:图结构清晰表达流程逻辑,便于调试和扩展;
- 生态集成:无缝对接 LangChain 组件,降低开发成本。