📚 什么是长期记忆?

Long-term Memory(长期记忆)是 AI Agent 跨会话保存和检索信息的能力。 与短期记忆(Checkpointer)不同,长期记忆专注于存储结构化的持久数据, 如用户偏好、历史行为、知识库等。

💡 长期记忆 vs 短期记忆
特性 短期记忆(Checkpointer) 长期记忆(Store)
用途 对话历史、会话状态 用户偏好、知识库、持久数据
数据结构 消息列表、状态字典 JSON 文档
生命周期 单次会话或相关会话 跨会话、长期保存
检索方式 按 thread_id 加载 按 namespace + key 或搜索
适用场景 多轮对话、上下文理解 个性化、用户画像、动态知识

典型应用场景

  • 用户偏好:语言、主题、通知设置
  • 用户画像:兴趣、行为历史、订阅信息
  • 动态知识库:不断更新的业务知识、FAQ
  • 跨会话上下文:用户之前的问题、未完成的任务
  • 个性化推荐:基于历史交互的智能建议

🏗️ Store 存储架构

graph TB A[Agent 调用] --> B{需要访问长期记忆?} B -->|是| C[工具通过 ToolRuntime 访问] C --> D[Store.get/put/search] D --> E{操作类型} E -->|get| F[按 Namespace + Key 读取] E -->|put| G[按 Namespace + Key 写入] E -->|search| H[跨 Namespace 搜索] E -->|delete| I[删除特定记忆] F --> J[返回 StoreValue 对象] G --> K[更新存储] H --> L[返回匹配结果列表] I --> K J --> M[工具返回结果] K --> M L --> M M --> N[Agent 继续执行] subgraph "Store 存储层" O[InMemoryStore] P[PostgresStore] Q[自定义 Store] end D -.使用.-> O D -.使用.-> P D -.使用.-> Q style D fill:#3b82f6,color:#fff style J fill:#10b981,color:#fff style K fill:#f59e0b,color:#fff style L fill:#8b5cf6,color:#fff

核心概念

概念 说明 示例
Namespace 层级化命名空间(元组) ("users",), ("users", "preferences")
Key 唯一标识符(字符串) "user_123", "en-us"
Value JSON 可序列化的数据 {"name": "张三", "language": "zh-CN"}
StoreValue 存储对象,包含 value 和 metadata StoreValue(value={...}, metadata={...})

🧪 InMemoryStore - 开发测试

InMemoryStore 是内存存储实现,适合开发和测试环境。 生产环境应使用数据库支持的 Store(如 PostgresStore)。

Python 🟢 基础
"""
InMemoryStore 基础使用
功能:创建内存存储并执行基本操作
"""
from langgraph.store.memory import InMemoryStore

# 定义嵌入函数(用于向量搜索)
def embed(texts: list[str]) -> list[list[float]]:
    """简单的嵌入函数(生产环境使用真实模型)"""
    return [[1.0, 2.0, 3.0] for _ in texts]

# 创建 Store
store = InMemoryStore(
    index={
        "embed": embed,  # 嵌入函数
        "dims": 3        # 向量维度
    }
)

# 存储用户信息
store.put(
    ("users",),           # Namespace(元组)
    "user_123",          # Key
    {                    # Value(JSON 可序列化)
        "name": "张三",
        "language": "zh-CN",
        "preferences": {
            "theme": "dark",
            "notifications": True
        }
    }
)

# 读取用户信息
user_info = store.get(("users",), "user_123")

if user_info:
    print(f"用户名: {user_info.value['name']}")
    print(f"语言: {user_info.value['language']}")
    print(f"主题: {user_info.value['preferences']['theme']}")
else:
    print("用户不存在")
⚠️ InMemoryStore 限制

InMemoryStore 仅将数据存储在内存中,应用重启后所有数据丢失。 仅用于开发和测试环境,生产环境必须使用持久化存储。

🔧 核心 API 详解

1. put() - 写入数据

