【智能体】从一个聊天工作流了解LangGraph

1. 前言

这篇文章将从如何搭建一个带网络搜索功能的聊天机器人工作流,带你初步了解 LangGraph。

 2. 前提条件

3. 什么是LangGraph

LangGraph 是由 LnagChain 创造者 LangChain Inc 开发的一款基于图结构的开源框架,其专注于构建有状态、多角色的应用程序,特别是与大型语言模型(LLMs)一起使用时,用于创建智能体和多智能体工作流。

3.1 为什么选择LangGraph

LangGraph 作为底层基础设施,支持 LLM 应用中的工作流(Workflow)和智能代理(Agentic System),提供持久化、流式处理和调试部署能力,助力构建更强大、更可控的 LLM 应用。其有以下三大核心优势:

1. 持久化(Persistence)  

  • 记忆能力(Memory):支持存储应用状态,实现对话记忆和跨用户交互的状态管理。

  • 人机协作(Human-in-the-loop):状态检查点化,支持执行中断与恢复,便于人工决策、验证和修正。  

2. 流式处理(Streaming)  

  • 支持工作流/代理状态的流式传输,使用户或开发者能在执行过程中获取实时反馈。  

  • 允许流式传输事件(如工具调用反馈)和 LLM 生成的 tokens,以提升交互体验。  

3. 调试与部署(Debugging and Deployment)

  • 通过 LangGraph Platform 提供简便的测试、调试和部署能力。  

  • 通过 LangGraph Studio 提供可视化工作流,支持交互式调试。

  • 提供多种部署选项,方便应用上线。  

3.2 和LangChain的关系

LangGraph 是 LangChain 生态中的一个子项目,专门用于构建图(Graph)结构的 LLM 工作流。它可以被认为是 LangChain 的补充,用于管理复杂的流程控制。它可以独立于LangChain使用。

3.3 LangGraph核心概念

LangGraph 框架中,会将智能体工作流(agent workflows)建模为图(Graphs),构建和运行图(Graphs)有三个核心概念:

1. State(状态):

  • 通常为 TypedDict(字典)或 Pydantic BaseModel(对象), 用于存储图运行时的状态信息。它在图的执行过程中被传递给各个节点和条件函数,用于存储和传递数据。你可以将 State 理解为各节点和条件函数间的上下文。

2. Nodes(节点):

  • 是一个 Python 函数,用来执行特定的操作或逻辑(比如数据处理、调用外部服务等)。节点接收当前的 State 作为入参,在执行一系列业务逻辑后,并返回更新后的 State。

3. Edges(边):

  • 也是一个 Python 函数,用于定义节点之间的连接关系,控制图的执行流程。边可以是无条件的,也可以是条件的。

简而言之,节点用于执行工作,边指示下一步做什么。

4. 聊天机器人实现

4.1 安装LangGraph

这个例子中需要使用 LangChain 构建与大模型对话的 ChatModel,所以我们需要安装 LangChain 相关包。我使用的是 0.3.0 版本。

# 安装 LangChain 和 LangChain OpenAI
pip install langchain==0.3.0 
pip install -U langchain-openai

# 安装最新版 LangGraph
pip install -U langgraph

# 安装tavily,tavily是一个网络检索工具 
pip install -U tavily-python

4.2 准备工作

4.2.1 选择模型

选择一个支持函数调(Function Calling)用的模型,并创建一个 ChatModel,我使用的是月之暗面的 moonshot-v1-8k 模型。

from langchain_openai import ChatOpenAI

# 构建一个chatModel
llm = ChatOpenAI(
    model="moonshot-v1-8k",
    openai_api_base="https://api.moonshot.cn/v1",
    openai_api_key="your_api_key",
    temperature=0.7,
    streaming=True,
)

4.2.2 申请tavily秘钥

tavily 是一个网络检索工具,我们需要在tavily官网申请一个秘钥来使用它(tavily 每月免费提供1000条搜索返回)。地址:Tavily AI

