大模型:langgraph 如何实现长期存储
在 LangGraph 中长期记忆是通过Store接口实现的。它与管理单次会话线程的短期记忆Checkpointer是互补的两种持久化机制。简单来说Checkpointer像是一个会话的“书签”帮你记住当前对话进行到哪了而Store则像一个跨会话的“笔记本”用来记录用户的偏好、个人信息等需要长期保留的知识。 短期记忆 vs. 长期记忆特性短期记忆 (Short-term Memory)长期记忆 (Long-term Memory)作用范围单个会话线程内跨会话、跨线程核心组件Checkpointer(如MemorySaver,PostgresSaver)Store(如InMemoryStore,PostgresStore)存储内容图的状态 (State)、对话历史用户画像、偏好、事实知识等 JSON 文档生命周期线程结束或手动清除持久化可长期保留典型用途维护当前对话的上下文在多轮对话中记住用户信息⚙️ 核心组件Store接口Store是一个简单的、基于命名空间的键值存储其核心设计如下存储模型记忆以JSON 文档的形式存储。组织方式通过namespace命名空间和key键来组织。namespace是一个元组用于逻辑分组例如(memories, user_id)方便隔离不同用户或应用的数据。核心操作Store接口支持put写入、get读取和search搜索等基本操作。存储后端LangGraph 提供了多种Store实现InMemoryStore数据存储在内存中进程重启后丢失适合开发和测试。PostgresStore使用 PostgreSQL 作为持久化后端适合生产环境。 如何在 LangGraph 中实现长期记忆1. 初始化Store实例首先你需要创建一个Store实例。在测试时可以使用InMemoryStore。fromlanggraph.store.memoryimportInMemoryStore# 创建一个内存存储实例用于开发和测试storeInMemoryStore()2. 将Store注入 Agent创建 Agent 时通过store参数将存储实例传入。fromlangchain.agentsimportcreate_agentfromlangchain_core.runnablesimportRunnable# ... (初始化模型、工具等)# 将 store 注入 agentagent:Runnablecreate_agent(modelyour-model,tools[...],storestore,# 关键注入 store 实例)3. 在工具中读写记忆这是长期记忆发挥作用的核心。在自定义工具中可以通过ToolRuntime访问store实例。写入记忆从上下文中获取user_id构建namespace然后使用store.put()保存信息。读取记忆同样在工具中通过store.get()读取特定键的记忆或使用store.search()进行搜索。 设计与最佳实践命名空间设计建议使用(user_id, context)的结构例如(user_id, preferences)或(user_id, interests)以便于管理和检索。记忆的写入时机可以由 Agent 主动调用工具写入或利用langmem等库提供的工具让模型自主决定何时写入记忆。关键在于设计清晰的 Prompt 和 Tool 描述引导模型正确使用。数据的演进长期记忆是动态的。可以设计工具来更新或删除已有的记忆保持信息的准确性和时效性。总而言之LangGraph 通过Store接口提供了一种灵活、可扩展的长期记忆方案让你可以根据应用场景自由定制记忆的存储、检索和管理逻辑。长期记忆的判断逻辑一个完整的工程方案面试官追问的核心是“你怎么区分‘值得记住’和‘不值得记住’的对话内容”这是一个非常关键的系统设计问题。你不需要真的在生产环境实现过完整的判断逻辑但需要展示出你对这个问题的深度思考和系统设计能力。下面是一个完整、可直接落地的三层判断方案包含清晰的代码示例和面试话术。 为什么这个问题这么重要面试官真正想考察的不是你用了什么存储技术而是你有没有思考过“记忆的价值”。如果把所有对话都往长期记忆里存会出现存储成本无限增长检索效率下降噪音太多模型生成时被大量无关信息干扰上下文污染因此设计一个“记忆过滤器”是长期记忆系统的核心工程决策。️ 完整的三层判断架构用户输入 ↓ ┌─────────────────────────────────────────────────┐ │ ① 语义分类意图识别 │ │ - 个人信息姓名、年龄、职业→ 高优先级 │ │ - 偏好设置喜欢什么、讨厌什么→ 高优先级 │ │ - 重要事件计划、承诺、约定→ 中优先级 │ │ - 闲聊、问候、无关问题 → 低优先级/不存 │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ ② 重要性评分规则 语义 │ │ 计算综合得分0~1超过阈值才存 │ │ 因子实体密度、情感强度、承诺性词汇、消息长度 │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ ③ 定期摘要压缩后台任务 │ │ - 每周对已存记忆做合并和压缩 │ │ - 保留关键信息丢弃冗余细节 │ │ - 防止长期记忆无限膨胀 │ └─────────────────────────────────────────────────┘ 完整代码实现importrefromtypingimportList,Dict,Any,Optionalfromlangchain_openaiimportChatOpenAIfromlangchain.promptsimportPromptTemplateclassLongTermMemoryFilter: 长期记忆智能判断过滤器 决定哪些用户输入应该存入长期记忆 def__init__(self,llm:Optional[ChatOpenAI]None):self.llmllm self.importance_threshold0.6# 存入长期记忆的阈值# 高优先级关键词个人信息、偏好self.high_priority_keywords[我叫,我的名字,我是,姓,名,喜欢,讨厌,爱好,偏好,最,生日,出生,年,岁,年龄,职业,工作,公司,职位,岗位]# 中优先级关键词计划、承诺self.medium_priority_keywords[计划,打算,准备,约,答应,承诺,一定要,必须,保证]def_classify_intent(self,text:str)-str:① 语义分类基于规则判断意图类型text_lowertext.lower()# 个人信息ifany(kwintext_lowerforkwin[我叫,我的名字,我是,姓]):returnpersonal_info# 偏好设置ifany(kwintext_lowerforkwin[喜欢,讨厌,爱好,偏好,最]):returnpreference# 重要事件/计划ifany(kwintext_lowerforkwin[计划,打算,答应,承诺]):returnimportant_event# 简单问候ifany(kwintext_lowerforkwin[你好,hi,hello,谢谢,感谢]):returngreetingreturnunknowndef_compute_importance_score(self,text:str,intent:str)-float:② 计算重要性得分0~1score0.0# 基础意图分intent_base_score{personal_info:0.85,preference:0.80,important_event:0.70,greeting:0.10,unknown:0.25}scoreintent_base_score.get(intent,0.25)# 实体密度加分出现人名、地名、时间entity_patterns[r[\u4e00-\u9fa5]{2,4},# 中文2-4字r\d{4}[-年]\d{1,2}[-月]\d{1,2},# 日期r[0-9][点分时]# 时间]entity_count0forpatterninentity_patterns:entity_countlen(re.findall(pattern,text))ifentity_count3:score0.15elifentity_count1:score0.08# 长度加分较长的消息包含更多信息iflen(text)30:score0.10eliflen(text)15:score0.05# 承诺性词汇加分ifany(kwintextforkwin[一定,务必,记住,以后,将来]):score0.10# 情感强度加分程度副词ifany(kwintextforkwin[非常,特别,很,超级,极其]):score0.05returnmin(score,1.0)defshould_store(self,text:str)-bool:③ 综合判断是否应该存入长期记忆intentself._classify_intent(text)scoreself._compute_importance_score(text,intent)print(f[评估] 消息: {text[:30]}... 意图:{intent}, 得分:{score:.2f})# 闲聊类直接忽略即使得分高也可能误判ifintentgreeting:returnFalsereturnscoreself.importance_thresholddefextract_key_facts(self,text:str)-dict:从消息中提取关键事实用于结构化存储facts{}# 提取姓名name_matchre.search(r[我姓|我叫|我是](\S{2,4}),text)ifname_match:facts[name]name_match.group(1)# 提取年龄age_matchre.search(r(\d{1,3})[岁],text)ifage_match:facts[age]int(age_match.group(1))# 提取偏好like_matchre.search(r喜欢(\S{2,6}),text)iflike_match:facts[likes]like_match.group(1)returnfacts# 使用示例 classMemoryManager:记忆管理器集成过滤逻辑def__init__(self):self.filterLongTermMemoryFilter()self.long_term_memory[]# 实际生产会用向量库defprocess_user_message(self,text:str)-dict:处理用户消息result{original:text,stored:False,intent:None,score:0.0,facts:{}}# 1. 判断是否存入ifself.filter.should_store(text):result[stored]Trueresult[intent]self.filter._classify_intent(text)result[score]self.filter._compute_importance_score(text,result[intent])result[facts]self.filter.extract_key_facts(text)# 存入长期记忆self.long_term_memory.append({content:text,facts:result[facts],score:result[score],intent:result[intent]})returnresultdefgenerate_summary(self)-str:生成记忆摘要iflen(self.long_term_memory)20:# 触发摘要压缩第四层# 实际可用LLM进行摘要pass# 测试 if__name____main__:managerMemoryManager()test_messages[你好我叫张三。,我是一名软件工程师在腾讯工作。,今天天气真好。,我喜欢打篮球和看电影。,谢谢你的帮助。,我计划下个月去日本旅游。,我会记住你说的话。]formsgintest_messages:resultmanager.process_user_message(msg)ifresult[stored]:print(f✅ 已存入:{msg}(得分:{result[score]:.2f}))else:print(f❌ 忽略:{msg})print(---)print(f\n 长期记忆共{len(manager.long_term_memory)}条:)foriteminmanager.long_term_memory:print(f -{item[content]}(事实:{item[facts]}))预期输出[评估] 消息: 你好我叫张三。... 意图: personal_info, 得分: 0.92 ✅ 已存入: 你好我叫张三。 (得分: 0.92) --- [评估] 消息: 我是一名软件工程师在腾讯工作。... 意图: personal_info, 得分: 0.90 ✅ 已存入: 我是一名软件工程师在腾讯工作。 (得分: 0.90) --- [评估] 消息: 今天天气真好。... 意图: greeting, 得分: 0.12 ❌ 忽略: 今天天气真好。 --- ... 面试话术完整版如果面试官问“你怎么判断哪些用户输入需要存长期记忆”“我会分层设计一个判断逻辑第一层是语义分类。我预先定义了几类值得存储的意图个人信息姓名、职业、偏好设置喜欢什么、重要事件计划、承诺。通过关键词规则或小模型做分类闲聊、问候类直接过滤掉。第二层是重要性评分。对每条消息计算综合得分考虑因子包括实体密度有没有出现人名、地名、时间、是否包含承诺性词汇、消息长度和情感强度。只有得分超过阈值才会存入长期记忆。第三层是定期摘要压缩。长期记忆不是无限的我会定期对存储的记忆做合并和摘要用 LLM 把多条记忆压缩成一段概述既保留关键信息又控制存储规模。当然这套方案可以根据业务需求调整——比如在客服场景可以额外识别‘投诉’、‘退换货’这类高优先级意图让系统自动记住用户的问题历史。”

