LangGraph框架概览

1、LangGraph简介

  • 与传统的线性流程或树状结构截然不同,LangGraph 采用了状态图结构来设计 AI 智能体的工作流,将 AI 智能体执行任务的过程抽象为一个由节点(Node)和边 (Edge)构成的有向循环图(Directed Cyclic Graph,DCG)。这种状态图结构不仅 赋予了 LangGraph 框架极大的灵活性,更使其能够有效地构建状态化(Stateful)和 多智能体(Multi-agent)的复杂 AI 应用,从而应对传统框架难以企及的挑战。

  • 下图展示了 LangGraph 核心架构,它由节点(Node)、边(Edge)和状态(State) 组成。节点代表工作流中的计算单元,边定义节点之间的流向,状态则用于在节点之间传递和共享信息。

1.1 节点

  • 节点是 LangGraph 图中的基本构建块。它们代表了智能体工作流中的一个个独 立的计算单元或操作步骤。每个节点都封装了特定的功能逻辑,负责执行特定的任务。 LangGraph 的节点形式非常丰富,可以根据不同的应用需求进行灵活选择和组合,常 见的节点类型如下所示。
    • 大语言模型调用节点。这是 LangGraph 中最核心的节点形式之一,负责与大语言模型进行交互。通过大语 言模型调用节点(LLM Call Node),AI 智能体可以利用大语言模型的强大能力,执行各 种自然语言处理任务,例如文本生成、文本理解、语义分析等。开发者可以根据具体需求, 选择不同的大语言模型,并配置不同的提示词,以控制大语言模型的行为和输出。
    • 工具调用节点。AI 智能体的能力不仅仅局限于大语言模型本身,还需要能够与外部世界进行交 互才能完成更复杂的任务。工具 (Tool) 就是 AI 智能体与外部世界交互的桥梁。工具调用节点(Tool Call Node)允许 AI 智能体在工作流中调用各种外部工具或 API, 执行特定的操作。例如,AI 智能体可以使用搜索引擎工具获取网络信息,使用数据 库查询工具访问数据库,使用计算器工具进行数学计算,使用天气 API 查询天气信息,等等。通过工具调用节点,AI 智能体可以扩展自身的能力边界,完成更加多样化和 实用的任务。
    • 自定义函数节点。除大语言模型调用和工具调用外,开发者往往还需要在 AI 智能体的工作流中集 成自定义的业务逻辑或数据处理逻辑。自定义函数节点(Custom Function Node)允 许开发者将任何 Python 函数封装成 LangGraph 的节点,从而方便地将自定义的逻辑 融入 AI 智能体的工作流程中。这些自定义函数可以执行各种任务,例如数据预处理、 数据清洗、业务规则判断、外部系统集成等。自定义函数节点的灵活性极高,为开发者提供了无限的扩展空间。
    • 子图节点。当 AI 智能体的工作流变得非常复杂时,为了提高代码的模块化和可维护性, LangGraph 引入了子图 (Subgraph) 的概念。子图节点(Subgraph Node)允许开发 者将一组相关的节点和边封装成一个独立的子图,然后在主图中将这个子图作为一个 节点来使用。子图可以嵌套使用,用来构建层次化和模块化的复杂 AI 智能体系统。 子图节点大大提高了代码的可重用性和可组织性,使构建和维护大型 AI 智能体系统变得更加容易。

