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系统的设计,将记忆分为三个层级:

  1. 瞬时记忆(Working Memory) :对应LLM的上下文窗口。它处理当前对话回合的输入、思考链(Chain-of-Thought)和即时输出。这部分是“思考的草稿纸”,速度快但容量有限。我的设计是,在每次Agent运行结束时,自动将本轮对话中的关键决策点、执行结果和用户反馈,从“瞬时记忆”中提炼出来,准备存入长期记忆。

  2. 短期记忆(Short-term Memory) :存储近期(如过去几天)的高频、高相关性记忆片段。我使用向量数据库(如Chroma或Qdrant)来实现。每一段记忆(例如:“用户要求将‘月度报告.pdf’转换为Markdown格式,我成功调用了‘pdf_to_md’这个Skill完成”)会被转换成一个文本片段,并通过嵌入模型(Embedding Model)转化为向量。向量数据库支持基于语义相似度的快速检索。当新任务到来时,系统会从短期记忆中检索出最相关的几条记忆,作为上下文提供给LLM,帮助它做出更相关的决策。

  3. 长期记忆(Long-term Memory) :存储重要的经验、提炼出的知识、以及Agent自己创造的资产(如Skill代码)。这部分使用传统的关系型数据库(如SQLite或PostgreSQL)和文件系统。关系库用于存储记忆的元数据(ID、类型、创建时间、关联标签等),而具体的知识内容或Skill代码则以文本或文件形式存储。长期记忆的关键在于“摘要”和“索引”。系统会定期(或触发式)对短期记忆中的相关片段进行总结,形成更高阶的“经验知识”(例如:“用户通常在周一上午需要处理文档格式转换”),并存入长期记忆。同时,所有记忆都通过关键词和语义标签进行索引,方便多维度检索。

注意 :记忆的存储不是单向的。一个高效的MemOS需要设计记忆的“激活”机制。当处理任务时,系统首先从长期记忆中通过关键词召回一批相关记忆,再用这些记忆的摘要去向量库做更精细的语义检索,最后将最相关的几条记忆与瞬时记忆结合。这模仿了人类的记忆唤醒过程。

2.2 记忆的生成、索引与检索流程

记忆不是被动存储的,而是主动生成的。我设计了一个“记忆生成器”模块,它作为WorkBuddy Action的一个环节,在每次任务循环结束后被调用。其工作流程如下:

  1. 事件捕获 :监听Agent的核心事件,如“Skill执行完成”、“用户给出明确反馈(好评/差评)”、“任务成功/失败”、“出现了需要总结的复杂情况”。
  2. 内容提炼 :对于捕获的事件,不是原始日志全存。我编写了提炼提示词,让一个小型LLM(如GPT-3.5-Turbo或本地轻量模型)对事件进行总结,生成结构化的记忆片段。例如,输入原始日志:“调用天气查询Skill,参数{city: ‘北京’},返回成功,气温22度。” 提炼后记忆:“成功执行‘天气查询’技能,用户询问了北京天气,结果正常。关联标签:#天气 #查询 #成功”。
  3. 向量化与存储 :将提炼后的记忆文本,通过嵌入模型(我选用 text-embedding-3-small ,平衡效果与成本)转化为向量,并存入向量数据库(短期记忆)。同时,将记忆文本、元数据(类型、时间戳、关联的Skill ID、任务ID)和向量ID的映射关系,存入关系数据库(长期记忆索引)。
  4. 检索策略 :当新任务到来时,“记忆检索器”模块开始工作。首先,它解析当前任务描述和上下文,生成一组关键词。用这些关键词在关系数据库中进行初步筛选。然后,将当前任务描述也向量化,用这个向量去向量数据库中执行相似度搜索(通常用余弦相似度),找出最相关的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):

  1. Post-Action Hook(动作后钩子) :在每个Skill执行完成后,无论成功与否,自动触发“记忆生成器”,将本次执行的关键信息提炼存储。
  2. Pre-Decision Hook(决策前钩子) :在主LLM进行任务规划或Skill选择之前,先调用“记忆检索器”,获取与当前任务相关的历史记忆,并将其作为系统提示词的一部分附加进去,让LLM做出更明智的决策。
  3. Scheduler(调度器) :引入一个轻量级后台调度(如使用 apscheduler 库),定时触发“定期反思”任务。
  4. 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决策时,检索到的记忆与当前任务无关,或者检索过程明显拖慢了响应速度。
  • 排查与解决
    1. 检查嵌入模型 :语义搜索不准,首先怀疑嵌入模型。对于中文场景, text-embedding-3-small 对英文优化更好,可以尝试专门的中文嵌入模型,如 BAAI/bge-large-zh-v1.5 。用一组已知相关的query-doc对测试不同模型的检索命中率。
    2. 优化记忆片段质量 :垃圾进,垃圾出。如果存储的是原始冗长的日志,检索效果必然差。 务必强化“记忆生成器”的提炼能力 。我后来改进了提示词,要求LLM必须提取“动作主体、对象、结果状态和关键参数”,形成标准化更高的记忆文本,检索准确率提升了约40%。
    3. 调整检索策略 :单纯靠向量相似度可能不够。我引入了 混合检索 :先用关键词(从记忆标签和任务描述中提取)在关系数据库里做一次筛选,缩小范围,再用向量相似度在这个子集里精搜。这既提高了相关性,也加快了速度。
    4. 限制检索数量 :不要一次性检索太多条记忆。对于大多数任务,3-5条最相关的记忆已经足够。在 retrieve_related_memories 函数中, n_results 参数从默认的10调到了4,响应速度有可感知的提升。
    5. 向量索引优化 :如果记忆量非常大(>10万条),需要考虑使用支持更高效索引的向量数据库,如Qdrant的HNSW索引,并确保数据持久化到SSD硬盘。

