Skip to content

内存

LangGraph 支持两种类型的内存,这对于构建对话代理至关重要:

  • 短期记忆:通过维护会话中的消息历史记录来跟踪正在进行的对话。
  • 长期记忆:在会话之间存储用户特定或应用程序级别的数据。

本指南演示了如何使用 LangGraph 中代理的这两种类型的记忆。为了更深入地理解记忆概念,请参阅 LangGraph 记忆文档

图像

无论是短期记忆还是长期记忆,都需要持久化存储以维持跨大型语言模型交互的连续性。在生产环境中,这些数据通常存储在数据库中。

术语

在 LangGraph 中:

  • 短期记忆 也被称作 线程级记忆
  • 长期记忆 也被称为 跨线程记忆

一个 线程 表示由相同的 thread_id 分组的相关运行序列。

短期记忆

短期记忆使代理能够跟踪多轮对话。要使用它,您必须:

  1. 在创建代理时提供一个 checkpointercheckpointer 允许持久化代理的状态。
  2. 在运行代理时提供的配置中提供一个 thread_idthread_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"It's always sunny in {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": "what is the weather in sf"}]},
    # 高亮下一行
    config
)

# 使用相同的 thread_id 继续对话
ny_response = agent.invoke(
    {"messages": [{"role": "user", "content": "what about new york?"}]},
    # 高亮下一行
    config # (4)!
)
  1. InMemorySaver 是一个存储代理状态在内存中的 checkpointer。在生产环境中,通常会使用数据库或其他持久性存储。请参阅checkpointer 文档以了解更多信息。如果您正在使用**LangGraph 平台**部署,平台将为您提供一个生产级的 checkpointer
  2. checkpointer 传递给代理。这使得代理能够在调用之间持久化其状态。请注意,
  3. 在配置中提供一个唯一的 thread_id。此 ID 用于识别对话会话。值由用户控制,可以是任意字符串。
  4. 代理将继续使用相同的 thread_id 进行对话。这将允许代理推断出用户具体询问的是纽约的**天气**。

当代理第二次被调用时,使用相同的 thread_id,第一次对话的消息历史记录将自动包含在内,允许代理推断出用户具体询问的是纽约的**天气**。

LangGraph 平台提供生产级的 checkpointer

如果您正在使用LangGraph 平台,在部署时您的 checkpointer 将被自动配置为使用生产级数据库。

消息历史总结

image

消息历史可能会迅速增长并超出LLM的上下文窗口。常见的解决方案是维护对话的滚动摘要。这允许代理在不超出LLM的上下文窗口的情况下跟踪对话。

长时间对话可能会超过LLM的上下文窗口。为了处理这种情况,您可以通过指定一个pre_model_hook来对较旧的消息进行总结,例如预构建的SummarizationNode

API Reference: 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):
    # 注意:我们添加了这个键来跟踪之前的摘要信息
    # 以确保我们不会在每次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,
)
  1. InMemorySaver 是一个存储代理状态在内存中的 checkpointer。在生产环境中,通常会使用数据库或其他持久性存储。请参阅checkpointer 文档以了解更多信息。如果您正在使用**LangGraph 平台**部署,平台将为您提供一个生产级的 checkpointer
  2. 在代理的状态中添加了一个 context 键。该键包含用于总结节点的记账信息。它用于跟踪最后一次摘要信息,并确保代理不会在每次LLM调用时都进行总结,这可能是低效的。
  3. checkpointer 传递给代理。这使得代理能够在调用之间持久化其状态。
  4. pre_model_hook 设置为 SummarizationNode。此节点将在发送到LLM之前对消息历史进行总结。总结节点将自动处理总结过程,并更新代理的状态以包含新的摘要。如果愿意,您可以将其替换为自定义实现。请参阅create_react_agent API 参考以了解更多信息。
  5. state_schema 设置为 State 类,这是包含额外 context 键的自定义状态。

要了解更多关于使用 pre_model_hook 管理消息历史的信息,请参阅此如何指南

长期记忆

使用长期记忆来存储跨会话的用户特定或应用程序特定的数据。这对于像聊天机器人这样的应用非常有用,在这些应用中,您希望记住用户的偏好或其他信息。

要使用长期记忆,请执行以下步骤:

  1. 配置一个存储库,以在调用之间持久化数据。
  2. 使用get_store函数从工具或提示内部访问存储库。

读取

一个代理可以使用的工具来查找用户信息
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.get("configurable", {}).get("user_id")
    user_info = store.get(("users",), user_id) # (7)!
    return str(user_info.value) if user_info else "未知用户"

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[get_user_info],
    store=store # (8)!
)

# 运行代理
agent.invoke(
    {"messages": [{"role": "user", "content": "查找用户信息"}]},
    config={"configurable": {"user_id": "user_123"}}
)
  1. InMemoryStore 是一种存储库,它将数据存储在内存中。在生产环境中,通常会使用数据库或其他持久性存储。请参阅存储库文档以获取更多选项。如果您使用的是**LangGraph平台**,该平台将为您提供一个生产就绪的存储库。
  2. 在此示例中,我们使用put方法向存储库写入一些示例数据。请参阅BaseStore.put API参考以获取更多详细信息。
  3. 第一个参数是命名空间。这用于将相关数据分组在一起。在此情况下,我们使用users命名空间来分组用户数据。
  4. 命名空间内的键。此示例使用用户ID作为键。
  5. 要为给定用户存储的数据。
  6. get_store 函数用于访问存储库。您可以在代码中的任何地方调用它,包括工具和提示。此函数返回创建代理时传递的存储库。
  7. get 方法用于从存储库检索数据。第一个参数是命名空间,第二个参数是键。这将返回一个StoreValue对象,其中包含值及其元数据。
  8. 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.get("configurable", {}).get("user_id")
    store.put(("users",), user_id, user_info) # (5)!
    return "成功保存用户信息。"

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[save_user_info],
    store=store
)

# 运行代理
agent.invoke(
    {"messages": [{"role": "user", "content": "我的名字是John Smith"}]},
    config={"configurable": {"user_id": "user_123"}} # (6)!
)

# 您可以直接访问存储库以获取值
store.get(("users",), "user_123").value
  1. InMemoryStore 是一种存储库,它将数据存储在内存中。在生产环境中,通常会使用数据库或其他持久性存储。请参阅存储库文档以获取更多选项。如果您使用的是**LangGraph平台**,该平台将为您提供一个生产就绪的存储库。
  2. UserInfo 类是一个TypedDict,定义了用户信息的结构。LLM将使用此结构来根据模式格式化响应。
  3. save_user_info 函数是一个工具,允许代理更新用户信息。这对于聊天应用程序非常有用,在这些应用程序中,用户希望更新其个人资料信息。
  4. get_store 函数用于访问存储库。您可以在代码中的任何地方调用它,包括工具和提示。此函数返回创建代理时传递的存储库。
  5. put 方法用于将数据存储在存储库中。第一个参数是命名空间,第二个参数是键。这将把用户信息存储在存储库中。
  6. user_id 在配置中传递。这用于标识正在更新信息的用户。

预构建的记忆工具

LangMem 是由LangChain维护的一个库,提供了管理代理长期记忆的工具。有关使用示例,请参阅LangMem文档

额外资源

Comments