1. LangGraph是什么?
LangGraph是一个用于构建基于大型语言模型(LLM)的复杂应用程序的开源框架。它是由LangChain Labs开发的,作为LangChain生态系统的一部分。以下是LangGraph的主要特点和功能:
-
状态机和有向图:LangGraph允许开发者将LLM应用程序构建为状态机或有向图,这使得创建复杂的、多步骤的工作流变得更加简单。
-
循环和条件逻辑:LangGraph支持循环和条件逻辑,这在传统的LLM应用构建框架中通常很难实现。这意味着你可以创建能够进行多轮推理、递归思考或重复特定操作直到满足条件的应用。
-
可视化和调试:LangGraph提供了工作流可视化工具,帮助开发者理解和调试他们的应用程序。
-
与LangChain集成:作为LangChain生态系统的一部分,LangGraph可以与LangChain的其他组件无缝集成,如检索增强生成(RAG)、代理和工具使用等。
-
可扩展性:LangGraph被设计为可扩展的,允许开发者根据自己的需求自定义和扩展框架。
LangGraph特别适合构建需要多步推理、决策点或循环的复杂LLM应用,如对话代理、复杂的问答系统、多步骤任务执行等。它帮助开发者克服了单个LLM调用的限制,使构建更复杂、更强大的AI应用成为可能。
2. LangGraph 状态、节点、边
LangGraph中的状态、节点和边
LangGraph是一个强大的框架,它允许我们将LLM应用程序构建为状态机或有向图。这种方法使复杂的应用流程变得更加清晰和可管理。让我来详细解释LangGraph的三个核心概念:
1. 状态 (State)
状态是LangGraph应用中的核心数据容器,它记录了应用在任何时刻的完整信息:
- 定义方式:通常使用Python的TypedDict定义,明确指定包含哪些数据字段
- 包含内容:可以包含消息历史、中间计算结果、标志位、检索到的信息等
- 不可变性:状态本身是不可变的,节点处理会返回新的状态,而不是修改现有状态
- 完整性:状态必须包含应用运行所需的所有信息
例如,一个简单对话应用的状态可能是:
class ConversationState(TypedDict):
messages: List[dict] # 对话历史
current_thought: str # 当前思考过程
response: Optional[str] # 最终回复
2. 节点 (Node)
节点是执行计算逻辑的地方:
- 功能:节点是一个函数,接收当前状态并返回更新后的状态
- 操作:节点可以调用LLM、使用工具、检索信息或执行任何计算
- 纯函数:节点应该是纯函数,仅基于输入状态产生输出,不应有副作用
- 目的性:每个节点都有明确的职责,如"分析用户查询"、"生成回复"等
节点示例:
def analyze_query(state: ConversationState) -> ConversationState:
# 分析逻辑
return {
**state, "current_thought": "用户似乎在询问..."}
3. 边 (Edge)
边定义了状态在节点之间如何流转:
-
类型:
- 简单边:固定连接,状态总是从一个节点流向另一个特定节点
- 条件边:基于状态内容动态决定下一个节点
- 循环:允许状态回到之前的节点,实现迭代处理
-
功能:边定义了应用的执行路径和决策点
-
条件函数:条件边使用函数评估状态并返回下一个目标节点的名称
边的例子:
# 简单边
builder.add_edge("analyze", "generate")
# 条件边
def router(state):
if "需要检索" in state["current_thought"]:
return "retrieval"
return "generate"
builder.add_conditional_edges("analyze", router, {
"retrieval": "retrieve",
"generate": "generate"
})
状态机的运行流程
- 从初始状态开始
- 进入入口节点进行处理
- 处理完成后,根据边的定义决定下一个节点
- 重复处理直到到达终点或满足停止条件
LangGraph的强大之处在于它允许构建包含循环和条件分支的复杂应用流程,这在传统的链式调用中很难实现。它特别适合需要多轮思考、递归处理或基于条件执行不同路径的应用场景。
3. LangGraph 综合案例
1. 案例背景
在电子商务领域,客服是连接用户和企业的关键环节。传统的电商客服面临以下挑战:
- 处理大量重复性查询(订单状态、物流查询等)
- 需要跨系统获取信息(订单系统、物流系统、产品系统)
- 多轮对话解决复杂问题时效率低下
- 客服人员培训成本高、流动性大
这个案例开发一个基于LangGraph的智能电商客服代理,能够处理用户常见查询、使用多种工具获取信息,并通过状态管理进行复杂的多轮对话。
2. 需求分析
功能需求
- 订单查询:根据订单号查询订单状态
- 产品咨询:提供产品信息、规格和价格
- 物流追踪:根据物流单号提供物流状态和预计送达时间
- 退款处理:评估退款资格并处理退款请求
- 多轮对话:能够处理需要多个步骤的复杂问题
- 状态保持:在对话期间维持上下文理解
技术需求
- 状态管理:使用LangGraph管理复杂对话状态
- 工具集成:集成多个查询和操作工具
- 检查点功能:支持对话状态的保存和恢复
- 决策循环:实现"工具使用→分析→进一步对话"的循环
- 灵活流程:根据不同查询类型使用不同处理路径
3. 构建思路
状态设计
客服代理的状态需要包含:
- 对话历史
- 用户意图
- 提取的关键信息
- 工具使用历史
- 对话完成状态
节点设计
将客服流程拆分为以下关键节点:
- 意图识别:分析用户查询,确定意图并提取关键信息
- 工具决策:决定是否需要使用工具及使用哪个工具
- 工具使用:调用适当的工具获取信息
- 回复生成:基于所有信息生成回复
- 完成检查:确定对话是否可以结束
- 发送回复:将回复添加到对话历史
边与流程设计
- 基本流程:意图识别 → 工具决策 → (可选)工具使用 → 回复生成 → 完成检查
- 条件边:
- 工具决策节点后:根据是否需要工具分流
- 完成检查节点后:根据对话是否完成决定结束或继续
循环实现
通过完成检查节点和条件边实现对话循环:
- 如果对话未完成:完成检查 → 发送回复 → (用户新消息) → 意图识别…
- 如果对话完成:完成检查 → 结束
检查点功能
使用LangGraph的Checkpoint功能保存对话状态,支持:
- 对话恢复
- 异常处理
- 潜在的分布式部署
4. 核心实现亮点
-
状态定义:使用TypedDict严格定义状态结构,包含所有必要信息
class CustomerServiceState(TypedDict): messages: List[Dict] intent: Optional[str] extracted_info: Dict needs_tool: bool tool_history: List[Dict] conversation_finished: bool reasoning: Optional[str] final_response: Optional[str]
-
工具集成:定义了多个工具函数,模拟真实系统API
@tool def check_order_status(order_id: str) -> Dict: # 实现订单查询逻辑 ... @tool def track_shipping(tracking_number: str) -> Dict: # 实现物流查询逻辑 ...
-
条件边逻辑:使用简洁的条件函数实现复杂决策流程
def should_use_tool(state: CustomerServiceState) -> str: return "use_tool" if state["needs_tool"] else "skip_tool" def is_conversation_finished(state: CustomerServiceState) -> str: return "end" if state["conversation_finished"] else "continue"
-
图构建:清晰的状态图定义,包含节点、边和条件边
# 条件边:是否使用工具 builder.add_conditional_edges( "determine_tool", should_use_tool, { "use_tool": "use_tool", "skip_tool": "generate_response" } )
-
检查点实现:使用MemorySaver和Checkpoint实现状态保存
memory = MemorySaver() checkpoint = Checkpoint(memory, "customer_service_state")
5. 工作流程图
以一个订单查询为例,完整流程如下:
- 用户输入:“我想查询订单ORD12345的状态”
- 意图识别节点:识别意图为"order_status",提取订单号"ORD12345"
- 工具决策节点:决定需要使用"check_order_status"工具
- 工具使用节点:调用工具获取订单信息
- 回复生成节点:基于工具结果生成友好回复
- 完成检查节点:判断对话是否需要继续
- 发送回复节点:将回复添加到对话历史
如果用户继续提问:“这个订单什么时候能到?”,系统会保持上下文理解,开始新的循环:
- 意图识别节点:识别意图为"shipping_inquiry",理解上下文中的订单
- 工具决策节点:决定使用"track_shipping"工具
- … 以此类推
这种方式使代理能够进行自然的多轮对话,同时保持对话历史和上下文理解。
总结
这个LangGraph综合案例展示了如何构建一个具有复杂状态管理和决策流程的智能代理。通过分解为清晰的节点和边,即使是复杂的多轮对话也能保持结构化和可维护性。代码实现了工具使用、循环决策和状态保存等高级特性,为构建企业级LLM应用提供了完整模板。
"""
电商智能客服代理 - 基于LangGraph的实现
这个代理可以:
1. 查询订单状态
2. 处理退款请求
3. 回答产品相关问题
4. 处理物流查询
5. 多轮对话解决复杂问题
"""
import os
import json
import uuid
from typing import Dict, List, Optional, TypedDict, Annotated, Tuple, Any
from datetime import datetime, timedelta
import random
# LangChain相关
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
# LangGraph相关
from langgraph.graph import StateGraph, END
from langgraph.checkpoint import MemorySaver, Checkpoint
# 设置OpenAI API密钥(实际使用时请通过环境变量或安全方式设置)
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
# --------------- 工具函数定义 ---------------
# 模拟的数据库
ORDERS_DB = {
"ORD12345": {
"customer_id": "CUST001",
"status": "shipped",
"items": [
{
"product_id": "PROD001", "name": "智能手表", "quantity": 1, "price": 299.99},
],
"total": 299.99,
"timestamp": "2024-03-18T14:30:00",
"shipping": {
"carrier": "顺丰",
"tracking_number": "SF1234567890",
"status": "in_transit",
"estimated_delivery": "2024-03-21",
}
},
"ORD12346": {
"customer_id": "CUST002",
"status": "delivered",
"items": [
{
"product_id": "PROD002", "name": "无线耳机", "quantity": 1, "price": 159.99},
{
"product_id": "PROD003", "name": "手机壳", "quantity": 2, "price": 19.99}
],
"total": 199.97,
"timestamp": "2024-03-15T09:20:00",
"shipping": {