LangGraph State记忆机制深度解析:短期与长期记忆的实现原理与实战

LangGraph State记忆机制深度解析:短期与长期记忆的实现原理与实战

前言

在构建基于大语言模型的AI智能体时,一个核心痛点始终挥之不去:如何让智能体拥有真正的"记忆"? 传统的无状态问答系统每次交互都是一张白纸,无论你之前和它聊过什么,它转头就忘。而LangGraph作为专为智能体设计的流程编排框架,通过精巧的双层记忆架构------短期记忆(Short-term Memory)长期记忆(Long-term Memory),为这一问题提供了工业级的解决方案。

本文将深入剖析LangGraph中状态(State)实现的记忆机制,从短期记忆的Checkpointer原理到长期记忆的Store架构,从代码实现到生产级部署,手把手带你构建真正有状态的AI智能体。

一、LangGraph记忆架构概览:Checkpointer + Store 双层设计

LangGraph的内存架构是一个精心设计的双系统,旨在模拟不同层次的人类记忆:
#mermaid-svg-9c0EkdVLetBuaKzC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9c0EkdVLetBuaKzC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9c0EkdVLetBuaKzC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9c0EkdVLetBuaKzC .error-icon{fill:#552222;}#mermaid-svg-9c0EkdVLetBuaKzC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9c0EkdVLetBuaKzC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9c0EkdVLetBuaKzC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9c0EkdVLetBuaKzC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9c0EkdVLetBuaKzC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9c0EkdVLetBuaKzC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9c0EkdVLetBuaKzC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9c0EkdVLetBuaKzC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9c0EkdVLetBuaKzC .marker.cross{stroke:#333333;}#mermaid-svg-9c0EkdVLetBuaKzC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9c0EkdVLetBuaKzC p{margin:0;}#mermaid-svg-9c0EkdVLetBuaKzC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9c0EkdVLetBuaKzC .cluster-label text{fill:#333;}#mermaid-svg-9c0EkdVLetBuaKzC .cluster-label span{color:#333;}#mermaid-svg-9c0EkdVLetBuaKzC .cluster-label span p{background-color:transparent;}#mermaid-svg-9c0EkdVLetBuaKzC .label text,#mermaid-svg-9c0EkdVLetBuaKzC span{fill:#333;color:#333;}#mermaid-svg-9c0EkdVLetBuaKzC .node rect,#mermaid-svg-9c0EkdVLetBuaKzC .node circle,#mermaid-svg-9c0EkdVLetBuaKzC .node ellipse,#mermaid-svg-9c0EkdVLetBuaKzC .node polygon,#mermaid-svg-9c0EkdVLetBuaKzC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9c0EkdVLetBuaKzC .rough-node .label text,#mermaid-svg-9c0EkdVLetBuaKzC .node .label text,#mermaid-svg-9c0EkdVLetBuaKzC .image-shape .label,#mermaid-svg-9c0EkdVLetBuaKzC .icon-shape .label{text-anchor:middle;}#mermaid-svg-9c0EkdVLetBuaKzC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9c0EkdVLetBuaKzC .rough-node .label,#mermaid-svg-9c0EkdVLetBuaKzC .node .label,#mermaid-svg-9c0EkdVLetBuaKzC .image-shape .label,#mermaid-svg-9c0EkdVLetBuaKzC .icon-shape .label{text-align:center;}#mermaid-svg-9c0EkdVLetBuaKzC .node.clickable{cursor:pointer;}#mermaid-svg-9c0EkdVLetBuaKzC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9c0EkdVLetBuaKzC .arrowheadPath{fill:#333333;}#mermaid-svg-9c0EkdVLetBuaKzC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9c0EkdVLetBuaKzC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9c0EkdVLetBuaKzC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9c0EkdVLetBuaKzC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9c0EkdVLetBuaKzC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9c0EkdVLetBuaKzC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9c0EkdVLetBuaKzC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9c0EkdVLetBuaKzC .cluster text{fill:#333;}#mermaid-svg-9c0EkdVLetBuaKzC .cluster span{color:#333;}#mermaid-svg-9c0EkdVLetBuaKzC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9c0EkdVLetBuaKzC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9c0EkdVLetBuaKzC rect.text{fill:none;stroke-width:0;}#mermaid-svg-9c0EkdVLetBuaKzC .icon-shape,#mermaid-svg-9c0EkdVLetBuaKzC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9c0EkdVLetBuaKzC .icon-shape p,#mermaid-svg-9c0EkdVLetBuaKzC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9c0EkdVLetBuaKzC .icon-shape .label rect,#mermaid-svg-9c0EkdVLetBuaKzC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9c0EkdVLetBuaKzC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9c0EkdVLetBuaKzC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9c0EkdVLetBuaKzC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} LangGraph State 核心
长期记忆层 - Store
短期记忆层 - Checkpointer
thread-scoped

线程作用域
自动保存状态快照
支持中断恢复/时间旅行
每个Superstep自动触发
跨线程共享

namespace组织
显式读写操作
语义搜索/向量检索
持久化JSON文档存储
State Graph

