
补齐短板长期记忆的智能判断逻辑在面试中你需要展示你不仅知道“长期记忆和短期记忆的区别”还要知道“如何设计一个系统让 Agent 自动决定该记住什么该遗忘什么”。下面是一个完整的设计方案和代码实现涵盖了三层过滤机制语义分类 → 重要性评分 → 摘要压缩。 设计目标长期记忆存储对用户有长期价值的信息如姓名、喜好、职业、重要计划。短期记忆存储当前会话的上下文用于多轮对话。自动决策每次收到用户消息后系统自动判断该消息是否值得存入长期记忆。️ 架构与流程用户输入 ↓ ① 语义分类意图识别 ├── 个人信息姓名、年龄、职业→ 高优先级 ├── 偏好设置喜欢什么、讨厌什么→ 高优先级 ├── 重要事件计划、承诺→ 中优先级 └── 闲聊、问候、无关问题 → 低优先级 ↓ ② 重要性评分规则 小模型 - 计算实体数量人名、地名、日期 - 情感强度 - 是否包含“记住”、“以后”等关键词 - 综合得分 0~1 ↓ ③ 决定是否存储 - 如果得分 阈值如 0.6→ 存入长期记忆向量库 - 否则 → 只保留在短期记忆中会话窗口 ↓ ④ 定期摘要压缩每周/每月 - 对长期记忆中的相似内容合并 - 对旧的短期记忆做摘要提炼关键信息存入长期记忆 代码实现LangChain 简单规则以下是一个完整的MemoryManager类它实现了上述三层逻辑。importrefromtypingimportList,Dict,Anyfromlangchain.embeddingsimportOpenAIEmbeddingsfromlangchain.vectorstoresimportChromafromlangchain.llmsimportOpenAIfromlangchain.chainsimportLLMChainfromlangchain.promptsimportPromptTemplatefromlangchain.schemaimportDocumentimportnumpyasnpclassMemoryManager:def__init__(self,llm,embeddings,vectorstore):self.llmllm self.embeddingsembeddings self.vectorstorevectorstore self.conversation_history[]# 短期记忆会话内self.long_term_memory[]# 长期记忆文档列表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_infoifany(kwintext_lowerforkwin[喜欢,讨厌,爱好,偏好]):returnpreferenceifany(kwintext_lowerforkwin[计划,打算,约定,承诺,以后]):returnimportant_eventifany(kwintext_lowerforkwin[今天天气,你好,谢谢]):returnchitchatreturnunknowndef_compute_importance_score(self,text:str,intent:str)-float:② 计算重要性得分0~1score0.0# 基于意图的基础分intent_score_map{personal_info:0.9,preference:0.8,important_event:0.7,chitchat:0.2,unknown:0.3}scoreintent_score_map.get(intent,0.3)# 实体数量加分人名、地名、日期entity_countlen(re.findall(r[\u4e00-\u9fa5]{2,4},text))# 简单中文名字/地点ifentity_count2:score0.1# 包含“记住”、“以后”等词加分ifany(kwintextforkwin[记住,以后,一定,务必]):score0.1# 长度加分较长的消息可能包含更多信息iflen(text)20:score0.05# 情感强度简单规则包含“很”、“非常”、“特别”ifany(kwintextforkwin[很,非常,特别,超级]):score0.05returnmin(score,1.0)def_needs_long_term_storage(self,text:str)-bool:③ 综合判断是否存入长期记忆intentself._classify_intent(text)scoreself._compute_importance_score(text,intent)print(f[评估] 消息: {text[:30]}... 意图:{intent}, 得分:{score:.2f})returnscoreself.importance_thresholddefadd_message(self,role:str,content:str):处理一条新消息来自用户或AI# 先存入短期记忆不管是否重要self.conversation_history.append({role:role,content:content})# 只对用户消息做长期存储判断ifroleuser:ifself._needs_long_term_storage(content):# 存入长期记忆向量库docDocument(page_contentcontent,metadata{source:user,timestamp:now})self.vectorstore.add_documents([doc])self.long_term_memory.append(content)print(f[长期记忆] 已存储:{content})defget_conversation_context(self,max_turns5):获取短期记忆最近N轮returnself.conversation_history[-max_turns*2:]defget_long_term_memories(self,query:str,k3):从长期记忆中检索相关内容RAGdocsself.vectorstore.similarity_search(query,kk)return[doc.page_contentfordocindocs]defsummarize_long_term_memories(self):④ 摘要压缩定期对长期记忆做合并和压缩# 如果长期记忆条目超过50条触发摘要iflen(self.long_term_memory)50:promptPromptTemplate.from_template(以下是用户的所有长期记忆条目请将它们合并成一份简洁的摘要保留关键个人信息和事件\n{memories}\n\n摘要)chainLLMChain(llmself.llm,promptprompt)summarychain.run(memories\n.join(self.long_term_memory))# 清空旧记忆存入摘要实际生产可保留部分最新self.vectorstore.delete_collection()new_docDocument(page_contentsummary,metadata{type:summary})self.vectorstore.add_documents([new_doc])self.long_term_memory[summary]print(f[摘要] 长期记忆已压缩为{summary[:100]}...) 测试示例fromlangchain_openaiimportChatOpenAI,OpenAIEmbeddingsfromlangchain.vectorstoresimportChroma# 初始化组件llmChatOpenAI(modelgpt-3.5-turbo,temperature0)embeddingsOpenAIEmbeddings()vectorstoreChroma(collection_namelong_term_memory,embedding_functionembeddings)# 创建记忆管理器mem_managerMemoryManager(llm,embeddings,vectorstore)# 模拟对话user_inputs[你好我叫张三是一名软件工程师。,我今天心情不错。,我喜欢打篮球和看电影。,北京今天天气怎么样,我计划下个月去日本旅游。,谢谢你的帮助。,]formsginuser_inputs:mem_manager.add_message(user,msg)print(---)# 查询长期记忆query我的职业是什么resultsmem_manager.get_long_term_memories(query,k2)print(f查询结果:{results})# 获取短期上下文contextmem_manager.get_conversation_context(max_turns3)print(f最近对话:{context})输出示例可能因模型和阈值不同而略有差异[评估] 消息: 你好我叫张三是一名软件工程师。... 意图: personal_info, 得分: 0.95 [长期记忆] 已存储: 你好我叫张三是一名软件工程师。 --- [评估] 消息: 我今天心情不错。... 意图: chitchat, 得分: 0.25 --- [评估] 消息: 我喜欢打篮球和看电影。... 意图: preference, 得分: 0.85 [长期记忆] 已存储: 我喜欢打篮球和看电影。 --- ... 查询结果: [你好我叫张三是一名软件工程师。, 我喜欢打篮球和看电影。]️ 面试回答话术“在设计长期记忆系统时我采用了三层判断逻辑语义分类我预先定义了一组规则或小模型将用户输入分为个人信息、偏好、重要事件、闲聊等类别。个人信息如姓名、职业和偏好会被标记为高优先级。重要性评分对于每一条用户消息我会计算一个综合得分考量因素包括是否包含姓名/地点等实体、是否包含承诺性词汇如‘以后’、‘一定’、消息长度、情感强度等。得分超过阈值如0.6才会被存入长期记忆。摘要压缩为了防止长期记忆无限膨胀我会定期对存储的内容进行摘要合并。当条目过多时使用LLM将多条记忆压缩成一段概述既保留关键信息又节省存储空间。这套方案结合了规则引擎的快速性和LLM的语义理解能力在实际项目中取得了不错的效果。当然如果资源允许我会用一个小型的分类器模型如BERT替换规则进一步提升判断精度。”MD5 组件哈希世界的“老牌主力”1. MD5 是什么MD5Message Digest Algorithm 5消息摘要算法第五版是一种广泛使用的密码学哈希函数由 Ronald Rivest 于 1991 年设计。它接收任意长度的输入输出一个128 位16 字节的固定长度哈希值通常表示为 32 位的十六进制字符串例如d41d8cd98f00b204e9800998ecf8427e。在 Python 中MD5 通过内置的hashlib模块提供importhashlib md5hashlib.md5()md5.update(bhello world)print(md5.hexdigest())# 输出: 5eb63bbbe01eeed093cb22bb8f5acdc32. MD5 的核心特性特性说明固定长度无论输入多大输出始终是 128 位16 字节。单向性无法从哈希值反推出原始输入理论上。雪崩效应输入微小变化会导致输出巨大变化。快速计算计算速度快适合大量数据。碰撞风险已被证明存在理论碰撞两个不同输入产生相同哈希不适用于安全场景。3. MD5 在 LLM/RAG 项目中的典型应用结合你的经历在你之前的 Excel 比较智能体代码中hashlib.md5被用来生成文件的版本指纹以判断两次上传的内容是否发生变化content_hashhashlib.md5(json.dumps(all_sheets).encode()).hexdigest()为什么要这样做避免重复处理相同内容的文件去重。快速判断文件是否被修改无需逐行比较整个文件。作为缓存键例如如果哈希没变直接从缓存返回结果。除此之外MD5 在 RAG 系统中还有这些常见用途场景说明文本块去重对切分后的 Chunk 生成哈希在入库前检查是否已存在避免重复向量化。缓存键生成将用户 Query 的 MD5 作为缓存键相同问题直接返回缓存答案降低 LLM 调用成本。数据完整性校验确保传输的文档如上传的 PDF未被篡改。版本跟踪对知识库的增量更新时只更新发生变化的片段通过比对哈希。4. MD5 的安全隐患面试重点重要结论MD5 已不再安全不应在安全敏感场景中使用如密码存储、数字证书。碰撞攻击2004 年研究人员已发现 MD5 的碰撞方法两个不同文件可生成相同哈希。2010 年进一步改进普通 PC 也能快速制造碰撞。破解速度如今 GPU 可在数秒内破解短密码的 MD5 哈希。替代方案场景推荐算法密码存储使用bcrypt、PBKDF2、Argon2加盐、迭代文件完整性校验使用SHA-256或SHA-3去重/缓存键仍可用 MD5非安全场景追求速度5. 面试高频追问与回答Q1MD5 和 SHA-256 有什么区别对比维度MD5SHA-256输出长度128 位256 位安全性低已被攻破高至今无有效碰撞速度极快较慢但现代硬件可接受适用场景非安全去重、缓存安全场景数字签名、文件校验Q2既然 MD5 不安全为什么还在用A因为它的速度优势在非安全场景中依然显著例如去重、缓存、版本检测这些场景不需要防御恶意碰撞。但如果是涉及用户隐私或防篡改的场景必须弃用。Q3在 LangChain/RAG 系统中你如何用 MD5 优化性能A我会对文档块Chunk生成 MD5 哈希作为文档 ID存入向量库时检查 ID 是否存在实现增量更新。另外对高频 Query 做 MD5 缓存键减少 LLM 调用成本但需配合时效性设计如 TTL。Q4如何应对 MD5 的碰撞问题A在安全场景我使用 SHA-256 或 SHA-3。在非安全场景如去重碰撞概率极低2^128且即使发生也无大碍因此可以接受。6. 实战代码示例结合 LangChainimporthashlibfromlangchain.schemaimportDocumentdefget_document_id(doc:Document)-str:使用 MD5 生成文档唯一 ID基于内容元数据contentdoc.page_content meta_strstr(sorted(doc.metadata.items()))combinedcontentmeta_strreturnhashlib.md5(combined.encode(utf-8)).hexdigest()# 使用示例docDocument(page_contenthello world,metadata{source:test.txt})doc_idget_document_id(doc)print(f文档 ID:{doc_id})7. 总结话术面试收尾“MD5 是一个经典的哈希算法虽然因为碰撞问题不再适合安全场景但它在去重、缓存和版本控制等性能敏感场景中依然有巨大价值。在实际项目中我会区分用途用 MD5 做快速指纹生成用 SHA-256 做数据完整性校验用 bcrypt 做密码存储。理解每个算法的强弱是工程选型的基本功。”