如何从节点更新图状态¶
本指南演示了如何在 LangGraph 中定义和更新状态。我们将演示
我们将在示例中使用消息。这代表了许多 LLM 应用的一种通用的状态表示形式。请参阅我们的概念页面了解更多详细信息。
设置¶
首先,让我们安装 langgraph
设置LangSmith以获得更好的调试体验
注册 LangSmith,快速发现问题并提升 LangGraph 项目的性能。LangSmith 允许你使用跟踪数据来调试、测试和监控使用 LangGraph 构建的 LLM 应用——在文档中阅读更多关于如何入门的信息。
示例图¶
定义状态¶
LangGraph 中的状态可以是 TypedDict
、Pydantic
模型或数据类 (dataclass)。下面我们将使用 TypedDict
。有关使用 Pydantic 的详细信息,请参阅本指南。
默认情况下,图将具有相同的输入和输出模式,状态决定了该模式。有关如何定义不同的输入和输出模式,请参阅本指南。
让我们考虑一个简单的示例
API 参考:AnyMessage
from langchain_core.messages import AnyMessage
from typing_extensions import TypedDict
class State(TypedDict):
messages: list[AnyMessage]
extra_field: int
此状态跟踪消息对象列表,以及一个额外的整数字段。
定义图结构¶
让我们构建一个包含单个节点的示例图。我们的节点只是一个 Python 函数,它读取图的状态并对其进行更新。此函数的第一个参数始终是状态
API 参考:AIMessage
from langchain_core.messages import AIMessage
def node(state: State):
messages = state["messages"]
new_message = AIMessage("Hello!")
return {"messages": messages + [new_message], "extra_field": 10}
此节点仅将一条消息附加到我们的消息列表中,并填充一个额外字段。
重要提示
节点应直接返回状态更新,而不是改变状态。
接下来,让我们定义一个包含此节点的简单图。我们使用StateGraph来定义一个在该状态上操作的图。然后我们使用add_node来填充我们的图。
API 参考:StateGraph
from langgraph.graph import StateGraph
graph_builder = StateGraph(State)
graph_builder.add_node(node)
graph_builder.set_entry_point("node")
graph = graph_builder.compile()
LangGraph 提供了用于可视化图的内置实用工具。让我们检查一下我们的图。有关可视化的详细信息,请参阅本指南。
在这种情况下,我们的图只执行一个节点。
使用图¶
让我们进行一个简单的调用
API 参考:HumanMessage
from langchain_core.messages import HumanMessage
result = graph.invoke({"messages": [HumanMessage("Hi")]})
result
{'messages': [HumanMessage(content='Hi', additional_kwargs={}, response_metadata={}),
AIMessage(content='Hello!', additional_kwargs={}, response_metadata={})],
'extra_field': 10}
请注意
- 我们通过更新状态的单个键来启动调用。
- 我们在调用结果中接收到整个状态。
为了方便起见,我们经常通过 pretty-print 来检查消息对象的内容
================================ Human Message =================================
Hi
================================== Ai Message ==================================
Hello!
使用 Reducer 处理状态更新¶
状态中的每个键都可以有其独立的Reducer函数,它控制如何应用来自节点的更新。如果未显式指定 Reducer 函数,则假定对该键的所有更新都应覆盖它。
对于 TypedDict
状态模式,我们可以通过使用 Reducer 函数注释状态的相应字段来定义 Reducer。
在前面的示例中,我们的节点通过将消息附加到状态中的 "messages"
键来更新它。下面,我们为此键添加一个 Reducer,以便自动附加更新。
from typing_extensions import Annotated
def add(left, right):
"""Can also import `add` from the `operator` built-in."""
return left + right
class State(TypedDict):
messages: Annotated[list[AnyMessage], add]
extra_field: int
现在我们的节点可以简化了
def node(state: State):
new_message = AIMessage("Hello!")
return {"messages": [new_message], "extra_field": 10}
API 参考:START
from langgraph.graph import START
graph = StateGraph(State).add_node(node).add_edge(START, "node").compile()
result = graph.invoke({"messages": [HumanMessage("Hi")]})
for message in result["messages"]:
message.pretty_print()
================================ Human Message =================================
Hi
================================== Ai Message ==================================
Hello!
MessagesState¶
实践中,更新消息列表还有其他注意事项
- 我们可能希望更新状态中的现有消息。
- 我们可能希望接受消息格式的简写,例如OpenAI 格式。
LangGraph 包含一个内置的 Reducer add_messages
,用于处理这些注意事项
API 参考:add_messages
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list[AnyMessage], add_messages]
extra_field: int
def node(state: State):
new_message = AIMessage("Hello!")
return {"messages": [new_message], "extra_field": 10}
graph = StateGraph(State).add_node(node).set_entry_point("node").compile()
input_message = {"role": "user", "content": "Hi"}
result = graph.invoke({"messages": [input_message]})
for message in result["messages"]:
message.pretty_print()
================================ Human Message =================================
Hi
================================== Ai Message ==================================
Hello!
MessagesState
以方便使用,因此我们可以
下一步¶
- 继续阅读图 API 基础知识指南。
- 查看更多关于状态管理的详细信息。