当前位置: 首页 > news >正文

【langgraph 从入门到精通graphApi 篇】Memory 与长期记忆

文章目录

    • 第 8 章:Memory 与长期记忆
      • 8.1 本章目标
      • 8.2 核心概念
        • Checkpoint vs Store
        • 短期记忆 vs 长期记忆架构
        • Store 命名空间设计
      • 8.3 实战
        • 实战 1:用户偏好记忆
        • 实战 2:语义记忆搜索
      • 8.4 API 速查
      • 8.5 错误与避坑指南
        • 坑 1:混淆 Store 和 Checkpoint
        • 坑 2:命名空间设计不当
        • 坑 3:语义搜索未配置 embedding
        • 坑 4:忘记在 compile 时传入 store
      • 8.6 最佳实践总结

第 8 章:Memory 与长期记忆

8.1 本章目标

学完本章你将能够:

  1. 理解短期记忆(Checkpoint)与长期记忆(Store)的区别
  2. 掌握 InMemoryStore / PostgresStore 的配置和使用
  3. 学会在节点中通过 Runtime 访问 Store
  4. 实现语义记忆搜索功能

8.2 核心概念

Checkpoint vs Store
特性Checkpoint(短期记忆)Store(长期记忆)
存储内容图状态快照(State 的完整副本)应用定义的键值数据
作用范围单个 Thread(对话线程)跨 Thread(跨会话)
生命周期对话结束后可清理持久保留
典型用途对话连续性、HITL、容错用户偏好、知识库、共享信息
访问方式自动(每个 super-step 保存)手动(节点中显式读写)

比喻:Checkpoint 就像"草稿自动保存"——每次编辑后自动保存当前状态。Store 就像"客户档案"——记录客户的长期偏好,所有对话都能访问。

短期记忆 vs 长期记忆架构

Store (长期记忆)

Checkpointer (短期记忆)

会话 2 (thread-2)

会话 1 (thread-1)

自动保存

自动保存

读写

读写

对话1

对话2

对话3

对话1

对话2

thread-1
checkpoints

thread-2
checkpoints

用户偏好
历史摘要
共享知识

Store 命名空间设计
# 命名空间使用 tuple 结构,支持层级隔离("user_123","memories")# 用户 123 的记忆("user_123","preferences")# 用户 123 的偏好("user_456","memories")# 用户 456 的记忆("global","knowledge")# 全局知识库

8.3 实战

实战 1:用户偏好记忆
fromtypingimportTypedDict,Annotatedfromdataclassesimportdataclassfromlanggraph.graphimportStateGraph,START,END,add_messagesfromlanggraph.checkpoint.memoryimportMemorySaverfromlanggraph.store.memoryimportInMemoryStorefromlanggraph.runtimeimportRuntimefromlangchain_core.messagesimportBaseMessage,HumanMessage,AIMessage# ============================================# 定义 Context(运行时上下文)# ============================================@dataclassclassContext:user_id:str# ============================================# 定义 State# ============================================classState(TypedDict):messages:Annotated[list[BaseMessage],add_messages]# ============================================# 定义节点(使用 Runtime 访问 Store)# ============================================asyncdefmemory_node(state:State,runtime:Runtime[Context])->dict:""" 使用 Runtime 访问 Store 实现长期记忆。 关键点: 1. 在函数签名中声明 runtime: Runtime[Context] 参数 2. LangGraph 自动注入 Runtime 实例 3. 通过 runtime.context 访问上下文 4. 通过 runtime.store 访问 Store """user_id=runtime.context.user_id namespace=(user_id,"memories")# 从 Store 读取用户记忆memories=awaitruntime.store.asearch(namespace,limit=10)# 构建包含记忆的回复ifmemories:memory_text="我记得以下信息:\n"+"\n".join(f" -{m.value.get('content','')}"forminmemories)else:memory_text="我还没有关于你的记忆。"# 如果有新信息,存入 Storelast_msg=state["messages"][-1]if"记住"inlast_msg.contentor"我叫"inlast_msg.content:awaitruntime.store.aput(namespace,f"memory_{len(memories)+1}",{"content":last_msg.content},)return{"messages":[AIMessage(content=f"收到!{memory_text}")]}# ============================================# 构建图# ============================================store=InMemoryStore()checkpointer=MemorySaver()builder=StateGraph(State)builder.add_node("memory",memory_node)builder.add_edge(START,"memory")builder.add_edge("memory",END)# 编译时传入 store 和 context_schemagraph=builder.compile(checkpointer=checkpointer,store=store,context_schema=Context,)# ============================================# 异步运行# ============================================importasyncioasyncdefmain():config={"configurable":{"thread_id":"mem-001"}}context=Context(user_id="user_123")# 第一次对话result=awaitgraph.ainvoke({"messages":[HumanMessage(content="我叫小明,记住这个")]},config=config,context=context,)print(f"AI:{result['messages'][-1].content}")# 第二次对话(新 thread,但同一 user_id)config2={"configurable":{"thread_id":"mem-002"}}result=awaitgraph.ainvoke({"messages":[HumanMessage(content="你还记得我叫什么吗?")]},config=config2,context=context,)print(f"AI:{result['messages'][-1].content}")asyncio.run(main())
实战 2:语义记忆搜索
fromlanggraph.store.memoryimportInMemoryStore# 创建带语义搜索的 Storestore=InMemoryStore(index={"embed":"openai:text-embedding-3-small",# 嵌入模型"dims":1536,# 嵌入维度"fields":["content","$"],# 要索引的字段})# 存储带语义信息的记忆asyncdefstore_with_semantics():awaitstore.aput(("user_123","memories"),"mem_1",{"content":"用户喜欢喝咖啡,尤其是拿铁"},)awaitstore.aput(("user_123","memories"),"mem_2",{"content":"用户是 Python 程序员"},)awaitstore.aput(("user_123","memories"),"mem_3",{"content":"用户住在北京朝阳区"},)# 语义搜索:自然语言查询results=awaitstore.asearch(("user_123","memories"),query="用户喜欢喝什么饮料?",# 自然语言查询limit=3,)foriteminresults:print(f" [{item.key}]{item.value['content']}")# 输出: [mem_1] 用户喜欢喝咖啡,尤其是拿铁asyncio.run(store_with_semantics())

