【LangGraph】强大的功能人类和agent的交互(上)

397 阅读3分钟

【LangGraph】手把手实现人类怎么和agent的交互

LangGraph 是一个使用 LLM 构建有状态、多参与者应用程序的库,用于创建代理和多代理工作流。与其他 LLM 框架相比,它具有以下核心优势:循环、可控性和持久性。LangGraph 允许您定义涉及循环的流程,这对于大多数代理架构来说都是必不可少的,这使它有别于基于 DAG 的解决方案。作为一个非常低级的框架,它提供了对应用程序的流程和状态的细粒度控制,这对于创建可靠的代理至关重要。此外,LangGraph 还包括内置持久性,可实现高级的人机循环和记忆功能。下面我们来讲述一下怎么用 LangGraph 实现人类怎么和 agent 交互。

一、定义环境和图

  1. 设置环境的引用
from dotenv import load_dotenv
load_dotenv()
from typing import Annotated

from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from typing_extensions import TypedDict

from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, START
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
  1. 定义状态包含的消息格式和状态图
class State(TypedDict):
    messages: Annotated[list, add_messages]

graph_builder = StateGraph(State)

二、agent的暂停

  1. 定义一个搜索工具 TavilySearch ,也可以自定义,如下:
tool = TavilySearchResults(max_results=2)
tools = [tool]
  1. 初始化一个大模型,如下:
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools(tools)
  1. 定义一个回调大模型并返回大模型结果的的方法:
def chatbot(state: State):
    return {"messages": [llm_with_tools.invoke(state["messages"])]}
  1. 增加大模型回调方法节点
graph_builder.add_node("chatbot", chatbot)
  1. 增加使用工具节点
tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
  1. 增加条件边,以 chatbot 为起点,tools_condition - 这是一个条件函数,它决定下一步应该跳转到哪个节点,这里要么是tool节点要么是 END 节点,这也告诉图表“任何时候 chatbot 节点运行时,如果它调用工具,则转到‘工具’,如果它直接响应,则结束循环。
graph_builder.add_conditional_edges(
    "chatbot",
    tools_condition,
)
  1. 增加边从 toolschatbot(大模型回调方法节点)
graph_builder.add_edge("tools", "chatbot")
  1. 增加边从 STARTchatbot(大模型回调方法节点)
graph_builder.add_edge(START, "chatbot")
  1. 我们使用内存检查点。它将所有内容保存在内存中。在生产应用程序中,您可能会将其更改为使用 SqliteSaverPostgresSaver 并连接到您自己的数据库。
memory = MemorySaver()
  1. 现在,编译图表,指定 interrupt_before 节点 tools
graph = graph_builder.compile(
    checkpointer=memory,
    interrupt_before=["tools"],
)
  1. 接下来,开始呼叫我们的聊天机器人。
user_input = "I'm learning LangGraph. Could you do some research on it for me?"
config = {"configurable": {"thread_id": "2"}}
events = graph.stream(
    {"messages": [("user", user_input)]}, config, stream_mode="values"
)
for event in events:
    if "messages" in event:
        event["messages"][-1].pretty_print()

是不是中断了 那让我们检查图形状态以确认它有效。下面图片是执行结果:

snapshot = graph.get_state(config)
print(f"snapshot.next: {snapshot.next}")

在这里插入图片描述 由于这里我们把“下一个”节点设置为“工具”。我们在这里中断了!让我们检查一下工具调用。下面图片是执行结果:

existing_message = snapshot.values["messages"][-1]
print(f"existing_message.tool_calls: {existing_message.tool_calls}")

在这里插入图片描述 要让我们的图标继续运行,接下来,传入 None 就会让图表从中断处继续,而不会向状态添加任何新内容。

events = graph.stream(None, config, stream_mode="values")
for event in events:
    if "messages" in event:
        event["messages"][-1].pretty_print()

在这里插入图片描述

三、总结

上面就是我们控制状态图 agent 的第一步,我们已经使用 interruptagent 添加了人机交互中的断点,以便在需要时进行人工监督和干预。由于我们已经添加了检查点,因此图表可以无限期暂停并随时恢复,就像什么都没发生过一样。 下面,我们将探讨如何使用自定义状态更新进一步定制机器人的行为。