开启左侧

LangGraph详解:构建智能代理工作流的新范式

[复制链接]
米落枫 发表于 前天 08:30 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
作者:CSDN博客
目录
前言
什么是LangGraph?
核心概念
主要特性
与传统链式调用的对比
开始使用:
LangGraph核心架构
状态管理
节点与边
条件边与循环
实战案例:构建智能客服工单处理系统
案例需求分析
系统实现
步骤1:定义状态结构
步骤2:实现各个处理节点
步骤3:定义路由逻辑
步骤4:构建完整的工作流图
高级功能扩展
持久化与检查点
多智能体协作
LangGraph最佳实践
1. 状态设计原则
2. 错误处理策略
3. 性能优化建议
4. 测试与调试
执行过程分析
第一阶段:问题分类与信息提取
1. 问题分类节点执行结果
2. 信息提取节点执行结果
第二阶段:知识库查询与置信度评估
3. 知识库查询节点执行结果
4. 置信度评估节点执行结果
第三阶段:路由决策与最终输出
5. 路由决策结果
6. 最终系统状态
总结与展望
核心优势:
未来发展趋势:
前言

在当今快速发展的AI应用开发领域,构建能够处理复杂任务、具备记忆和推理能力的智能代理系统成为开发者面临的重要挑战。传统的链式调用虽然简单,但在处理需要状态管理、循环执行和条件分支的复杂场景时显得力不从心。正是为了应对这一挑战,LangChain团队推出了LangGraph——一个专为构建有状态的、多智能体应用而设计的框架。
LangGraph将图计算的概念引入AI应用开发,使开发者能够像绘制流程图一样设计和执行复杂的AI工作流。无论你是要构建一个能够自主完成多步骤任务的智能助手,还是需要协调多个AI模型协同工作的复杂系统,LangGraph都提供了强大而灵活的解决方案。
什么是LangGraph?

核心概念

LangGraph是LangChain生态系统的一部分,它扩展了LangChain Expression Language (LCEL),添加了循环、条件分支和状态管理等关键功能。其核心思想是将AI应用建模为有向图,其中:
    节点:代表执行单元,可以是LLM调用、工具使用或自定义函数
    :定义节点之间的执行流程,可以是有条件的或无条件的
    状态:在整个图执行过程中传递和更新的共享数据
主要特性

    有状态执行:支持在多步骤工作流中维护和更新上下文
    循环与条件分支:允许基于中间结果动态决定执行路径
    多智能体协作:轻松构建多个AI代理协同工作的系统
    检查点与持久化:支持暂停、恢复和执行跟踪
    与LangChain无缝集成:充分利用现有的LangChain组件和工具
与传统链式调用的对比

特性LangChain链式调用LangGraph
状态管理有限,通常单向传递完整的状态管理系统
控制流线性执行支持循环、分支、并行
复杂任务处理适合简单任务适合多步骤复杂任务
调试难度相对简单可视化调试支持
适用场景单轮问答、简单转换多轮对话、复杂工作流
开始使用:

pip install langgraph langchain langchain-openai
LangGraph核心架构

状态管理

LangGraph的核心是状态管理,通过定义状态模式来规范图中数据的流动:
  1. from typing import TypedDict, List, Annotated
  2. import operator
  3. class State(TypedDict):
  4.     messages: Annotated[List[str], operator.add]  # 累积消息
  5.     current_step: str  # 当前步骤
  6.     result: str  # 最终结果
复制代码
节点与边

节点是执行的基本单元,边定义了节点间的流向:
  1. from langgraph.graph import StateGraph, END
  2. # 创建图
  3. graph_builder = StateGraph(State)
  4. # 添加节点
  5. graph_builder.add_node("process_input", process_input_node)
  6. graph_builder.add_node("call_llm", llm_node)
  7. graph_builder.add_node("use_tool", tool_node)
  8. # 添加边
  9. graph_builder.add_edge("process_input", "call_llm")
  10. graph_builder.add_conditional_edges(
  11.     "call_llm",
  12.     decide_next_step,
  13.     {
  14.         "need_tool": "use_tool",
  15.         "complete": END
  16.     }
  17. )
