【LangGraph】手把手实现人类怎么和agent的交互
LangGraph
是一个使用 LLM
构建有状态、多参与者应用程序的库,用于创建代理和多代理工作流。与其他 LLM
框架相比,它具有以下核心优势:循环、可控性和持久性。LangGraph
允许您定义涉及循环的流程,这对于大多数代理架构来说都是必不可少的,这使它有别于基于 DAG
的解决方案。作为一个非常低级的框架,它提供了对应用程序的流程和状态的细粒度控制,这对于创建可靠的代理至关重要。此外,LangGraph 还包括内置持久性,可实现高级的人机循环和记忆功能。下面我们来讲述一下怎么用 LangGraph
实现人类怎么和 agent
交互。
一、定义环境和图
- 设置环境的引用
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
- 定义状态包含的消息格式和状态图
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
二、agent的暂停
- 定义一个搜索工具
TavilySearch
,也可以自定义,如下:
tool = TavilySearchResults(max_results=2)
tools = [tool]
- 初始化一个大模型,如下:
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools(tools)
- 定义一个回调大模型并返回大模型结果的的方法:
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
- 增加大模型回调方法节点
graph_builder.add_node("chatbot", chatbot)
- 增加使用工具节点
tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
- 增加条件边,以
chatbot
为起点,tools_condition
- 这是一个条件函数,它决定下一步应该跳转到哪个节点,这里要么是tool节点要么是END
节点,这也告诉图表“任何时候chatbot
节点运行时,如果它调用工具,则转到‘工具’,如果它直接响应,则结束循环。
graph_builder.add_conditional_edges(
"chatbot",
tools_condition,
)
- 增加边从
tools
到chatbot
(大模型回调方法节点)
graph_builder.add_edge("tools", "chatbot")
- 增加边从
START
到chatbot
(大模型回调方法节点)
graph_builder.add_edge(START, "chatbot")
- 我们使用内存检查点。它将所有内容保存在内存中。在生产应用程序中,您可能会将其更改为使用
SqliteSaver
或PostgresSaver
并连接到您自己的数据库。
memory = MemorySaver()
- 现在,编译图表,指定
interrupt_before
节点tools
。
graph = graph_builder.compile(
checkpointer=memory,
interrupt_before=["tools"],
)
- 接下来,开始呼叫我们的聊天机器人。
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
的第一步,我们已经使用 interrupt
为 agent
添加了人机交互中的断点,以便在需要时进行人工监督和干预。由于我们已经添加了检查点,因此图表可以无限期暂停并随时恢复,就像什么都没发生过一样。
下面,我们将探讨如何使用自定义状态更新进一步定制机器人的行为。