1.2 边

  • 边在 LangGraph 中定义了节点之间的连接和数据流向。它们决定了 AI 智能体工作流的执行顺序和逻辑。边就像是连接各节点的“管道”,负责将数据从一个节点传递到另一个节点,并控制着工作流的走向。LangGraph 支持多种类型的边,以满足不 同的工作流控制需求。
    • 普通边。普通边(Normal Edge)是最基本的边类型,定义了节点之间的直接顺序执行关系。 当工作流从一个节点通过普通边连接到另一个节点时,意味着前一个节点执行完成后, 会立即执行后一个节点。普通边用于构建线性的、顺序执行的工作流,例如,先执行节点 A,再执行节点 B,然后执行节点 C,依次类推。
    • 条件边。条件边(Conditional Edge)赋予了 LangGraph 工作流动态分支和条件判断的能力。 与普通边不同,条件边不是直接连接到下一个节点,而是连接到一个路由函数(Routing Function)。这个路由函数会根据当前的状态 (State) 或前一个节点的输出,动态 地决定下一个要执行的节点。条件边实现了工作流的分支逻辑,例如,如果满足条件 X, 则执行节点 B,否则执行节点 C。条件边是构建决策型 AI 智能体的关键,它使 AI 智能体能够根据不同的情况采取不同的行动。
    • 入口点。入口点(Entry Point)定义了 LangGraph 工作流的起始位置,即图的入口节点。 当一个工作流开始执行时,会从入口点指定的节点开始。每个 LangGraph 图都必须至少定义一个入口点。入口点通常指向工作流的第一个节点,例如,接收用户输入的 节点,或者初始化系统状态的节点。
    • 条件入口点。条件入口点(Conditional Entry Point)是入口点的扩展形式,通过初始条件动态 选择起始节点。与固定起始节点的普通入口点不同,条件入口点能够通过路由函数基于初始状态确定工作流程的起始执行节点。这种机制使 LangGraph 能够根据初始条 件启动不同的工作流程分支,显著提升了系统的灵活性。

1.3 状态

  • tateGraph 是 LangGraph 框架的核心图管理类。开发者通过其实例构建图结构来 定义节点与边的关系,并实现工作流逻辑。在实例化 StateGraph 时,必须预先定义状态(State)的数据结构。状态作为图的全局数据容器,承担着以下关键功能。
    • 上下文信息存储:状态可以记录 AI 智能体的完整交互历史,例如用户对话记录、任务执行进度、中间处理结果等。这构成了 AI 智能体的上下文 (Context), 使 AI 智能体能够理解对话的语境,记住用户的偏好,跟踪任务的进度,从而实现连贯的对话和持续的任务执行。
    • 节点间数据传递:状态是节点间数据传递的主要机制。每个节点执行完成后将输出写入状态,后续节点可以从状态中读取所需输入。状态就像一个共享的黑板, 使不同节点能够协同完成复杂任务。
    • 状态持久化:LangGraph 框架内置的状态持久化 (State Persistence) 机制, 支持将状态保存到外部存储介质中,例如内存、文件、数据库等。状态持久化使智能 体应用具备了记忆能力、容错能力和可恢复性。即使应用重启或发生错误,状态也能 够被保存和恢复,保证了 AI 智能体应用的可靠性和稳定性。此外,状态持久化还支持时间旅行 (Time Travel) 功能,开发者可回溯到历史状态并重新执行工作流,便于调试和优化。
    • 多智能体共享:在多智能体场景中,状态空间作为共享信息空间发挥着重 要作用。多个智能体可以同时访问和修改同一状态,实现信息共享与任务协同。这种 机制使不同智能体能够共同维护全局信息,高效完成复杂协作任务。
  • 虽然状态结构支持任意 Python 对象,但为了提高代码的质量和可维护性,通常 建议使用 TypedDict 或 Pydantic BaseModel 来进行明确定义。TypedDict 提供了类型 注解的功能,可以定义状态中包含的字段名称和数据类型。Pydantic BaseModel 则提供了更强大的数据验证、序列化 / 反序列化功能,可以定义默认值、数据约束、自定义校验逻辑等。
  • 总的来说,LangGraph 框架以其图架构、节点和边的灵活组合,以及强大的状态管理机制,为开发者提供了一个构建新一代 AI 智能体系统的理想平台。它不仅能够 处理传统的线性工作流,更擅长应对需要复杂状态管理、迭代逻辑和多智能体协作的 挑战性场景。LangGraph 的出现,标志着智能体开发进入了一个新的阶段,使开发者能够构建出更智能、更自主、更可靠的 AI 系统,推动各行各业实现革命性的变革。