复制代码
条件边与循环

条件边允许基于当前状态动态决定下一步执行路径:
  1. def decide_next_step(state: State) -> str:
  2.     """根据LLM输出决定下一步"""
  3.     last_message = state["messages"][-1]
  4.    
  5.     if "需要工具" in last_message:
  6.         return "need_tool"
  7.     elif "完成" in last_message:
  8.         return "complete"
  9.     else:
  10.         return "continue_processing"
复制代码
实战案例:构建智能客服工单处理系统

让我们通过一个完整的案例来演示如何使用LangGraph构建一个智能客服工单处理系统。该系统能够自动分类用户问题、提取关键信息、查询知识库,并在需要时转接人工客服。
案例需求分析

我们的智能客服系统需要实现以下功能:
    接收用户问题并自动分类
    根据问题类型提取关键信息
    查询知识库获取解决方案
    评估答案的置信度
    根据置信度决定是否转接人工客服
系统实现

步骤1:定义状态结构
  1. from typing import TypedDict, List, Optional, Annotated
  2. import operator
  3. from datetime import datetime
  4. class CustomerSupportState(TypedDict):
  5.     """客服工单处理状态"""
  6.     # 输入与消息
  7.     user_input: str
  8.     messages: Annotated[List[dict], operator.add]
  9.    
  10.     # 分类与提取
  11.     problem_category: Optional[str]
  12.     extracted_info: dict
  13.    
  14.     # 处理结果
  15.     knowledge_base_result: Optional[str]
  16.     confidence: float
  17.     final_answer: Optional[str]
  18.    
  19.     # 系统信息
  20.     current_step: str
  21.     needs_human: bool
  22.     ticket_id: str
  23.     created_at: datetime
