如何从节点更新图状态¶
本指南演示了如何在 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 基础知识指南。
- 查看更多关于状态管理的详细信息。