为AI Agent构建记忆操作系统:从向量检索到自我进化的工程实践
1. 项目概述:当AI助手拥有“记忆”与“进化”能力
最近在捣鼓一个叫WorkBuddy的AI助手框架,它本质上是一个帮你处理各种任务的智能体(AI Agent)。但玩久了总觉得差点意思:每次对话都像是“重启”,它不记得之前聊过什么,更别提从历史交互中学习并自我改进了。这就像和一个只有短期记忆的朋友合作,效率总卡在瓶颈上。
于是,我萌生了一个想法:能不能给WorkBuddy装上一个“记忆操作系统”?这个想法源自对现有AI Agent局限性的观察。大多数Agent,包括WorkBuddy的默认配置,其“记忆”是短暂且孤立的。一次会话中的上下文窗口消耗完,之前的对话、决策逻辑、乃至成功或失败的经验就都消失了。这不仅导致重复劳动,更阻碍了Agent的长期学习和能力沉淀。所谓的“记忆操作系统”(MemOS),并非指一个具体的、现成的软件,而是一种架构理念和功能集合。它的核心目标是赋予AI Agent持续的记忆存储、检索、反思和基于记忆进行自主创造(如编写新Skill)的能力。简单说,就是让WorkBuddy从一个“健忘的执行者”,变成一个“有经验的、能自我进化的伙伴”。
这个项目的价值在于,它直接回应了当前AI Agent领域的一个核心痛点:如何实现持续学习和能力累积。无论是个人用来管理日常任务、学习新技能,还是团队用于构建复杂的自动化工作流,一个拥有记忆和进化能力的Agent,其效率和智能水平将是指数级提升。它开始能记住你的偏好、总结工作模式、甚至在遇到类似问题时,主动调用或组合已有的技能(Skill)来生成更优的解决方案,最终实现“自己写Skill,自己进化”。这听起来有点科幻,但基于现有的技术栈,是完全可实现的工程实践。接下来,我就把自己从构思到实现这套“记忆操作系统”的全过程,包括核心设计、技术选型、踩过的坑和最终效果,毫无保留地分享出来。
2. 记忆操作系统(MemOS)的核心架构设计
给WorkBuddy添加记忆能力,绝不是简单加个数据库存聊天记录那么简单。它需要一套完整的、分层的架构来处理信息的生命周期:从感知、存储、索引、检索到应用与生成。我设计的MemOS架构主要包含四个核心层次,每一层都有其明确的职责和技术考量。
2.1 记忆的层次化存储模型
记忆不能是“一锅粥”,必须结构化。我借鉴了认知科学和现有AI系统的设计,将记忆分为三个层级:
-
瞬时记忆(Working Memory) :对应LLM的上下文窗口。它处理当前对话回合的输入、思考链(Chain-of-Thought)和即时输出。这部分是“思考的草稿纸”,速度快但容量有限。我的设计是,在每次Agent运行结束时,自动将本轮对话中的关键决策点、执行结果和用户反馈,从“瞬时记忆”中提炼出来,准备存入长期记忆。
-
短期记忆(Short-term Memory) :存储近期(如过去几天)的高频、高相关性记忆片段。我使用向量数据库(如Chroma或Qdrant)来实现。每一段记忆(例如:“用户要求将‘月度报告.pdf’转换为Markdown格式,我成功调用了‘pdf_to_md’这个Skill完成”)会被转换成一个文本片段,并通过嵌入模型(Embedding Model)转化为向量。向量数据库支持基于语义相似度的快速检索。当新任务到来时,系统会从短期记忆中检索出最相关的几条记忆,作为上下文提供给LLM,帮助它做出更相关的决策。
-
长期记忆(Long-term Memory) :存储重要的经验、提炼出的知识、以及Agent自己创造的资产(如Skill代码)。这部分使用传统的关系型数据库(如SQLite或PostgreSQL)和文件系统。关系库用于存储记忆的元数据(ID、类型、创建时间、关联标签等),而具体的知识内容或Skill代码则以文本或文件形式存储。长期记忆的关键在于“摘要”和“索引”。系统会定期(或触发式)对短期记忆中的相关片段进行总结,形成更高阶的“经验知识”(例如:“用户通常在周一上午需要处理文档格式转换”),并存入长期记忆。同时,所有记忆都通过关键词和语义标签进行索引,方便多维度检索。
注意 :记忆的存储不是单向的。一个高效的MemOS需要设计记忆的“激活”机制。当处理任务时,系统首先从长期记忆中通过关键词召回一批相关记忆,再用这些记忆的摘要去向量库做更精细的语义检索,最后将最相关的几条记忆与瞬时记忆结合。这模仿了人类的记忆唤醒过程。
2.2 记忆的生成、索引与检索流程
记忆不是被动存储的,而是主动生成的。我设计了一个“记忆生成器”模块,它作为WorkBuddy Action的一个环节,在每次任务循环结束后被调用。其工作流程如下:
- 事件捕获 :监听Agent的核心事件,如“Skill执行完成”、“用户给出明确反馈(好评/差评)”、“任务成功/失败”、“出现了需要总结的复杂情况”。
- 内容提炼 :对于捕获的事件,不是原始日志全存。我编写了提炼提示词,让一个小型LLM(如GPT-3.5-Turbo或本地轻量模型)对事件进行总结,生成结构化的记忆片段。例如,输入原始日志:“调用天气查询Skill,参数{city: ‘北京’},返回成功,气温22度。” 提炼后记忆:“成功执行‘天气查询’技能,用户询问了北京天气,结果正常。关联标签:#天气 #查询 #成功”。
- 向量化与存储 :将提炼后的记忆文本,通过嵌入模型(我选用
text-embedding-3-small,平衡效果与成本)转化为向量,并存入向量数据库(短期记忆)。同时,将记忆文本、元数据(类型、时间戳、关联的Skill ID、任务ID)和向量ID的映射关系,存入关系数据库(长期记忆索引)。 - 检索策略 :当新任务到来时,“记忆检索器”模块开始工作。首先,它解析当前任务描述和上下文,生成一组关键词。用这些关键词在关系数据库中进行初步筛选。然后,将当前任务描述也向量化,用这个向量去向量数据库中执行相似度搜索(通常用余弦相似度),找出最相关的N条短期记忆。最后,将两类结果去重、排序,合并成一个增强的上下文,注入给负责决策的LLM。
这个流程确保了记忆是高质量的、可检索的,并且检索过程是高效、精准的。
2.3 基于记忆的反思与Skill进化机制
记忆的终极价值在于驱动进化。MemOS最核心的功能,就是让WorkBuddy能够“反思”记忆,并据此创造新Skill或优化旧Skill。我设计了两种进化触发机制:
-
定期反思(Scheduled Reflection) :像一个定期的复盘会议。系统设置一个后台任务,例如每天凌晨,分析过去24小时内存储的所有记忆。它会关注:
- 重复模式 :用户是否频繁提出某一类请求?现有的Skill组合起来是否能解决?如果不能,是否需要新Skill?
- 失败案例 :哪些任务失败了?失败原因是什么?是Skill能力不足、参数错误,还是需要外部信息?
- 成功模式 :哪些任务完成得特别出色?其执行路径是否可以抽象成一个更高效的新流程或Skill? 反思过程由一个具有较强分析能力的LLM(如Claude 3或GPT-4)驱动,它读取一批相关记忆,并输出反思报告,报告可能包含“建议创建新Skill”的提案。
-
事件触发反思(Event-triggered Reflection) :当发生特定高价值事件时立即启动。例如:
- 用户对某个Skill的输出给出了“大拇指 down”的负面反馈。
- 一个复杂任务经过多轮工具调用才勉强完成。
- Agent发现自己无法处理一个请求,因为缺少对应的Skill。 这时,系统会立即围绕该事件检索相关记忆,启动一个高优先级的反思会话,分析问题根源并生成解决方案,如优化现有Skill的提示词,或起草一个新Skill的需求描述。
从反思到Skill创建 :当反思报告建议创建新Skill时,MemOS不会直接写代码。它会生成一个详细的“Skill需求说明书”(PRD),包括Skill的功能描述、输入/输出格式、可能用到的API或工具、以及测试用例。然后,这个PRD会被送入“Skill编码器”模块。这个模块可以是另一个专精代码生成的LLM(如Claude 3.5 Sonnet或DeepSeek-Coder),它根据PRD和类似的现有Skill作为参考,生成初始的Skill代码(可能是Python函数、一段脚本或一个插件配置)。生成的代码会经过简单的语法检查,并保存到Skill仓库中,等待用户或管理员的审核与激活。至此,一个基于记忆和反思的“自我进化”循环就完成了。
3. 技术栈选型与核心组件集成
实现MemOS,需要谨慎选择每一个技术组件,并让它们在WorkBuddy的生态中无缝协作。我的选型原则是:优先考虑成熟度、社区活跃度、与Python生态的兼容性,以及轻量级,毕竟这是给一个AI Agent增加的“外挂”系统。
3.1 记忆存储组件:向量数据库与关系数据库
-
向量数据库 :我选择了 ChromaDB 。原因很简单:它轻量、易嵌入、API简单,并且专门为AI应用设计。它可以直接在Python进程中运行,无需单独部署服务器,这对于集成到WorkBuddy中非常友好。将记忆片段向量化后,用
chromadb客户端直接存入集合(Collection)即可。检索时,一句collection.query就能搞定。它的持久化模式也足够可靠,可以将数据保存在本地目录。- 备选方案 :如果对性能和大规模生产环境有更高要求, Qdrant 或 Weaviate 是更强大的选择,但它们需要单独部署服务,增加了系统复杂度。对于个人或小团队使用的WorkBuddy,Chroma是起步的最佳选择。
-
关系数据库 :我选择了 SQLite 。WorkBuddy本身可能就使用SQLite来管理配置和基础数据,延续使用可以避免引入新的依赖。它零配置、单文件、性能对于记忆元数据的管理绰绰有余。我设计了几张核心表:
memory_metadata: 存储记忆ID、类型、摘要、时间戳、关联的skill_id、task_id等。skill_definitions: 存储Skill的元数据(名称、描述、作者、版本、代码路径)。reflection_logs: 存储每次反思会话的输入、输出和结论。 SQLite的简洁性让整个MemOS的部署变得极其简单。
3.2 嵌入模型与LLM的选型考量
-
嵌入模型(Embedding Model) :这是记忆检索准确性的基石。我主要使用OpenAI的
text-embedding-3-small。它在效果和成本之间取得了完美平衡,对于记忆片段这种短文本,其语义捕捉能力足够强,且API调用速度快、价格低廉。如果追求完全本地化,可以选用 BAAI/bge-small-zh-v1.5 或 thenlper/gte-small 这类开源模型,通过sentence-transformers库集成。但需要权衡本地推理的计算资源消耗。- 实操心得 :对于记忆检索,嵌入模型的速度和稳定性比极致的精度更重要。
text-embedding-3-small的维度是1536,在Chroma中检索效率很高。如果使用开源模型,务必测试其编码速度,避免拖慢Agent的整体响应。
- 实操心得 :对于记忆检索,嵌入模型的速度和稳定性比极致的精度更重要。
-
核心LLM(用于决策与反思) :WorkBuddy的主脑LLM选择很多。对于日常任务决策,可以使用性价比较高的模型,如 GPT-3.5-Turbo 或 Claude 3 Haiku 。但对于“反思”和“Skill生成”这类需要深度推理和创造性的任务,我强烈建议使用能力更强的模型,如 GPT-4 、 Claude 3.5 Sonnet 或 DeepSeek-V2 。这部分投入是值得的,因为高质量的反思和代码生成能极大提升进化的有效性,减少后续人工修正的工作量。
- 注意事项 :需要为不同的任务类型配置不同的LLM。在代码中,这意味着要有清晰的“路由”逻辑:任务决策走经济型模型API,反思生成走高性能模型API。这能有效控制成本。
3.3 与WorkBuddy框架的融合方式
WorkBuddy通常有一个主循环,处理用户输入、调用工具(Skill)、返回结果。集成MemOS,需要在几个关键节点插入钩子(Hooks):
- Post-Action Hook(动作后钩子) :在每个Skill执行完成后,无论成功与否,自动触发“记忆生成器”,将本次执行的关键信息提炼存储。
- Pre-Decision Hook(决策前钩子) :在主LLM进行任务规划或Skill选择之前,先调用“记忆检索器”,获取与当前任务相关的历史记忆,并将其作为系统提示词的一部分附加进去,让LLM做出更明智的决策。
- Scheduler(调度器) :引入一个轻量级后台调度(如使用
apscheduler库),定时触发“定期反思”任务。 - Event Bus(事件总线) :建立一个小型的事件系统。当发生用户反馈、任务失败等事件时,发布相应事件。“事件触发反思”模块监听这些事件并做出响应。
这种“非侵入式”的集成,保证了MemOS可以作为WorkBuddy的一个插件或扩展模块来开发,而不需要大量修改WorkBuddy的核心代码,提高了可维护性。
4. 实操搭建:从零到一的MemOS实现步骤
理论说再多,不如动手做一遍。下面是我在本地搭建并集成MemOS到WorkBuddy的具体步骤,你可以跟着一步步实现。
4.1 基础环境与依赖安装
假设你已经有一个基础的WorkBuddy运行环境(基于Python)。首先,为MemOS创建独立的依赖环境。
# 在WorkBuddy项目根目录下,创建并激活虚拟环境(可选但推荐)
python -m venv venv_memos
source venv_memos/bin/activate # Linux/Mac
# venv_memos\Scripts\activate # Windows
# 安装核心依赖
pip install chromadb # 向量数据库
pip install openai # 用于嵌入模型和LLM API调用(如果使用)
pip install sentence-transformers # 如果使用开源嵌入模型
pip install apscheduler # 用于定时任务
pip install sqlalchemy # ORM,方便操作SQLite
pip install pydantic # 用于数据验证和设置管理
接下来,在WorkBuddy的项目结构中,创建一个新的模块目录,例如 workbuddy_memos/ 。
4.2 记忆存储模块的代码实现
在 workbuddy_memos/ 目录下,创建以下几个核心文件:
1. models.py - 定义数据模型
from pydantic import BaseModel
from datetime import datetime
from typing import Optional, List
import sqlalchemy as sa
from sqlalchemy.orm import declarative_base
Base = declarative_base()
# Pydantic模型,用于API和逻辑处理
class MemoryFragment(BaseModel):
id: Optional[str] = None
content: str # 提炼后的记忆文本
embedding: Optional[List[float]] = None
memory_type: str # 如 "skill_execution", "user_feedback", "task_result"
timestamp: datetime
skill_id: Optional[str] = None
task_id: Optional[str] = None
tags: List[str] = []
# SQLAlchemy模型,用于数据库持久化
class MemoryMetadata(Base):
__tablename__ = 'memory_metadata'
id = sa.Column(sa.String, primary_key=True)
content = sa.Column(sa.Text, nullable=False)
memory_type = sa.Column(sa.String, nullable=False)
timestamp = sa.Column(sa.DateTime, default=datetime.utcnow)
skill_id = sa.Column(sa.String)
task_id = sa.Column(sa.String)
vector_id = sa.Column(sa.String) # 关联Chroma中的ID
tags = sa.Column(sa.JSON) # 存储标签列表
class SkillDefinition(Base):
__tablename__ = 'skill_definitions'
id = sa.Column(sa.String, primary_key=True)
name = sa.Column(sa.String, unique=True, nullable=False)
description = sa.Column(sa.Text)
code_path = sa.Column(sa.String) # Skill代码文件路径
author = sa.Column(sa.String, default='MemOS')
created_at = sa.Column(sa.DateTime, default=datetime.utcnow)
is_active = sa.Column(sa.Boolean, default=True)
2. storage.py - 实现存储与检索类
import chromadb
from chromadb.config import Settings
from sentence_transformers import SentenceTransformer
import sqlalchemy as sa
from sqlalchemy.orm import sessionmaker
from .models import Base, MemoryMetadata
from typing import List, Dict, Any
import uuid
class MemoryStorage:
def __init__(self, persist_dir: str = "./chroma_db", embedding_model_name: str = "all-MiniLM-L6-v2"):
# 初始化Chroma客户端(持久化模式)
self.chroma_client = chromadb.PersistentClient(path=persist_dir)
self.collection = self.chroma_client.get_or_create_collection(name="workbuddy_memories")
# 初始化嵌入模型(这里以开源模型为例)
self.embedding_model = SentenceTransformer(embedding_model_name)
# 初始化SQLite数据库
self.engine = sa.create_engine('sqlite:///./workbuddy_memos.db')
Base.metadata.create_all(self.engine)
self.SessionLocal = sessionmaker(bind=self.engine)
def store_memory(self, memory: MemoryFragment):
"""存储一段记忆到向量库和关系库"""
# 生成唯一ID
memory_id = str(uuid.uuid4())
# 生成向量
embedding = self.embedding_model.encode(memory.content).tolist()
# 存入Chroma
self.collection.add(
documents=[memory.content],
metadatas=[{"type": memory.memory_type, "skill_id": memory.skill_id, "task_id": memory.task_id}],
embeddings=[embedding],
ids=[memory_id]
)
# 存入SQLite
with self.SessionLocal() as session:
db_memory = MemoryMetadata(
id=memory_id,
content=memory.content,
memory_type=memory.memory_type,
skill_id=memory.skill_id,
task_id=memory.task_id,
vector_id=memory_id,
tags=memory.tags
)
session.add(db_memory)
session.commit()
def retrieve_related_memories(self, query: str, n_results: int = 5) -> List[Dict[str, Any]]:
"""根据查询文本检索相关记忆"""
# 将查询文本向量化
query_embedding = self.embedding_model.encode(query).tolist()
# 从Chroma中查询
results = self.collection.query(
query_embeddings=[query_embedding],
n_results=n_results
)
# 组织返回结果
memories = []
if results['documents']:
for i in range(len(results['documents'][0])):
memory = {
"content": results['documents'][0][i],
"metadata": results['metadatas'][0][i],
"distance": results['distances'][0][i]
}
memories.append(memory)
return memories
4.3 记忆生成与反思引擎的实现
3. memory_generator.py - 记忆提炼
import openai
from .models import MemoryFragment
from datetime import datetime
class MemoryGenerator:
def __init__(self, llm_client):
self.llm = llm_client # 传入一个配置好的LLM客户端,如OpenAI或ChatOLLM
def generate_from_event(self, event_type: str, raw_data: dict) -> MemoryFragment:
"""根据原始事件数据,生成结构化的记忆片段"""
prompt = f"""
你是一个记忆提炼助手。请将以下AI Agent执行事件提炼成一段简洁、结构化、未来易于检索的记忆。
事件类型:{event_type}
原始数据:{raw_data}
请按以下格式输出记忆内容:
[动作描述]。结果:[成功/失败/部分成功]。关键信息:[提取关键参数或结果]。关联标签:[列出2-4个相关标签,以#开头]。
例如:成功执行‘文件转换’技能,将‘report.pdf’转换为Markdown格式。结果:成功。关键信息:输入文件=report.pdf,输出格式=md。关联标签:#文件转换 #pdf #markdown #成功。
"""
try:
response = self.llm.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}],
temperature=0.2 # 低温度保证输出稳定
)
memory_text = response.choices[0].message.content.strip()
# 简单解析出标签(这里简化处理,实际可以更复杂)
tags = []
if "关联标签:" in memory_text:
tag_part = memory_text.split("关联标签:")[-1]
tags = [tag.strip() for tag in tag_part.split('#') if tag.strip()]
return MemoryFragment(
content=memory_text,
memory_type=event_type,
timestamp=datetime.now(),
skill_id=raw_data.get("skill_id"),
task_id=raw_data.get("task_id"),
tags=tags
)
except Exception as e:
print(f"记忆生成失败: {e}")
# 降级方案:生成一个简单的记忆
return MemoryFragment(
content=f"{event_type}: {str(raw_data)[:200]}",
memory_type=event_type,
timestamp=datetime.now(),
skill_id=raw_data.get("skill_id"),
task_id=raw_data.get("task_id"),
tags=[f"#{event_type}"]
)
4. reflection_engine.py - 定期反思
from apscheduler.schedulers.background import BackgroundScheduler
from .storage import MemoryStorage
import openai
from datetime import datetime, timedelta
class ReflectionEngine:
def __init__(self, memory_storage: MemoryStorage, powerful_llm_client):
self.storage = memory_storage
self.llm = powerful_llm_client # 使用更强的LLM,如GPT-4
self.scheduler = BackgroundScheduler()
def start_periodic_reflection(self, interval_hours=24):
"""启动定时反思任务"""
self.scheduler.add_job(
self._run_reflection,
'interval',
hours=interval_hours,
next_run_time=datetime.now() # 立即运行一次
)
self.scheduler.start()
print("定期反思引擎已启动。")
def _run_reflection(self):
"""执行反思分析"""
print(f"{datetime.now()}: 开始执行定期反思...")
# 1. 从存储中获取近期记忆(例如过去24小时)
# 这里需要扩展MemoryStorage,添加按时间查询的方法(略)
# recent_memories = self.storage.get_memories_since(datetime.now() - timedelta(hours=24))
# 2. 构建反思提示词
reflection_prompt = f"""
你是一个AI Agent的自我进化分析引擎。请分析以下近期的工作记忆,并给出进化建议。
近期记忆摘要(最近24小时):
[这里应拼接近期记忆的摘要内容]
请从以下角度分析:
1. **重复模式识别**:用户请求中是否存在频繁出现的、未被现有Skill很好满足的需求模式?
2. **失败根因分析**:哪些任务失败了?根本原因是什么?(例如:缺少特定数据、Skill逻辑错误、外部API变化)
3. **成功经验固化**:哪些任务完成得特别好?其执行流程是否可以抽象成新的、可复用的Skill或工作流?
4. **Skill缺口发现**:是否存在用户明确或隐含请求,但当前没有任何Skill能处理的情况?
请输出一份结构化的反思报告,并至少提出一个具体的“新Skill创建提案”或“现有Skill优化建议”。
提案格式:
- 提案类型:[新建/优化]
- 目标Skill名称:
- 功能描述:
- 触发场景:
- 预期输入/输出:
- 参考代码或实现思路(如可能):
"""
# 3. 调用LLM进行反思
try:
response = self.llm.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": reflection_prompt}],
temperature=0.7
)
reflection_report = response.choices[0].message.content
print("反思报告生成完毕。")
# 4. 解析报告,提取提案,并触发Skill创建流程(下一节实现)
self._process_reflection_report(reflection_report)
except Exception as e:
print(f"反思过程出错: {e}")
4.4 Skill自动生成器的实现
5. skill_creator.py - 从提案到代码
import re
import os
from pathlib import Path
class SkillCreator:
def __init__(self, code_llm_client, skill_directory: str = "./skills/generated"):
self.llm = code_llm_client # 专精代码生成的LLM,如Claude 3.5 Sonnet
self.skill_dir = Path(skill_directory)
self.skill_dir.mkdir(parents=True, exist_ok=True)
def create_skill_from_proposal(self, proposal: dict):
"""根据反思报告中的提案,生成Skill代码"""
# proposal 是一个字典,包含反思报告解析出的字段
skill_name = proposal.get("target_skill_name", "new_skill").replace(" ", "_").lower()
description = proposal.get("function_description", "")
trigger = proposal.get("trigger_scenario", "")
# 构建代码生成提示词
coding_prompt = f"""
你是一个资深的AI Skill开发助手。请根据以下需求,编写一个WorkBuddy可用的Skill。
Skill名称:{skill_name}
功能描述:{description}
触发场景:{trigger}
输入/输出要求:{proposal.get('input_output', '待定')}
WorkBuddy Skill通常是一个Python函数,它接收一个字典参数`params`,并返回一个字符串或字典结果。
请遵循以下规范:
1. 函数名应为 `execute_{skill_name}`。
2. 包含详细的文档字符串(docstring)。
3. 包含必要的错误处理。
4. 如果需要调用外部API,请使用`requests`库,并处理好网络异常。
5. 代码应简洁、高效、可读性强。
只输出最终的Python代码,无需任何解释。
"""
try:
response = self.llm.chat.completions.create(
model="claude-3-5-sonnet-20241022", # 示例,实际需替换为正确模型名
messages=[{"role": "user", "content": coding_prompt}],
temperature=0.3
)
code = response.choices[0].message.content
# 清理代码块标记(如果LLM返回了```python ... ```)
code = re.sub(r'```python\n', '', code)
code = re.sub(r'\n```', '', code)
# 保存代码文件
file_path = self.skill_dir / f"{skill_name}.py"
with open(file_path, 'w', encoding='utf-8') as f:
f.write(code)
print(f"Skill代码已生成并保存至: {file_path}")
# 更新Skill元数据到数据库(需要调用storage模块)
# self._register_skill_to_db(skill_name, description, str(file_path))
return file_path
except Exception as e:
print(f"Skill代码生成失败: {e}")
return None
4.5 集成到WorkBuddy主循环
最后,需要在WorkBuddy的主应用文件中,初始化MemOS组件,并挂载钩子。
6. 在主应用中的集成示例 ( app.py 或 main.py )
# 假设这是你的WorkBuddy主文件
from workbuddy_memos.storage import MemoryStorage
from workbuddy_memos.memory_generator import MemoryGenerator
from workbuddy_memos.reflection_engine import ReflectionEngine
from workbuddy_memos.skill_creator import SkillCreator
import openai
import asyncio
# 初始化组件
openai_client = openai.OpenAI(api_key="your-api-key")
memory_storage = MemoryStorage()
memory_gen = MemoryGenerator(llm_client=openai_client)
reflection_engine = ReflectionEngine(memory_storage, openai_client)
skill_creator = SkillCreator(code_llm_client=openai_client)
# 启动定期反思(例如每12小时一次)
reflection_engine.start_periodic_reflection(interval_hours=12)
# 假设WorkBuddy有一个处理用户请求的核心异步函数
async def handle_user_request(user_input: str, context: dict):
"""
WorkBuddy原有的任务处理函数
"""
# 1. 【决策前钩子】检索相关记忆
related_memories = memory_storage.retrieve_related_memories(user_input, n_results=3)
enhanced_prompt = build_prompt_with_memories(user_input, related_memories)
# 2. WorkBuddy原有逻辑:LLM规划,选择并执行Skill...
# 假设这里调用某个Skill,得到结果
skill_result = await execute_skill(skill_name, params)
# 3. 【动作后钩子】生成并存储记忆
event_data = {
"user_input": user_input,
"skill_name": skill_name,
"skill_id": get_skill_id(skill_name),
"task_id": context.get("task_id"),
"result": skill_result,
"success": is_success(skill_result)
}
memory_fragment = memory_gen.generate_from_event("skill_execution", event_data)
memory_storage.store_memory(memory_fragment)
# 4. 【事件触发反思】如果结果失败或用户反馈差,立即触发反思
if not event_data["success"] or context.get("negative_feedback"):
reflection_engine.trigger_immediate_reflection(event_data)
return skill_result
def build_prompt_with_memories(user_input: str, memories: list) -> str:
"""将检索到的记忆构建成提示词的一部分"""
memory_context = "\n".join([f"- {m['content']}" for m in memories[:3]]) # 取前3条
base_system_prompt = "你是一个有帮助的AI助手..."
enhanced_system_prompt = f"""{base_system_prompt}
以下是你过去的相关经验(记忆),供本次决策参考:
{memory_context}
请基于以上经验和当前请求,做出最佳回应。"""
return enhanced_system_prompt
至此,一个具备记忆存储、检索、反思和Skill生成能力的MemOS就初步集成到WorkBuddy中了。启动你的WorkBuddy,它现在不仅能记住过去,还能从中学习并创造未来。
5. 核心问题排查与优化经验
在实际搭建和运行这套系统的过程中,我遇到了不少坑,也总结出一些优化经验。这里分享几个最关键的问题和解决方案。
5.1 记忆检索不准或速度慢
- 问题现象 :Agent决策时,检索到的记忆与当前任务无关,或者检索过程明显拖慢了响应速度。
- 排查与解决 :
- 检查嵌入模型 :语义搜索不准,首先怀疑嵌入模型。对于中文场景,
text-embedding-3-small对英文优化更好,可以尝试专门的中文嵌入模型,如BAAI/bge-large-zh-v1.5。用一组已知相关的query-doc对测试不同模型的检索命中率。 - 优化记忆片段质量 :垃圾进,垃圾出。如果存储的是原始冗长的日志,检索效果必然差。 务必强化“记忆生成器”的提炼能力 。我后来改进了提示词,要求LLM必须提取“动作主体、对象、结果状态和关键参数”,形成标准化更高的记忆文本,检索准确率提升了约40%。
- 调整检索策略 :单纯靠向量相似度可能不够。我引入了 混合检索 :先用关键词(从记忆标签和任务描述中提取)在关系数据库里做一次筛选,缩小范围,再用向量相似度在这个子集里精搜。这既提高了相关性,也加快了速度。
- 限制检索数量 :不要一次性检索太多条记忆。对于大多数任务,3-5条最相关的记忆已经足够。在
retrieve_related_memories函数中,n_results参数从默认的10调到了4,响应速度有可感知的提升。 - 向量索引优化 :如果记忆量非常大(>10万条),需要考虑使用支持更高效索引的向量数据库,如Qdrant的HNSW索引,并确保数据持久化到SSD硬盘。
- 检查嵌入模型 :语义搜索不准,首先怀疑嵌入模型。对于中文场景,
5.2 反思报告空洞或无法生成可行提案
- 问题现象 :定期反思运行了,但生成的报告都是“未发现明显模式”、“一切正常”之类的空话,或者提出的Skill提案天马行空,无法实现。
- 排查与解决 :
- 提供更丰富的上下文 :反思LLM不能只给记忆文本。我修改了
_run_reflection方法,在提示词中额外提供了:- 现有Skill的清单和功能描述。
- 近期用户请求的原始文本样本(而不仅是记忆摘要)。
- 历史上成功创建的Skill案例作为参考。 这给了LLM一个更全面的“视野”来做分析。
- 设计更结构化的反思流程 :将单一的反思提示拆分成多步链式思考(Chain-of-Thought)。例如:
- 第一步:总结归纳 。要求LLM先将近期记忆分类(如:文件操作、信息查询、数据整理等)。
- 第二步:模式识别 。针对每一类,找出重复的请求、共同的痛点或成功的模式。
- 第三步:提案生成 。基于第二步的发现,结合现有Skill库,提出具体、可行的新建或优化提案。 通过分步引导,LLM的思考更聚焦,输出质量显著提高。
- 设置提案可行性过滤器 :在
skill_creator接收到提案后,增加一个“可行性评估”步骤。用一个简单的规则引擎或另一个LLM调用来判断:这个提案需要的API或数据是否可获取?实现复杂度是否过高?如果评估不通过,则打回反思引擎重新生成,或标记为“需人工审核”。 - 人工反馈循环 :初期,系统生成的Skill代码不可能完美。我建立了一个简单的审核界面,所有自动生成的Skill都处于“未激活”状态。我会快速浏览代码,进行简单修正或直接批准。系统会记录我的审核动作(批准/驳回/修改),这些反馈本身又作为新的记忆存入系统,用于训练反思引擎的未来判断,形成一个持续改进的闭环。
- 提供更丰富的上下文 :反思LLM不能只给记忆文本。我修改了
5.3 系统资源占用与成本控制
- 问题现象 :MemOS运行后,WorkBuddy内存占用变大,响应变慢,且API调用费用(尤其是GPT-4)增长较快。
- 排查与解决 :
- 记忆存储优化 :
- 设置记忆过期与降级 :不是所有记忆都需要永久保存。我实现了策略:短期记忆(向量库)只保留最近30天的;30天以上的记忆,仅将其摘要文本存入关系数据库长期存档,并从向量库中删除以节省空间和检索开销。
- 记忆去重 :在存储前,计算新记忆与已有记忆的向量相似度。如果相似度超过一个阈值(如0.95),则视为重复记忆,只更新原有记忆的时间戳和关联信息,而非新增一条。
- LLM调用优化 :
- 分级模型使用 :严格贯彻“轻活用小模型,重活用大模型”的原则。记忆提炼、简单的文本处理用GPT-3.5-Turbo;核心任务规划用Claude 3 Haiku或同等模型;只有深度反思和Skill生成才调用GPT-4或Claude 3.5 Sonnet。
- 反思任务合并 :将一些低优先级的反思分析合并执行,而不是一有事件就触发。例如,收集一段时间内的用户负面反馈,集中进行一次分析。
- 缓存嵌入结果 :对于常见的查询关键词或固定的系统提示词部分,其嵌入向量是固定的。可以将这些向量的计算结果缓存起来,避免重复调用嵌入模型API。
- 异步与非阻塞设计 :记忆存储、反思分析、Skill生成这些后台任务, 绝对不能阻塞主Agent的同步响应 。务必使用异步(
asyncio)或消息队列(如Celery)将这些耗时操作放到后台线程或进程中执行。确保用户请求的响应路径是快速的。
- 记忆存储优化 :
5.4 生成的Skill代码质量不稳定
- 问题现象 :
SkillCreator生成的代码有时语法错误,有时逻辑混乱,无法直接运行。 - 排查与解决 :
- 提供更详细的Skill模板和规范 :在给代码生成LLM的提示词中,提供1-2个写得非常好的现有Skill作为“范例”(Few-shot Learning)。明确列出代码风格、错误处理、日志记录等要求。
- 引入静态代码分析 :生成代码后,自动调用
py_compile或ast模块进行简单的语法检查。如果语法错误,则尝试让LLM重新生成,或直接标记为失败,等待人工处理。 - 分步生成 :对于复杂Skill,不要指望一步到位。我改进了生成流程:
- 第一步:生成设计稿 。先让LLM输出函数签名、输入输出格式、以及主要步骤的伪代码。
- 第二步:人工/自动审核设计稿 。确认设计合理。
- 第三步:根据审核后的设计稿生成完整代码 。 虽然多了一步,但成功率大幅提高。
- 建立Skill测试套件 :为生成的Skill自动创建一个简单的单元测试脚本,测试其基本功能。如果测试不通过,则代码不予激活。这能过滤掉大部分有严重逻辑缺陷的Skill。
6. 效果评估与未来演进方向
经过几周的运行和迭代,这个为WorkBuddy添加的“记忆操作系统”已经展现出明显的价值。
最直观的效果 是任务处理的 上下文连贯性 大大增强。当我第二次说“把那个文件像上次一样整理好”时,WorkBuddy能准确地回忆起上周我是如何定义“整理好”的(特定格式、保存路径等),并执行相同的操作。 决策质量 也提升了,尤其是在复杂任务规划时,它能借鉴过去的成功或失败经验,选择更可靠的Skill组合。
进化的萌芽 已经出现。系统在运行一周后,通过反思我频繁进行的“从网页抓取数据并制表”的操作,自动生成了一个名为 web_scrape_to_table 的新Skill提案。我审核后稍作修改便激活了它,现在这个任务从过去需要手动组合3个步骤,变成了一个指令直接完成。
当然,这套系统还处于早期阶段。我规划了几个未来的演进方向:
- 记忆的关联与图谱化 :目前的记忆还是孤立的片段。下一步是建立记忆之间的关联,形成知识图谱。例如,记忆A(学习Python装饰器)和记忆B(使用装饰器优化Skill)应该被关联起来。这样,当遇到“如何优化Skill性能”的问题时,系统能沿着图谱找到更根本的知识点。
- 个性化与用户建模 :MemOS目前主要记忆“事”,未来可以更主动地记忆“人”。通过分析历史交互,逐渐构建用户画像:偏好什么沟通风格?通常在什么时间处理什么类型的任务?对哪些错误容忍度低?基于这些画像,Agent可以提供更个性化的服务。
- 多模态记忆扩展 :当前的记忆主要是文本。如果WorkBuddy接入了图像识别、语音处理等能力,那么MemOS也需要支持存储和检索图像特征向量、音频片段等,实现真正的多模态记忆和联想。
- 安全的进化与伦理边界 :自我进化是一把双刃剑。必须设置安全围栏。例如,任何涉及外部网络访问、文件删除、敏感信息处理的Skill生成,都必须经过严格的人工审核。需要建立一个“Skill安全策略”模型,自动评估新Skill的潜在风险。
给AI Agent装上记忆和进化的能力,不再是遥不可及的研究课题,而是可以通过工程化落地的实践。这套MemOS的实现,就像为WorkBuddy点亮了一盏通往更智能、更自主未来的灯。虽然过程中调试提示词、处理边界情况颇费周折,但看到它开始“记住”并“学习”的那一刻,感觉所有努力都值了。如果你也在构建或使用AI Agent,不妨从为一个核心动作添加记忆开始,亲手感受一下智能体“活”起来的过程。
更多推荐


所有评论(0)