状态流转
节点/边执行
消息传递

1.1 两种记忆机制的定位

维度 短期记忆(Checkpointer) 长期记忆(Store)
核心定位 线程级状态持久化,实现"会话记忆" 跨会话数据持久化,实现"用户知识"
作用域 限定在单个thread_id内 跨多个thread_id,任意线程可访问
触发方式 自动:每个Superstep自动保存 显式:通过put/get/search方法调用
存储内容 对话历史、状态通道值、中间结果 用户偏好、知识库、应用配置
生命周期 与线程绑定,线程结束则记忆失效 独立持久化存储,与线程无关
类比 浏览器的Session Cookie 用户配置文件数据库

二、短期记忆(STM):通过Checkpointer实现的线程级状态

短期记忆让你的AI智能体能够在单个线程或对话中记住之前的交互。LangGraph将短期记忆作为智能体状态的一部分进行管理,并通过检查点(Checkpointer) 持久化到数据库中。

2.1 Checkpointer核心机制

Checkpointer是LangGraph短期记忆的引擎,其工作模式是自动化的:每当图执行一步(例如调用一个节点函数),checkpointer就会自动将图的当前完整状态保存为一个快照,即"检查点"(Checkpoint)。
#mermaid-svg-REXwGqEdCxDefj5I{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-REXwGqEdCxDefj5I .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-REXwGqEdCxDefj5I .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-REXwGqEdCxDefj5I .error-icon{fill:#552222;}#mermaid-svg-REXwGqEdCxDefj5I .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-REXwGqEdCxDefj5I .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-REXwGqEdCxDefj5I .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-REXwGqEdCxDefj5I .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-REXwGqEdCxDefj5I .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-REXwGqEdCxDefj5I .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-REXwGqEdCxDefj5I .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-REXwGqEdCxDefj5I .marker{fill:#333333;stroke:#333333;}#mermaid-svg-REXwGqEdCxDefj5I .marker.cross{stroke:#333333;}#mermaid-svg-REXwGqEdCxDefj5I svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-REXwGqEdCxDefj5I p{margin:0;}#mermaid-svg-REXwGqEdCxDefj5I .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-REXwGqEdCxDefj5I .cluster-label text{fill:#333;}#mermaid-svg-REXwGqEdCxDefj5I .cluster-label span{color:#333;}#mermaid-svg-REXwGqEdCxDefj5I .cluster-label span p{background-color:transparent;}#mermaid-svg-REXwGqEdCxDefj5I .label text,#mermaid-svg-REXwGqEdCxDefj5I span{fill:#333;color:#333;}#mermaid-svg-REXwGqEdCxDefj5I .node rect,#mermaid-svg-REXwGqEdCxDefj5I .node circle,#mermaid-svg-REXwGqEdCxDefj5I .node ellipse,#mermaid-svg-REXwGqEdCxDefj5I .node polygon,#mermaid-svg-REXwGqEdCxDefj5I .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-REXwGqEdCxDefj5I .rough-node .label text,#mermaid-svg-REXwGqEdCxDefj5I .node .label text,#mermaid-svg-REXwGqEdCxDefj5I .image-shape .label,#mermaid-svg-REXwGqEdCxDefj5I .icon-shape .label{text-anchor:middle;}#mermaid-svg-REXwGqEdCxDefj5I .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-REXwGqEdCxDefj5I .rough-node .label,#mermaid-svg-REXwGqEdCxDefj5I .node .label,#mermaid-svg-REXwGqEdCxDefj5I .image-shape .label,#mermaid-svg-REXwGqEdCxDefj5I .icon-shape .label{text-align:center;}#mermaid-svg-REXwGqEdCxDefj5I .node.clickable{cursor:pointer;}#mermaid-svg-REXwGqEdCxDefj5I .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-REXwGqEdCxDefj5I .arrowheadPath{fill:#333333;}#mermaid-svg-REXwGqEdCxDefj5I .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-REXwGqEdCxDefj5I .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-REXwGqEdCxDefj5I .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-REXwGqEdCxDefj5I .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-REXwGqEdCxDefj5I .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-REXwGqEdCxDefj5I .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-REXwGqEdCxDefj5I .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-REXwGqEdCxDefj5I .cluster text{fill:#333;}#mermaid-svg-REXwGqEdCxDefj5I .cluster span{color:#333;}#mermaid-svg-REXwGqEdCxDefj5I div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-REXwGqEdCxDefj5I .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-REXwGqEdCxDefj5I rect.text{fill:none;stroke-width:0;}#mermaid-svg-REXwGqEdCxDefj5I .icon-shape,#mermaid-svg-REXwGqEdCxDefj5I .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-REXwGqEdCxDefj5I .icon-shape p,#mermaid-svg-REXwGqEdCxDefj5I .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-REXwGqEdCxDefj5I .icon-shape .label rect,#mermaid-svg-REXwGqEdCxDefj5I .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-REXwGqEdCxDefj5I .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-REXwGqEdCxDefj5I .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-REXwGqEdCxDefj5I :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 中断恢复流程
服务重启/中断
通过thread_id加载
恢复上次状态
从断点继续
短期记忆执行流程


