多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

基于向量数据库与LangChain构建AI记忆系统:从原理到工程实践

基于向量数据库与LangChain构建AI记忆系统:从原理到工程实践 1. 从“健忘”到“长情”为什么你的AI助手需要记忆系统最近在折腾AI助手的朋友可能都遇到过一种让人哭笑不得的尴尬你昨天刚跟它聊过你养的那只叫“元宝”的猫今天再问它“我的猫叫什么”它大概率会一脸茫然地反问你“您之前提到过您的宠物吗”。这种感觉就像你花了大把时间跟一个朋友掏心掏肺结果第二天见面他连你名字都忘了。没错这就是当前大多数AI模型尤其是基于大型语言模型LLM构建的聊天机器人或智能体Agent的普遍痛点——它们没有“记忆”。这个现象背后是LLM本身的工作机制决定的。你可以把LLM想象成一个知识渊博但患有严重瞬时失忆症的天才。它拥有海量的通用知识能对任何输入做出精彩绝伦的即时反应。然而它没有“自我”没有“经历”也没有“持续的意识流”。每一次对话对于模型来说都是一次全新的、独立的推理过程。模型只处理你当前输入的提示词Prompt和它内部预训练的参数而不会主动记住上一轮、上上一轮对话的内容除非你手动把这些历史对话内容作为新的提示词的一部分再次“喂”给它。这就引出了“记忆系统”的核心价值。它不是一个花哨的附加功能而是让AI从“一次性问答机”进化为“个性化伙伴”的关键桥梁。一个有效的记忆系统能够跨越单次对话的边界持续地、结构化地记录关于“你”的信息——你的偏好、习惯、说过的重要事情、未完成的任务等等。下次你再与它交互时系统会自动检索并注入这些记忆让AI的回应变得连贯、个性化和富有上下文。今天我们要深入探讨的就是围绕“OpenClaw”这个概念展开的记忆系统构建指南。OpenClaw并非某个具体的开源项目名称在撰写本文时没有广为人知的同名开源项目它更像是一个象征代表了“开源、可定制、能牢牢抓住Claw用户信息”的记忆系统架构理念。我们将完全从零开始拆解如何为你的AI应用构建一个健壮、高效且隐私友好的记忆系统让它不再健忘永远“记住”你。2. 记忆系统的核心架构从存储到检索的完整链条构建一个记忆系统远不止是找个数据库把对话记录存起来那么简单。它是一个涉及数据采集、处理、存储、检索和应用的完整工程体系。一个典型的记忆系统架构可以分为三层记忆的采集与生成层、记忆的存储与管理层、记忆的检索与应用层。2.1 记忆的采集与生成从原始对话到结构化知识记忆的源头是用户与AI的每一次交互。但直接存储原始对话文本是低效且笨拙的。想象一下你记日记如果只记流水账“今天说了A明天说了B”查找起来会非常困难。我们需要的是从对话中提取出结构化的“知识片段”。关键步骤一实时信息提取在对话进行中系统需要实时监听识别并提取出可能成为长期记忆的信息点。这些信息点通常包括实体信息人名、宠物名、项目名、地点、产品等。用户声明“我喜欢吃辣”、“我对花生过敏”、“我每周三晚上要健身”。待办事项与承诺“记得提醒我明天下午三点开会”、“帮我订下周五的机票”。情感与偏好用户在对话中流露出的对某事物积极或消极的态度。关键步骤二记忆的向量化与摘要生成提取出的原始文本需要转化为机器更易处理的形式。这里核心的技术是文本嵌入Embedding。通过嵌入模型如OpenAI的text-embedding-3-small或开源的BGE、SentenceTransformers系列模型我们将一段文本例如“用户的猫叫元宝是一只三岁的英短”转换成一个高维空间中的向量一组数字。这个向量包含了这段文本的语义信息语义相近的文本其向量在空间中的距离也更近。这为后续的相似性检索奠定了基础。同时对于较长的对话轮次或复杂描述可以调用LLM生成一个简洁的摘要Summary作为这段记忆的“标题”或“核心描述”便于管理和快速浏览。2.2 记忆的存储与管理数据库选型与组织策略存储层需要解决两个问题存什么以及怎么高效地存和取。存储内容结构每条记忆通常是一个结构化的JSON对象包含以下字段{ memory_id: uuid, user_id: user_123, content: 用户的猫叫元宝是一只三岁的英短。, embedding: [0.12, -0.45, 0.78, ...], // 向量数组 summary: 宠物猫信息元宝, metadata: { entity_type: pet, importance: 0.8, // 记忆重要性权重0-1 created_at: 2024-05-27T10:30:00Z, last_accessed_at: 2024-05-28T15:20:00Z, access_count: 5 }, source_dialogue_ids: [msg_001, msg_002] // 关联的原始消息ID }数据库选型向量数据库是标配传统的关系型数据库如MySQL、PostgreSQL擅长处理结构化查询但不擅长做基于语义的相似性搜索。这正是向量数据库Vector Database的用武之地。它们专门为存储和检索向量数据而优化能快速执行“近似最近邻搜索ANN”即找到与查询向量最相似的存储向量。Pinecone / Weaviate / Qdrant成熟的云原生向量数据库服务开箱即用API友好适合快速原型和中小规模生产。pgvectorPostgreSQL的扩展将向量搜索能力直接集成到成熟的PG生态中。优势是能与现有的用户数据、事务处理放在同一个数据库保证数据一致性管理也更简单。对于已经使用PostgreSQL的团队这是极具吸引力的选择。Chroma轻量级、嵌入式的向量数据库非常适合本地开发、测试和小型应用。实操心得在项目早期或数据量不大时使用pgvector可以极大简化技术栈。你不需要维护另一个数据库服务复杂的联表查询比如结合用户订单历史来增强记忆也会变得非常直接。只有当向量数据量达到亿级对检索速度和规模有极致要求时才需要考虑独立的向量数据库服务。2.3 记忆的检索与应用让记忆在对话中“复活”这是记忆系统价值最终体现的环节。当用户发起新对话时系统需要做以下工作查询向量化将用户当前的问题或陈述例如“我的猫最近有点掉毛”通过同样的嵌入模型转化为查询向量。向量相似性检索在向量数据库中以查询向量为基准搜索与该用户相关的、最相似的N条记忆向量。数据库会返回相似度分数如余弦相似度最高的几条记忆。记忆筛选与排序仅靠向量相似度可能不够。我们需要一个“记忆评分”函数来综合排序最终分数 相似度分数 * α 记忆重要性权重 * β 时间衰减因子(最近访问) * γ其中α, β, γ是可调参数。这确保了高重要性、最近被提及过的记忆有更高优先级。记忆注入提示词将筛选出的Top K条记忆以结构化的格式例如“以下是关于用户的已知信息1. 宠物猫叫元宝三岁英短。2. 用户对花生过敏。3. 用户偏好用Markdown格式接收报告。”插入到发送给LLM的最终提示词Prompt中。这通常放在系统指令System Message或用户消息的上下文部分。至此LLM在生成回复时就能“看到”这些关于你的背景信息从而做出有记忆的、个性化的回应。3. 构建实战基于LangChain与pgvector实现OpenClaw记忆系统理论讲完我们进入实战环节。我将以Python生态中流行的LangChain框架和PostgreSQL配合pgvector扩展为例展示如何搭建一个基础但完整的记忆系统。我们称这个Demo项目为“OpenClaw记忆内核”。3.1 环境准备与依赖安装首先确保你的环境已安装Python 3.8。我们使用pip安装核心库# 安装LangChain及其相关组件 pip install langchain langchain-community langchain-openai # 安装PostgreSQL驱动及pgvector扩展支持 # 注意pgvector扩展需要在数据库服务端安装这里安装的是Python客户端和集成工具 pip install psycopg2-binary langchain-postgres # 安装文本嵌入模型这里以OpenAI为例也可用HuggingFace模型 # 如需本地嵌入模型可安装 sentence-transformers pip install openai # 可选用于示例和工具 pip install python-dotenv你需要一个运行中的PostgreSQL数据库版本12。通过Docker可以快速启动一个docker run --name openclaw-pg -e POSTGRES_PASSWORDyourpassword -p 5432:5432 -d postgres:15然后连接到数据库创建pgvector扩展-- 在psql或pgAdmin中执行 CREATE EXTENSION IF NOT EXISTS vector;3.2 核心模块一记忆存储与向量化服务我们创建一个memory_store.py文件实现记忆的存储和检索核心逻辑。import os from datetime import datetime, timezone from typing import List, Dict, Any, Optional from uuid import uuid4 import json from langchain_openai import OpenAIEmbeddings from langchain_postgres import PGVector from langchain_postgres.vectorstores import PGVector from langchain_core.documents import Document from langchain_core.embeddings import Embeddings from dotenv import load_dotenv load_dotenv() # 加载环境变量如OPENAI_API_KEY class OpenClawMemoryStore: OpenClaw记忆存储核心类 def __init__(self, connection_string: str, embedding_model: Optional[Embeddings] None): 初始化记忆存储。 Args: connection_string: PostgreSQL连接字符串例如 postgresql://username:passwordlocalhost:5432/database_name embedding_model: 嵌入模型实例。默认为OpenAI的text-embedding-3-small。 self.connection_string connection_string self.embedding_model embedding_model or OpenAIEmbeddings( modeltext-embedding-3-small, openai_api_keyos.getenv(OPENAI_API_KEY) ) # 初始化LangChain的PGVector向量存储 # collection_name 类似于命名空间可以按用户或应用分隔 self.vector_store PGVector( embeddingsself.embedding_model, collection_nameuser_memories, connectionconnection_string, use_jsonbTrue, # 使用jsonb存储元数据查询更灵活 ) # 我们还需要一个普通的数据库连接来执行复杂查询 import psycopg2 self.conn psycopg2.connect(connection_string) self.conn.autocommit True def _create_memory_document(self, user_id: str, content: str, metadata: Dict[str, Any]) - Document: 将记忆内容封装为LangChain Document对象 # 生成唯一ID memory_id str(uuid4()) # 基础元数据 base_metadata { memory_id: memory_id, user_id: user_id, created_at: datetime.now(timezone.utc).isoformat(), last_accessed_at: datetime.now(timezone.utc).isoformat(), access_count: 0, } base_metadata.update(metadata) return Document( page_contentcontent, # 记忆的文本内容 metadatabase_metadata ) def store_memory(self, user_id: str, content: str, metadata: Dict[str, Any]) - str: 存储一条记忆。 Returns: 存储的记忆ID。 doc self._create_memory_document(user_id, content, metadata) # 添加到向量存储这会自动计算嵌入向量并存入数据库 doc_ids self.vector_store.add_documents([doc]) return doc_ids[0] if doc_ids else None def search_similar_memories(self, user_id: str, query: str, k: int 5, score_threshold: float 0.7) - List[Dict]: 为用户搜索相似的记忆。 Args: user_id: 用户ID用于过滤 query: 查询文本 k: 返回的最相似记忆数量 score_threshold: 相似度分数阈值低于此值的记忆将被过滤 Returns: 记忆字典列表按相似度降序排列。 # 1. 通过向量存储进行相似性搜索 docs_with_scores self.vector_store.similarity_search_with_score(query, kk*2) # 多取一些方便后续过滤 relevant_memories [] for doc, score in docs_with_scores: # 2. 过滤必须属于该用户且分数高于阈值 if doc.metadata.get(user_id) user_id and score score_threshold: memory_data { content: doc.page_content, score: float(score), metadata: doc.metadata } relevant_memories.append(memory_data) # 3. 更新该条记忆的访问时间和次数异步或后续批量更新更好此处为演示 self._update_memory_access(doc.metadata.get(memory_id)) # 4. 按分数排序并返回前k个 relevant_memories.sort(keylambda x: x[score], reverseTrue) return relevant_memories[:k] def _update_memory_access(self, memory_id: str): 更新记忆的访问时间和次数 try: with self.conn.cursor() as cur: cur.execute( UPDATE langchain_pg_embedding SET metadata jsonb_set( jsonb_set( metadata, {last_accessed_at}, to_jsonb(%s::text) ), {access_count}, to_jsonb((metadata-access_count)::int 1) ) WHERE metadata-memory_id %s , (datetime.now(timezone.utc).isoformat(), memory_id)) except Exception as e: print(f更新记忆访问记录失败: {e}) def delete_memory(self, user_id: str, memory_id: str) - bool: 删除特定用户的某条记忆 try: with self.conn.cursor() as cur: # LangChain PGVector 将文档和向量存储在 langchain_pg_embedding 表 cur.execute( DELETE FROM langchain_pg_embedding WHERE metadata-user_id %s AND metadata-memory_id %s , (user_id, memory_id)) return cur.rowcount 0 except Exception as e: print(f删除记忆失败: {e}) return False def get_user_memory_summary(self, user_id: str, limit: int 20) - List[Dict]: 获取用户最近或最重要的记忆摘要非向量搜索直接数据库查询 try: with self.conn.cursor() as cur: cur.execute( SELECT page_content, metadata-summary as summary, metadata-created_at as created_at, (metadata-access_count)::int as access_count FROM langchain_pg_embedding WHERE metadata-user_id %s ORDER BY metadata-created_at DESC LIMIT %s , (user_id, limit)) rows cur.fetchall() return [ { content: r[0], summary: r[1], created_at: r[2], access_count: r[3] } for r in rows ] except Exception as e: print(f获取用户记忆摘要失败: {e}) return [] def close(self): 关闭数据库连接 if self.conn: self.conn.close()这个类封装了记忆的存储、向量化检索、更新和查询等基本操作。它利用LangChain的PGVector类简化了与向量数据库的交互。3.3 核心模块二记忆生成与对话集成代理仅有存储和检索还不够我们需要一个“记忆生成器”它能从对话中智能地提取值得长期记忆的信息。同时还需要一个“记忆代理”在每次对话时自动处理记忆的检索和注入。我们创建memory_agent.pyfrom typing import List, Dict, Any from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.messages import SystemMessage, HumanMessage, AIMessage from .memory_store import OpenClawMemoryStore class MemoryExtractor: 记忆提取器从对话中识别并提取结构化记忆 def __init__(self, llm): self.llm llm self.extraction_prompt ChatPromptTemplate.from_messages([ SystemMessage(content你是一个信息提取助手。你的任务是从用户的对话中识别出值得长期记忆的、关于用户个人的事实性信息或偏好。 请严格按以下JSON格式输出如果没有值得记忆的信息则返回空列表。 输出格式 { memories: [ { content: 清晰、简洁的事实陈述句。例如用户有一只名叫元宝的猫品种是英短三岁。, summary: 记忆的简短摘要用于快速浏览如宠物猫信息, metadata: { category: 实体|偏好|任务|其他, // 分类 importance: 0.5, // 重要性0-1之间 tags: [宠物, 猫] // 相关标签 } } ] } 注意只提取用户明确陈述或强烈暗示的客观事实和个人偏好。避免推测或假设。), MessagesPlaceholder(variable_nameconversation_history), HumanMessage(content请从以上对话的最后几轮中提取需要长期记忆的信息。) ]) def extract_from_conversation(self, conversation_history: List[Dict]) - List[Dict]: 从对话历史中提取记忆 try: # 将历史格式化为LangChain消息 messages [] for msg in conversation_history[-6:]: # 只看最近几轮避免上下文过长 role msg.get(role) content msg.get(content) if role user: messages.append(HumanMessage(contentcontent)) elif role assistant: messages.append(AIMessage(contentcontent)) chain self.extraction_prompt | self.llm response chain.invoke({conversation_history: messages}) # 解析LLM的JSON输出 import json result json.loads(response.content) return result.get(memories, []) except Exception as e: print(f记忆提取失败: {e}) return [] class OpenClawMemoryAgent: OpenClaw记忆代理集成记忆存储、提取和对话 def __init__(self, memory_store: OpenClawMemoryStore, llm): self.memory_store memory_store self.llm llm self.extractor MemoryExtractor(llm) # 定义系统提示词模板其中包含记忆插槽 self.system_template 你是一个有帮助的AI助手并且拥有关于用户的长期记忆。 以下是关于用户的已知信息记忆 {memories_context} 当前对话历史最近几轮 {conversation_history} 请基于以上记忆和对话历史回应用户的最新请求。如果记忆中有相关信息请自然地利用它们。如果用户提供了新信息你可以选择性地更新记忆但不要在你的回复中讨论记忆系统本身。 def process_conversation(self, user_id: str, user_input: str, conversation_history: List[Dict]) - Dict[str, Any]: 处理一轮对话检索记忆、生成回复、并可能存储新记忆。 Returns: 包含AI回复和本次使用的记忆的字典。 # 1. 检索相关记忆 relevant_memories self.memory_store.search_similar_memories(user_id, user_input, k3) memories_context \n.join([f- {mem[content]} for mem in relevant_memories]) if relevant_memories else 暂无相关记忆 # 2. 准备完整的对话历史用于LLM上下文 # 注意实际生产中这里需要做上下文窗口长度管理避免超出token限制 history_for_llm [] for msg in conversation_history[-10:]: # 限制历史长度 if msg[role] user: history_for_llm.append(HumanMessage(contentmsg[content])) else: history_for_llm.append(AIMessage(contentmsg[content])) # 3. 构建最终提示词并调用LLM prompt ChatPromptTemplate.from_messages([ SystemMessage(contentself.system_template.format( memories_contextmemories_context, conversation_history\n.join([f{msg.type}: {msg.content} for msg in history_for_llm[:-1]]) if len(history_for_llm) 1 else 无历史对话 )), *history_for_llm[-1:], # 加入最后一轮用户输入 ]) chain prompt | self.llm ai_response chain.invoke({}).content # 4. 从本轮对话中提取可能的新记忆 new_memories self.extractor.extract_from_conversation(conversation_history [{role: user, content: user_input}]) for mem in new_memories: # 避免重复存储高度相似的记忆简单去重生产环境需更严谨 existing self.memory_store.search_similar_memories(user_id, mem[content], k1, score_threshold0.9) if not existing: self.memory_store.store_memory( user_iduser_id, contentmem[content], metadata{ summary: mem.get(summary, ), category: mem[metadata][category], importance: mem[metadata][importance], tags: mem[metadata][tags] } ) print(f存储新记忆: {mem[content]}) return { response: ai_response, memories_used: [mem[content] for mem in relevant_memories], new_memories_stored: [mem[content] for mem in new_memories] }3.4 运行一个完整的示例最后我们创建一个main.py来演示整个流程import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from memory_store import OpenClawMemoryStore from memory_agent import OpenClawMemoryAgent load_dotenv() def main(): # 0. 配置 PG_CONN_STR postgresql://postgres:yourpasswordlocalhost:5432/postgres USER_ID test_user_001 # 1. 初始化组件 print(初始化记忆存储和AI模型...) memory_store OpenClawMemoryStore(PG_CONN_STR) llm ChatOpenAI(modelgpt-3.5-turbo, temperature0.7, openai_api_keyos.getenv(OPENAI_API_KEY)) agent OpenClawMemoryAgent(memory_store, llm) # 模拟对话历史 conversation_history [] # 2. 第一轮对话用户提供信息 print(\n--- 第一轮对话 ---) user_input_1 你好我有一只猫它叫元宝是只三岁的英短特别黏人。 print(f用户: {user_input_1}) conversation_history.append({role: user, content: user_input_1}) result_1 agent.process_conversation(USER_ID, user_input_1, conversation_history) print(fAI: {result_1[response]}) print(f本次使用的记忆: {result_1[memories_used]}) print(f存储的新记忆: {result_1[new_memories_stored]}) conversation_history.append({role: assistant, content: result_1[response]}) # 3. 第二轮对话几天后用户基于记忆提问 print(\n--- 第二轮对话几天后 ---) # 注意在实际应用中conversation_history会被持久化这里我们清空历史模拟新会话但记忆系统仍工作 new_conversation_history [] user_input_2 我的猫最近掉毛有点多有什么建议吗 print(f用户: {user_input_2}) new_conversation_history.append({role: user, content: user_input_2}) result_2 agent.process_conversation(USER_ID, user_input_2, new_conversation_history) print(fAI: {result_2[response][:200]}...) # 截取部分回复 print(f本次使用的记忆: {result_2[memories_used]}) # 一个理想的回复应该体现出它知道“元宝”是只“英短猫”并可能给出针对该品种的建议。 # 4. 查看用户的记忆库摘要 print(\n--- 用户记忆库摘要 ---) summaries memory_store.get_user_memory_summary(USER_ID, limit5) for i, summary in enumerate(summaries, 1): print(f{i}. [{summary[summary]}] {summary[content]} (访问次数: {summary[access_count]})) # 5. 清理 memory_store.close() print(\n演示结束。) if __name__ __main__: main()运行这个示例你将看到AI在第一轮对话后存储了关于“元宝”的记忆并在第二轮关于“猫掉毛”的提问中成功检索并利用了这条记忆使回复更具针对性。4. 超越基础高级记忆模式与生产环境考量上面的实现是一个可运行的原型但要投入生产环境还需要考虑更多复杂因素和高级模式。4.1 记忆的抽象化从事实到关系与图谱基础记忆存储的是孤立的“事实”。更高级的系统会建立记忆之间的关系形成知识图谱。例如“元宝” -IS_A- “猫”“元宝” -OWNED_BY- “用户A”“用户A” -LIKES- “辣食”“辣食” -AVOIDED_BY- “元宝”因为猫不能吃辣这样当用户说“给我和元宝推荐个晚餐”系统可以通过图谱推理出需要给人推荐辣食给猫推荐猫粮且两者要分开。实现上可以在存储记忆时用LLM或规则抽取出实体和关系存入图数据库如Neo4j或作为元数据关联。4.2 记忆的动态管理重要性、衰减与合并记忆不能只增不减需要一套管理策略重要性加权不是所有信息都同等重要。“我对花生过敏”的重要性远高于“我今天喝了咖啡”。可以在提取记忆时由LLM打分或根据用户反馈如用户多次纠正、明确说“这个很重要”动态调整。时间衰减久未提及的记忆应逐渐降低检索优先级。可以通过在检索评分函数中加入时间衰减因子来实现例如衰减因子 exp(-λ * 天数)。记忆合并与冲突解决用户可能在不同时间提供了矛盾的信息如“我讨厌苹果” vs “给我买个苹果手机”。系统需要检测冲突并有一套解决机制例如时间戳最新的优先、用户明确确认的优先、或主动询问用户澄清。4.3 检索优化从相似性搜索到混合搜索单纯的向量相似性搜索有其局限。例如用户问“我上周三说了什么”这是一个基于时间的精确查询向量搜索可能不准。因此需要混合搜索Hybrid Search关键词/过滤器搜索在元数据上执行精确或模糊查询WHERE metadata-category task AND created_at 2024-05-20。向量相似性搜索在内容上进行语义搜索。结果融合将两者的结果按权重合并、重新排序。pgvector支持同时进行向量搜索和基于元数据的过滤非常适合实现混合搜索。4.4 隐私、安全与用户控制记忆系统涉及大量个人数据必须严肃对待数据加密静态数据数据库存储和传输数据应加密。访问控制严格确保用户只能访问自己的记忆。记忆查看与编辑必须向用户提供界面让其查看、修正或删除AI关于自己的任何记忆。这是建立信任的基石。我们的示例中已经提供了get_user_memory_summary和delete_memory方法为后端API打下基础。合规性遵循相关数据保护法规如GDPR提供数据导出和彻底删除功能。4.5 性能与规模化当用户量和记忆量增长时索引优化为向量列和常用的元数据字段如user_id,created_at建立索引。分库分表/分区可以按user_id进行数据分区将不同用户的数据分布到不同的物理存储上。缓存对高频访问的“核心记忆”如用户的基本偏好进行缓存减少数据库查询。异步处理记忆的提取、向量化、存储等操作可以放入消息队列如RabbitMQ, Celery异步执行不阻塞主对话流程。5. 避坑指南从原型到产品路上常见的“坑”在实际开发和部署这样一个系统时我踩过不少坑这里分享几个关键的坑一记忆的“过度提取”与“幻觉”LLM在提取记忆时有时会“过度解读”或“无中生有”。比如用户说“今天好累”模型可能错误地提取出“用户身体虚弱”作为记忆。解决方案设置严格的提取规则和置信度阈值。可以设计一个“审核”层对于重要性高的记忆如健康、财务信息需要用户明确确认“是否需要我记住‘你对花生过敏’这件事”后才存入长期记忆。坑二上下文窗口与记忆注入的权衡LLM有上下文长度限制。如果检索出太多记忆全塞进Prompt会挤占对话历史的空间甚至超出限制。解决方案记忆摘要不是注入原始记忆而是注入由LLM生成的、更简短的记忆摘要。分层记忆分为“工作记忆”当前会话相关、“短期记忆”最近几天、“长期记忆”核心事实。每次只注入最相关的一层。动态上下文管理实时计算Token数优先保留高相关度记忆和最近的对话历史必要时对较旧的对话历史进行摘要压缩。坑三向量搜索的“语义漂移”嵌入模型并非完美。有时语义上相关的查询向量距离却不一定近。比如“我的座驾”和“我的汽车”如果训练语料中关联不强可能搜索不到。解决方案采用查询扩展Query Expansion。在搜索前先用LLM对用户查询进行同义改写或扩展生成多个相关的查询语句分别进行向量搜索然后合并结果。例如将“我的座驾”扩展为[“我的汽车” “我开的车” “我的车辆”]。坑四记忆更新的“冷启动”与“数据稀疏”新用户几乎没有记忆系统无法提供个性化服务。解决方案设计一个友好的“ onboarding ”流程主动询问用户一些基本但有用的信息如称呼、主要使用场景、希望AI记住什么等作为初始记忆种子。也可以从用户已有的历史数据经用户授权中安全地初始化一些记忆。构建一个真正“长情”的AI记忆系统是一项融合了算法、工程和产品思维的挑战。从简单的向量存储到复杂的知识图谱和动态管理每一步都需要根据实际应用场景仔细权衡。本文提供的OpenClaw指南和代码实现为你打下了一个坚实的基础。记住最好的记忆系统是让用户感受不到它的存在却又处处受益于它的存在——它记得你的喜好理解你的上下文像一个真正了解你的老朋友一样与你对话。
返回列表