Python 🟢 基础
"""
put() 方法:写入或更新数据
"""
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

# 写入用户偏好
store.put(
    ("users", "preferences"),  # Namespace(可以是多层)
    "user_123",               # Key
    {
        "language": "zh-CN",
        "timezone": "Asia/Shanghai",
        "email_notifications": True
    }
)

# 写入订单历史
store.put(
    ("users", "orders"),
    "user_123",
    {
        "orders": [
            {"id": "ORDER-001", "product": "iPhone 15"},
            {"id": "ORDER-002", "product": "AirPods"}
        ],
        "total_spent": 15000.0
    }
)

print("✅ 数据写入成功")

2. get() - 读取数据

Python 🟢 基础
"""
get() 方法:读取特定 Key 的数据
"""
# 读取用户偏好
preferences = store.get(("users", "preferences"), "user_123")

if preferences:
    print(f"语言: {preferences.value['language']}")
    print(f"时区: {preferences.value['timezone']}")
    print(f"邮件通知: {preferences.value['email_notifications']}")

    # 访问元数据
    print(f"创建时间: {preferences.created_at}")
    print(f"更新时间: {preferences.updated_at}")
else:
    print("未找到用户偏好")

3. search() - 搜索数据

Python 🟡 中级
"""
search() 方法:跨 Namespace 搜索数据
功能:支持过滤和向量相似度搜索
"""
# 示例 1:使用过滤条件搜索
results = store.search(
    ("users", "preferences"),
    filter={"language": "zh-CN"}  # 过滤条件
)

print(f"找到 {len(results)} 个中文用户")
for item in results:
    print(f"- 用户 {item.key}: {item.value}")

# 示例 2:向量相似度搜索
results = store.search(
    ("knowledge_base",),
    query="如何重置密码?",  # 查询字符串
    limit=5                  # 返回最相关的 5 个结果
)

for i, item in enumerate(results):
    print(f"\n结果 {i+1}:")
    print(f"  Key: {item.key}")
    print(f"  内容: {item.value}")
    # print(f"  相似度: {item.score}")

4. delete() - 删除数据

Python 🟢 基础
"""
delete() 方法:删除特定数据
"""
# 删除用户的订单历史
store.delete(("users", "orders"), "user_123")

# 验证删除
orders = store.get(("users", "orders"), "user_123")
if orders is None:
    print("✅ 订单历史已删除")

🔗 与 Agent Runtime 集成

通过 ToolRuntime,工具可以访问 Store 来读写长期记忆。

读取长期记忆

Python 🟡 中级
"""
工具中读取长期记忆示例
功能:根据用户 ID 查询用户偏好
"""
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent, AgentState
from langgraph.store.memory import InMemoryStore
from typing_extensions import TypedDict

# 定义上下文 Schema
class Context(TypedDict):
    user_id: str

@tool
def get_user_language(runtime: ToolRuntime[Context]) -> str:
    """获取用户的语言偏好"""
    # 从 Runtime 获取 Store
    store = runtime.store

    # 从 Context 获取 user_id
    user_id = runtime.context["user_id"]

    # 读取用户偏好
    preferences = store.get(("users", "preferences"), user_id)

    if preferences:
        language = preferences.value.get("language", "en-US")
        return f"用户 {user_id} 的语言偏好是: {language}"
    else:
        return f"用户 {user_id} 没有设置语言偏好"

# 创建 Store
store = InMemoryStore()

# 预先存储一些数据
store.put(
    ("users", "preferences"),
    "user_123",
    {"language": "zh-CN", "theme": "dark"}
)

# 创建 Agent
agent = create_agent(
    model="gpt-4o",
    tools=[get_user_language],
    store=store,               # 传递 Store
    context_schema=Context     # 传递 Context Schema
)

# 调用 Agent(提供 context)
result = agent.invoke(
    {
        "messages": [{"role": "user", "content": "查询我的语言设置"}]
    },
    {
        "context": {"user_id": "user_123"}
    }
)