用户输入
图执行Step
有Checkpointer?
自动保存状态快照
持久化到存储
继续下一步
状态丢失

2.2 thread_id:区分对话的"会话钥匙"

thread_id是激活和区分不同对话线程的唯一钥匙。在调用图的invokestream方法时,通过configurable字典传入一个thread_id,就等于告诉LangGraph:"这次操作属于这个特定的对话"。
#mermaid-svg-h8zLklgGGNSbOLSs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-h8zLklgGGNSbOLSs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-h8zLklgGGNSbOLSs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-h8zLklgGGNSbOLSs .error-icon{fill:#552222;}#mermaid-svg-h8zLklgGGNSbOLSs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-h8zLklgGGNSbOLSs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-h8zLklgGGNSbOLSs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-h8zLklgGGNSbOLSs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-h8zLklgGGNSbOLSs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-h8zLklgGGNSbOLSs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-h8zLklgGGNSbOLSs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-h8zLklgGGNSbOLSs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-h8zLklgGGNSbOLSs .marker.cross{stroke:#333333;}#mermaid-svg-h8zLklgGGNSbOLSs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-h8zLklgGGNSbOLSs p{margin:0;}#mermaid-svg-h8zLklgGGNSbOLSs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-h8zLklgGGNSbOLSs .cluster-label text{fill:#333;}#mermaid-svg-h8zLklgGGNSbOLSs .cluster-label span{color:#333;}#mermaid-svg-h8zLklgGGNSbOLSs .cluster-label span p{background-color:transparent;}#mermaid-svg-h8zLklgGGNSbOLSs .label text,#mermaid-svg-h8zLklgGGNSbOLSs span{fill:#333;color:#333;}#mermaid-svg-h8zLklgGGNSbOLSs .node rect,#mermaid-svg-h8zLklgGGNSbOLSs .node circle,#mermaid-svg-h8zLklgGGNSbOLSs .node ellipse,#mermaid-svg-h8zLklgGGNSbOLSs .node polygon,#mermaid-svg-h8zLklgGGNSbOLSs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-h8zLklgGGNSbOLSs .rough-node .label text,#mermaid-svg-h8zLklgGGNSbOLSs .node .label text,#mermaid-svg-h8zLklgGGNSbOLSs .image-shape .label,#mermaid-svg-h8zLklgGGNSbOLSs .icon-shape .label{text-anchor:middle;}#mermaid-svg-h8zLklgGGNSbOLSs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-h8zLklgGGNSbOLSs .rough-node .label,#mermaid-svg-h8zLklgGGNSbOLSs .node .label,#mermaid-svg-h8zLklgGGNSbOLSs .image-shape .label,#mermaid-svg-h8zLklgGGNSbOLSs .icon-shape .label{text-align:center;}#mermaid-svg-h8zLklgGGNSbOLSs .node.clickable{cursor:pointer;}#mermaid-svg-h8zLklgGGNSbOLSs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-h8zLklgGGNSbOLSs .arrowheadPath{fill:#333333;}#mermaid-svg-h8zLklgGGNSbOLSs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-h8zLklgGGNSbOLSs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-h8zLklgGGNSbOLSs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h8zLklgGGNSbOLSs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-h8zLklgGGNSbOLSs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h8zLklgGGNSbOLSs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-h8zLklgGGNSbOLSs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-h8zLklgGGNSbOLSs .cluster text{fill:#333;}#mermaid-svg-h8zLklgGGNSbOLSs .cluster span{color:#333;}#mermaid-svg-h8zLklgGGNSbOLSs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-h8zLklgGGNSbOLSs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-h8zLklgGGNSbOLSs rect.text{fill:none;stroke-width:0;}#mermaid-svg-h8zLklgGGNSbOLSs .icon-shape,#mermaid-svg-h8zLklgGGNSbOLSs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h8zLklgGGNSbOLSs .icon-shape p,#mermaid-svg-h8zLklgGGNSbOLSs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-h8zLklgGGNSbOLSs .icon-shape .label rect,#mermaid-svg-h8zLklgGGNSbOLSs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h8zLklgGGNSbOLSs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-h8zLklgGGNSbOLSs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-h8zLklgGGNSbOLSs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线程隔离示意
隔离
隔离
thread_id: user_001
状态1

对话历史A
thread_id: user_002
状态2

对话历史B
thread_id: user_003
状态3

对话历史C

概念类比:可以将checkpointer和thread_id的关系类比为网站的会话(Session)Cookie。当您登录一个网站后,浏览器会保存一个会话Cookie,网站通过这个Cookie识别您的身份,从而保持您的登录状态。同样,thread_id让LangGraph智能体在多轮对话中能够"记住"您是谁以及你们正在聊什么。

2.3 短期记忆的代码实现

基本用法:

python 复制代码
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import StateGraph, MessagesState

# 1. 创建 checkpointer
checkpointer = InMemorySaver()