定义 Tavily Search 工具

tavily_tool = TavilySearchResults(
    # 返回的最大搜索条数
    max_results=2,
    tavily_api_key="your_tavily_api_key",
)

4.3 代码实现

4.3.1 流程图

工作流主要包含两个节点和两个条件边:

  • chatbot:聊天节点,负责与 LLM 交互。

  • tools:工具节点,负责调用 Tavily 搜索工具。

  • edge1:条件边(使用虚线表示),LLM会根据用户输入的内容自动判断是否调用tools节点,如果不需要调用会直接返回。

  • edge2:普通边,tools节点完成搜索任务后,返回chatbot节点继续对话。

4.3.2 完整代码

以下是整个带网络搜索功能的聊天机器人的完整代码

from typing import Annotated

from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from typing_extensions import TypedDict


# 定义一个状态类型,用于保存工作流中的上下文信息,为 TypedDict 类型
class State(TypedDict):
    # messages 用于记录与AI对话的记录,为 list 类型
    # add_messages 用于定义这个值的更新方式,即 将对话消息追加到列表中,而不是覆盖
    messages: Annotated[list, add_messages]


# 定义一个工作流,使用 State 类型作为输入和输出
working_flow = StateGraph(State)

# 定义 TavilySearchResults 工具
tavily_tool = TavilySearchResults(
    max_results=2,
    tavily_api_key="",
)
# 定义 ChatOpenAI 模型,并绑定工具
llm = ChatOpenAI(
    model="moonshot-v1-8k",
    openai_api_base="https://api.moonshot.cn/v1",
    openai_api_key="",
    temperature=0.7,
    streaming=True,
)
# 绑定工具
tools = [tavily_tool]
llm_with_tools = llm.bind_tools(tools)


# 聊天节点逻辑
def chatbot(state: State):
    # 调用大模型,LLM 会自动决定是否调用Tavily工具
    # 返回值是更新后的聊天记录
    return {"messages": [llm_with_tools.invoke(state["messages"])]}


# 添加节点
working_flow.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=tools)
working_flow.add_node("tools", tool_node)

# 添加条件边和普通边
working_flow.add_conditional_edges("chatbot", tools_condition, )
working_flow.add_edge("tools", "chatbot")

# 设置起点
working_flow.set_entry_point("chatbot")

# 创建MemorySaver,用于存储工作流的对话历史
memory = MemorySaver()
# 编译工作流
graph = working_flow.compile(checkpointer=memory)

4.3.3 运行测试

以下代码用于使用工作流并进行问答:

# 配置参数,包括唯一的线程ID,用于记录对话历史
config = {"configurable": {"thread_id": "1"}}
def stream_graph_updates(user_input: str):
    # 流式处理图的事件
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]},
                              config,
                              ):
        for value in event.values():
            # 打印助手的回复
            print("Assistant:", value["messages"][-1].content)


while True:
    try:
        # 获取用户输入
        user_input = input("User: ")
        # 检查退出条件
        if user_input.lower() in ["quit", "exit", "q"]:
            print("再见!")
            break

        # 调用函数处理用户输入
        stream_graph_updates(user_input)
    except KeyboardInterrupt:
        # 处理用户中断输入的情况
        print("\n输入被中断,再见!")
        break
    except Exception as e:
        # 捕获其他异常并打印错误信息
        print(f"发生错误: {e}")
        break

首先我们先问几个简单的问题,比如“你好”、“你是谁”,这些问题不足以让大模型调用Tavily工具。

然后我们尝试问大模型依据自身无法回答的问题,比如:”南京今天天气如何?“,我们发现大模型自动调用了Tavily工具,接着我们继续问“明天呢”,看看工作流是否具备聊天记忆。

到此为止,一个简单的聊天机器人就完成了。当然 LangGraph 还有很多高级功能,比如人机交互(Humman-in-the-loop)、时间旅行(Time-travel)等,我在之后的文章中会介绍。

5. 参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值