print(result["messages"][-1].content)

写入长期记忆

Python 🟡 中级
"""
工具中写入长期记忆示例
功能:保存用户偏好设置
"""
from langchain.tools import tool, ToolRuntime
from typing_extensions import TypedDict

class UserPreferences(TypedDict):
    language: str
    theme: str
    notifications: bool

@tool
def save_user_preferences(
    preferences: UserPreferences,
    runtime: ToolRuntime[Context]
) -> str:
    """保存用户偏好设置"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    # 写入 Store
    store.put(
        ("users", "preferences"),
        user_id,
        preferences
    )

    return f"成功保存用户 {user_id} 的偏好设置"

@tool
def get_user_preferences(runtime: ToolRuntime[Context]) -> str:
    """获取用户偏好设置"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    preferences = store.get(("users", "preferences"), user_id)

    if preferences:
        prefs = preferences.value
        return f"""
        语言: {prefs.get('language', '未设置')}
        主题: {prefs.get('theme', '未设置')}
        通知: {'开启' if prefs.get('notifications') else '关闭'}
        """
    else:
        return "未找到用户偏好设置"

# 创建支持读写的 Agent
agent = create_agent(
    model="gpt-4o",
    tools=[save_user_preferences, get_user_preferences],
    store=store,
    context_schema=Context
)

# 保存偏好
result1 = agent.invoke(
    {
        "messages": [{
            "role": "user",
            "content": "帮我设置:语言中文、深色主题、开启通知"
        }]
    },
    {"context": {"user_id": "user_456"}}
)

# 查询偏好
result2 = agent.invoke(
    {
        "messages": [{"role": "user", "content": "查询我的偏好设置"}]
    },
    {"context": {"user_id": "user_456"}}
)

print(result2["messages"][-1].content)

🗂️ Namespace 设计模式

合理的 Namespace 设计能够实现高效的数据组织和检索。

Python 🔴 高级
"""
Namespace 设计模式示例
功能:演示不同的命名空间组织方式
"""
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

# 模式 1:按用户组织
store.put(
    ("users", "user_123", "profile"),
    "basic_info",
    {"name": "张三", "email": "[email protected]"}
)

store.put(
    ("users", "user_123", "preferences"),
    "settings",
    {"language": "zh-CN", "theme": "dark"}
)

# 模式 2:按功能模块组织
store.put(
    ("orders", "user_123"),
    "ORDER-001",
    {"product": "iPhone 15", "status": "shipped"}
)

store.put(
    ("orders", "user_123"),
    "ORDER-002",
    {"product": "MacBook Pro", "status": "processing"}
)

# 模式 3:按时间组织
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")

store.put(
    ("analytics", "daily", today),
    "user_123",
    {"visits": 5, "actions": 12}
)

# 模式 4:多租户组织
store.put(
    ("tenants", "company_A", "users"),
    "user_001",
    {"name": "员工A", "role": "admin"}
)

store.put(
    ("tenants", "company_B", "users"),
    "user_001",
    {"name": "员工B", "role": "viewer"}
)

# 查询示例:获取用户的所有订单
orders = store.search(("orders", "user_123"))
print(f"用户有 {len(orders)} 个订单")
for order in orders:
    print(f"- {order.key}: {order.value['product']}")
✅ Namespace 设计建议
  • 层级清晰:使用元组表示层级关系,如 ("users", user_id, "preferences")
  • 一致性:保持相同类型数据的 Namespace 结构一致
  • 可扩展:预留扩展空间,避免频繁重构
  • 隔离性:不同租户或业务使用不同的顶层 Namespace
  • 语义化:使用有意义的名称,方便理解和维护

🎯 完整示例:个性化推荐系统

