langgraph 介绍
了解项目的详细信息和使用方法
🦜🕸️LangGraph
⚡ 构建语言智能体的图形 ⚡
概述
LangGraph 是一个用于构建有状态的多角色应用程序的库,使用大语言模型(LLMs)来创建智能体和多智能体工作流程。与其他 LLM 框架相比,它提供了以下核心优势:循环、可控性和持久性。LangGraph 允许您定义包含循环的流程,这对于大多数智能体架构至关重要,从而区别于基于有向无环图(DAG)的解决方案。作为一个非常底层的框架,它提供了对应用程序流程和状态的精细控制,这对于创建可靠的智能体至关重要。此外,LangGraph 包含内置的持久性功能,支持高级的人机协作和记忆功能。
LangGraph 的灵感来源于 Pregel 和 Apache Beam。公共接口借鉴了 NetworkX 的设计。LangGraph 由 LangChain Inc 开发,虽然与 LangChain 紧密集成,但可以独立使用。
主要特性
- 循环和分支:在您的应用程序中实现循环和条件语句。
- 持久性:在图形的每一步自动保存状态。支持错误恢复、人机协作工作流、时间旅行等功能,可以在任何时候暂停和恢复图形执行。
- 人机协作:在图形执行过程中中断,以批准或编辑智能体计划的下一个动作。
- 流支持:在每个节点产生输出时进行流式传输(包括 Token 流式传输)。
- 与 LangChain 的集成:LangGraph 与 LangChain 和 LangSmith 无缝集成(但不强制要求使用它们)。
安装
shell1pip install -U langgraph
示例
LangGraph 的核心概念之一是状态。每次图形执行都会创建一个状态,该状态在图形中的各个节点之间传递,并且每个节点在执行后会用其返回值更新内部状态。图形更新其内部状态的方式由选择的图形类型或自定义函数定义。
让我们来看一个使用搜索工具的简单智能体示例。
shell1pip install lang 2 3chain-anthropic
shell1export ANTHROPIC_API_KEY=sk-...
可选地,我们可以设置 LangSmith 以实现一流的可观察性。
shell1export LANGSMITH_TRACING=true 2export LANGSMITH_API_KEY=lsv2_sk_...
python1from typing import Annotated, Literal, TypedDict 2 3from langchain_core.messages import HumanMessage 4from langchain_anthropic import ChatAnthropic 5from langchain_core.tools import tool 6from langgraph.checkpoint import MemorySaver 7from langgraph.graph import END, StateGraph, MessagesState 8from langgraph.prebuilt import ToolNode 9 10 11# 定义智能体使用的工具 12@tool 13def search(query: str): 14 """调用上网搜索。""" 15 # 这是一个占位符,但不要告诉大语言模型…… 16 if "sf" in查询.lower()或"san francisco"在查询.lower()中: 17 return ["60度,起雾。"] 18 return ["90度,晴天。"] 19 20tools = [search] 21 22tool_node = ToolNode(tools) 23 24model = ChatAnthropic(model="claude-3-5-sonnet-20240620", temperature=0).bind_tools(tools) 25 26# 定义是否继续的函数 27def should_continue(state: MessagesState) -> Literal["tools", END]: 28 messages = state['messages'] 29 last_message = messages[-1] 30 # 如果大语言模型发出工具调用,则路由到 "tools" 节点 31 if last_message.tool_calls: 32 return "tools" 33 # 否则,停止(回复用户) 34 return END 35 36# 定义调用模型的函数 37def call_model(state: MessagesState): 38 messages = state['messages'] 39 response = model.invoke(messages) 40 # 返回一个列表,因为这将被添加到现有列表中 41 return {"messages": [response]} 42 43# 定义新图形 44workflow = StateGraph(MessagesState) 45 46# 定义我们将循环的两个节点 47workflow.add_node("agent", call_model) 48workflow.add_node("tools", tool_node) 49 50# 设置入口点为 "agent" 51# 这意味着这是第一个被调用的节点 52workflow.set_entry_point("agent") 53 54# 我们现在添加一个条件边 55workflow.add_conditional_edges( 56 # 首先,我们定义起始节点。我们使用 "agent"。 57 # 这意味着这些是 "agent" 节点被调用后采取的边。 58 "agent", 59 # 接下来,我们传递决定下一个被调用节点的函数。 60 should_continue, 61) 62 63# 我们现在添加从 "tools" 到 "agent" 的普通边。 64# 这意味着调用 "tools" 后,下一步调用 "agent" 节点。 65workflow.add_edge("tools", 'agent') 66 67# 初始化内存以在图形运行之间持久化状态 68checkpointer = MemorySaver() 69 70# 最后,我们编译它! 71# 这将其编译成一个 LangChain 可运行对象, 72# 这意味着你可以像使用其他可运行对象一样使用它。 73# 注意,我们在编译图形时(可选地)传递了内存 74app = workflow.compile(checkpointer=checkpointer) 75 76# 使用可运行对象 77final_state = app.invoke( 78 {"messages": [HumanMessage(content="sf 的天气如何")]}, 79 config={"configurable": {"thread_id": 42}} 80) 81final_state["messages"][-1].content
"根据搜索结果,我可以告诉你当前旧金山的天气是:\n\n温度:60华氏度\n情况:起雾\n\n旧金山以其微气候和频繁的雾而闻名,特别是在夏季。60华氏度(约15.5摄氏度)的温度对于该市来说是非常典型的,全年气温较为温和。雾,常被当地人称为“卡尔的雾”,是旧金山天气的特征,尤其在早晨和傍晚。\n\n你还想知道旧金山或其他地方的天气情况吗?"
现在当我们传递相同的 "thread_id"
时,对话上下文通过保存的状态(即存储的消息列表)得以保留。
python1final_state = app.invoke( 2 {"messages": [HumanMessage(content="ny 的天气如何")]}, 3 config={"configurable": {"thread_id": 42}} 4) 5final_state["messages"][-1].content
"根据搜索结果,我可以告诉你当前纽约市的天气是:\n\n温度:90华氏度(约32.2摄氏度)\n情况:晴天\n\n这种天气与我们刚刚看到的旧金山的天气完全不同。纽约现在的气温要高得多。以下是几个需要注意的要点:\n\n1. 90华氏度的温度非常热,是纽约市夏季天气的典型代表。\n2. 晴天意味着晴朗的天空,这对户外活动来说很棒,但也意味着由于阳光直射,感觉可能会更热。\n3. 这种天气在纽约经常伴随着高湿度,这会使实际感觉比实际温度更热。\n\n看到旧金山温和的雾天和纽约炎热的晴天之间的鲜明对比很有趣。这种差异说明了美国不同地区在同一天内天气的多样性。\n\n你还想知道纽约或其他地方的天气情况吗?"
分步讲解
-
初始化模型和工具。
- 我们使用
ChatAnthropic
作为我们的 LLM。注意: 我们需要确保模型知道它有这些可调用的工具。我们可以通过使用.bind_tools()
方法将 LangChain 工具转换为 OpenAI 工具调用格式来实现这一点。 - 我们定义了要使用的工具 - 在我们的例子中是一个搜索工具。创建自己的工具非常简单 - 有关如何执行此操作的文档请参见这里。
- 我们使用
-
初始化带状态的图形。
- 我们通过传递状态架构(在我们的例子中为
MessagesState
)来初始化图形(StateGraph
) MessagesState
是一个预构建的状态架构,具有一个属性——LangChainMessage
对象列表,以及用于合并每个节点的更新到状态中的逻辑
- 我们通过传递状态架构(在我们的例子中为
-
定义图形节点。
我们需要的两个主要节点是:
agent
节点:负责决定是否采取任何行动。tools
节点:调用工具:如果智能体决定采取行动,则该节点将执行该行动。
-
定义入口点和图形边。
首先,我们需要设置图形执行的入口点 -
agent
节点。然后我们定义一个普通边和一个条件边。条件边意味着目标取决于图形状态的内容(
MessageState
)。在我们的例子中,目标直到智能体(LLM)决定后才确定。- 条件边:在调用智能体后,我们应该:
- a. 如果智能体说要采取行动,则运行工具,或者
- b. 如果智能体没有要求运行工具,则结束(回复用户)
- 普通边:在调用工具后,图形应始终返回到智能体,以决定下一步该做什么
- 条件边:在调用智能体后,我们应该:
-
编译图形。
- 当我们编译图形时,我们将其转变为 LangChain Runnable,这会自动启用用输入调用
.invoke()
、.stream()
和.batch()
。 - 我们还可以选择传递检查点对象以在图形运行之间持久化状态,并启用内存、人机协作工作流、时间旅行等功能。在我们的例子中,我们使用
MemorySaver
- 一个简单的内存检查点器。
- 当我们编译图形时,我们将其转变为 LangChain Runnable,这会自动启用用输入调用
-
执行图形。
-
LangGraph 将输入消息添加到内部状态,然后将状态传递到入口点节点,
"agent"
。 -
"agent"
节点执行,调用聊天模型。 -
聊天模型返回一个
AIMessage
。LangGraph 将其添加到状态中。 -
图形循环以下步骤,直到
AIMessage
上没有更多的tool_calls
:- 如果
AIMessage
有tool_calls
,则"tools"
节点执行 "agent"
节点再次执行并返回AIMessage
- 如果
-
执行进程到达特殊的
END
值并输出最终状态。 结果,我们得到所有聊天消息的列表作为输出。
-
文档
- 教程:通过指导示例学习使用 LangGraph 进行
构建。