LangGraph工作流
概述
LangGraph是LangChain团队开发的基于图的Agent工作流框架,用于构建复杂的、有状态的LLM应用。它提供了更灵活的控制流和状态管理能力,适合构建需要多步推理和决策的Agent系统。
核心概念
1. 图结构(Graph)
LangGraph基于有向图结构,包含:
- 节点(Nodes):执行具体操作的单元
- 边(Edges):连接节点的转移关系
- 条件边(Conditional Edges):根据条件选择路径
- 状态(State):在节点间传递的数据
2. 状态管理(State Management)
LangGraph的状态管理特点:
- 全局状态:所有节点共享的状态对象
- 状态更新:节点可以读取和更新状态
- 状态持久化:支持状态持久化和恢复
- 状态验证:支持状态模式验证
3. 工作流模式
LangGraph支持多种工作流模式:
- 顺序执行:节点按顺序执行
- 条件分支:根据条件选择执行路径
- 并行执行:多个节点并行执行
- 循环执行:重复执行直到满足条件
4. 人机交互
LangGraph支持人机交互模式:
- 人工审批:在关键节点等待人工审批
- 人工输入:在需要时获取人工输入
- 中断恢复:支持中断和恢复执行
- 检查点:支持执行检查点
架构设计
1. 核心架构
应用层
├── 图定义(Graph Definition)
├── 执行引擎(Execution Engine)
└── 状态管理(State Management)
├── 节点(Nodes)
├── 边(Edges)
└── 状态(State)2. 执行流程
开始 → 初始状态 → 节点执行 → 状态更新 → 边判断 → 下一节点 → 结束
↑ ↓
└──────── 循环执行 ←───────────┘3. 组件交互
python
# 图定义
graph = StateGraph(State)
# 添加节点
graph.add_node("node1", function1)
graph.add_node("node2", function2)
# 添加边
graph.add_edge("node1", "node2")
graph.add_conditional_edges("node2", condition_function)
# 编译和执行
app = graph.compile()
result = app.invoke(initial_state)核心API
1. 状态图定义
python
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
# 定义状态
class State(TypedDict):
messages: list
current_step: str
results: dict
# 创建状态图
graph = StateGraph(State)2. 节点定义
python
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
# 定义节点函数
def process_input(state: State) -> State:
"""处理输入节点"""
messages = state["messages"]
# 处理逻辑
return {"messages": messages, "current_step": "processed"}
def generate_response(state: State) -> State:
"""生成响应节点"""
llm = ChatOpenAI(model="gpt-4o-mini")
response = llm.invoke(state["messages"])
return {"messages": [response], "current_step": "completed"}
# 添加节点到图
graph.add_node("process_input", process_input)
graph.add_node("generate_response", generate_response)3. 边定义
python
# 添加普通边
graph.add_edge("process_input", "generate_response")
# 添加条件边
def should_continue(state: State) -> str:
"""判断是否继续"""
if state["current_step"] == "completed":
return "end"
return "continue"
graph.add_conditional_edges(
"generate_response",
should_continue,
{
"continue": "process_input",
"end": END
}
)4. 图编译和执行
python
# 设置入口点
graph.set_entry_point("process_input")
# 编译图
app = graph.compile()
# 执行图
initial_state = {
"messages": [HumanMessage(content="你好!")],
"current_step": "start",
"results": {}
}
result = app.invoke(initial_state)5. 流式执行
python
# 流式执行
for event in app.stream(initial_state):
print(event)实践指南
1. 环境准备
bash
# 安装LangGraph
pip install langgraph langchain-openai
# 设置环境变量
export OPENAI_API_KEY="your-openai-key"2. 基础示例
python
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
from typing import TypedDict, Annotated
# 定义状态
class AgentState(TypedDict):
messages: list
next_step: str
# 定义节点
def chat_node(state: AgentState) -> AgentState:
"""聊天节点"""
llm = ChatOpenAI(model="gpt-4o-mini")
response = llm.invoke(state["messages"])
return {
"messages": state["messages"] + [response],
"next_step": "end"
}
# 创建图
graph = StateGraph(AgentState)
graph.add_node("chat", chat_node)
# 设置边
graph.set_entry_point("chat")
graph.add_edge("chat", END)
# 编译和执行
app = graph.compile()
result = app.invoke({
"messages": [HumanMessage(content="你好!")],
"next_step": "start"
})
print(result["messages"][-1].content)3. 条件路由示例
python
from langgraph.graph import StateGraph, END
from typing import TypedDict, Literal
# 定义状态
class RouterState(TypedDict):
input: str
route: str
output: str
# 定义节点
def classify_input(state: RouterState) -> RouterState:
"""分类输入"""
input_text = state["input"].lower()
if "天气" in input_text:
route = "weather"
elif "新闻" in input_text:
route = "news"
else:
route = "general"
return {"input": state["input"], "route": route, "output": ""}
def handle_weather(state: RouterState) -> RouterState:
"""处理天气查询"""
return {"input": state["input"], "route": state["route"], "output": "天气查询结果"}
def handle_news(state: RouterState) -> RouterState:
"""处理新闻查询"""
return {"input": state["input"], "route": state["route"], "output": "新闻查询结果"}
def handle_general(state: RouterState) -> RouterState:
"""处理一般查询"""
return {"input": state["input"], "route": state["route"], "output": "一般查询结果"}
# 创建图
graph = StateGraph(RouterState)
graph.add_node("classify", classify_input)
graph.add_node("weather", handle_weather)
graph.add_node("news", handle_news)
graph.add_node("general", handle_general)
# 设置条件边
def route_function(state: RouterState) -> str:
return state["route"]
graph.add_conditional_edges(
"classify",
route_function,
{
"weather": "weather",
"news": "news",
"general": "general"
}
)
# 设置出口
graph.add_edge("weather", END)
graph.add_edge("news", END)
graph.add_edge("general", END)
# 编译和执行
graph.set_entry_point("classify")
app = graph.compile()
result = app.invoke({"input": "北京天气怎么样?", "route": "", "output": ""})
print(result["output"])4. 人机交互示例
python
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from typing import TypedDict
# 定义状态
class HumanLoopState(TypedDict):
messages: list
human_input: str
approved: bool
# 定义节点
def process_node(state: HumanLoopState) -> HumanLoopState:
"""处理节点"""
return {
"messages": state["messages"],
"human_input": "",
"approved": False
}
def human_approval_node(state: HumanLoopState) -> HumanLoopState:
"""人工审批节点"""
# 这里可以集成人工审批界面
print("需要人工审批")
return {
"messages": state["messages"],
"human_input": "approved",
"approved": True
}
def final_node(state: HumanLoopState) -> HumanLoopState:
"""最终节点"""
return {
"messages": state["messages"],
"human_input": state["human_input"],
"approved": True
}
# 创建图
graph = StateGraph(HumanLoopState)
graph.add_node("process", process_node)
graph.add_node("human_approval", human_approval_node)
graph.add_node("final", final_node)
# 设置边
graph.set_entry_point("process")
graph.add_edge("process", "human_approval")
graph.add_edge("human_approval", "final")
graph.add_edge("final", END)
# 使用检查点
checkpointer = MemorySaver()
app = graph.compile(checkpointer=checkpointer, interrupt_before=["human_approval"])
# 执行
config = {"configurable": {"thread_id": "1"}}
result = app.invoke({
"messages": [],
"human_input": "",
"approved": False
}, config)最佳实践
1. 图设计原则
- 模块化设计:每个节点只做一件事
- 清晰的状态定义:明确定义状态结构
- 合理的错误处理:添加错误处理节点
- 可测试性:设计可测试的节点
2. 性能优化
- 并行执行:独立节点并行执行
- 状态优化:减少状态传递的数据量
- 缓存机制:缓存中间结果
- 异步执行:使用异步节点提升性能
3. 调试技巧
- 可视化图:使用可视化工具查看图结构
- 日志记录:记录每个节点的执行日志
- 断点调试:在关键节点设置断点
- 状态检查:检查每个节点的状态变化
常见问题
1. 状态管理问题
- 状态不一致:确保所有节点正确更新状态
- 状态丢失:使用检查点持久化状态
- 状态验证:添加状态验证逻辑
2. 执行流程问题
- 死循环:设置最大执行次数
- 条件判断错误:仔细检查条件函数
- 节点执行失败:添加错误处理和重试机制
3. 性能问题
- 执行慢:优化节点函数,减少不必要的计算
- 内存占用高:优化状态结构,减少数据传递
- 并发限制:使用异步执行提升并发能力