2、LangGraph与LangChain的关系

  • LangGraph 和 LangChain 虽然都出自 LangChain 团队之手,且在名称上有着明显 的关联,但二者在框架定位、设计理念、功能侧重及适用场景上都存在本质区别。理 解二者之间的关系和差异,对于开发者选择合适的框架,以及构建更强大的 AI 应用至关重要。

  • 在深入探讨 LangGraph 与 LangChain 的关系之前,有必要先介绍 LangChain 表达式语言 (LangChain Expression Language,LCEL)。LCEL 是 LangChain 框架中用 于构建链式应用的声明式语法,通过简洁直观的方式连接 LangChain 的各种组件,例 如提示、模型、工具等,以构建 LLM 应用流水线。其核心理念在于声明式,开发者只需描述工作流结构和组件连接方式,而无须关注底层执行细节。这使 LCEL 非常适合快速进行原型开发和构建结构清晰、易于维护的 LLM 应用。

  • LCEL 基于有向无环图(Directed Acyclic Graph,DAG)架构,其中,节点代表 工作步骤(例如,LLM 调用、工具使用),边代表数据流向。“有向”意味着数据 只能单向流动,从一个节点流向下一个节点;“无环”则意味着工作流中数据不回流。 这种架构非常适合构建线性顺序执行的工作流,例如,“数据检索 → 文档摘要 → 答案生成”这样的流水线。LCEL 的优势在于其简洁性、高效性和易于理解的线性流程, 是构建从简单到中等复杂度的 LLM 应用的理想选择。

  • 然而,DAG 架构的线性特性在处理复杂动态的工作流中存在局限。在需要状态保持、迭代循环或多智能体协作的场景中,DAG 架构就显得力不从心。例如,在多轮对话智能体或者多智能体协同系统等需要复杂流程控制的场景中,线性的 DAG 架 构就难以有效地表达这些非线性的工作流。

  • LangGraph 的出现正是为了弥补 LCEL 在处理复杂工作流方面的不足。与 LCEL 的 DAG 架构不同,LangGraph 采用了有向循环图架构。DCG 允许在工作流图中存在 环路。这意味着数据可以在节点间循环流动,工作流迭代执行,并且根据状态或条件动态回溯。这一架构使 LangGraph 框架能处理复杂的状态化迭代工作流,例如,在 构建 ReAct 模式的智能体时,其推理节点和行动节点形成的循环,可以让 AI 智能体在推理和行动之间持续迭代优化解决方案。

  • 除了架构上的差异,LangGraph 的另一个重要特点是其独立性。虽然 LangGraph 由 LangChain 团队开发,并且可以很好地与 LangChain 的组件集成,但 LangGraph 实际上可以完全独立于 LangChain 使用。LangGraph 的节点可以是任意的 Python 函数, 甚至可以无缝集成其他框架的组件,例如,AutoGen、CrewAI、LlamaIndex 等。开发 者可以将这些框架定义的智能体封装成 LangGraph 的节点,在图中与其他节点连接, 构建跨框架的多智能体系统。这种高度的灵活性和开放性,使 LangGraph 不仅仅是 LangChain 生态系统的一部分,更是一个通用的智能体工作流编排平台。

  • 总而言之,LCEL 和 LangGraph 代表了 LangChain 生态系统中构建 LLM 应用的 两种不同范式:LCEL 擅长构建简单线性的流水线应用,基于 DAG 架构,简洁高效;而 LangGraph 则专注处理复杂状态化迭代流程,基于 DCG 架构,灵活强大。开发者可以根据具体场景需求单独选用,或者将二者结合使用,构建更加多样化和更加强大 的 AI 应用系统。

  • 为了更清晰地展现 LangChain(特别是 LCEL)和 LangGraph 在功能和应用场景 上的差异,我们将功能对比信息拆分到表中进行展示。

    • LangChain 和 LangGraph 核心架构与设计理念对比

      特性 LangChain (LCEL) LangGraph
      核心架构 基于链 (Chain-based), 有向无环图 (DAG) 基于图(Graph-based),有向循 环图 (DCG)
      设计理念 简化 LLM 应用开发,快速原 型开发,线性流程 构建复杂、状态化、多角色的 AI 智 能体系统,支持循环和迭代的工作流
    • LangChain 和 LangGraph 状态管理与工作流对比

      特性 LangChain (LCEL) LangGraph
      状态管理 相对简单,主要通过Memory组件
      实现短期记忆,状态管理能力有限
      强大,内置状态管理和持久化机制,支持长期记忆、
      状态回溯、时间旅行、多智能体共享状态等高级功能,状态管理能力强大
      工作流 线性或分支流程,流程相对固定,DAG 架构, 无环 循环流程,流程动态可变,支持迭代、循环、条件判断、
      动态分支等复杂逻辑,DCG 架构,支持环路
      多智能体 协作 支持,但相对复杂,需要手动管理智能体之间 的通信和协作 内置多智能体协作机制,通过图架构和状态共享,更易于构建复杂的多智能体协作系统,实现智能体之间的协同工作和任务委派
    • LangChain 与 LangGraph 适用场景与特点对比

      特性 LangChain (LCEL) LangGraph
      适用场景 聊天机器人、文档问答、文本摘要、
      代码生成等,简单流程应用,快速原型开发, 轻量级应用
      复杂智能体、多智能体系统、自动化工作流编排、
      需要状态保持、 长期记忆、迭代优化和动态决策的应用,构建高可靠性、高复杂 度的系统
      学习曲线 相对平缓,易于上手,对初学者友好 相对陡峭,需要理解图论、状态管理、并发编程等概念,对开发者技术能力要求更高
      框架复杂性 相对简单,框架结构清晰, 易于理解和使用 相对复杂,框架功能强大,但学习和使用成本较高
      生态系统 庞大而成熟,拥有丰富的组件库、工具和社区支持 相对年轻,生态系统仍在发展中, 但发展迅速,
      与 LangChain 生态深度融合,且可独立使用
      核心优势 易用性、快速原型开发、丰富的组件库、线性流程高效 执行 强大的状态管理、灵活的工作流控 制、
      构建复杂智能体系统的能力、 高可靠性、高扩展性、高灵活性、 支持混合框架集成
  • 从协同开发的角度来看,最佳实践是将 LangChain 和 LangGraph 结合使用, 充分发挥各自的优势。可以将 LangChain 视为 LangGraph 的“组件库”,利用 LangChain 提供的各种组件,例如模型(Model)、提示(Prompt)、链 (Chain)、 工具(Tool)等来构建 LangGraph 中的节点。LangChain 丰富的生态和便捷性可以加速 LangGraph 应用的开发过程。而 LangGraph 则提供了一个更高级的框架,用于组织和编排这些组件,构建更复杂的工作流和智能体系统。例如,可以使用 LangChain 的 ChatOpenAI 模型和 PromptTemplate 提示模板来构建 LangGraph 中的 LLM 调用节点,使用 LangChain 的 SerpAPI 工具(一个用于搜索引擎查询的工具)来构建 LangGraph 中的工具调用节点,等等。

  • 在实际项目开发中,框架的选择应该根据具体的应用场景和需求来决定。对于简单的、线性流程的应用,例如简单的问答机器人、文本摘要工具等,LangChain 通常就足够胜任,并且开发效率更高。LangChain 的易用性和快速原型开发能力可以帮 助开发者快速搭建应用原型,验证想法。

  • 而对于需要复杂状态管理、多智能体协作或迭代逻辑的应用,例如,复杂的 AI 助手、自动化工作流编排系统、多智能体对话系统、自主导航机器人等,LangGraph 则是更合适的选择。LangGraph 的图结构和强大的状态管理能力可以更好地应对这些 复杂场景带来的挑战,从而构建更强大、更可靠、更智能的 AI 系统。

  • 总而言之,LangChain 和 LangGraph 并非互相替代的关系,而是互补共生的关 系。LangChain 提供了 LLM 应用开发所需的基础组件和工具,LangGraph 则提供了 更高级的架构。开发者可以根据自己的需求灵活选择或组合使用这两个框架。理解 LangChain 和 LangGraph 的功能边界和协同方式,是成为一名优秀的 AI 应用开发者的必备技能。