Python 🔴 高级 - 完整项目
"""
个性化推荐系统完整示例
功能:基于用户历史行为和偏好,提供智能推荐
"""
from langchain.agents import create_agent
from langchain.tools import tool, ToolRuntime
from langgraph.store.memory import InMemoryStore
from typing_extensions import TypedDict
from datetime import datetime
import json

# ==================== 上下文定义 ====================

class Context(TypedDict):
    user_id: str
    session_id: str

# ==================== 初始化 Store ====================

store = InMemoryStore()

# 预置一些用户数据
store.put(
    ("users", "user_001", "profile"),
    "basic",
    {
        "name": "张三",
        "email": "[email protected]",
        "joined_date": "2024-01-15"
    }
)

store.put(
    ("users", "user_001", "preferences"),
    "settings",
    {
        "language": "zh-CN",
        "categories": ["电子产品", "图书", "运动"],
        "price_range": {"min": 100, "max": 5000}
    }
)

store.put(
    ("users", "user_001", "history"),
    "browsed_products",
    {
        "products": [
            {"id": "P001", "name": "iPhone 15", "category": "电子产品", "viewed_at": "2024-12-20"},
            {"id": "P002", "name": "Python 编程", "category": "图书", "viewed_at": "2024-12-21"},
            {"id": "P003", "name": "跑步鞋", "category": "运动", "viewed_at": "2024-12-22"}
        ]
    }
)

store.put(
    ("users", "user_001", "history"),
    "purchased_products",
    {
        "products": [
            {"id": "P002", "name": "Python 编程", "price": 89, "purchased_at": "2024-12-21"}
        ],
        "total_spent": 89
    }
)

# ==================== 工具定义 ====================

@tool
def get_user_profile(runtime: ToolRuntime[Context]) -> str:
    """获取用户基本信息"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    profile = store.get(("users", user_id, "profile"), "basic")

    if profile:
        info = profile.value
        return f"""
        用户姓名:{info['name']}
        邮箱:{info['email']}
        注册时间:{info['joined_date']}
        """
    else:
        return "未找到用户信息"

@tool
def get_user_preferences(runtime: ToolRuntime[Context]) -> str:
    """获取用户偏好设置"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    prefs = store.get(("users", user_id, "preferences"), "settings")

    if prefs:
        data = prefs.value
        return f"""
        偏好语言:{data['language']}
        感兴趣的类别:{', '.join(data['categories'])}
        价格范围:{data['price_range']['min']} - {data['price_range']['max']} 元
        """
    else:
        return "未找到用户偏好"

@tool
def get_browsing_history(runtime: ToolRuntime[Context]) -> str:
    """查询用户浏览历史"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    history = store.get(("users", user_id, "history"), "browsed_products")

    if history:
        products = history.value["products"]
        result = "最近浏览的商品:\n"
        for p in products[-5:]:  # 最近5个
            result += f"- {p['name']} ({p['category']}) - {p['viewed_at']}\n"
        return result
    else:
        return "暂无浏览历史"

@tool
def get_purchase_history(runtime: ToolRuntime[Context]) -> str:
    """查询用户购买历史"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    purchases = store.get(("users", user_id, "history"), "purchased_products")

    if purchases:
        data = purchases.value
        products = data["products"]
        result = f"购买记录(总消费:¥{data['total_spent']}):\n"
        for p in products:
            result += f"- {p['name']} - ¥{p['price']} - {p['purchased_at']}\n"
        return result
    else:
        return "暂无购买记录"