5.2 反思报告空洞或无法生成可行提案

  • 问题现象 :定期反思运行了,但生成的报告都是“未发现明显模式”、“一切正常”之类的空话,或者提出的Skill提案天马行空,无法实现。
  • 排查与解决
    1. 提供更丰富的上下文 :反思LLM不能只给记忆文本。我修改了 _run_reflection 方法,在提示词中额外提供了:
      • 现有Skill的清单和功能描述。
      • 近期用户请求的原始文本样本(而不仅是记忆摘要)。
      • 历史上成功创建的Skill案例作为参考。 这给了LLM一个更全面的“视野”来做分析。
    2. 设计更结构化的反思流程 :将单一的反思提示拆分成多步链式思考(Chain-of-Thought)。例如:
      • 第一步:总结归纳 。要求LLM先将近期记忆分类(如:文件操作、信息查询、数据整理等)。
      • 第二步:模式识别 。针对每一类,找出重复的请求、共同的痛点或成功的模式。
      • 第三步:提案生成 。基于第二步的发现,结合现有Skill库,提出具体、可行的新建或优化提案。 通过分步引导,LLM的思考更聚焦,输出质量显著提高。
    3. 设置提案可行性过滤器 :在 skill_creator 接收到提案后,增加一个“可行性评估”步骤。用一个简单的规则引擎或另一个LLM调用来判断:这个提案需要的API或数据是否可获取?实现复杂度是否过高?如果评估不通过,则打回反思引擎重新生成,或标记为“需人工审核”。
    4. 人工反馈循环 :初期,系统生成的Skill代码不可能完美。我建立了一个简单的审核界面,所有自动生成的Skill都处于“未激活”状态。我会快速浏览代码,进行简单修正或直接批准。系统会记录我的审核动作(批准/驳回/修改),这些反馈本身又作为新的记忆存入系统,用于训练反思引擎的未来判断,形成一个持续改进的闭环。

5.3 系统资源占用与成本控制

  • 问题现象 :MemOS运行后,WorkBuddy内存占用变大,响应变慢,且API调用费用(尤其是GPT-4)增长较快。
  • 排查与解决
    1. 记忆存储优化
      • 设置记忆过期与降级 :不是所有记忆都需要永久保存。我实现了策略:短期记忆(向量库)只保留最近30天的;30天以上的记忆,仅将其摘要文本存入关系数据库长期存档,并从向量库中删除以节省空间和检索开销。
      • 记忆去重 :在存储前,计算新记忆与已有记忆的向量相似度。如果相似度超过一个阈值(如0.95),则视为重复记忆,只更新原有记忆的时间戳和关联信息,而非新增一条。
    2. LLM调用优化
      • 分级模型使用 :严格贯彻“轻活用小模型,重活用大模型”的原则。记忆提炼、简单的文本处理用GPT-3.5-Turbo;核心任务规划用Claude 3 Haiku或同等模型;只有深度反思和Skill生成才调用GPT-4或Claude 3.5 Sonnet。
      • 反思任务合并 :将一些低优先级的反思分析合并执行,而不是一有事件就触发。例如,收集一段时间内的用户负面反馈,集中进行一次分析。
      • 缓存嵌入结果 :对于常见的查询关键词或固定的系统提示词部分,其嵌入向量是固定的。可以将这些向量的计算结果缓存起来,避免重复调用嵌入模型API。
    3. 异步与非阻塞设计 :记忆存储、反思分析、Skill生成这些后台任务, 绝对不能阻塞主Agent的同步响应 。务必使用异步( asyncio )或消息队列(如 Celery )将这些耗时操作放到后台线程或进程中执行。确保用户请求的响应路径是快速的。