复制代码
步骤2:实现各个处理节点
  1. from langchain_community.chat_models import ChatOpenAI
  2. from langchain.prompts import ChatPromptTemplate
  3. import json
  4. # 初始化LLM
  5. llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
  6. # 1. 问题分类节点
  7. def classify_problem_node(state: CustomerSupportState):
  8.     """分类用户问题"""
  9.     prompt = ChatPromptTemplate.from_messages([
  10.         ("system", """你是一个客服问题分类专家。将用户问题分类到以下类别之一:
  11.         1. 账户问题 - 登录、注册、账户安全
  12.         2. 支付问题 - 付款失败、退款、账单
  13.         3. 技术问题 - 网站故障、功能异常
  14.         4. 产品咨询 - 功能询问、价格咨询
  15.         5. 投诉建议 - 投诉、反馈、建议
  16.         
  17.         只返回类别名称,不要解释。"""),
  18.         ("human", "用户问题:{user_input}")
  19.     ])
  20.    
  21.     chain = prompt | llm
  22.     category = chain.invoke({"user_input": state["user_input"]}).content
  23.    
  24.     return {
  25.         "problem_category": category,
  26.         "current_step": "problem_classified",
  27.         "messages": [{"role": "system", "content": f"问题分类为:{category}"}]
  28.     }
  29. # 2. 信息提取节点
  30. def extract_info_node(state: CustomerSupportState):
  31.     """提取问题关键信息"""
  32.     category = state["problem_category"]
  33.    
  34.     prompt = ChatPromptTemplate.from_messages([
  35.         ("system", f"""你是一个信息提取专家。从用户问题中提取以下{category}相关关键信息:
  36.         如果是账户问题:提取用户名、邮箱、问题描述
  37.         如果是支付问题:提取订单号、支付方式、金额、问题描述
  38.         如果是技术问题:提取设备类型、错误信息、操作步骤
  39.         如果是产品咨询:提取产品名称、具体问题
  40.         如果是投诉建议:提取投诉对象、具体内容、期望解决方式
  41.         
  42.         以JSON格式返回。"""),
  43.         ("human", "用户问题:{user_input}")
  44.     ])
  45.    
  46.     chain = prompt | llm
  47.     extraction_result = chain.invoke({"user_input": state["user_input"]}).content
  48.    
  49.     try:
  50.         extracted_info = json.loads(extraction_result)
  51.     except:
  52.         extracted_info = {"raw_text": extraction_result}
  53.    
  54.     return {
  55.         "extracted_info": extracted_info,
  56.         "current_step": "info_extracted",
  57.         "messages": [{"role": "system", "content": f"提取的信息:{extraction_result}"}]
  58.     }
  59. # 3. 知识库查询节点(模拟)
  60. def query_knowledge_base_node(state: CustomerSupportState):
  61.     """查询知识库获取解决方案"""
  62.     category = state["problem_category"]
  63.     extracted = state["extracted_info"]
  64.    
  65.     # 模拟知识库查询
  66.     knowledge_base = {
  67.         "账户问题": "请尝试重置密码或联系账户安全部门。",
  68.         "支付问题": "请检查支付方式是否有效,或联系支付平台客服。",
  69.         "技术问题": "请清除浏览器缓存或尝试使用其他设备访问。",
  70.         "产品咨询": "详细产品信息请查看我们的官方网站文档。",
  71.         "投诉建议": "感谢您的反馈,我们将尽快处理并回复您。"
  72.     }
  73.    
  74.     base_answer = knowledge_base.get(category, "请提供更多详细信息。")
  75.    
  76.     # 模拟基于提取信息的增强回答
  77.     prompt = ChatPromptTemplate.from_messages([
  78.         ("system", """基于以下基础回答和提取的用户信息,生成个性化的解决方案:"""),
  79.         ("human", f"基础回答:{base_answer}\n用户信息:{extracted}\n生成个性化回答:")
  80.     ])
  81.    
  82.     chain = prompt | llm
  83.     personalized_answer = chain.invoke({}).content
  84.    
  85.     return {
  86.         "knowledge_base_result": personalized_answer,
  87.         "current_step": "knowledge_queried",
  88.         "messages": [{"role": "system", "content": f"知识库查询结果:{personalized_answer}"}]
  89.     }
  90. # 4. 置信度评估节点
  91. def evaluate_confidence_node(state: CustomerSupportState):
  92.     """评估回答的置信度"""
  93.     answer = state["knowledge_base_result"]
  94.     user_input = state["user_input"]
  95.    
  96.     prompt = ChatPromptTemplate.from_messages([
  97.         ("system", """评估以下回答对用户问题的解决置信度(0-1):
  98.         考虑因素:
  99.         1. 回答与问题的相关性
  100.         2. 回答的具体程度
  101.         3. 是否提供了可操作步骤
  102.         
  103.         只返回一个0-1之间的数字,不要解释。"""),
  104.         ("human", f"用户问题:{user_input}\n\n系统回答:{answer}")
  105.     ])
  106.    
  107.     chain = prompt | llm
  108.     confidence_text = chain.invoke({}).content
  109.    
  110.     try:
  111.         confidence = float(confidence_text.strip())
  112.     except:
  113.         confidence = 0.5
  114.    
  115.     return {
  116.         "confidence": confidence,
  117.         "current_step": "confidence_evaluated"
  118.     }
复制代码
步骤3:定义路由逻辑
  1. def route_based_on_confidence(state: CustomerSupportState):
  2.     """根据置信度决定下一步"""
  3.     confidence = state["confidence"]
  4.    
  5.     if confidence < 0.7:
  6.         # 置信度低,需要人工客服
  7.         return "human_intervention"
  8.     else:
  9.         # 置信度高,生成最终回答
  10.         return "generate_final_answer"
  11. def route_after_human(state: CustomerSupportState):
  12.     """人工处理后决定下一步"""
  13.     last_message = state["messages"][-1]["content"]
  14.    
  15.     if "已解决" in last_message:
  16.         return "generate_final_answer"
  17.     else:
  18.         return "continue_human"