# 2. 编译图时启用 checkpointer
graph = builder.compile(checkpointer=checkpointer)

# 3. 第一次对话 - 指定 thread_id
config = {"configurable": {"thread_id": "user_123"}}
graph.invoke({"messages": [("user", "我叫张三")]}, config)

# 4. 第二次对话 - 同一个 thread_id,可以访问之前的消息
graph.invoke({"messages": [("user", "我刚才说我叫什么?")]}, config)
# Agent 可以回答:"你刚才说你叫张三"

生产环境使用数据库Checkpointer:

python 复制代码
from langgraph.checkpoint.postgres import PostgresSaver

DB_URI = "postgresql://user:password@localhost:5432/dbname"
checkpointer = PostgresSaver.from_conn_string(DB_URI)

# 首次使用时需要初始化表结构
# await checkpointer.setup()

graph = builder.compile(checkpointer=checkpointer)

2.4 Checkpointer的存储后端矩阵

LangGraph提供多种checkpointer实现,可根据场景选择:

实现类 存储介质 适用场景 性能特征
MemorySaver 内存 开发测试、单元测试 访问延迟<1ms
FileCheckpointer 本地文件系统 单机生产环境 吞吐量约50MB/s
SqliteSaver SQLite数据库 小规模部署 支持ACID事务
PostgresSaver PostgreSQL 生产环境、高可用需求 分布式持久化
RedisSaver Redis集群 分布式系统、低延迟场景 跨节点同步延迟<10ms

注意 :使用Postgres等数据库checkpointer前,需要调用setup()方法创建必要的数据库表结构。

三、长期记忆(LTM):通过Store实现的跨会话持久化

与专注于单次对话的短期记忆不同,长期记忆旨在存储跨越不同对话的用户特定或应用级别的数据。这是智能体积累知识、形成对用户长期认知的地方。

3.1 Store核心机制

Store本质上是一个暴露给图节点和工具的键值数据库 。与checkpointer的自动化快照不同,对Store的操作是显式和主动的 ------开发者需要在节点或工具的逻辑中,通过调用store.put()store.get()store.search()等方法来精确地读写信息。

3.2 Namespace:分层组织记忆的目录结构

Store使用层次化的命名空间来组织数据。命名空间是一个元组(类似文件夹路径),用于实现数据隔离和高效检索:

python 复制代码
# 用户数据存储
["users", "user_123", "preferences"]   # 用户偏好
["users", "user_123", "history"]        # 用户历史
["users", "user_123", "settings"]       # 用户设置

# 应用数据存储
["app", "config", "version"]            # 应用配置
["app", "knowledge", "faq"]             # 知识库FAQ

# 组织级数据存储
["orgs", "org_456", "members"]          # 组织成员
["orgs", "org_456", "policies"]         # 组织策略

#mermaid-svg-Bhhb8NnuMlGnuPfy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Bhhb8NnuMlGnuPfy .error-icon{fill:#552222;}#mermaid-svg-Bhhb8NnuMlGnuPfy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Bhhb8NnuMlGnuPfy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .marker.cross{stroke:#333333;}#mermaid-svg-Bhhb8NnuMlGnuPfy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Bhhb8NnuMlGnuPfy p{margin:0;}#mermaid-svg-Bhhb8NnuMlGnuPfy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .cluster-label text{fill:#333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .cluster-label span{color:#333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .cluster-label span p{background-color:transparent;}#mermaid-svg-Bhhb8NnuMlGnuPfy .label text,#mermaid-svg-Bhhb8NnuMlGnuPfy span{fill:#333;color:#333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .node rect,#mermaid-svg-Bhhb8NnuMlGnuPfy .node circle,#mermaid-svg-Bhhb8NnuMlGnuPfy .node ellipse,#mermaid-svg-Bhhb8NnuMlGnuPfy .node polygon,#mermaid-svg-Bhhb8NnuMlGnuPfy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Bhhb8NnuMlGnuPfy .rough-node .label text,#mermaid-svg-Bhhb8NnuMlGnuPfy .node .label text,#mermaid-svg-Bhhb8NnuMlGnuPfy .image-shape .label,#mermaid-svg-Bhhb8NnuMlGnuPfy .icon-shape .label{text-anchor:middle;}#mermaid-svg-Bhhb8NnuMlGnuPfy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Bhhb8NnuMlGnuPfy .rough-node .label,#mermaid-svg-Bhhb8NnuMlGnuPfy .node .label,#mermaid-svg-Bhhb8NnuMlGnuPfy .image-shape .label,#mermaid-svg-Bhhb8NnuMlGnuPfy .icon-shape .label{text-align:center;}#mermaid-svg-Bhhb8NnuMlGnuPfy .node.clickable{cursor:pointer;}#mermaid-svg-Bhhb8NnuMlGnuPfy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .arrowheadPath{fill:#333333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Bhhb8NnuMlGnuPfy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bhhb8NnuMlGnuPfy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Bhhb8NnuMlGnuPfy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bhhb8NnuMlGnuPfy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Bhhb8NnuMlGnuPfy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Bhhb8NnuMlGnuPfy .cluster text{fill:#333;}#mermaid-svg-Bhhb8NnuMlGnuPfy .cluster span{color:#333;}#mermaid-svg-Bhhb8NnuMlGnuPfy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Bhhb8NnuMlGnuPfy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Bhhb8NnuMlGnuPfy rect.text{fill:none;stroke-width:0;}#mermaid-svg-Bhhb8NnuMlGnuPfy .icon-shape,#mermaid-svg-Bhhb8NnuMlGnuPfy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bhhb8NnuMlGnuPfy .icon-shape p,#mermaid-svg-Bhhb8NnuMlGnuPfy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Bhhb8NnuMlGnuPfy .icon-shape .label rect,#mermaid-svg-Bhhb8NnuMlGnuPfy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bhhb8NnuMlGnuPfy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Bhhb8NnuMlGnuPfy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Bhhb8NnuMlGnuPfy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 命名空间树形结构
根命名空间
users
user_123
user_456
preferences
history
settings
app
config
knowledge
faq
orgs
org_456
members

