langgraph入门教案

LangGraph 深度学习教案

目录

  1. 引言
    • LangChain 与 LangGraph 的关系
    • 为什么选择 LangGraph
  2. LangGraph 基础概念
    • 节点(Nodes)
    • 边(Edges)
    • 状态(State)
  3. 环境配置
    • 安装必要的库
    • 配置数据库和模型
  4. 构建单代理工作流程
    • 定义 SQL 执行工具
    • 定义代理状态
    • 构建代理
    • 可视化代理图
    • 测试代理
  5. 持久化和流式处理
    • 持久化状态
    • 流式处理数据
    • 多线程交互
  6. 构建多代理系统
    • 定义多代理状态
    • 构建路由器节点
    • 构建专家节点
    • 构建编辑器和人类反馈节点
    • 测试多代理系统
  7. 总结

1. 引言

LangChain 与 LangGraph 的关系

LangChain 是一个用于构建由大型语言模型(LLM)驱动的应用程序的领先框架。它允许开发者使用 LangChain 表达语言(LCEL)来定义和执行操作序列,这些序列被称为(Chains)。这些链可以视为有向无环图(DAG),用于线性执行任务。

然而,随着 LLM 应用程序的发展,特别是在构建代理(Agents)时,我们需要更复杂的交互,包括循环、条件逻辑和多步骤推理。这就引入了 LangGraph,它是 LangChain 的一个新模块,允许我们将交互建模为循环图,从而支持更复杂的工作流和代理行为。

为什么选择 LangGraph

LangGraph 提供了以下优势:

  • 灵活性:支持循环和条件逻辑,能够构建复杂的对话和推理流程。
  • 模块化设计:通过节点和边的组合,可以轻松地添加或修改代理的行为。
  • 持久化和恢复:状态在每个步骤后自动保存,允许在任何时刻暂停和恢复执行,这对于需要人机交互的应用程序非常重要。

2. LangGraph 基础概念

在开始实际编码之前,我们需要理解 LangGraph 的三个核心概念:节点、边和状态。

节点(Nodes)

节点代表实际的操作,可以是以下之一:

  • LLM 调用:调用大型语言模型进行推理或生成文本。
  • 代理:可以是另一个嵌套的代理,负责特定任务。
  • 函数或工具:执行特定的功能,如数据库查询、API 调用等。

边(Edges)

连接节点,确定图的执行流程。边有两种类型:

  • 基本边:简单地将一个节点连接到下一个节点,表示顺序执行。
  • 条件边:包含条件逻辑,根据状态决定下一步执行哪个节点。

状态(State)

状态是图的快照,包含执行过程中所有需要共享或持久化的数据。状态在节点之间传递,并可以被节点读取或修改。状态的设计对于代理的正确执行至关重要,因为它允许节点之间共享信息,并支持复杂的交互。


3. 环境配置

在开始编写代码之前,我们需要设置开发环境,安装必要的库,并配置模型和数据库。

安装必要的库

确保您的计算机上安装了 Python 3.6 或更高版本。

# 安装 langchain_community
pip install langchain_community

# 更新安装 langgraph
pip install -U langgraph

# 安装 graphviz(用于绘制图形)
brew install graphviz  # 如果您使用的是 macOS

# 安装 pygraphviz(用于在 Python 中使用 graphviz)
pip install pygraphviz

注意:在安装 pygraphviz 时,可能需要指定编译选项,以正确找到 graphviz 的头文件和库文件。如果遇到安装问题,请参考 pygraphviz 的安装指南

配置数据库和模型

在本教案中,我们将使用 ClickHouse 数据库和 OpenAI 的 GPT-4 模型(或其替代模型)。

import os
import json

# 读取配置文件(假设您有一个包含 API 密钥的 config.json 文件)
with open('config.json') as f:
    config = json.loads(f.read())

# 设置环境变量
os.environ["OPENAI_MODEL_NAME"] = 'gpt-4o-mini'  # 或者您选择的模型
os.environ["OPENAI_API_KEY"] = config['OPENAI_API_KEY']
os.environ["TAVILY_API_KEY"] = config["TAVILY_API_KEY"]

4. 构建单代理工作流程

在这一部分中,我们将构建一个简单的代理,能够根据用户输入执行 SQL 查询,并返回结果。

4.1 定义 SQL 执行工具

首先,我们需要定义一个工具,用于执行 SQL 查询。

from langchain_core.tools import tool
from pydantic.v1 import BaseModel, Field

# 定义 SQL 查询的参数模型
class SQLQuery(BaseModel):
    query: str = Field(description="要执行的 SQL 查询")

# 定义执行 SQL 的工具
@tool(args_schema=SQLQuery)
def execute_sql(query: str) -> str:
    """返回 SQL 查询执行的结果"""
    return get_clickhouse_data(query)

我们还需要定义 get_clickhouse_data 函数,用于实际执行 SQL 查询。

CH_HOST = 'http://localhost:8123'  # ClickHouse 默认地址
import requests

def get_clickhouse_data(query, host=CH_HOST, connection_timeout=1500):
    r = requests.post(host, params={
   
   'query': query}, timeout=connection_timeout)
    if r.status_code == 200:
        return r.text
    else:
        return '数据库返回以下错误:\n' + r.text

说明

  • 我们使用 @tool 装饰器将 execute_sql 函数注册为 LangChain 工具。
  • SQLQuery 是一个 Pydantic 模型,用于定义工具的参数和描述,帮助 LLM 正确地调用工具。
  • execute_sql 函数调用了 get_clickhouse_data 来执行实际的 SQL 查询。

4.2 定义代理状态

接下来,我们需要定义代理的状态,以便在节点之间共享信息。

from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator
from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage, ToolMessage

# 定义代理状态
class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]

说明

  • AgentState 是一个字典类型,包含一个 messages 列表,用于存储对话历史。
  • Annotatedoperator.add 用于指示在状态更新时,新的消息将添加到列表中,而不是替换。

4.3 构建代理

现在,我们开始构建代理,定义其节点和执行逻辑。

class SQLAgent:
    def __init__(self, model, tools, system_prompt=""):
        self.system_prompt = system_prompt
        graph = StateGraph(AgentState)

        # 添加节点
        graph.add_node("llm", self.call_llm)
        graph.add_node("function", self.execute_function)

        # 添加条件边:如果存在函数调用,则执行函数节点,否则结束
        graph.add_conditional_edges(
            "llm",
            self.exists_function_calling,
            {
   
   True: "function", False: END}
        )

        # 添加边:从函数节点回到 llm 节点
        graph.add_edge("function", "llm")

        # 设置起点
        graph.set_entry_point("llm")

        # 编译图
        self.graph = graph.compile()
        self.tools = {
   
   t.name: t for t in tools}
        self.model = model.bind_tools(tools)

    # 检查是否存在函数调用
    def exists_function_calling(self, state: AgentState):
        result = state['messages'][-1]
        return len(result.tool_calls) > 0

    # 调用 LLM
    def call_llm(self, state: AgentState):
        messages = state['messages']
        if self.system_prompt:
            messages = [SystemMessage(content=self.system_prompt)] + messages
        message = self.model.invoke(messages)
        return {
   
   'messages': [message]}

    # 执行函数调用
    def execute_function(self, state: AgentState):
        tool_calls = state['messages'][-1].tool_calls
        results = []
        for t in tool_calls:
            if not t['name'] in self.tools:
                result = "错误:没有这样的工具,请重试"
            else:
                result = self.tools[t['name']].invoke(t
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值