内存¶
LangGraph 支持两种构建对话代理所必需的内存类型:
本指南将演示如何在 LangGraph 中的代理中使用这两种内存类型。如需更深入地了解内存概念,请参考 LangGraph 内存文档。
短期记忆¶
短期记忆使代理能够跟踪多轮对话。要使用它,你必须:
- 在创建代理时提供一个
checkpointer
。该checkpointer
使代理的状态可以 持久化。 - 在运行代理时配置中提供一个
thread_id
。thread_id
是会话的唯一标识符。
API Reference: create_react_agent | InMemorySaver
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver() # (1)
def get_weather(city: str) -> str:
"""获取给定城市的天气信息。"""
return f"{city} 的天气总是晴朗!"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_weather],
checkpointer=checkpointer # (2)
)
# 运行代理
config = {
"configurable": {
"thread_id": "1" # (3)
}
}
sf_response = agent.invoke(
{"messages": [{"role": "user", "content": "旧金山的天气如何"}]},
config
)
# 使用相同的 thread_id 继续对话
ny_response = agent.invoke(
{"messages": [{"role": "user", "content": "纽约呢?"}]},
config # (4)
)
InMemorySaver
是一个检查点存储器,它将代理的状态存储在内存中。在生产环境中,通常会使用数据库或其他持久存储。请查看 检查点文档 获取更多选项。如果你使用的是 LangGraph 平台,平台将为你提供一个生产就绪的检查点存储器。- 将
checkpointer
传递给代理。这使得代理可以在调用之间持久化其状态。 - 配置中提供了唯一的
thread_id
。这个 ID 用于识别会话。值由用户控制,可以是任何字符串。 - 代理将使用相同的
thread_id
继续对话。这将允许代理推断出用户正在询问 天气 在纽约的具体情况。
当代理第二次使用相同的 thread_id
被调用时,第一次对话的消息历史记录将自动包含在内,使代理能够推断出用户正在询问 天气 在纽约的具体情况。
LangGraph 平台提供生产就绪的检查点存储器
如果你使用 LangGraph 平台,在部署期间你的检查点存储器将被自动配置为使用一个生产就绪的数据库。
管理消息历史¶
长时间的对话可能会超出 LLM 的上下文窗口。常见的解决方案包括:
这允许代理在不超出 LLM 上下文窗口的情况下跟踪对话。
要管理消息历史,指定 pre_model_hook
—— 一个函数(节点),它总是在调用语言模型之前运行。
摘要消息历史¶
要摘要消息历史,你可以使用 pre_model_hook
和预构建的 SummarizationNode
:
API Reference: ChatAnthropic | count_tokens_approximately | create_react_agent | AgentState | InMemorySaver
from langchain_anthropic import ChatAnthropic
from langmem.short_term import SummarizationNode
from langchain_core.messages.utils import count_tokens_approximately
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.checkpoint.memory import InMemorySaver
from typing import Any
model = ChatAnthropic(model="claude-3-7-sonnet-latest")
summarization_node = SummarizationNode( # (1)
token_counter=count_tokens_approximately,
model=model,
max_tokens=384,
max_summary_tokens=128,
output_messages_key="llm_input_messages",
)
class State(AgentState):
# NOTE: 我们添加这个键来跟踪之前的摘要信息
# 以确保我们不是每次 LLM 调用都进行摘要
context: dict[str, Any] # (2)
checkpointer = InMemorySaver() # (3)
agent = create_react_agent(
model=model,
tools=tools,
pre_model_hook=summarization_node, # (4)
state_schema=State, # (5)
checkpointer=checkpointer,
)
InMemorySaver
是一个检查点存储器,它将代理的状态存储在内存中。在生产环境中,通常会使用数据库或其他持久存储。请查看 检查点文档 获取更多选项。如果你使用的是 LangGraph 平台,平台将为你提供一个生产就绪的检查点存储器。- 添加了
context
键到代理的状态中。该键包含摘要节点的簿记信息。它用于跟踪最后的摘要信息,并确保代理不会在每次 LLM 调用时都进行摘要,这可能效率不高。 - 将
checkpointer
传递给代理。这使得代理可以在调用之间持久化其状态。 - 设置
pre_model_hook
为SummarizationNode
。此节点将在将消息历史发送给 LLM 之前对其进行摘要。摘要节点将自动处理摘要过程并更新代理的状态以包含新的摘要。如果需要,你可以将其替换为自定义实现。请参阅 create_react_agent API 参考以获取更多细节。 state_schema
设置为State
类,这是包含额外context
键的自定义状态。
修剪消息历史¶
要修剪消息历史,你可以使用 pre_model_hook
与 trim_messages
函数:
API Reference: trim_messages | count_tokens_approximately | create_react_agent
from langchain_core.messages.utils import (
trim_messages,
count_tokens_approximately
)
from langgraph.prebuilt import create_react_agent
# 每次在调用 LLM 的节点之前都会调用此函数
def pre_model_hook(state):
trimmed_messages = trim_messages(
state["messages"],
strategy="last",
token_counter=count_tokens_approximately,
max_tokens=384,
start_on="human",
end_on=("human", "tool"),
)
return {"llm_input_messages": trimmed_messages}
checkpointer = InMemorySaver()
agent = create_react_agent(
model,
tools,
pre_model_hook=pre_model_hook,
checkpointer=checkpointer,
)
有关使用 pre_model_hook
管理消息历史的更多信息,请参阅此 指南
读取工具¶
LangGraph 允许代理在其工具内部访问其短期记忆(状态)。
API Reference: InjectedState | create_react_agent
from typing import Annotated
from langgraph.prebuilt import InjectedState, create_react_agent
class CustomState(AgentState):
user_id: str
def get_user_info(
state: Annotated[CustomState, InjectedState]
) -> str:
"""查找用户信息。"""
user_id = state["user_id"]
return "用户是 John Smith" if user_id == "user_123" else "未知用户"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
state_schema=CustomState,
)
agent.invoke({
"messages": "查找用户信息",
"user_id": "user_123"
})
有关更多信息,请参阅 Context 指南。
写入工具¶
要在执行过程中修改代理的短期记忆(状态),你可以直接从工具返回状态更新。这对于持久化中间结果或使信息对后续工具或提示可用非常有用。
API Reference: InjectedToolCallId | RunnableConfig | ToolMessage | InjectedState | create_react_agent | AgentState | Command
from typing import Annotated
from langchain_core.tools import InjectedToolCallId
from langchain_core.runnables import RunnableConfig
from langchain_core.messages import ToolMessage
from langgraph.prebuilt import InjectedState, create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.types import Command
class CustomState(AgentState):
user_name: str
def update_user_info(
tool_call_id: Annotated[str, InjectedToolCallId],
config: RunnableConfig
) -> Command:
"""查找并更新用户信息。"""
user_id = config["configurable"].get("user_id")
name = "John Smith" if user_id == "user_123" else "Unknown user"
return Command(update={
"user_name": name,
# 更新消息历史
"messages": [
ToolMessage(
"成功查找了用户信息",
tool_call_id=tool_call_id
)
]
})
def greet(
state: Annotated[CustomState, InjectedState]
) -> str:
"""一旦找到用户信息,使用此方法向用户打招呼。"""
user_name = state["user_name"]
return f"你好 {user_name}!"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[update_user_info, greet],
state_schema=CustomState
)
agent.invoke(
{"messages": [{"role": "user", "content": "问候用户"}]},
config={"configurable": {"user_id": "user_123"}}
)
有关详细信息,请参阅 如何从工具更新状态。
长期记忆¶
使用长期记忆来跨会话存储用户特定或应用特定的数据。这对于聊天机器人等应用非常有用,您希望记住用户的偏好或其他信息。
要使用长期记忆,您需要:
读取¶
from langchain_core.runnables import RunnableConfig
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore
store = InMemoryStore() # (1)!
store.put( # (2)!
("users",), # (3)!
"user_123", # (4)!
{
"name": "John Smith",
"language": "English",
} # (5)!
)
def get_user_info(config: RunnableConfig) -> str:
"""查找用户信息."""
# 与提供给 `create_react_agent` 的相同
store = get_store() # (6)!
user_id = config["configurable"].get("user_id")
user_info = store.get(("users",), user_id) # (7)!
return str(user_info.value) if user_info else "Unknown user"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
store=store # (8)!
)
# 运行代理
agent.invoke(
{"messages": [{"role": "user", "content": "look up user information"}]},
config={"configurable": {"user_id": "user_123"}}
)
InMemoryStore
是一个将数据存储在内存中的存储。在生产环境中,通常会使用数据库或其他持久化存储。请查看 存储文档 以获取更多选项。如果您使用 **LangGraph 平台**进行部署,平台将为您提供一个生产就绪的存储。- 在这个示例中,我们使用
put
方法向存储中写入一些示例数据。请参阅 BaseStore.put API 文档以获取更多细节。 - 第一个参数是命名空间。这用于将相关数据分组。在此情况下,我们使用
users
命名空间来对用户数据进行分组。 - 命名空间内的一个键。此示例使用用户 ID 作为键。
- 我们想要为该用户存储的数据。
get_store
函数用于访问存储。您可以从代码的任何位置调用它,包括工具和提示。此函数返回传递给代理时的存储。- 使用
get
方法从存储中检索数据。第一个参数是命名空间,第二个参数是键。这将返回一个StoreValue
对象,其中包含值和有关值的元数据。 - 将
store
传递给代理。这使得代理可以在运行工具时访问存储。您也可以使用get_store
函数从代码的任何地方访问存储。
写入¶
from typing_extensions import TypedDict
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore
store = InMemoryStore() # (1)!
class UserInfo(TypedDict): # (2)!
name: str
def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str: # (3)!
"""保存用户信息."""
# 与提供给 `create_react_agent` 的相同
store = get_store() # (4)!
user_id = config["configurable"].get("user_id")
store.put(("users",), user_id, user_info) # (5)!
return "Successfully saved user info."
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[save_user_info],
store=store
)
# 运行代理
agent.invoke(
{"messages": [{"role": "user", "content": "My name is John Smith"}]},
config={"configurable": {"user_id": "user_123"}} # (6)!
)
# 您可以直接访问存储以获取值
store.get(("users",), "user_123").value
InMemoryStore
是一个将数据存储在内存中的存储。在生产环境中,通常会使用数据库或其他持久化存储。请查看 存储文档 以获取更多选项。如果您使用 **LangGraph 平台**进行部署,平台将为您提供一个生产就绪的存储。UserInfo
类是一个TypedDict
,它定义了用户信息的结构。LLM 将使用此结构根据模式格式化响应。save_user_info
函数是一个允许代理更新用户信息的工具。这在用户想要更新其个人资料信息的聊天应用中可能会很有用。get_store
函数用于访问存储。您可以从代码的任何位置调用它,包括工具和提示。此函数返回传递给代理时的存储。put
方法用于将数据存储在存储中。第一个参数是命名空间,第二个参数是键。这将把用户信息存储在存储中。user_id
是通过配置传递的。这用于识别正在更新信息的用户。
语义搜索¶
LangGraph 还允许您通过语义相似性在长期记忆中搜索项目。
预构建的记忆工具¶
LangMem 是一个由 LangChain 维护的库,提供了用于管理代理长期记忆的工具。请参阅 LangMem 文档 以获取使用示例。