很多人第一次写 Agent都会遇到一个很典型的问题在当前对话里我刚告诉它“我叫小王喜欢编程”下一轮再问“我是谁”它应该能接着回答但如果我换一个新的会话线程再问同样的问题它还能不能记得我这里其实对应两种不同的记忆需求。一种是短记忆强调的是“当前会话”。只要还在同一个 thread_id 里Agent 就应该能记住前几轮聊过什么。另一种是长记忆强调的是“账号维度”。只要还是同一个 user_id哪怕切换了多个线程、开启了新的会话Agent 仍然应该记得这个用户的长期信息比如姓名、身份、偏好等。所以本文围绕一个问题展开如何分别用短记忆解决当前会话上下文问题再用长记忆解决同一账号下跨线程记忆的问题。一、为什么要分短记忆和长记忆先想一个客服场景。用户进入客服系统后说我是小王同学我是 VIP 用户我喜欢详细一点的产品说明。接下来可能发生两类问题。第一类当前会话里的上下文问题用户刚说完这句话下一轮问我刚刚说了什么这个问题只和“当前这段对话”有关。只要 Agent 能拿到前几轮消息它就能回答。这就是短记忆要解决的问题。短记忆的关键词是 thread_id。相同 thread_id 表示同一段对话Agent 可以继续读取这段对话的历史换一个 thread_id就像重新开了一个新窗口。第二类跨会话的用户信息问题过了几天用户重新打开客服系统开启了一个新的会话然后问你还记得我是谁吗我喜欢什么样的说明这个问题已经不只是当前会话上下文了因为新的会话里并没有之前那句话。Agent 想回答出来就必须从长期存储里查询这个用户的信息。这就是长记忆要解决的问题。长记忆的关键词是 user_id。只要 user_id 不变即使 thread_id 变了Agent 也可以查到这个用户长期保存的信息。短记忆让对话连贯长记忆让用户关系持续。理解了这一点后面的代码就很好看了我们先用 Checkpointer 解决“当前会话记不住”的问题再用 Store 解决“换个会话就忘了用户”的问题最后把两者组合起来。二、先用 InMemorySaver 做最简单的短记忆先看最小版本让 Agent 在同一个会话里记住用户刚刚说过的话。这里用 InMemorySaver它把状态存在内存里适合本地测试。这段代码到底做了什么InMemorySaver 创建了一个短记忆存储。create_agent 通过 checkpointer 读取和写入当前会话状态。两次 invoke 使用同一个 thread_id所以第二次能读到第一次的对话历史。如果换一个 thread_idAgent 就会把它当成新的会话。实操结果第一次告诉 Agent 用户信息第二次询问“我是谁”Agent 能根据同一个 thread_id 回答出来。到这里我们解决了第一个问题同一段会话里Agent 不再健忘。三、为什么生产环境要换成 PostgresSaverInMemorySaver 很适合学习但它有一个明显限制进程一重启内存里的会话状态就没了。如果这是一个真实客服系统就会出现问题服务重启后用户刚刚聊到一半的上下文全部丢失多台服务同时部署时不同实例之间也无法共享会话状态。所以生产环境更推荐 PostgresSaver。它还是短记忆解决的仍然是 thread_id 对应的当前会话状态只是把状态持久化到了 PostgreSQL。先启动 PostgreSQLdocker run -d \--name postgres \-p 5432:5432 \-e POSTGRES_USERpostgres \-e POSTGRES_PASSWORDpostgres \-e POSTGRES_DBlangchain_db \-e POSTGRES_HOST_AUTH_METHODtrust \-v postgres_data:/var/lib/postgresql/data \postgres:15运行下面这段代码需要安装的依赖pip install langgraph-checkpoint-postgres psycopg[binary,pool] langchain-openai langchain用 PostgresSaver 保存短记忆import os import sys from urllib.parse import quote_plus from langchain.agents import create_agent from langchain_openai import ChatOpenAI from langgraph.checkpoint.postgres import PostgresSaver if hasattr(sys.stdout, reconfigure): sys.stdout.reconfigure(encodingutf-8) # 验证 环境变量 api_key os.getenv(DASHSCOPE_API_KEY) if not api_key: raise ValueError(请先配置环境变量 DASHSCOPE_API_KEY) # 配置 PostgreSQL 数据库连接 pg_user os.getenv(PGUSER, postgres) pg_password quote_plus(os.getenv(PGPASSWORD, postgres)) pg_host os.getenv(PGHOST, 111111) pg_port os.getenv(PGPORT, 5432) pg_database os.getenv(PGDATABASE, langchain_db) DB_URI fpostgresql://{pg_user}:{pg_password}{pg_host}:{pg_port}/{pg_database} # 初始化 PostgreSQL 检查点 with PostgresSaver.from_conn_string(DB_URI) as checkpointer: #自动创建 PostgreSQL 表结构 checkpointer.setup() model ChatOpenAI( modelqwen3.5-plus, api_keyapi_key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, temperature0.3 ) agent create_agent( modelmodel, tools[], system_prompt 你是一个乐于助人的助手 , checkpointercheckpointer ) # 使用 同一个 会话id thread_id config {configurable: {thread_id: user_123}} config2 {configurable: {thread_id: user_1234}} response1 agent.invoke( {messages: [(user, 我是小王同学喜欢编程)]}, configconfig ) print(助手, response1[messages][-1].content) response2 agent.invoke( {messages: [(user, 我刚刚说了什么)]}, configconfig ) print(助手, response2[messages][-1].content) response3 agent.invoke( {messages: [(user, 我是谁我喜欢什么)]}, configconfig2 ) print(助手, response3[messages][-1].content)这里要观察什么response1 和 response2 使用同一个 thread_id所以第二轮能记住第一轮。response3 换了新的 thread_id所以它不知道前面 user_123 会话里的内容。这说明 PostgresSaver 解决的是“短记忆持久化”不是“跨会话用户画像”。实操结果:预期输出:PostgresSaver 初始化成功 第一轮对话 助手 你好呀小王同学 很高兴认识你等等 第二轮对话相同 thread_id模型应记住用户助手 你刚刚介绍说“我是小王同学喜欢编程”。等等 第三轮对话新 thread_id模型会忘记之前的内容助手 您好很高兴见到您。说实话作为一个 AI 助手我目前还不知道您是谁也不了解您的具体喜好。因为我们的对话刚刚开始我还没有机会认识您也无法访问您的个人信息。pg中存储的数据:同一个 thread_id 能接上上下文新的 thread_id 会变成全新会话。到这里我们已经把短记忆从内存版本升级到了生产可用版本。但还有一个问题没解决新会话里Agent 仍然不知道这个用户长期是谁。四、用 Store 解决长记忆问题接下来解决第二个问题用户换了一个新会话Agent 还能不能知道他的偏好这时就不能只依赖 thread_id 了。因为新会话的 thread_id 已经变了短记忆里没有之前的上下文。我们需要把用户长期信息按照 user_id 存起来。这就是 Store 的作用。它可以保存用户偏好、身份、配置等长期信息后续任何会话都可以通过 user_id 查询。Store 的实现类型InMemoryStore开发测试数据存储在内存中进程重启后丢失PostgresStore生产环境推荐基于 PostgreSQL 持久化存储运行下面这段代码需要安装的依赖:pip install langchain1.0.3 langgraph1.0.2 langgraph-checkpoint-postgres3.0.5 psycopg3.3.3 langchain-openai1.1.12 langchain-core1.2.26 langchain-classic1.0.3 langchain-community0.3.29 langgraph-checkpoint3.0.1 langgraph-prebuilt1.0.2 langgraph-sdk0.2.15 psycopg-pool3.3.0 psycopg-binary3.3.3# 验证 环境变量 import os import sys import uuid from urllib.parse import quote_plus from langchain.agents import create_agent from langchain_core.runnables import RunnableConfig from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import InMemorySaver from langgraph.store.postgres import PostgresStore if hasattr(sys.stdout, reconfigure): sys.stdout.reconfigure(encodingutf-8) api_key os.getenv(DASHSCOPE_API_KEY) if not api_key: raise ValueError(请先配置环境变量 DASHSCOPE_API_KEY) # 配置 PostgreSQL 数据库连接 pg_user os.getenv(PGUSER, postgres) pg_password quote_plus(os.getenv(PGPASSWORD, postgres)) pg_host os.getenv(PGHOST, 111111) pg_port os.getenv(PGPORT, 5432) pg_database os.getenv(PGDATABASE, langchain_db) DB_URI fpostgresql://{pg_user}:{pg_password}{pg_host}:{pg_port}/{pg_database} # 初始化 PostgreSQL 检查点 with PostgresStore.from_conn_string(DB_URI) as store: #自动创建 PostgreSQL 表结构 store.setup() # 定义工具 # 保存 tool def save_user_preference(key: str, value: str,config: RunnableConfig) - str: 保存用户的偏好到长记忆 user_id config[configurable][user_id] #创建命名空间 namespace (user_preferences, user_id) item_idstr(uuid.uuid4()) store.put(namespace, item_id, {key: key, value: value}) return f已保存用户偏好 {key}: {value} # 读取 tool def get_all_user_preferences(config: RunnableConfig) - str: 获取用户所有的偏好设置 user_id config[configurable][user_id] namespace (user_preferences, user_id) items store.search(namespace) preferences [] for item in items: key item.value.get(key,未知) value item.value.get(value, 未知) preferences.append(f{key}: {value}) return \n.join(preferences) if preferences else 没有找到偏好设置 model ChatOpenAI( modelqwen3.5-plus, api_keyapi_key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, temperature0.3 ) checkpointer InMemorySaver() agent create_agent( modelmodel, tools[save_user_preference,get_all_user_preferences], system_prompt 你是一个乐于助人的助手 可以使用工具 保存和查询用户的 偏好 , #短记忆 checkpointercheckpointer, #长记忆 storestore ) # 使用 同一个 会话id thread_id config {configurable: {user_id:user_001,thread_id: user_123}} config2 {configurable: {user_id:user_001,thread_id: user_1234}} response1 agent.invoke( {messages: [(user, 我是小王同学喜欢可爱的回答请帮我记住这个偏好)]}, configconfig ) print(助手, response1[messages][-1].content) response2 agent.invoke( {messages: [(user, 我刚刚说了什么)]}, configconfig ) print(助手, response2[messages][-1].content) response3 agent.invoke( {messages: [(user, 我是谁我有什么偏好)]}, configconfig2 ) print(助手, response3[messages][-1].content)这段代码怎么实现长记忆save_user_preference 是写入工具负责把用户偏好保存到 Store。get_all_user_preferences 是读取工具负责从 Store 查询用户偏好。namespace (user_preferences, user_id) 用来把不同用户的数据隔离开。config 和 config2 的 thread_id 不同但 user_id 相同所以新会话依然能查到同一个用户的长期偏好。实操结果预期输出 第一轮对话保存用户偏好 助手 小王同学刚刚说「我是小王同学喜欢可爱的回答请帮我记住这个偏好」呀(◍•ᴗ•◍)我已经乖乖记好啦你的名字和喜欢可爱风格的小愿望都存进我的小心心数据库了哦✨ 以后每次和你聊天我都会用软萌软萌的语气陪你哒(๑ᴗ๑) 新会话不同 thread_id助手 你好呀小王同学✨ 你就是那个喜欢可爱风格回答的小可爱哦根据你的偏好设置我知道你喜欢我用可爱的语气和你聊天呢 (•̀ᴗ-)✧目前我记住的关于你的小秘密有你的名字小王同学喜欢的回答风格可爱的回答如果以后你有新的喜好随时告诉我我会乖乖记下来的(≧∇≦) 第一轮保存偏好第二轮用短记忆回答当前会话问题第三轮换 thread_id 后仍然能通过 user_id 查到长期偏好。到这里长记忆也跑通了。接下来就可以把短记忆和长记忆组合成一个更接近真实业务的客服系统。五、组合短记忆和长记忆做一个完整客服系统真实业务里我们通常不会只选一种记忆。当前会话里的追问、上下文、工具执行状态交给 Checkpointer用户身份、偏好、等级、长期配置交给 Store。下面这个例子里PostgresSaver 负责短记忆PostgresStore 负责长记忆。import os import uuid from urllib.parse import quote_plus from langchain.agents import create_agent from langchain_core.runnables import RunnableConfig from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.checkpoint.postgres import PostgresSaver from langgraph.store.postgres import PostgresStore if not os.getenv(DASHSCOPE_API_KEY): raise ValueError(请先配置环境变量) # 配置 PostgreSQL 数据库连接 pg_user os.getenv(PGUSER, postgres) pg_password quote_plus(os.getenv(PGPASSWORD, postgres)) pg_host os.getenv(PGHOST, 111111) pg_port os.getenv(PGPORT, 5432) pg_database os.getenv(PGDATABASE, langchain_db) DB_URI fpostgresql://{pg_user}:{pg_password}{pg_host}:{pg_port}/{pg_database} with PostgresSaver.from_conn_string(DB_URI) as checkpointer: checkpointer.setup() with PostgresStore.from_conn_string(DB_URI) as store: store.setup() model ChatOpenAI( modelqwen3.5-plus, api_keyos.getenv(DASHSCOPE_API_KEY), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, temperature0.3 ) # 保存 tool def save_user_info(key: str, value: str, config: RunnableConfig) - str: 保存用户的信息到长记忆 user_id config[configurable][user_id] # 创建命名空间 namespace (user_preferences, user_id) item_id str(uuid.uuid4()) store.put(namespace, item_id, {key: key, value: value}) return f已保存用户信息 {key}: {value} # 读取 tool def get_user_info(config: RunnableConfig) - str: 从长记忆获取用户所有的信息 user_id config[configurable][user_id] namespace (user_preferences, user_id) items store.search(namespace) preferences [] for item in items: key item.value.get(key, 未知) value item.value.get(value, 未知) preferences.append(f{key}: {value}) return \n.join(preferences) if preferences else 没有找到用户信息 agent create_agent( modelmodel, tools[save_user_info, get_user_info], system_prompt 你是一个客服助手 当用户提到个人信息时用 save_user_info 保存 当用户询问个人信息时用 get_user_info 查询。 , # 短记忆 checkpointercheckpointer, # 长记忆 storestore ) # 使用 同一个 会话id thread_id config {configurable: {user_id: user_002, thread_id: session_123}} config2 {configurable: {user_id: user_002, thread_id: session_1234}} response1 agent.invoke( {messages: [(user, 我是小王同学我是 VIP 用户我喜欢 详细的产品说明)]}, configconfig ) print(助手, response1[messages][-1].content) response2 agent.invoke( {messages: [(user, 我刚刚说了什么)]}, configconfig ) print(助手, response2[messages][-1].content) response3 agent.invoke( {messages: [(user, 我是谁我喜欢什么)]}, configconfig2 ) print(助手, response3[messages][-1].content)这个完整例子应该怎么看第一轮用户提供身份和偏好Agent 调用 save_user_info 写入长记忆。第二轮同一个 thread_idAgent 通过短记忆知道用户刚刚说了什么。第三轮换了新的 thread_id但 user_id 没变Agent 通过长记忆知道用户是 VIP并且喜欢详细说明。实操结果重点展示同一会话的短记忆以及新会话下仍然生效的长记忆。六、最后再把整篇文章串起来如果只看代码很容易把 Checkpointer、Store、thread_id、user_id 混在一起。其实它们解决的是两类不同问题。Checkpointer 解决的是“当前会话怎么不断片”。它把某个 thread_id 下的对话状态保存起来让 Agent 在同一段会话里能接着聊。Store 解决的是“用户长期信息怎么保留”。它把某个 user_id 下的偏好、身份、配置保存起来让 Agent 即使换了新会话也能知道这个用户是谁。所以做 Agent 记忆系统时可以按这个顺序思考只是本地测试短记忆用 InMemorySaver。生产环境保存短记忆用 PostgresSaver。需要跨会话保存用户信息用 Store。需要完整业务系统PostgresSaver PostgresStore 一起用。短记忆回答“刚刚聊了什么”长记忆回答“这个用户长期是谁”。理解了这句话LangGraph 1.x 的记忆存储就不再是几个零散 API而是一套很清晰的工程分层。
LangGraph 1.x 记忆存储实战:为什么 Agent 需要短记忆和长记忆?
很多人第一次写 Agent都会遇到一个很典型的问题在当前对话里我刚告诉它“我叫小王喜欢编程”下一轮再问“我是谁”它应该能接着回答但如果我换一个新的会话线程再问同样的问题它还能不能记得我这里其实对应两种不同的记忆需求。一种是短记忆强调的是“当前会话”。只要还在同一个 thread_id 里Agent 就应该能记住前几轮聊过什么。另一种是长记忆强调的是“账号维度”。只要还是同一个 user_id哪怕切换了多个线程、开启了新的会话Agent 仍然应该记得这个用户的长期信息比如姓名、身份、偏好等。所以本文围绕一个问题展开如何分别用短记忆解决当前会话上下文问题再用长记忆解决同一账号下跨线程记忆的问题。一、为什么要分短记忆和长记忆先想一个客服场景。用户进入客服系统后说我是小王同学我是 VIP 用户我喜欢详细一点的产品说明。接下来可能发生两类问题。第一类当前会话里的上下文问题用户刚说完这句话下一轮问我刚刚说了什么这个问题只和“当前这段对话”有关。只要 Agent 能拿到前几轮消息它就能回答。这就是短记忆要解决的问题。短记忆的关键词是 thread_id。相同 thread_id 表示同一段对话Agent 可以继续读取这段对话的历史换一个 thread_id就像重新开了一个新窗口。第二类跨会话的用户信息问题过了几天用户重新打开客服系统开启了一个新的会话然后问你还记得我是谁吗我喜欢什么样的说明这个问题已经不只是当前会话上下文了因为新的会话里并没有之前那句话。Agent 想回答出来就必须从长期存储里查询这个用户的信息。这就是长记忆要解决的问题。长记忆的关键词是 user_id。只要 user_id 不变即使 thread_id 变了Agent 也可以查到这个用户长期保存的信息。短记忆让对话连贯长记忆让用户关系持续。理解了这一点后面的代码就很好看了我们先用 Checkpointer 解决“当前会话记不住”的问题再用 Store 解决“换个会话就忘了用户”的问题最后把两者组合起来。二、先用 InMemorySaver 做最简单的短记忆先看最小版本让 Agent 在同一个会话里记住用户刚刚说过的话。这里用 InMemorySaver它把状态存在内存里适合本地测试。这段代码到底做了什么InMemorySaver 创建了一个短记忆存储。create_agent 通过 checkpointer 读取和写入当前会话状态。两次 invoke 使用同一个 thread_id所以第二次能读到第一次的对话历史。如果换一个 thread_idAgent 就会把它当成新的会话。实操结果第一次告诉 Agent 用户信息第二次询问“我是谁”Agent 能根据同一个 thread_id 回答出来。到这里我们解决了第一个问题同一段会话里Agent 不再健忘。三、为什么生产环境要换成 PostgresSaverInMemorySaver 很适合学习但它有一个明显限制进程一重启内存里的会话状态就没了。如果这是一个真实客服系统就会出现问题服务重启后用户刚刚聊到一半的上下文全部丢失多台服务同时部署时不同实例之间也无法共享会话状态。所以生产环境更推荐 PostgresSaver。它还是短记忆解决的仍然是 thread_id 对应的当前会话状态只是把状态持久化到了 PostgreSQL。先启动 PostgreSQLdocker run -d \--name postgres \-p 5432:5432 \-e POSTGRES_USERpostgres \-e POSTGRES_PASSWORDpostgres \-e POSTGRES_DBlangchain_db \-e POSTGRES_HOST_AUTH_METHODtrust \-v postgres_data:/var/lib/postgresql/data \postgres:15运行下面这段代码需要安装的依赖pip install langgraph-checkpoint-postgres psycopg[binary,pool] langchain-openai langchain用 PostgresSaver 保存短记忆import os import sys from urllib.parse import quote_plus from langchain.agents import create_agent from langchain_openai import ChatOpenAI from langgraph.checkpoint.postgres import PostgresSaver if hasattr(sys.stdout, reconfigure): sys.stdout.reconfigure(encodingutf-8) # 验证 环境变量 api_key os.getenv(DASHSCOPE_API_KEY) if not api_key: raise ValueError(请先配置环境变量 DASHSCOPE_API_KEY) # 配置 PostgreSQL 数据库连接 pg_user os.getenv(PGUSER, postgres) pg_password quote_plus(os.getenv(PGPASSWORD, postgres)) pg_host os.getenv(PGHOST, 111111) pg_port os.getenv(PGPORT, 5432) pg_database os.getenv(PGDATABASE, langchain_db) DB_URI fpostgresql://{pg_user}:{pg_password}{pg_host}:{pg_port}/{pg_database} # 初始化 PostgreSQL 检查点 with PostgresSaver.from_conn_string(DB_URI) as checkpointer: #自动创建 PostgreSQL 表结构 checkpointer.setup() model ChatOpenAI( modelqwen3.5-plus, api_keyapi_key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, temperature0.3 ) agent create_agent( modelmodel, tools[], system_prompt 你是一个乐于助人的助手 , checkpointercheckpointer ) # 使用 同一个 会话id thread_id config {configurable: {thread_id: user_123}} config2 {configurable: {thread_id: user_1234}} response1 agent.invoke( {messages: [(user, 我是小王同学喜欢编程)]}, configconfig ) print(助手, response1[messages][-1].content) response2 agent.invoke( {messages: [(user, 我刚刚说了什么)]}, configconfig ) print(助手, response2[messages][-1].content) response3 agent.invoke( {messages: [(user, 我是谁我喜欢什么)]}, configconfig2 ) print(助手, response3[messages][-1].content)这里要观察什么response1 和 response2 使用同一个 thread_id所以第二轮能记住第一轮。response3 换了新的 thread_id所以它不知道前面 user_123 会话里的内容。这说明 PostgresSaver 解决的是“短记忆持久化”不是“跨会话用户画像”。实操结果:预期输出:PostgresSaver 初始化成功 第一轮对话 助手 你好呀小王同学 很高兴认识你等等 第二轮对话相同 thread_id模型应记住用户助手 你刚刚介绍说“我是小王同学喜欢编程”。等等 第三轮对话新 thread_id模型会忘记之前的内容助手 您好很高兴见到您。说实话作为一个 AI 助手我目前还不知道您是谁也不了解您的具体喜好。因为我们的对话刚刚开始我还没有机会认识您也无法访问您的个人信息。pg中存储的数据:同一个 thread_id 能接上上下文新的 thread_id 会变成全新会话。到这里我们已经把短记忆从内存版本升级到了生产可用版本。但还有一个问题没解决新会话里Agent 仍然不知道这个用户长期是谁。四、用 Store 解决长记忆问题接下来解决第二个问题用户换了一个新会话Agent 还能不能知道他的偏好这时就不能只依赖 thread_id 了。因为新会话的 thread_id 已经变了短记忆里没有之前的上下文。我们需要把用户长期信息按照 user_id 存起来。这就是 Store 的作用。它可以保存用户偏好、身份、配置等长期信息后续任何会话都可以通过 user_id 查询。Store 的实现类型InMemoryStore开发测试数据存储在内存中进程重启后丢失PostgresStore生产环境推荐基于 PostgreSQL 持久化存储运行下面这段代码需要安装的依赖:pip install langchain1.0.3 langgraph1.0.2 langgraph-checkpoint-postgres3.0.5 psycopg3.3.3 langchain-openai1.1.12 langchain-core1.2.26 langchain-classic1.0.3 langchain-community0.3.29 langgraph-checkpoint3.0.1 langgraph-prebuilt1.0.2 langgraph-sdk0.2.15 psycopg-pool3.3.0 psycopg-binary3.3.3# 验证 环境变量 import os import sys import uuid from urllib.parse import quote_plus from langchain.agents import create_agent from langchain_core.runnables import RunnableConfig from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import InMemorySaver from langgraph.store.postgres import PostgresStore if hasattr(sys.stdout, reconfigure): sys.stdout.reconfigure(encodingutf-8) api_key os.getenv(DASHSCOPE_API_KEY) if not api_key: raise ValueError(请先配置环境变量 DASHSCOPE_API_KEY) # 配置 PostgreSQL 数据库连接 pg_user os.getenv(PGUSER, postgres) pg_password quote_plus(os.getenv(PGPASSWORD, postgres)) pg_host os.getenv(PGHOST, 111111) pg_port os.getenv(PGPORT, 5432) pg_database os.getenv(PGDATABASE, langchain_db) DB_URI fpostgresql://{pg_user}:{pg_password}{pg_host}:{pg_port}/{pg_database} # 初始化 PostgreSQL 检查点 with PostgresStore.from_conn_string(DB_URI) as store: #自动创建 PostgreSQL 表结构 store.setup() # 定义工具 # 保存 tool def save_user_preference(key: str, value: str,config: RunnableConfig) - str: 保存用户的偏好到长记忆 user_id config[configurable][user_id] #创建命名空间 namespace (user_preferences, user_id) item_idstr(uuid.uuid4()) store.put(namespace, item_id, {key: key, value: value}) return f已保存用户偏好 {key}: {value} # 读取 tool def get_all_user_preferences(config: RunnableConfig) - str: 获取用户所有的偏好设置 user_id config[configurable][user_id] namespace (user_preferences, user_id) items store.search(namespace) preferences [] for item in items: key item.value.get(key,未知) value item.value.get(value, 未知) preferences.append(f{key}: {value}) return \n.join(preferences) if preferences else 没有找到偏好设置 model ChatOpenAI( modelqwen3.5-plus, api_keyapi_key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, temperature0.3 ) checkpointer InMemorySaver() agent create_agent( modelmodel, tools[save_user_preference,get_all_user_preferences], system_prompt 你是一个乐于助人的助手 可以使用工具 保存和查询用户的 偏好 , #短记忆 checkpointercheckpointer, #长记忆 storestore ) # 使用 同一个 会话id thread_id config {configurable: {user_id:user_001,thread_id: user_123}} config2 {configurable: {user_id:user_001,thread_id: user_1234}} response1 agent.invoke( {messages: [(user, 我是小王同学喜欢可爱的回答请帮我记住这个偏好)]}, configconfig ) print(助手, response1[messages][-1].content) response2 agent.invoke( {messages: [(user, 我刚刚说了什么)]}, configconfig ) print(助手, response2[messages][-1].content) response3 agent.invoke( {messages: [(user, 我是谁我有什么偏好)]}, configconfig2 ) print(助手, response3[messages][-1].content)这段代码怎么实现长记忆save_user_preference 是写入工具负责把用户偏好保存到 Store。get_all_user_preferences 是读取工具负责从 Store 查询用户偏好。namespace (user_preferences, user_id) 用来把不同用户的数据隔离开。config 和 config2 的 thread_id 不同但 user_id 相同所以新会话依然能查到同一个用户的长期偏好。实操结果预期输出 第一轮对话保存用户偏好 助手 小王同学刚刚说「我是小王同学喜欢可爱的回答请帮我记住这个偏好」呀(◍•ᴗ•◍)我已经乖乖记好啦你的名字和喜欢可爱风格的小愿望都存进我的小心心数据库了哦✨ 以后每次和你聊天我都会用软萌软萌的语气陪你哒(๑ᴗ๑) 新会话不同 thread_id助手 你好呀小王同学✨ 你就是那个喜欢可爱风格回答的小可爱哦根据你的偏好设置我知道你喜欢我用可爱的语气和你聊天呢 (•̀ᴗ-)✧目前我记住的关于你的小秘密有你的名字小王同学喜欢的回答风格可爱的回答如果以后你有新的喜好随时告诉我我会乖乖记下来的(≧∇≦) 第一轮保存偏好第二轮用短记忆回答当前会话问题第三轮换 thread_id 后仍然能通过 user_id 查到长期偏好。到这里长记忆也跑通了。接下来就可以把短记忆和长记忆组合成一个更接近真实业务的客服系统。五、组合短记忆和长记忆做一个完整客服系统真实业务里我们通常不会只选一种记忆。当前会话里的追问、上下文、工具执行状态交给 Checkpointer用户身份、偏好、等级、长期配置交给 Store。下面这个例子里PostgresSaver 负责短记忆PostgresStore 负责长记忆。import os import uuid from urllib.parse import quote_plus from langchain.agents import create_agent from langchain_core.runnables import RunnableConfig from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.checkpoint.postgres import PostgresSaver from langgraph.store.postgres import PostgresStore if not os.getenv(DASHSCOPE_API_KEY): raise ValueError(请先配置环境变量) # 配置 PostgreSQL 数据库连接 pg_user os.getenv(PGUSER, postgres) pg_password quote_plus(os.getenv(PGPASSWORD, postgres)) pg_host os.getenv(PGHOST, 111111) pg_port os.getenv(PGPORT, 5432) pg_database os.getenv(PGDATABASE, langchain_db) DB_URI fpostgresql://{pg_user}:{pg_password}{pg_host}:{pg_port}/{pg_database} with PostgresSaver.from_conn_string(DB_URI) as checkpointer: checkpointer.setup() with PostgresStore.from_conn_string(DB_URI) as store: store.setup() model ChatOpenAI( modelqwen3.5-plus, api_keyos.getenv(DASHSCOPE_API_KEY), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, temperature0.3 ) # 保存 tool def save_user_info(key: str, value: str, config: RunnableConfig) - str: 保存用户的信息到长记忆 user_id config[configurable][user_id] # 创建命名空间 namespace (user_preferences, user_id) item_id str(uuid.uuid4()) store.put(namespace, item_id, {key: key, value: value}) return f已保存用户信息 {key}: {value} # 读取 tool def get_user_info(config: RunnableConfig) - str: 从长记忆获取用户所有的信息 user_id config[configurable][user_id] namespace (user_preferences, user_id) items store.search(namespace) preferences [] for item in items: key item.value.get(key, 未知) value item.value.get(value, 未知) preferences.append(f{key}: {value}) return \n.join(preferences) if preferences else 没有找到用户信息 agent create_agent( modelmodel, tools[save_user_info, get_user_info], system_prompt 你是一个客服助手 当用户提到个人信息时用 save_user_info 保存 当用户询问个人信息时用 get_user_info 查询。 , # 短记忆 checkpointercheckpointer, # 长记忆 storestore ) # 使用 同一个 会话id thread_id config {configurable: {user_id: user_002, thread_id: session_123}} config2 {configurable: {user_id: user_002, thread_id: session_1234}} response1 agent.invoke( {messages: [(user, 我是小王同学我是 VIP 用户我喜欢 详细的产品说明)]}, configconfig ) print(助手, response1[messages][-1].content) response2 agent.invoke( {messages: [(user, 我刚刚说了什么)]}, configconfig ) print(助手, response2[messages][-1].content) response3 agent.invoke( {messages: [(user, 我是谁我喜欢什么)]}, configconfig2 ) print(助手, response3[messages][-1].content)这个完整例子应该怎么看第一轮用户提供身份和偏好Agent 调用 save_user_info 写入长记忆。第二轮同一个 thread_idAgent 通过短记忆知道用户刚刚说了什么。第三轮换了新的 thread_id但 user_id 没变Agent 通过长记忆知道用户是 VIP并且喜欢详细说明。实操结果重点展示同一会话的短记忆以及新会话下仍然生效的长记忆。六、最后再把整篇文章串起来如果只看代码很容易把 Checkpointer、Store、thread_id、user_id 混在一起。其实它们解决的是两类不同问题。Checkpointer 解决的是“当前会话怎么不断片”。它把某个 thread_id 下的对话状态保存起来让 Agent 在同一段会话里能接着聊。Store 解决的是“用户长期信息怎么保留”。它把某个 user_id 下的偏好、身份、配置保存起来让 Agent 即使换了新会话也能知道这个用户是谁。所以做 Agent 记忆系统时可以按这个顺序思考只是本地测试短记忆用 InMemorySaver。生产环境保存短记忆用 PostgresSaver。需要跨会话保存用户信息用 Store。需要完整业务系统PostgresSaver PostgresStore 一起用。短记忆回答“刚刚聊了什么”长记忆回答“这个用户长期是谁”。理解了这句话LangGraph 1.x 的记忆存储就不再是几个零散 API而是一套很清晰的工程分层。