J'Blog

6 课 · 进阶

语义检索

基于 Chroma 向量库,与 Workspace 知识库分离。用自然语言描述你想查的内容。 非管理员每人每天可检索 5 次(消耗站点 AI 配额)。

添加内存

原文:Add Memory

一句话

LangGraph 支持两种内存类型:短期内存(thread-level persistence)用于多轮对话,长期内存用于跨会话存储用户特定或应用级数据。

什么时候翻这页

当你需要实现 Agent 的记忆功能,使其能够记住之前的对话内容或用户信息时。

核心概念

  • 短期内存:作为 Agent 状态的一部分,用于多轮对话的上下文保持
  • 长期内存:用于存储用户特定或应用级数据,可在不同会话间保持
  • Checkpoint:检查点机制,用于保存和恢复 Agent 的状态
  • StateGraph:LangGraph 中的核心图结构,用于构建 Agent 工作流
  • Store:长期存储接口,用于持久化数据

怎么做

添加短期内存

短期内存通过在编译 StateGraph 时提供 checkpointer 实现:

from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import StateGraph

checkpointer = InMemorySaver()
builder = StateGraph(...)
graph = builder.compile(checkpointer=checkpointer)

graph.invoke(
    {"messages": [{"role": "user", "content": "hi! i am Bob"}]},
    {"configurable": {"thread_id": "1"}},
)

生产环境中的短期内存

在生产环境中,使用数据库支持的 checkpointer:

from langgraph.checkpoint.postgres import PostgresSaver

DB_URI = "postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable"
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
    builder = StateGraph(...)
    graph = builder.compile(checkpointer=checkpointer)

添加长期内存

长期内存通过在编译 StateGraph 时提供 store 实现:

from langgraph.store.memory import InMemoryStore
from langgraph.graph import StateGraph

store = InMemoryStore()
builder = StateGraph(...)
graph = builder.compile(store=store)

在节点中访问 Store

一旦编译了带有 store 的图,LangGraph 会自动将 store 注入到节点函数中:

from dataclasses import dataclass
from langgraph.runtime import Runtime
from langgraph.graph import StateGraph, MessagesState, START
import uuid

@dataclass
class Context:
    user_id: str

async def call_model(state: MessagesState, runtime: Runtime[Context]):
    user_id = runtime.context.user_id
    namespace = (user_id, "memories")
    
    # 搜索相关记忆
    memories = await runtime.store.asearch(
        namespace, query=state["messages"][-1].content, limit=3
    )
    info = "\n".join([d.value["data"] for d in memories])
    
    # 在模型调用中使用记忆
    
    # 存储新记忆
    await runtime.store.aput(
        namespace, str(uuid.uuid4()), {"data": "User prefers dark mode"}
    )

builder = StateGraph(MessagesState, context_schema=Context)
builder.add_node(call_model)
builder.add_edge(START, "call_model")
graph = builder.compile(store=store)

管理检查点

可以查看和删除 checkpointer 存储的信息:

# 查看线程状态
config = {
    "configurable": {
        "thread_id": "1",
        # 可选提供特定检查点的 ID
        # "checkpoint_id": "1f029ca3-1f5b-6704-8004-820c16b69a5a"
    }
}
graph.get_state(config)

# 查看线程历史
list(graph.get_state_history(config))

# 删除线程的所有检查点
checkpointer.delete_thread("1")

命令 / API 速查

短期内存相关

  • InMemorySaver(): 内存中的检查点保存器
  • PostgresSaver.from_conn_string(DB_URI): 从连接字符串创建 PostgreSQL 检查点保存器
  • MongoDBSaver.from_conn_string(MONGODB_URI): 从连接字符串创建 MongoDB 检查点保存器
  • RedisSaver.from_conn_string(DB_URI): 从连接字符串创建 Redis 检查点保存器
  • OracleSaver.from_conn_string(DB_URI): 从连接字符串创建 Oracle 检查点保存器
  • graph.compile(checkpointer=checkpointer): 编译图时指定检查点保存器
  • graph.invoke(..., {"configurable": {"thread_id": "1"}}): 调用图时指定线程 ID

长期内存相关

  • InMemoryStore(): 内存中的存储
  • PostgresStore.from_conn_string(DB_URI): 从连接字符串创建 PostgreSQL 存储
  • builder.compile(store=store): 编译图时指定存储
  • runtime.store.asearch(namespace, query, limit): 异步搜索存储中的数据
  • runtime.store.aput(namespace, key, value): 异步存储数据
  • graph.invoke(..., context=Context(user_id="1")): 调用图时传递上下文

检查点管理

  • graph.get_state(config): 获取当前状态
  • graph.get_state_history(config): 获取状态历史
  • checkpointer.delete_thread(thread_id): 删除线程的所有检查点

与 Hello-Agents / Claude Code 的联系

在 Hello-Agents 中,我们介绍了 LangGraph 的基本概念和简单工作流。本章节扩展了这些概念,添加了内存功能,使 Agent 能够记住之前的交互。这与 Claude Code 中的持久化概念类似,但提供了更细粒度的控制和更丰富的功能。

初学者易错点

  1. 忘记在调用图时提供 thread_id,导致无法正确恢复对话状态
  2. 混淆短期内存和长期内存的用途,错误地使用其中一种来实现另一种功能
  3. 在使用数据库支持的 checkpointer 或 store 时忘记调用 setup() 方法
  4. 在节点函数中错误地访问 store,没有通过 Runtime 对象
  5. 忽略了异步操作的需要,特别是在使用数据库存储时

相关词条

官方原文:https://docs.langchain.com/oss/python/langgraph/add-memory