3、基于LangGraph实现ReAct设计模式

  • 为了帮助大家深入理解 LangGraph 框架的图构建过程,并掌握如何从零开始搭建智能体,在这里将使用 Qwen 的模型,构建一个能够使用搜索工具查询天气信息的智能体。与之后将介绍的预制 API 不同,这次我们将从最基础的 LangGraph 组件开始,一步步构建 ReAct 智能体的工作流程,让大家能够清晰地看到图是如何被定义、节点和边是如何被添加和连接的,从而真正理解 LangGraph 的核心原理。

    • 首先,使用 pip 命令安装必要的 LangGraph 和 LangChain 核心库:

      1
      pip install langgraph langchain-openai
    • 使用 python-dotenv 库来管理环境变量:

      1
      pip install python-dotenv
    • 在当前工作目录下创建一个名为 .env 的文件,并添加以下内容:

      1
      2
      OPENAI_API_KEY1 = 'xxx'
      OPENAI_BASE_URL = 'xxx'
      1
      2
      3
      4
      import dotenv

      # 加载.env 文件中的环境变量,请确保.env 文件位于当前工作目录下
      dotenv.load_dotenv()

      现在,就可以开始实现 ReAct 智能体:导入必要的 LangGraph 和 LangChain 组件, 并定义智能体可以使用的工具——search。此工具用于模拟网页搜索功能,查询城市的天气信息。

    • 定义工具和工具节点。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      from langchain_core.tools import tool #导入tool装饰器,用于定义工具
      from langgraph.prebuilt import ToolNode # 导入 ToolNode,用于封装工具节点

      # 定义工具search,用于模拟网页搜索功能,查询城市的天气信息
      @tool
      def search(query: str):
      """ 设计网页搜索工具 """
      # 这是一个占位符工具,实际应用中需要替换为真正的搜索功能
      if "sf" in query.lower() or "san francisco" in query.lower():
      return "It's 16 degrees and foggy."
      return "It's 32 degrees and sunny."

      tools = [search] # 将 search 工具放入工具列表
      tool_node = ToolNode(tools) # 创建 ToolNode,将工具列表封装成 LangGraph 节点

      在这段代码中,我们定义了 search 工具,并使用 ToolNode 将工具列表 tools 封装成一个 LangGraph 节点 tool_node。ToolNode 是 LangGraph 预置的节点类型,专门用于执行工具调用。它接收工具列表作为输入,并在图执行过程中根据智能体的指令调用相应的工具。

    • 接下来,我们需要初始化语言模型。我们使用 OpenAI 平台提供的 gpt-4o-mini 模型,并将其配置为能够调用工具。

      1
      2
      3
      4
      from langchain_openai import ChatOpenAI

      # 初始化语言模型,使用gpt-4-turbo模型,并绑定工具
      model = ChatOpenAI(model="gpt-4-turbo", temperature=0).bind_tools(tools)

      这里 bind_tools(tools) 方法至关重要。它将我们定义的工具列表 tools 绑定到 ChatOpenAI 上,使该对话模型对象知道它可以使用哪些工具,以及如何调用这些工具。

    • 现在,我们开始构建 LangGraph 的工作流。首先,我们需要创建一个 StateGraph 实例。StateGraph 是 LangGraph 中用于构建和管理图的核心类。在创建 StateGraph 实例时,我们需要指定状态的类型。在本例中使用 MessageState 作为状态类型。 MessageState 是 LangGraph 预置的状态类型,专门用于处理消息列表,非常适合构建对话型智能体。

      1
      2
      3
      4
      from langgraph.graph import StateGraph, MessagesState

      # 定义状态类型为MessageState,用于处理消息列表
      workflow = StateGraph(MessagesState)
    • 其次,我们需要向图中添加节点。在本例中,我们需要添加两个核心节点。

      • agent节点:负责调用语言模型进行推理,决定下一步的行动(是生成回复还是调用工具)。要定义一个 Python 函数 call_model 作为 agent 节点的执行函数。call_model 函数接收当前的状态 state 作为输入,调用语言模型 model 进行推理, 并将模型的响应消息添加到状态中。

        1
        2
        3
        4
        5
        6
        7
        8
        # 定义agent节点的执行函数:call_model
        def call_model(state):
        messages = state['messages'] # 从状态中获取消息列表
        response = model.invoke(messages) # 调用语言模型 model 进行推理,输入为消息列表
        return {"messages": [response]} # 将模型响应消息封装成字典返回,键为 messages,值为包含响应消息的列表

        # 将 call_model 函数添加到图中,并命名为agent节点
        workflow.add_node("agent", call_model)

        在 call_model 函数中,首先从状态 state 中获取消息列表 messages,然后调用已初始化并绑定了工具的语言模型 model 的 invoke() 方法进行推理。将模型生成的响应消息 response 添加为字典 {“messages”: [response]} 返回。需要注意的是,这里返回的是字典格式而非直接返回 response,因为 LangGraph 的节点函数要求返回字典格式以更新状态。

      • tools节点:负责执行工具调用。接下来添加 tools 节点。我们已经在本节的开头创建了 tool_node 实例,现在只需要将其添加到图中即可。

        1
        2
        # 将之前创建的tool_node实例添加到图中,并命名为tools节点
        workflow.add_node("tools", tool_node)
    • 添加完节点后,我们需要定义图的边,连接各节点,构建工作流。首先,我们需要设置图的入口点,即工作流的起始节点。在本例中,我们希望工作流从 agent 节点开始,因此将 agent 节点设置为图的入口点。

      1
      2
      # 设置图的入口点为agent节点,表示工作流从该节点开始执行
      workflow.set_entry_point("agent")
    • 然后,我们需要定义节点之间的边。在本例中,我们需要定义三种类型的边。

      • 从 agent 节点到 tools 节点的条件边:当 agent 节点的响应消息中包含工具调用指令时,工作流需要流向 tools 节点,执行工具调用。我们需要定义一个条件判断函数 should_continue 来决定是否继续执行工具调用。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        from langgraph.constants import END

        # 定义条件判断函数should_continue,决定下一步执行哪个节点
        def should_continue(state):
        messages = state['messages'] # 从状态中获取消息列表
        last_message = messages[-1] # 获取最后一条消息,即agent节点的输出消息
        # 如果agent节点的输出消息中包含工具调用指令,则流向tools节点
        if last_message.tool_calls:
        return "tools"
        # 否则,工作流结束,流向 END
        return END

        should_continue 函数接收当前的状态 state 作为输入,获取状态中的最后一条消息(agent 节点的输出消息),并检查该消息是否包含工具调用指令 last_message. tool_calls。如果包含工具调用指令,则返回 tools 字符串,表示工作流应该流向 tools 节点;否则,返回 END,表示工作流应该结束。 END 是 LangGraph 预定义的特殊值, 用于表示工作流的终点。

      • 从 agent 节点到 END 的条件边:当 agent 节点的响应消息中不包含工具调用指令时,表示智能体已经生成了最终回复,工作流应该结束。我们需要在 should_ continue 函数中判断这种情况,并返回 END,表示工作流结束。

        1
        2
        3
        4
        5
        # 添加条件边:从agent节点出发,根据 should_continue 函数的返回值,决定流向 tools节点或 END
        workflow.add_conditional_edges(
        "agent", # 起始节点为 agent 节点
        should_continue # 条件判断函数为 should_continue
        )

        workflow.add_conditional_edges(“agent”, should_continue) 方法添加了一条从 agent 节点出发的条件边,并指定 should_continue 函数作为条件判断函数。LangGraph 会在 agent 节点执行完成后,调用 should_continue 函数,根据其返回值来决定下一步工作流的走向。

      • 从 tools 节点到 agent 节点的普通边:当 tools 节点执行完工具调用后,工作流应该返回到 agent 节点,让大语言模型根据工具调用的结果,决定下一步的行动(是再次调用工具,还是生成最终回复)。

        1
        2
        # 添加普通边:从tools节点到agent节点,表示工具调用完成后,总是返回 agent 节点继续推理
        workflow.add_edge("tools", "agent")
    • 至此,我们已经完成了 LangGraph 工作流图的构建,包括添加节点、设置入口点和定义边。在完成图的构建后,我们需要编译图,将其转换为一个可执行的 LangChain Runnable 对象。Runnable 对象可以像 LangChain 中的其他组件一样被调用和执行。

      1
      2
      # 编译图,得到可执行的app对象
      app = workflow.compile()
    • 最后,我们可以运行编译后的 app 对象,向其发送用户查询,测试我们构建的 ReAct 智能体。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      # 运行智能体应用 App,处理用户查询
      final_state = app.invoke(
      {
      "messages": [
      {"role": "user", "content": "What is the weather in San Francisco"}
      ]
      }
      )

      # 打印智能体的最后一条回复消息的内容
      print(final_state["messages"])
      # [HumanMessage(content='What is the weather in San Francisco', additional_kwargs={}, response_metadata={}, id='0d5763d1-a12b-4e30-8e34-21f98eab5024'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 16, 'prompt_tokens': 53, 'total_tokens': 69, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'gpt-4-turbo-2024-04-09', 'system_fingerprint': 'fp_5603ee5e2e', 'id': 'chatcmpl-CW0NRpc7DulJte0blDNZNeCCLu2q5', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--81560247-00b5-491e-be7a-809eecb7a03c-0', tool_calls=[{'name': 'search', 'args': {'query': 'weather in San Francisco'}, 'id': 'call_T7VG31XBXhUeVmiUdh1IucHs', 'type': 'tool_call'}], usage_metadata={'input_tokens': 53, 'output_tokens': 16, 'total_tokens': 69, 'input_token_details': {}, 'output_token_details': {}}), ToolMessage(content="It's 16 degrees and foggy.", name='search', id='2c7a1b71-c76f-45a9-a2a7-01618f6bc327', tool_call_id='call_T7VG31XBXhUeVmiUdh1IucHs'), AIMessage(content='The current weather in San Francisco is 16 degrees and foggy.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 83, 'total_tokens': 98, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'gpt-4-turbo-2024-04-09', 'system_fingerprint': 'fp_5603ee5e2e', 'id': 'chatcmpl-CW0NSFIBdxlST1MC8Rcmi5DoG9BPg', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--a75f4b94-ddbd-471e-a523-68b4174de149-0', usage_metadata={'input_tokens': 83, 'output_tokens': 15, 'total_tokens': 98, 'input_token_details': {}, 'output_token_details': {}})]

      print(final_state["messages"][-1].content)
      # The current weather in San Francisco is 16 degrees and foggy.
  • 为了帮助大家更深入地理解 LangGraph 的执行流程,我们来逐步分解一下当运 行 app.invoke() 方法时,LangGraph 内部是如何执行的。

    • 1、LangGraph 将输入消息添加到内部状态,并将状态传递给入口点节点 agent。
    • 2、agent 节点执行 call_model 函数,调用大语言模型进行推理。
    • 3、大语言模型返回 AIMessage,LangGraph 将其添加到状态中。
    • 4、LangGraph 检查 AIMessage 是否包含工具调用指令 tool_calls。
      • 如果 AIMessage 包含 tool_calls,则根据条件判断函数 should_continue 的判断结果,工作流流向 tools 节点。tools 节点执行,调用相应的工具。tools 节点执行完成后,根据普通边,工作流返回到 agent 节点,重复步骤2~4,进行下一轮推理和工具调用,直到语言模型生成最终回复。
      • 如果 AIMessage 不包含 tool_calls,则根据条件判断函数 should_continue 的判断结果,工作流流向 END,表示工作流结束。
    • 5、执行过程到达 END,输出最终状态。在本例中,最终状态包含了对话的所有消息记录,我们从中提取最后一条消息(智能体的回复消息)并打印出来。
  • 通过这个以手工构建图的方式实现的 ReAct 智能体示例,我们初步展示了如何使用 LangGraph 的核心组件构建图、添加节点、定义边、设置入口点,以及编译和运行图。同时,我们也可以了解到,LangGraph 并非仅仅是一个工具,更是一种构建复杂智能体系统的全新思路。它以图结构为核心,赋予了智能体强大的状态管理和工作流控制能力。