LangGraph的预构建状态MessagesState
官方参考链接
MessagesState源码:
from langchain_core.messages import AnyMessage
from langgraph.graph.message import add_messages
from typing import Annotated
from typing_extensions import TypedDict
class GraphState(TypedDict):
messages: Annotated[list[AnyMessage], add_messages]
为什么要使用消息?
大多数现代 LLM 提供商都有一个聊天模型接口,它接受消息列表作为输入。同时LangChain 的ChatModel 特别接受 Message 对象的列表作为输入。
在图中使用消息
在许多情况下,将之前的对话历史记录作为消息列表存储在图状态中很有帮助。为此,我们可以向图状态添加一个键(通道),该键存储 Message
对象的列表,并使用归约函数对其进行注释。
归约函数对于告诉图如何通过每次状态更新(例如,当节点发送更新时)来更新状态中的 Message
对象列表。如果您不指定归约器,则每次状态更新都将使用最新提供的值覆盖消息列表。
然而,您可能还希望手动更新图状态中的消息(例如,人工参与)。如果您使用 operator.add
作为归约器,则您发送到图的手动状态更新将被附加到现有消息列表,而不是更新现有消息。为避免这种情况,您需要一个能够跟踪消息 ID 并在更新时覆盖现有消息的归约器。为此,您可以使用预构建的 add_messages 函数。对于全新消息,它将简单地附加到现有列表;但它也会正确处理现有消息的更新。
序列化
除了跟踪消息 ID 之外,每当在 messages
通道上收到状态更新时,add_messages
函数还会尝试将消息反序列化为 LangChain Message
对象。
序列化官方参考链接
这允许以以下格式发送图输入/状态更新:
# this is supported
{"messages": [HumanMessage(content="message")]}
# and this is also supported
{"messages": [{"type": "human", "content": "message"}]}
由于在使用 add_messages
时状态更新总是反序列化为 LangChain Messages,因此您应该使用点表示法来访问消息属性,例如 state["messages"][-1].content
。
MessagesState
由于在状态中包含消息列表非常常见,因此存在一个预构建的状态,称为 MessagesState,它使得使用消息变得容易。MessagesState 定义了一个单独的 messages 键,它是一个 AnyMessage 对象列表,并使用 add_messages 归约器。我们可以通过以下方式添加更多字段:
from langgraph.graph import MessagesState
class State(MessagesState):
documents: list[str]