@tool
def record_product_view(
    product_id: str,
    product_name: str,
    category: str,
    runtime: ToolRuntime[Context]
) -> str:
    """记录用户浏览商品"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    # 获取现有历史
    history = store.get(("users", user_id, "history"), "browsed_products")

    if history:
        products = history.value["products"]
    else:
        products = []

    # 添加新记录
    products.append({
        "id": product_id,
        "name": product_name,
        "category": category,
        "viewed_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    })

    # 保留最近 50 条
    products = products[-50:]

    # 更新存储
    store.put(
        ("users", user_id, "history"),
        "browsed_products",
        {"products": products}
    )

    return f"已记录浏览:{product_name}"

@tool
def update_user_preferences(
    categories: list[str],
    runtime: ToolRuntime[Context]
) -> str:
    """更新用户偏好类别"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    # 获取现有偏好
    prefs = store.get(("users", user_id, "preferences"), "settings")

    if prefs:
        current = prefs.value
        current["categories"] = categories
    else:
        current = {
            "language": "zh-CN",
            "categories": categories,
            "price_range": {"min": 0, "max": 10000}
        }

    # 更新存储
    store.put(
        ("users", user_id, "preferences"),
        "settings",
        current
    )

    return f"已更新偏好类别为:{', '.join(categories)}"

@tool
def get_personalized_recommendations(runtime: ToolRuntime[Context]) -> str:
    """基于用户历史生成个性化推荐"""
    store = runtime.store
    user_id = runtime.context["user_id"]

    # 获取用户偏好
    prefs = store.get(("users", user_id, "preferences"), "settings")

    # 获取浏览历史
    history = store.get(("users", user_id, "history"), "browsed_products")

    if not prefs:
        return "无法生成推荐:未找到用户偏好"

    categories = prefs.value.get("categories", [])

    # 简化的推荐逻辑(实际应用会更复杂)
    recommendations = {
        "电子产品": ["MacBook Pro", "AirPods Pro", "iPad Air"],
        "图书": ["深度学习", "算法导论", "设计模式"],
        "运动": ["网球拍", "健身手环", "瑜伽垫"]
    }

    result = "🎯 为您推荐:\n\n"
    for category in categories:
        if category in recommendations:
            result += f"【{category}】\n"
            for item in recommendations[category][:2]:  # 每个类别推荐2个
                result += f"  • {item}\n"
            result += "\n"

    return result

# ==================== 创建 Agent ====================

recommendation_agent = create_agent(
    model="gpt-4o",
    tools=[
        get_user_profile,
        get_user_preferences,
        get_browsing_history,
        get_purchase_history,
        record_product_view,
        update_user_preferences,
        get_personalized_recommendations
    ],
    store=store,
    context_schema=Context,
    system_prompt="""你是个性化推荐助手。

职责:
1. 了解用户的偏好和历史行为
2. 记录用户的浏览行为
3. 基于用户数据生成个性化推荐
4. 帮助用户更新偏好设置

工作流程:
- 查询用户信息时,使用相应的查询工具
- 用户浏览商品时,记录到历史中
- 生成推荐时,综合考虑偏好和历史
- 始终保持友好和有帮助"""
)

# ==================== 测试场景 ====================

def simulate_user_interaction(user_id: str, query: str):
    """模拟用户交互"""
    print(f"\n{'='*60}")
    print(f"用户: {query}")
    print('='*60)

    result = recommendation_agent.invoke(
        {"messages": [{"role": "user", "content": query}]},
        {"context": {"user_id": user_id, "session_id": "session_001"}}
    )

    answer = result["messages"][-1].content
    print(f"\n🤖 助手:\n{answer}\n")
    return answer

# ==================== 执行测试 ====================

if __name__ == "__main__":
    user_id = "user_001"

    # 场景 1:查询用户信息
    simulate_user_interaction(
        user_id,
        "我的个人信息是什么?"
    )

    # 场景 2:查看偏好和历史
    simulate_user_interaction(
        user_id,
        "我之前浏览过哪些商品?我的偏好是什么?"
    )

    # 场景 3:记录新的浏览
    simulate_user_interaction(
        user_id,
        "我正在查看 MacBook Pro(电子产品类别),帮我记录一下"
    )

    # 场景 4:获取个性化推荐
    simulate_user_interaction(
        user_id,
        "根据我的偏好和历史,给我一些推荐吧"
    )

    # 场景 5:更新偏好
    simulate_user_interaction(
        user_id,
        "我想把偏好类别改成:电子产品、健康、旅游"
    )

    # 场景 6:再次获取推荐(基于新偏好)
    simulate_user_interaction(
        user_id,
        "现在给我推荐一些商品"
    )

    print("\n" + "="*60)
    print("个性化推荐系统测试完成!")
    print("="*60)