这种设计实现了三大优势:权限隔离 (不同业务模块访问独立命名空间)、版本控制 (通过时间戳实现记忆快照管理)和高效检索(构建空间索引提升查询性能)。

3.3 长期记忆的代码实现

基本用法:

python 复制代码
from langgraph.store.memory import InMemoryStore

# 1. 创建 store
store = InMemoryStore()

# 2. 保存用户偏好(跨会话)
await store.aput(
    ["users", "user_123", "preferences"],
    {"theme": "dark", "language": "zh-CN"}
)

# 3. 在任何线程中都可以访问
preferences = await store.aget(["users", "user_123", "preferences"])
print(preferences)  # {"theme": "dark", "language": "zh-CN"}

将Store集成到Agent中:

python 复制代码
from langchain.agents import create_agent

# 创建带有长期记忆的agent
store = InMemoryStore()
agent = create_agent(
    "claude-sonnet-4-6",
    tools=[],
    store=store,  # Store会自动注入到节点的Runtime对象中
)

LangGraph会自动将store注入到节点函数中,推荐通过Runtime对象访问。

3.4 语义记忆与向量检索

LangGraph的Store支持基于嵌入向量的语义搜索,让长期记忆能够智能检索相关内容。

配置支持语义搜索的Store:

python 复制代码
# 开发环境:内存存储 + 嵌入支持
from langgraph.store.memory import InMemoryStore

def embed(texts):
    # 实际环境中应使用openai:text-embedding-3-small等模型
    return [[0.1, 0.2, ...] for _ in texts]

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

# 生产环境:使用PostgreSQL + 向量扩展
from langgraph.store.postgres import AsyncPostgresStore

store = AsyncPostgresStore(
    connection_string="postgresql://user:pass@host:5432/db",
    index={
        "dims": 1536,
        "embed": "openai:text-embedding-3-small"
    }
)

语义搜索查询:

python 复制代码
# 使用语义搜索查找相关记忆
namespace = ("memories", "user_123")
results = store.search(
    namespace,
    query="用户关于黑暗模式的偏好",
    limit=5
)

3.5 LangMem:进阶的记忆管理

LangMem是建立在LangGraph BaseStore之上的高级记忆管理SDK,支持三种核心记忆模式:

模式 用途 命名空间示例 特性
Collection 语义记忆、情景记忆 ("memories", "{user_id}") 多文档,支持搜索和更新
Profile 用户画像、系统配置 ("profile", "{user_id}") 单文档,原地更新
Rules 行为规则、指令约束 ("rules", "system") 静态配置,几乎无变更
python 复制代码
from langmem import create_memory_manager

# 创建记忆管理器 - Collection模式
manager = create_memory_manager(
    "anthropic:claude-3-5-sonnet-latest",
    namespace=("memories", "{langgraph_user_id}"),
    enable_inserts=True,   # 允许添加新记忆
    enable_deletes=True    # 允许删除过期记忆
)

四、短期记忆与长期记忆的核心对比