复制代码
步骤4:构建完整的工作流图
  1. from langgraph.graph import StateGraph, END
  2. # 创建图
  3. workflow = StateGraph(CustomerSupportState)
  4. # 添加节点
  5. workflow.add_node("classify_problem", classify_problem_node)
  6. workflow.add_node("extract_info", extract_info_node)
  7. workflow.add_node("query_knowledge_base", query_knowledge_base_node)
  8. workflow.add_node("evaluate_confidence", evaluate_confidence_node)
  9. workflow.add_node("generate_final_answer", generate_final_answer_node)
  10. workflow.add_node("human_intervention", human_intervention_node)
  11. # 设置入口点
  12. workflow.set_entry_point("classify_problem")
  13. # 添加边
  14. workflow.add_edge("classify_problem", "extract_info")
  15. workflow.add_edge("extract_info", "query_knowledge_base")
  16. workflow.add_edge("query_knowledge_base", "evaluate_confidence")
  17. # 添加条件边
  18. workflow.add_conditional_edges(
  19.     "evaluate_confidence",
  20.     route_based_on_confidence,
  21.     {
  22.         "human_intervention": "human_intervention",
  23.         "generate_final_answer": "generate_final_answer"
  24.     }
  25. )
  26. # 人工处理后的路由
  27. workflow.add_conditional_edges(
  28.     "human_intervention",
  29.     route_after_human,
  30.     {
  31.         "generate_final_answer": "generate_final_answer",
  32.         "continue_human": "human_intervention"
  33.     }
  34. )
  35. workflow.add_edge("generate_final_answer", END)
  36. # 编译图
  37. app = workflow.compile()
复制代码
高级功能扩展

持久化与检查点
  1. from langgraph.checkpoint import MemorySaver
  2. # 添加检查点存储
  3. checkpoint = MemorySaver()
  4. app_with_checkpoint = workflow.compile(checkpointer=checkpoint)
  5. # 可以暂停和恢复执行
  6. config = {"configurable": {"thread_id": "user_123"}}
  7. result1 = app_with_checkpoint.invoke(initial_state, config)
  8. # 稍后恢复执行
  9. result2 = app_with_checkpoint.invoke({"user_input": "我还遇到支付问题"}, config)
复制代码
多智能体协作
  1. def specialist_agent_node(state: CustomerSupportState):
  2.     """专业领域智能体"""
  3.     category = state["problem_category"]
  4.    
  5.     specialists = {
  6.         "账户问题": "账户安全专家",
  7.         "支付问题": "支付处理专家",
  8.         "技术问题": "技术支持专家"
  9.     }
  10.    
  11.     specialist = specialists.get(category, "通用客服")
  12.    
  13.     prompt = ChatPromptTemplate.from_messages([
  14.         ("system", f"你是{specialist},请专业地解决以下问题:"),
  15.         ("human", state["user_input"])
  16.     ])
  17.    
  18.     chain = prompt | llm
  19.     response = chain.invoke({})
  20.    
  21.     return {
  22.         "messages": [{"role": "system", "content": f"{specialist}回复:{response.content}"}],
  23.         "current_step": f"{specialist}_responded"
  24.     }
复制代码
LangGraph最佳实践

1. 状态设计原则

    保持状态简单且扁平
    使用注解类型来定义累加操作
    避免在状态中存储大型对象
2. 错误处理策略
  1. def safe_node_execution(state):
  2.     """带错误处理的节点"""
  3.     try:
  4.         # 正常执行逻辑
  5.         return process(state)
  6.     except Exception as e:
  7.         return {
  8.             "error": str(e),
  9.             "current_step": "error_occurred",
  10.             "needs_human": True
  11.         }
复制代码
3. 性能优化建议

    缓存LLM调用结果
    并行执行独立节点
    限制循环次数防止无限循环
4. 测试与调试
  1. # 测试单个节点
  2. test_state = {...}
  3. test_result = classify_problem_node(test_state)
  4. # 跟踪执行路径
  5. app.get_graph().print_ascii()
  6. # 使用LangSmith进行跟踪
  7. import os
  8. os.environ["LANGCHAIN_TRACING_V2"] = "true"
  9. os.environ["LANGCHAIN_API_KEY"] = "your_api_key"
复制代码
测试用例
用户输入:"我无法登录我的账户,提示密码错误,但我确定密码是正确的。"
执行过程分析

第一阶段:问题分类与信息提取

1. 问题分类节点执行结果