❓ 常见问题

Q1: 长期记忆和短期记忆可以同时使用吗?

可以,而且推荐这样做。 Checkpointer 管理对话历史(短期), Store 管理用户数据和偏好(长期)。两者互补,共同实现完整的记忆系统。

Python
# 同时使用 Checkpointer 和 Store
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    checkpointer=InMemorySaver(),  # 短期记忆
    store=InMemoryStore(),         # 长期记忆
    context_schema=Context
)

Q2: 如何在生产环境使用 Store?

使用数据库支持的 Store 实现,如 PostgresStore(需要额外安装包):

Bash
# 安装 PostgreSQL Store(示例,实际包名可能不同)
pip install langgraph-store-postgres
Python
# 使用 PostgreSQL Store
from langgraph.store.postgres import PostgresStore

DB_URI = "postgresql://user:pass@localhost:5432/langchain"

with PostgresStore.from_conn_string(DB_URI) as store:
    store.setup()  # 创建表结构

    agent = create_agent(
        model="gpt-4o",
        tools=[...],
        store=store
    )

Q3: Store 中的数据什么时候会过期?

Store 默认不会自动删除数据。你需要实现自己的过期策略:

  • 在写入时添加 expires_at 元数据
  • 定期运行清理任务删除过期数据
  • 基于业务逻辑手动删除不再需要的数据

Q4: 如何实现跨用户的知识共享?

使用共享的 Namespace 存储公共知识:

Python
# 个人知识
store.put(("users", "user_123", "notes"), "note_001", {...})

# 团队共享知识
store.put(("teams", "team_A", "knowledge"), "doc_001", {...})

# 全局知识库
store.put(("global", "faq"), "how_to_reset_password", {...})

Q5: Store 支持事务吗?

InMemoryStore 不支持事务。生产级 Store(如 PostgresStore) 可能支持事务,具体取决于实现。如果需要原子操作, 考虑在应用层实现补偿逻辑或使用支持事务的数据库。

✨ 最佳实践

1. 选择合适的存储方案

环境 推荐 Store 理由
本地开发 InMemoryStore 快速迭代,无需配置
测试环境 InMemoryStore 或 SQLite 轻量级,易于重置
生产环境 PostgresStore 可靠、可扩展、支持备份

2. Namespace 命名规范

  • 使用有意义的名称("users", "preferences") 而非 ("u", "p")
  • 保持一致性:相同类型数据使用相同结构
  • 避免过深层级:通常 2-4 层足够
  • 考虑查询需求:设计时考虑如何检索数据

3. 数据设计原则

  • 最小化:只存储必要的信息
  • 结构化:使用清晰的 JSON 结构
  • 可扩展:预留扩展字段
  • 版本控制:考虑数据 Schema 演进
  • 隐私保护:不存储敏感信息的明文

4. 性能优化

  • 批量操作:尽可能批量读写,减少 I/O
  • 缓存策略:对热数据使用应用层缓存
  • 索引优化:为常用查询创建索引
  • 数据清理:定期清理过期或无用数据

5. 错误处理

Python
# 健壮的数据读取
@tool
def get_user_setting(runtime: ToolRuntime[Context]) -> str:
    """获取用户设置(带错误处理)"""
    try:
        store = runtime.store
        user_id = runtime.context["user_id"]

        settings = store.get(("users", user_id, "settings"), "config")

        if settings:
            return f"设置:{settings.value}"
        else:
            # 返回默认值
            return "使用默认设置"
    except Exception as e:
        # 记录错误并返回友好消息
        print(f"Error reading settings: {e}")
        return "无法读取设置,请稍后重试"

📖 参考资源