#mermaid-svg-C6Q30D7j8Lxw4iVa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-C6Q30D7j8Lxw4iVa .error-icon{fill:#552222;}#mermaid-svg-C6Q30D7j8Lxw4iVa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-C6Q30D7j8Lxw4iVa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .marker.cross{stroke:#333333;}#mermaid-svg-C6Q30D7j8Lxw4iVa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-C6Q30D7j8Lxw4iVa p{margin:0;}#mermaid-svg-C6Q30D7j8Lxw4iVa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .cluster-label text{fill:#333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .cluster-label span{color:#333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .cluster-label span p{background-color:transparent;}#mermaid-svg-C6Q30D7j8Lxw4iVa .label text,#mermaid-svg-C6Q30D7j8Lxw4iVa span{fill:#333;color:#333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .node rect,#mermaid-svg-C6Q30D7j8Lxw4iVa .node circle,#mermaid-svg-C6Q30D7j8Lxw4iVa .node ellipse,#mermaid-svg-C6Q30D7j8Lxw4iVa .node polygon,#mermaid-svg-C6Q30D7j8Lxw4iVa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-C6Q30D7j8Lxw4iVa .rough-node .label text,#mermaid-svg-C6Q30D7j8Lxw4iVa .node .label text,#mermaid-svg-C6Q30D7j8Lxw4iVa .image-shape .label,#mermaid-svg-C6Q30D7j8Lxw4iVa .icon-shape .label{text-anchor:middle;}#mermaid-svg-C6Q30D7j8Lxw4iVa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-C6Q30D7j8Lxw4iVa .rough-node .label,#mermaid-svg-C6Q30D7j8Lxw4iVa .node .label,#mermaid-svg-C6Q30D7j8Lxw4iVa .image-shape .label,#mermaid-svg-C6Q30D7j8Lxw4iVa .icon-shape .label{text-align:center;}#mermaid-svg-C6Q30D7j8Lxw4iVa .node.clickable{cursor:pointer;}#mermaid-svg-C6Q30D7j8Lxw4iVa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .arrowheadPath{fill:#333333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-C6Q30D7j8Lxw4iVa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C6Q30D7j8Lxw4iVa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-C6Q30D7j8Lxw4iVa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C6Q30D7j8Lxw4iVa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-C6Q30D7j8Lxw4iVa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-C6Q30D7j8Lxw4iVa .cluster text{fill:#333;}#mermaid-svg-C6Q30D7j8Lxw4iVa .cluster span{color:#333;}#mermaid-svg-C6Q30D7j8Lxw4iVa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-C6Q30D7j8Lxw4iVa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-C6Q30D7j8Lxw4iVa rect.text{fill:none;stroke-width:0;}#mermaid-svg-C6Q30D7j8Lxw4iVa .icon-shape,#mermaid-svg-C6Q30D7j8Lxw4iVa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C6Q30D7j8Lxw4iVa .icon-shape p,#mermaid-svg-C6Q30D7j8Lxw4iVa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-C6Q30D7j8Lxw4iVa .icon-shape .label rect,#mermaid-svg-C6Q30D7j8Lxw4iVa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C6Q30D7j8Lxw4iVa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-C6Q30D7j8Lxw4iVa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-C6Q30D7j8Lxw4iVa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 长期记忆层
短期记忆层
会话1
会话2
会话3
跨线程访问
上下文注入
thread_id: user_001
对话历史
对话历史
对话历史
user_id: user_001
namespace: users/user_001/preferences
namespace: users/user_001/history
namespace: users/user_001/settings

对比维度 短期记忆 长期记忆
核心组件 Checkpointer Store
作用域标识 thread_id namespace(通常含user_id)
操作方式 自动(每个superstep) 显式(put/get/search方法)
状态类型 状态通道值(对话历史、中间结果) JSON文档(用户偏好、知识库)
存储后端 MemorySaver/PostgresSaver/RedisSaver InMemoryStore/PostgresStore
检索能力 基于thread_id精确加载 精确匹配 + 语义向量搜索
生命周期 线程绑定 独立持久化

从存储底层看,两者共享类似的后端选择,但数据模型和访问模式截然不同 :Checkpointer按superstep自动保存状态通道值,Store按namespace显式管理JSON文档;Postgres既可以作为Checkpointer的存储后端用于短期记忆,也可以作为Store的后端用于长期记忆,但使用方式和意图不同

五、完整实战:构建有记忆的AI客服系统

下面我们将构建一个具备长短期记忆能力的AI客服系统,实现:

  1. 用短期记忆跟踪当前对话上下文
  2. 用长期记忆存储和检索用户偏好

5.1 完整架构流程图