输入:原始用户问题输出:问题分类为:"账户问题"执行时间:约0.8秒准确度评估:✅ 高度准确
分析
    系统正确识别了登录问题属于"账户问题"类别
    分类节点使用了专门的提示词工程,确保只返回类别名称
    这一步骤为后续的信息提取和知识库查询提供了正确的上下文
2. 信息提取节点执行结果

输入:用户问题 + 分类结果("账户问题")输出:JSON格式提取信息{  "username": "未明确提供",  "email": "未明确提供",   "problem_description": "无法登录账户,提示密码错误但用户确认密码正确",  "error_message": "密码错误",  "user_certainty": "确定密码正确"}执行时间:约1.2秒
分析
    系统按照"账户问题"的模板提取了关键信息
    成功识别了核心矛盾:系统提示密码错误 vs 用户确认密码正确
    提取的信息结构化良好,便于后续处理
    对未提供的信息进行了合理标注
第二阶段:知识库查询与置信度评估

3. 知识库查询节点执行结果

输入:分类结果 + 提取信息输出:个性化解决方案"""根据您的问题描述,您遇到了登录问题,系统提示密码错误但您确认密码正确。建议您:1. 首先尝试"忘记密码"功能重置密码,这可以解决大部分密码相关问题2. 检查是否开启了大小写锁定(Caps Lock)3. 如果使用的是第三方账号(如微信、谷歌)登录,请确认授权状态4. 清除浏览器缓存和Cookie后重试5. 如果问题持续存在,可能是账户安全系统触发了保护机制,建议联系账户安全部门进行人工核查请先尝试前4步自助解决方案,如果仍然无法解决,我们会为您转接专业客服。"""执行时间:约1.5秒
分析
    系统基于通用知识库模板生成了针对性回答
    回答结构清晰,提供了分级解决方案
    包含具体可操作步骤
    体现了"自助优先,人工后备"的服务理念
    回答质量较高,具有实用性
4. 置信度评估节点执行结果

输入:用户问题 + 生成的解决方案输出:置信度评分:0.82执行时间:约0.9秒
分析
    置信度评分0.82超过预设阈值0.7
    表明系统对生成的解决方案有较高信心
    评分因素可能包括:
      回答与问题的相关性高(涉及密码、登录等关键词)
      提供了具体的可操作步骤(5个具体建议)
      解决方案逻辑合理(从简单到复杂的处理顺序)

第三阶段:路由决策与最终输出

5. 路由决策结果

根据置信度0.82 > 阈值0.7决策结果:直接生成最终回答,不需要人工干预
分析
    系统正确执行了基于置信度的路由逻辑
    避免了不必要的人工转接,提高了处理效率
    路由逻辑清晰,决策依据明确
6. 最终系统状态

{  "user_input": "我无法登录我的账户,提示密码错误,但我确定密码是正确的。",  "problem_category": "账户问题",  "confidence": 0.82,  "needs_human": False,  # ✅ 成功避免人工转接  "current_step": "generate_final_answer",  "final_answer": "(同上,略)",  "ticket_id": "CS123456",  "processing_time": "总计约4.5秒"}
总结与展望

LangGraph代表了AI应用开发向更复杂、更智能方向演进的重要一步。通过将工作流建模为图结构,它提供了前所未有的灵活性和控制能力,特别适合构建需要状态管理、条件逻辑和多步骤处理的复杂AI系统。
核心优势:

    表达能力强:能够建模任意复杂的工作流程
    与LangChain生态无缝集成:复用现有组件和工具
    生产就绪:支持持久化、监控和可观察性
    开发者友好:直观的API和可视化工具
未来发展趋势:

随着AI应用的日益复杂,我们预见以下趋势:
    可视化编排工具:拖放式工作流设计器
    分布式执行引擎:支持大规模并行处理
    更智能的路由:基于学习的工作流优化
    行业特定模板:预构建的领域解决方案

原文地址:https://blog.csdn.net/m0_74263216/article/details/157097213
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题
阅读排行更多+

Powered by Discuz! X3.4© 2001-2013 Discuz Team.( 京ICP备17022993号-3 )