5.4 生成的Skill代码质量不稳定

  • 问题现象 SkillCreator 生成的代码有时语法错误,有时逻辑混乱,无法直接运行。
  • 排查与解决
    1. 提供更详细的Skill模板和规范 :在给代码生成LLM的提示词中,提供1-2个写得非常好的现有Skill作为“范例”(Few-shot Learning)。明确列出代码风格、错误处理、日志记录等要求。
    2. 引入静态代码分析 :生成代码后,自动调用 py_compile ast 模块进行简单的语法检查。如果语法错误,则尝试让LLM重新生成,或直接标记为失败,等待人工处理。
    3. 分步生成 :对于复杂Skill,不要指望一步到位。我改进了生成流程:
      • 第一步:生成设计稿 。先让LLM输出函数签名、输入输出格式、以及主要步骤的伪代码。
      • 第二步:人工/自动审核设计稿 。确认设计合理。
      • 第三步:根据审核后的设计稿生成完整代码 。 虽然多了一步,但成功率大幅提高。
    4. 建立Skill测试套件 :为生成的Skill自动创建一个简单的单元测试脚本,测试其基本功能。如果测试不通过,则代码不予激活。这能过滤掉大部分有严重逻辑缺陷的Skill。

6. 效果评估与未来演进方向

经过几周的运行和迭代,这个为WorkBuddy添加的“记忆操作系统”已经展现出明显的价值。

最直观的效果 是任务处理的 上下文连贯性 大大增强。当我第二次说“把那个文件像上次一样整理好”时,WorkBuddy能准确地回忆起上周我是如何定义“整理好”的(特定格式、保存路径等),并执行相同的操作。 决策质量 也提升了,尤其是在复杂任务规划时,它能借鉴过去的成功或失败经验,选择更可靠的Skill组合。

进化的萌芽 已经出现。系统在运行一周后,通过反思我频繁进行的“从网页抓取数据并制表”的操作,自动生成了一个名为 web_scrape_to_table 的新Skill提案。我审核后稍作修改便激活了它,现在这个任务从过去需要手动组合3个步骤,变成了一个指令直接完成。

当然,这套系统还处于早期阶段。我规划了几个未来的演进方向:

  1. 记忆的关联与图谱化 :目前的记忆还是孤立的片段。下一步是建立记忆之间的关联,形成知识图谱。例如,记忆A(学习Python装饰器)和记忆B(使用装饰器优化Skill)应该被关联起来。这样,当遇到“如何优化Skill性能”的问题时,系统能沿着图谱找到更根本的知识点。
  2. 个性化与用户建模 :MemOS目前主要记忆“事”,未来可以更主动地记忆“人”。通过分析历史交互,逐渐构建用户画像:偏好什么沟通风格?通常在什么时间处理什么类型的任务?对哪些错误容忍度低?基于这些画像,Agent可以提供更个性化的服务。
  3. 多模态记忆扩展 :当前的记忆主要是文本。如果WorkBuddy接入了图像识别、语音处理等能力,那么MemOS也需要支持存储和检索图像特征向量、音频片段等,实现真正的多模态记忆和联想。
  4. 安全的进化与伦理边界 :自我进化是一把双刃剑。必须设置安全围栏。例如,任何涉及外部网络访问、文件删除、敏感信息处理的Skill生成,都必须经过严格的人工审核。需要建立一个“Skill安全策略”模型,自动评估新Skill的潜在风险。

给AI Agent装上记忆和进化的能力,不再是遥不可及的研究课题,而是可以通过工程化落地的实践。这套MemOS的实现,就像为WorkBuddy点亮了一盏通往更智能、更自主未来的灯。虽然过程中调试提示词、处理边界情况颇费周折,但看到它开始“记住”并“学习”的那一刻,感觉所有努力都值了。如果你也在构建或使用AI Agent,不妨从为一个核心动作添加记忆开始,亲手感受一下智能体“活”起来的过程。

更多推荐