#mermaid-svg-FSY1HhkddH4wVpsA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FSY1HhkddH4wVpsA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FSY1HhkddH4wVpsA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FSY1HhkddH4wVpsA .error-icon{fill:#552222;}#mermaid-svg-FSY1HhkddH4wVpsA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FSY1HhkddH4wVpsA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FSY1HhkddH4wVpsA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FSY1HhkddH4wVpsA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FSY1HhkddH4wVpsA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FSY1HhkddH4wVpsA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FSY1HhkddH4wVpsA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FSY1HhkddH4wVpsA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FSY1HhkddH4wVpsA .marker.cross{stroke:#333333;}#mermaid-svg-FSY1HhkddH4wVpsA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FSY1HhkddH4wVpsA p{margin:0;}#mermaid-svg-FSY1HhkddH4wVpsA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FSY1HhkddH4wVpsA .cluster-label text{fill:#333;}#mermaid-svg-FSY1HhkddH4wVpsA .cluster-label span{color:#333;}#mermaid-svg-FSY1HhkddH4wVpsA .cluster-label span p{background-color:transparent;}#mermaid-svg-FSY1HhkddH4wVpsA .label text,#mermaid-svg-FSY1HhkddH4wVpsA span{fill:#333;color:#333;}#mermaid-svg-FSY1HhkddH4wVpsA .node rect,#mermaid-svg-FSY1HhkddH4wVpsA .node circle,#mermaid-svg-FSY1HhkddH4wVpsA .node ellipse,#mermaid-svg-FSY1HhkddH4wVpsA .node polygon,#mermaid-svg-FSY1HhkddH4wVpsA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FSY1HhkddH4wVpsA .rough-node .label text,#mermaid-svg-FSY1HhkddH4wVpsA .node .label text,#mermaid-svg-FSY1HhkddH4wVpsA .image-shape .label,#mermaid-svg-FSY1HhkddH4wVpsA .icon-shape .label{text-anchor:middle;}#mermaid-svg-FSY1HhkddH4wVpsA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FSY1HhkddH4wVpsA .rough-node .label,#mermaid-svg-FSY1HhkddH4wVpsA .node .label,#mermaid-svg-FSY1HhkddH4wVpsA .image-shape .label,#mermaid-svg-FSY1HhkddH4wVpsA .icon-shape .label{text-align:center;}#mermaid-svg-FSY1HhkddH4wVpsA .node.clickable{cursor:pointer;}#mermaid-svg-FSY1HhkddH4wVpsA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FSY1HhkddH4wVpsA .arrowheadPath{fill:#333333;}#mermaid-svg-FSY1HhkddH4wVpsA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FSY1HhkddH4wVpsA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FSY1HhkddH4wVpsA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FSY1HhkddH4wVpsA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FSY1HhkddH4wVpsA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FSY1HhkddH4wVpsA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FSY1HhkddH4wVpsA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FSY1HhkddH4wVpsA .cluster text{fill:#333;}#mermaid-svg-FSY1HhkddH4wVpsA .cluster span{color:#333;}#mermaid-svg-FSY1HhkddH4wVpsA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FSY1HhkddH4wVpsA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FSY1HhkddH4wVpsA rect.text{fill:none;stroke-width:0;}#mermaid-svg-FSY1HhkddH4wVpsA .icon-shape,#mermaid-svg-FSY1HhkddH4wVpsA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FSY1HhkddH4wVpsA .icon-shape p,#mermaid-svg-FSY1HhkddH4wVpsA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FSY1HhkddH4wVpsA .icon-shape .label rect,#mermaid-svg-FSY1HhkddH4wVpsA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FSY1HhkddH4wVpsA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FSY1HhkddH4wVpsA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FSY1HhkddH4wVpsA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 处理流程
长期记忆层
短期记忆层
用户交互层


用户输入
AI客服Agent
获取thread状态
Checkpointer加载上次对话
对话上下文注入
检索用户记忆
Store语义搜索
用户偏好/历史信息
LLM推理
需要更新记忆?
写入Store
输出回复
Checkpointer保存新状态

5.2 完整代码示例

python 复制代码
import asyncio
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
from typing import Literal

# 1. 配置嵌入函数(实际应调用OpenAI或本地嵌入模型)
def simple_embed(texts):
    # 简化示例,生产环境请使用真实的嵌入模型
    return [[hash(t[:10]) % 1000 / 1000.0] for t in texts]

# 2. 创建短期记忆(Checkpointer)和长期记忆(Store)
short_term_memory = InMemorySaver()
long_term_memory = InMemoryStore(
    index={"dims": 1, "embed": simple_embed}
)

# 3. 定义节点函数(Runtime自动注入store)
async def call_model(state: MessagesState, runtime):
    """调用LLM的核心节点,同时集成长期记忆"""
    user_id = runtime.config["configurable"].get("user_id", "unknown")
    
    # 从Store检索用户长期记忆
    memories = await runtime.store.asearch(
        ["memories", user_id],
        query=state["messages"][-1].content if state["messages"] else "",
        limit=5
    )
    
    # 构建包含记忆的prompt
    memory_context = "\n".join([m.dict() for m in memories]) if memories else ""
    messages = state["messages"]
    
    # 实际调用LLM...
    # response = llm.invoke(messages)
    
    return {"messages": messages + [("assistant", "AI回复内容")]}

async def update_memories(state: MessagesState, runtime):
    """更新长期记忆节点"""
    user_id = runtime.config["configurable"].get("user_id", "unknown")
    last_message = state["messages"][-1]
    
    # 分析并提取需要长期记忆的信息
    # 实际应使用LLM判断是否需要记忆
    
    # 示例:存储用户偏好
    if "偏好" in last_message.content:
        await runtime.store.aput(
            ["memories", user_id, "preferences"],
            {"content": last_message.content, "timestamp": "..."}
        )
    
    return state

# 4. 构建图并集成记忆
builder = StateGraph(MessagesState)
builder.add_node("call_model", call_model)
builder.add_node("update_memories", update_memories)
builder.add_edge(START, "call_model")
builder.add_edge("call_model", "update_memories")
builder.add_edge("update_memories", END)

# 5. 编译图,同时传入checkpointer和store
graph = builder.compile(
    checkpointer=short_term_memory,
    store=long_term_memory
)

# 6. 使用:传入thread_id(短期记忆)和user_id(长期记忆)配置
config = {
    "configurable": {
        "thread_id": "session_001",  # 用于短期记忆隔离
        "user_id": "user_123"        # 用于长期记忆命名空间
    }
}