8.4 API 速查

API完整签名入参说明返回值说明
InMemoryStore()InMemoryStore(index=...)index: 语义搜索配置(可选)Store 对象内存存储
PostgresStore(conn)PostgresStore(conn)conn: 数据库连接Store 对象Postgres 持久化
store.put(namespace, key, value)put(ns: tuple, key: str, value: dict)ns: 命名空间;key: 键;value: 值None存储数据
store.search(namespace, query, limit)search(ns: tuple, query: str, limit: int)ns: 命名空间;query: 查询;limit: 数量结果列表语义搜索(需 index)
store.aget/get/adelete异步版本同上同上节点中异步调用
Runtime[Context]Runtime[Context]Context: 上下文类型运行时对象节点中注入上下文
context_schemacompile(context_schema=Type)context_schema: Context 类型CompiledGraph编译时声明 Context

8.5 错误与避坑指南

坑 1:混淆 Store 和 Checkpoint
# ❌ 错误:把用户偏好存在 Checkpoint 中# Checkpoint 是 thread 级别的,换 thread 就丢失了!classState(TypedDict):user_preferences:dict# 不应该放在 State 中# ✅ 正确:用户偏好存在 Store 中# Store 跨 thread 共享,通过 user_id 隔离awaitstore.aput(("user_123","preferences"),"key",value)
坑 2:命名空间设计不当
# ❌ 错误:所有用户共享命名空间awaitstore.aput(("memories"),"key",value)# 所有用户混在一起# ✅ 正确:按用户 ID 隔离awaitstore.aput(("user_123","memories"),"key",value)awaitstore.aput(("user_456","memories"),"key",value)
坑 3:语义搜索未配置 embedding
# ❌ 错误:没有配置 indexstore=InMemoryStore()# 没有 indexawaitstore.asearch(ns,query="自然语言查询")# 无法语义搜索,只能精确匹配# ✅ 正确:配置 indexstore=InMemoryStore(index={"embed":"openai:text-embedding-3-small","dims":1536,"fields":["content"],})
坑 4:忘记在 compile 时传入 store
# ❌ 错误graph=builder.compile(checkpointer=...)# 节点中 runtime.store 不可用!# ✅ 正确graph=builder.compile(checkpointer=...,store=store,# 必须传入)

8.6 最佳实践总结

  1. 用户级数据用 Store,会话级数据用 Checkpoint:按数据生命周期选择存储
  2. 命名空间使用(user_id, "category")结构:层级隔离,清晰明了
  3. 生产环境使用 PostgresStore 持久化:数据不丢失,支持高并发
  4. 语义搜索时选择合适的 embedding 模型:平衡成本和效果
  5. Context Schema 用于注入运行时信息:如 user_id、tenant_id 等,不需要放在 State 中
http://www.cnnetsun.cn/news/3539761.html

相关文章:

  • HeyGen中文口型同步失真问题全解析,深度拆解TTS引擎底层逻辑与6步精准修复法
  • 为什么每个技术团队都需要开发者作品集平台:1881个案例的完整指南
  • 1位量化技术革命:Bonsai-8B-GGUF如何在5分钟内实现跨平台AI部署
  • 告别「握手」:MCP 2026-07-28 如何让 AI Agent 真正走向企业级部署
  • TinyMCE终极指南:如何在富文本编辑中无缝集成Markdown高效输入
  • 2026年AI写作工具深度测评:全面解析写小说软件与创作平台的优劣势
  • DASY5 Python
  • OpenNFS多平台构建指南:Windows/Mac/Linux完整编译教程
  • TMS320F280015x DCSM安全模块寄存器详解与实战配置指南
  • Nextcloud全文搜索技术实现:构建高效文件检索系统的完整指南
  • 如何有效提升ChatGLM-6B的对话质量与部署效率?
  • 深入解析TI DCAN接口寄存器:消息对象管理与IF2/IF3高效通信
  • Claude Code与Codex十大神级Skills解析与应用指南
  • ApolloScanner核心功能解析:从资产识别到漏洞检测
  • 78-商学院在职硕士如何拓展科技创业校友网络-交大MTT场景与行动清单
  • 单片机项目1
  • 中山市名豹灯饰有限公司全档介绍:酒店非标工程定制灯具的设计生产加工工程一体化实力
  • 15MW海上风电仿真终极指南:IEA-15-240-RWT完整实战教程
  • 临汾考公机构TOP3排名:口碑与实力双优之选(2026年最新横评)
  • 营销人必懂的统计显著性解码指南
  • 终极指南:5个简单技巧快速掌握KK_Plugins插件集
  • 最佳实践:如何让两者协同工作?
  • 告别直播手忙脚乱:OBS Studio如何成为你的专业直播助手
  • 从Ubuntu迁移到Garuda Linux:性能优化与滚动更新体验
  • 3步快速上手:如何用AwesomeBump免费生成专业级PBR材质纹理
  • arXiv学术平台使用指南与技巧
  • 前端转AI Agent:低门槛高回报,3个月从入门到实战,收藏这份学习路线!
  • ShardingSphere-JDBC分库分表与读写分离实战指南
  • Spring Cloud微服务架构实战与核心组件解析
  • RAP2-DELOS:企业级接口管理平台架构指南与实践方案