相关新闻

CoRe-MoE:人形机器人多地形自适应步态认知框架

CoRe-MoE:人形机器人多地形自适应步态认知框架

1. 项目概述:这不是又一个“调参式”步态控制器,而是一套让机器人真正“理解地形”的认知框架“CoRe-MoE:基于对比学习的混合专家框架实现人形机器人多地形自适应步态”——这个标题里每一个词都不是装饰。我第一次在ICRA 2024 workshop上看到…

2026/7/7 5:58:13阅读更多 →
【3.13】FFT变换testbench的设计

【3.13】FFT变换testbench的设计

目录 1.引言 2.testbench编写 3.仿真初步测试 1.引言 我们通过12小节的学习之后,初步完成了FFT变换的FPGA设计,在本小节,我们将完成FFT变换的仿真测试功能。 2.testbench编写 我们编写如下的testbench程序: `timescale 1ns / 1ps //////////////////////////////////…

2026/7/7 5:53:13阅读更多 →
Gin 架构在区块链应用中的最佳实践

Gin 架构在区块链应用中的最佳实践

1. 引言 在区块链技术快速发展的今天,如何构建高性能、可维护且安全的去中心化应用(DApp)后端服务成为开发者面临的关键挑战。Gin 是一个用 Go 语言编写的高性能 Web 框架,以其简洁的 API、出色的路由性能和中间件生态而闻名。本文…

2026/7/7 5:53:13阅读更多 →
SDD vs Vibe Coding:AI 编程时代的“自由派“与“规范派“,如何兼得?

SDD vs Vibe Coding:AI 编程时代的“自由派“与“规范派“,如何兼得?

一、两种范式的碰撞2025年,AI编程工具全面爆发。Cursor、Claude Code、GitHub Copilot、Windsurf……开发者们从未如此"高产"——一个曾经需要两周的登录模块,现在两小时就能跑起来。但与此同时,另一种声音也开始出现:&…

2026/7/7 7:08:18阅读更多 →
Godot引擎入门:从节点场景到Hello World的完整开发流程

Godot引擎入门:从节点场景到Hello World的完整开发流程

1. 项目概述:为什么是“Hello World”?如果你已经跟着前两期内容,成功安装了 Godot 引擎,并且熟悉了它的编辑器界面,那么恭喜你,你已经跨过了最枯燥的“准备”阶段。现在,我们终于要开始动手创造…

2026/7/7 7:08:18阅读更多 →
小红书4K视频与长图文生态:AIGC内容生产工具的技术机会解析

小红书4K视频与长图文生态:AIGC内容生产工具的技术机会解析

问题定义与范围随着数字内容消费升级,小红书近期对4K超高清视频与长图文笔记的流量扶持策略,标志着平台内容生态正式迈入“高清化”与“深度化”并重的新阶段。这一战略转向不仅重塑了用户的内容消费预期,更对创作者的生产力提出了严峻挑战。…

2026/7/7 7:08:18阅读更多 →
LabelPlus漫画翻译工具终极指南:从零开始的高效汉化解决方案

LabelPlus漫画翻译工具终极指南:从零开始的高效汉化解决方案

LabelPlus漫画翻译工具终极指南:从零开始的高效汉化解决方案 【免费下载链接】LabelPlus Easy tool for comic translation. 项目地址: https://gitcode.com/gh_mirrors/la/LabelPlus 还在为漫画翻译的繁琐流程而烦恼吗?LabelPlus漫画翻译辅助工具…

2026/7/7 7:08:18阅读更多 →
运算放大器 PCB 布局 5 大误区解析:从原理图正确到板级失效的根因

运算放大器 PCB 布局 5 大误区解析:从原理图正确到板级失效的根因

运算放大器 PCB 布局 5 大误区解析:从原理图正确到板级失效的根因当硬件工程师完成一个完美的运算放大器原理图设计,却在PCB打样后发现电路性能远低于预期时,问题往往出在那些容易被忽视的布局细节上。本文将深入剖析五个最常见的PCB布局误区…

2026/7/7 7:08:18阅读更多 →
Java多线程入门(上):从零认识线程,三种创建方式与常用方法

Java多线程入门(上):从零认识线程,三种创建方式与常用方法

Java多线程入门(上):从零认识线程,三种创建方式与常用方法想象一下:每年春节,你和几百万人在12306上抢票。如果网站只有一个"工作人员"(单线程)在处理所有人的请求&#x…

2026/7/7 7:03:17阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/7 4:43:43阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/7 2:56:31阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/7 1:03:28阅读更多 →
Acunetix v24.8 深度解析:DAST漏洞扫描器核心原理与DevSecOps实践

Acunetix v24.8 深度解析:DAST漏洞扫描器核心原理与DevSecOps实践

1. 项目概述:Acunetix v24.8 高级版漏洞扫描器深度解析作为一名在网络安全领域摸爬滚打多年的老兵,我深知一款趁手的“兵器”对于安全测试工作意味着什么。今天要聊的,就是Web应用安全测试领域里一个响当当的名字——Acunetix。特别是其v24.8…

2026/7/7 0:02:41阅读更多 →
国产化信创改造:达梦/人大金仓适配与多数据库兼容方案实战(SpringBoot)

国产化信创改造:达梦/人大金仓适配与多数据库兼容方案实战(SpringBoot)

国产化信创改造:达梦/人大金仓适配与多数据库兼容方案实战(SpringBoot) 🌐 演示地址:http://ruoyioffice.com | 📦 源码1GitHub:ruoyi-office | 📦 源码2GitCode:ruoyi-o…

2026/7/7 0:02:41阅读更多 →
CentOS 7/8 SSH 连接失败:5步系统性排错流程与决策树

CentOS 7/8 SSH 连接失败:5步系统性排错流程与决策树

CentOS SSH连接故障排查:从基础检查到深度修复的完整指南引言当你尝试通过Xshell或其他SSH客户端连接CentOS服务器时,突然遭遇"Connection refused"或"Connection timed out"的错误提示,这种经历对任何运维人员或开发者来…

2026/7/7 0:02:41阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/7 5:11:21阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/7 5:11:21阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/7 5:11:21阅读更多 →