# 运行
async def main():
    # 第一轮对话
    await graph.ainvoke(
        {"messages": [("user", "我喜欢简洁的回答风格")]},
        config
    )
    
    # 第二轮对话,短期记忆保留上下文,长期记忆已保存偏好
    result = await graph.ainvoke(
        {"messages": [("user", "你还记得我喜欢的回答风格吗?")]},
        config
    )
    print(result)

# asyncio.run(main())

六、生产级部署建议

6.1 存储后端选型指南

部署规模 短期记忆(Checkpointer) 长期记忆(Store)
开发/测试 MemorySaver(内存) InMemoryStore(内存)
单机生产 PostgresSaver PostgresStore
分布式高可用 RedisSaver AsyncPostgresStore + 集群
超大规模 分库分表 + 自定义实现 向量数据库(如Pinecone/Milvus)

实测表明,合理配置的检查点可将系统故障恢复时间从分钟级降至秒级。

6.2 安全审计与权限隔离

python 复制代码
# 使用命名空间实现数据隔离
class SecurityAudit:
    def get_user_namespace(self, user_id: str, permission: str):
        """基于RBAC构建命名空间"""
        if permission == "read":
            return ["read", user_id]    # 只读命名空间
        elif permission == "write":
            return ["write", user_id]   # 读写命名空间
        else:
            raise PermissionError("无权访问")

# 三级命名空间体系示例
memory_config = {
    "user_profile": {
        "basic_info": {},      # 一级:用户身份
        "preferences": {}      # 二级:用户偏好
    },
    "session_context": {
        "current_intent": "",  # 会话级记忆
        "last_response": ""
    }
}

6.3 TTL自动清理策略

json 复制代码
{
  "store": {
    "ttl": 2592000  // 30天过期,单位:秒
  }
}

配置TTL策略可自动管理数据生命周期,防止存储无限累积。

6.4 性能优化建议

  • 缓存策略:使用LangMem的语义缓存(Redis LangCache)减少LLM API调用,可将Token消耗降低30%-50%
  • 滑动窗口机制:短期记忆默认保留最近8-16轮对话,建议根据业务场景调优窗口大小
  • 混合检索:结构化数据用PostgreSQL,非结构化数据用向量数据库,结合语义搜索和精确匹配

七、总结

LangGraph通过Checkpointer(短期记忆)Store(长期记忆) 的巧妙设计,为AI智能体提供了工业级的记忆管理方案:

记忆类型 核心组件 作用域标识 操作方式 核心用途
短期记忆 Checkpointer thread_id 自动保存每个Superstep 多轮对话上下文连续性
长期记忆 Store namespace(如user_id) 显式put/get/search 用户偏好跨会话持久化

两者的核心差异在于:短期记忆回答"这次对话我们说了什么",长期记忆回答"关于这个用户我们都知道什么"。通过将短期记忆(Checkpointer)和长期记忆(Store)同时编译到图中,您可以构建既能维持多轮对话连贯性、又能跨会话沉淀用户知识的智能体系统------这正是LangGraph从"流程编排框架"进化为"智能体操作系统"的关键一步。

参考资料

  1. LangGraph Memory 机制详解
  2. 精通状态智能体:LangGraph 内存机制综合指南(长短期记忆)
  3. AI 智能体记忆架构在 LangGraph 中的落地实现
  4. LangGraph持久化机制深度解析
  5. Long-term memory - LangChain Docs
  6. Memory - LangChain Docs
  7. Storage - LangMem DeepWiki
  8. Building Stateful AI Agents with LangGraph and Redis
  9. 如何添加跨线程持久化
相关推荐
霸道流氓气质4 小时前
Kiro 多工程协作与上下文引用技巧
ai
小七-七牛开发者5 小时前
AI Agent 的 4 个工程关键词:Prompt、Context、Loop、Harness 到底是什么?
ai·大模型·agent·token·context·loop·codex·harness
yychen_java6 小时前
当算法成为武器:AI泛滥时代的多维危机透视与治理路径
网络·人工智能·ai
Samooyou6 小时前
大模型微调(Fine Tuning)
人工智能·python·ai·语言模型
土星云SaturnCloud6 小时前
边缘计算赋能智慧工地:从“看得见“到“管得住“的智能化升级
服务器·人工智能·ai·边缘计算
Flittly7 小时前
【AgentScope Java新手村系列】(2)第一个Agent-基础对话
java·spring boot·spring·ai
ZeroNews内网穿透7 小时前
NAS部署Hermes AI Agent + 零讯内网穿透,实现远程可管理的AI助手
人工智能·安全·ai·内网穿透
奶油话梅糖8 小时前
IMA 知识库体验(内有资源分享):把资料变成可以提问的 AI 知识助手
人工智能·ai·aigc·知识图谱·知识库·学习工具·ima
ZFSS8 小时前
VS Code + Luma MCP 使用教程
人工智能·ai·ai作画·copilot·ai编程·ai写作