在构建智能体(Agent)应用时,一个核心的痛点日益凸显:如何让AI记住与用户的每一次对话、每一次交互,并在后续的交流中灵活调用这些“记忆”,从而实现真正连贯、个性化的智能体验?传统的会话管理往往局限于单次对话的上下文窗口,一旦对话结束,AI便“失忆”了。今天,我们将深入探讨一个由OpenAI创始人Sam Altman投资、旨在解决这一难题的开源项目—— Cognee 。本文将带你从零开始,全面解析Cognee的核心概念、架构设计,并通过一个完整的实战案例,手把手教你如何为你的AI应用装上“长期记忆”。

1. 背景与核心概念:为什么AI需要记忆?

在深入Cognee之前,我们首先要理解“AI记忆”的必要性。当前主流的大语言模型(LLM)应用,无论是基于OpenAI API还是开源模型,其交互模式大多是“无状态”的。这意味着:

  • 上下文限制 :模型只能处理有限长度的提示词(Prompt),超出部分会被截断。
  • 会话隔离 :每次对话都是全新的开始,模型无法记住用户的历史偏好、习惯或之前讨论的细节。
  • 个性化缺失 :无法基于用户的长期行为数据提供定制化的回复或服务。

这严重限制了AI助手、客服机器人、个性化推荐系统等应用的深度和用户体验。 Cognee 应运而生,它将自己定位为一个 “AI记忆层” 或“长期记忆系统”。其核心目标是:为任何AI应用(尤其是基于LLM的智能体)提供一个统一、可扩展的框架,用于存储、检索和管理与实体(如用户、文档、会话)相关的长期记忆。

简单来说,Cognee就像是为你的AI大脑外接了一个“海马体”(大脑中负责记忆的区域)。它不替代LLM的推理能力,而是为其提供持久化的“经验”数据,让AI能够进行基于上下文的、连贯的、个性化的思考与回应。

2. Cognee 核心架构与工作原理

Cognee并非一个简单的键值存储数据库。它是一个精心设计的系统,其架构融合了现代AI工程的最佳实践。理解其架构是有效使用它的关键。

2.1 核心组件

Cognee的架构主要包含以下几个层次:

  1. 记忆存储(Memory Storage)

    • 功能 :持久化保存记忆数据。Cognee支持多种后端,包括本地文件系统、矢量数据库(如Chroma, Weaviate, Pinecone)、关系型数据库等。
    • 类比 :相当于计算机的硬盘,负责数据的长期存放。
  2. 记忆处理与索引(Memory Processing & Indexing)

    • 功能 :这是Cognee的“智能”所在。它使用嵌入模型(Embedding Model)将文本记忆转换为高维向量(Vector),并建立向量索引。同时,它可能对记忆进行结构化处理(如提取实体、关系、摘要)。
    • 类比 :相当于图书馆的编目系统,不仅藏书,还为每本书建立索引卡片(向量),方便快速查找。
  3. 记忆检索(Memory Retrieval)

    • 功能 :根据当前查询(用户问题或上下文),从记忆库中找出最相关的记忆片段。通常采用 语义搜索 (基于向量相似度)和/或 关键词搜索 相结合的方式。
    • 类比 :当你询问一个复杂问题时,图书管理员根据你的问题,从编目系统中找出最相关的几本书或章节。
  4. API与集成层(API & Integration Layer)

    • 功能 :提供简洁的编程接口(如Python SDK),让开发者能够轻松地“添加记忆”和“读取记忆”。它天然与LangChain、LlamaIndex等主流AI框架集成。
    • 类比 :图书馆的借阅台,提供标准的借书、还书服务接口。

2.2 工作流程

一个典型的使用Cognee的AI应用工作流程如下:

  1. 记忆创建 :当用户与AI交互产生有价值的信息时(例如,用户说“我喜欢科幻小说,尤其是《三体》”),应用调用Cognee API,将该信息作为一条“记忆”存储起来,并与用户ID关联。
  2. 记忆处理 :Cognee在后台使用嵌入模型将该文本转化为向量,并存入指定的矢量数据库。
  3. 记忆检索 :当用户再次发起对话(例如,问“有什么新书推荐吗?”),应用首先将当前问题(或结合对话历史)发送给Cognee进行检索。
  4. 上下文增强 :Cognee返回与当前问题最相关的几条历史记忆(如“用户喜欢科幻小说”)。这些记忆被拼接到原始的LLM提示词中,形成最终的、富含上下文的提示。
  5. LLM生成 :增强后的提示被发送给LLM(如GPT-4、Claude或本地模型),LLM基于包含用户长期偏好的上下文,生成个性化回复(“鉴于您喜欢《三体》,我推荐《银河帝国》系列…”)。

这个过程实现了AI的“记忆-回忆-应用”循环。

3. 环境准备与项目搭建

接下来,我们将通过一个实战项目来演示Cognee的使用。我们将构建一个简单的“个性化读书助手”智能体,它能记住用户喜欢的书籍类型和作者,并在后续聊天中进行推荐。

3.1 技术栈与版本说明

  • Python : 3.9+
  • 核心库 :
    • cognee : Cognee核心库(请关注其GitHub仓库获取最新版本,本文基于其早期公开API概念演示)。
    • langchain : 用于构建智能体链。版本 0.1.x
    • openai : OpenAI官方SDK(用于调用GPT模型)。如果你使用其他模型,可替换为相应SDK。
    • chromadb : 轻量级矢量数据库,作为Cognee的记忆存储后端。
  • IDE : 任意你喜欢的代码编辑器,如VSCode、PyCharm。
  • 虚拟环境 : 强烈建议使用 venv conda 创建隔离环境。

重要提示 :Cognee是一个快速迭代的开源项目,其API可能发生变化。以下示例代码旨在阐述核心概念和集成模式,实际使用时请务必参考其官方文档。

3.2 初始化项目与安装依赖

首先,创建项目目录并初始化虚拟环境。

# 创建项目目录
mkdir personalized-reading-assistant
cd personalized-reading-assistant

# 创建虚拟环境(以venv为例)
python -m venv venv

# 激活虚拟环境
# Windows:
venv\Scripts\activate
# Linux/Mac:
source venv/bin/activate

# 安装核心依赖
pip install langchain langchain-openai chromadb
# 注意:Cognee可能尚未发布到PyPI,或其包名有变。此处假设可通过pip安装其核心功能。
# 实际安装命令请以官方仓库为准,例如:pip install git+https://github.com/cognee-api/cognee.git
pip install cognee 

创建项目结构:

personalized-reading-assistant/
├── main.py          # 主程序入口
├── memory_system.py # 封装Cognee记忆操作
├── agent.py         # 定义LangChain智能体
└── requirements.txt

将依赖写入 requirements.txt :

langchain>=0.1.0
langchain-openai>=0.0.5
chromadb>=0.4.22
openai>=1.12.0
cognee>=0.1.0  # 请替换为实际版本

4. 实战:构建带记忆的个性化读书助手

4.1 步骤一:配置Cognee记忆系统

我们首先创建一个模块来初始化和封装Cognee的记忆操作。

# memory_system.py
import os
from typing import List, Optional, Dict, Any
# 假设Cognee提供类似的API,这里根据其设计模式进行示意性编写
from cognee import CognitiveMemory  # 示意类名
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

class MemorySystem:
    """
    封装Cognee记忆系统的类。
    负责记忆的存储、检索和与矢量数据库的交互。
    """
    def __init__(self, user_id: str, persist_directory: str = "./chroma_db"):
        """
        初始化记忆系统。
        Args:
            user_id: 唯一用户标识,用于隔离不同用户的记忆。
            persist_directory: Chroma向量数据库持久化目录。
        """
        self.user_id = user_id
        self.persist_directory = os.path.join(persist_directory, user_id)
        os.makedirs(self.persist_directory, exist_ok=True)
        
        # 初始化嵌入模型(用于将文本转为向量)
        # 注意:你需要设置OPENAI_API_KEY环境变量
        self.embedding_function = OpenAIEmbeddings(model="text-embedding-3-small")
        
        # 初始化向量数据库(Chroma作为后端)
        self.vectorstore = Chroma(
            collection_name=f"user_memories_{user_id}",
            embedding_function=self.embedding_function,
            persist_directory=self.persist_directory
        )
        
        # 初始化Cognee记忆核心(示意)
        # 这里将向量存储传递给Cognee,由它来管理记忆的增删改查逻辑
        self.memory_engine = CognitiveMemory(vector_store=self.vectorstore)
        print(f"记忆系统已为用户 {user_id} 初始化。")
    
    def add_memory(self, memory_text: str, metadata: Optional[Dict] = None):
        """
        添加一条文本记忆。
        Args:
            memory_text: 需要记住的文本信息。
            metadata: 额外的元数据,如记忆类型、时间戳等。
        """
        if metadata is None:
            metadata = {}
        metadata.update({"user_id": self.user_id, "type": "preference"})
        
        # 示意:Cognee引擎处理记忆(如生成摘要、提取关键词、创建向量等)
        processed_memory = self.memory_engine.process_and_store(
            content=memory_text,
            metadata=metadata
        )
        print(f"记忆已添加: {memory_text[:50]}...")
        return processed_memory
    
    def search_memories(self, query: str, k: int = 3) -> List[str]:
        """
        根据查询搜索相关记忆。
        Args:
            query: 搜索查询文本。
            k: 返回最相关的记忆条数。
        Returns:
            相关记忆文本的列表。
        """
        # 使用向量数据库进行语义搜索
        docs = self.vectorstore.similarity_search(query, k=k)
        memories = [doc.page_content for doc in docs]
        return memories
    
    def get_user_profile(self) -> str:
        """
        获取用户的记忆摘要,形成简易“用户画像”。
        在实际项目中,这里可以调用LLM对记忆进行总结。
        """
        # 简单返回最近或最核心的几条记忆
        all_docs = self.vectorstore.get() # 示意,实际API可能不同
        if not all_docs.get('documents'):
            return "该用户尚未提供任何偏好信息。"
        
        # 这里简化处理:拼接最近几条记忆
        profile_snippets = all_docs['documents'][:5]
        profile = " | ".join(profile_snippets)
        return f"已知用户偏好:{profile}"

4.2 步骤二:创建LangChain智能体

接下来,我们创建一个LangChain智能体,它将集成记忆系统,并在生成回复前动态检索相关记忆。

# agent.py
from langchain.agents import Tool, AgentExecutor, create_react_agent
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from memory_system import MemorySystem
from langchain.memory import ConversationBufferMemory
from langchain.tools import BaseTool
from typing import Type

class MemorySearchTool(BaseTool):
    """一个自定义LangChain工具,用于搜索用户记忆。"""
    name = "search_user_memory"
    description = "当需要根据用户的长期偏好或历史信息来回答问题或进行推荐时,使用此工具。输入应是一个描述当前需求或问题的查询语句。"
    memory_system: MemorySystem = None
    
    def _run(self, query: str) -> str:
        """执行工具。"""
        if not self.memory_system:
            return "记忆系统未初始化。"
        memories = self.memory_system.search_memories(query, k=3)
        if memories:
            return "\n".join([f"- {m}" for m in memories])
        else:
            return "未找到相关的历史记忆。"
    
    async def _arun(self, query: str) -> str:
        """异步执行(暂不实现)。"""
        raise NotImplementedError("此工具不支持异步。")

def create_personal_agent(user_id: str):
    """
    创建个性化智能体。
    Args:
        user_id: 用户ID,用于关联其专属记忆。
    Returns:
        配置好的智能体执行器。
    """
    # 1. 初始化记忆系统
    memory_sys = MemorySystem(user_id=user_id)
    
    # 2. 初始化LLM
    llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
    
    # 3. 创建记忆搜索工具,并注入记忆系统实例
    memory_tool = MemorySearchTool()
    memory_tool.memory_system = memory_sys
    
    # 4. 定义其他可能用到的工具(示例)
    # 例如,一个获取当前流行书籍的工具(这里用模拟工具)
    from langchain.tools import tool
    @tool
    def get_trending_books(genre: str) -> str:
        """获取某个类型的流行书籍列表。输入应为书籍类型,如‘科幻’、‘历史’。"""
        # 这里应该是调用真实API,我们模拟返回
        mock_data = {
            "科幻": ["《深渊的尽头》", "《星环纪元》", "《仿生人会梦见电子羊吗?》"],
            "历史": ["《明朝那些事儿》", "《人类群星闪耀时》", "《丝绸之路》"]
        }
        return ", ".join(mock_data.get(genre, ["暂无数据"]))
    
    # 工具列表
    tools = [memory_tool, get_trending_books]
    
    # 5. 创建智能体提示词模板
    # 这个模板指导智能体何时使用工具,并融入记忆信息
    prompt = PromptTemplate.from_template("""
    你是一个个性化的读书助手,专门为用户{user_id}服务。
    你的目标是利用你对用户的了解(他们的偏好、历史对话)来提供最贴切的推荐和帮助。
    
    你拥有以下工具:
    {tools}
    
    在回答用户问题时,请遵循以下步骤:
    1. 首先,思考用户的问题是否需要参考他的长期记忆(比如他过去喜欢什么书、讨厌什么作者)。
    2. 如果需要,使用`search_user_memory`工具,输入一个能概括当前需求的查询词(例如:“用户喜欢的书籍类型”、“用户讨厌的作者”)。
    3. 根据工具返回的记忆,结合你的知识和`get_trending_books`工具(如果需要当前流行信息),形成最终回答。
    4. 如果用户的问题中包含了新的、值得长期记住的偏好(例如:“我其实更喜欢悬疑小说了”),请在你的回答中确认这一点,并**在回答结束后,单独用一行输出以下格式的命令,以便系统记录**:
       `[MEMORY_TO_ADD]: 用户的新偏好或事实。`
    
    当前对话历史:
    {chat_history}
    
    用户输入:{input}
    
    开始思考:我应该使用工具吗?如果需要,用哪个?{agent_scratchpad}
    """)
    
    # 6. 创建对话记忆(短期,用于管理当前对话轮次)
    conversation_memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
    
    # 7. 创建智能体并返回执行器
    agent = create_react_agent(llm, tools, prompt)
    agent_executor = AgentExecutor(
        agent=agent,
        tools=tools,
        memory=conversation_memory,
        verbose=True,  # 设置为True可以看到智能体的思考过程,生产环境可设为False
        handle_parsing_errors=True
    )
    
    # 返回执行器和记忆系统(用于主程序添加记忆)
    return agent_executor, memory_sys

4.3 步骤三:主程序与交互循环

最后,我们编写主程序,它将协调智能体对话和记忆的添加。

# main.py
import re
from agent import create_personal_agent

def main():
    print("=== 个性化读书助手(带长期记忆)===")
    user_id = input("请输入您的用户ID(用于加载您的专属记忆): ").strip() or "default_user"
    
    # 创建智能体和记忆系统
    agent_executor, memory_system = create_personal_agent(user_id)
    
    print(f"\n您好,用户 {user_id}!我是您的读书助手。")
    print("我可以记住您喜欢的书籍类型和作者,为您提供个性化推荐。")
    print("输入 '退出' 或 'quit' 来结束对话。\n")
    
    # 初始时,可以尝试获取一次用户画像并显示
    profile = memory_system.get_user_profile()
    print(f"[系统提示] {profile}\n")
    
    while True:
        user_input = input("您: ").strip()
        if user_input.lower() in ['退出', 'quit', 'exit']:
            print("再见!期待下次为您服务。")
            break
        
        try:
            # 运行智能体
            response = agent_executor.invoke({"input": user_input, "user_id": user_id})
            full_response = response["output"]
            
            # 解析响应,检查是否有需要添加的新记忆
            memory_pattern = r'\[MEMORY_TO_ADD\]:\s*(.+)'
            match = re.search(memory_pattern, full_response, re.DOTALL)
            
            if match:
                # 提取出需要添加的记忆文本
                memory_to_add = match.group(1).strip()
                # 从最终回复中移除记忆添加指令行
                final_response = re.sub(memory_pattern, '', full_response).strip()
                # 添加记忆到长期存储
                memory_system.add_memory(memory_to_add, metadata={"source": "conversation"})
                print(f"\n助手: {final_response}")
                print(f"[系统] 已记录新偏好:{memory_to_add}")
            else:
                final_response = full_response
                print(f"\n助手: {final_response}")
                
        except Exception as e:
            print(f"\n助手: 抱歉,处理您的请求时出现了问题。({e})")
        print()  # 空行分隔对话轮次

if __name__ == "__main__":
    main()

5. 运行与效果演示

  1. 首次运行

    python main.py
    

    输入用户ID(例如 alice )。系统会提示没有已知偏好。

  2. 提供偏好

    您: 我喜欢刘慈欣的科幻小说,特别是《三体》。
    

    智能体会正常回复,并因为检测到新偏好,在回复末尾输出 [MEMORY_TO_ADD]: ... 指令。我们的主程序会捕获这个指令,并将其存入Cognee记忆系统。

  3. 基于记忆的推荐

    您: 最近有什么好书推荐吗?
    

    智能体会先调用 search_user_memory 工具,搜索与“推荐好书”相关的记忆。工具会返回“我喜欢刘慈欣的科幻小说...”。智能体结合此记忆和 get_trending_books 工具(获取科幻类流行书),生成一个个性化推荐:“鉴于您喜欢刘慈欣和《三体》,我推荐您关注近期流行的科幻作品《深渊的尽头》和《星环纪元》...”。

  4. 记忆的演进

    您: 其实我最近也对历史传记感兴趣了。
    

    同样,这个新偏好会被识别并存储。

  5. 后续对话 :无论何时,只要对话涉及书籍推荐,智能体都会检索所有相关记忆(科幻、历史传记),提供综合建议。

6. 常见问题与排查思路

在集成Cognee或类似记忆系统时,你可能会遇到以下问题:

问题现象 可能原因 排查思路与解决方案
记忆检索不相关 1. 嵌入模型不匹配或质量差。
2. 记忆文本过于冗长或噪声大。
3. 检索查询(query)构造不佳。
1. 尝试更换或微调嵌入模型(如 text-embedding-3-large )。
2. 在存储记忆前进行预处理:摘要、关键词提取、去噪。
3. 优化查询构造,可以尝试用LLM将用户问题重写为更适合搜索的格式。
记忆添加失败 1. 向量数据库连接错误。
2. Cognee处理过程出错。
3. 元数据格式不符合要求。
1. 检查向量数据库(如Chroma)是否正常运行,路径权限是否正确。
2. 查看Cognee日志或错误信息,确认其API调用方式。
3. 确保传入的metadata是字典格式,且不包含不可序列化的对象。
智能体不调用记忆工具 1. 工具描述(description)不清晰。
2. 提示词(Prompt)未有效引导。
3. LLM温度(temperature)设置过高,导致行为随机。
1. 优化工具的描述,明确其适用场景。
2. 强化提示词中关于“先思考是否需要记忆”的指令。
3. 适当降低LLM的temperature值,使其更遵循指令。
记忆混淆(用户间串扰) 不同用户的记忆存储在同一个集合或未有效隔离。 确保初始化记忆系统时, user_id 被正确使用,并用于隔离向量数据库的集合(Collection)或命名空间(Namespace)。
性能问题 1. 记忆条目过多,检索慢。
2. 嵌入模型推理耗时。
1. 对记忆进行定期归档或摘要,减少活跃记忆数量。实现分页或分层检索。
2. 考虑使用更快的嵌入模型,或对向量索引进行优化(如HNSW参数调整)。

7. 最佳实践与工程建议

将长期记忆系统投入生产环境,需要考虑更多工程细节:

  1. 记忆的粒度与结构

    • 不要存储原始对话日志 :应提取结构化信息(如 (用户, 喜欢, 科幻) )或生成简洁的摘要。
    • 分类存储 :可以为记忆打上类型标签( preference fact goal ),便于分类检索。
    • 关联实体 :记忆不仅关联用户,还可以关联书籍、作者等实体,构建知识图谱。
  2. 记忆的更新与遗忘

    • 实现记忆更新 :用户偏好可能改变。系统应支持用新记忆覆盖或修正旧记忆,或为记忆添加置信度和时间戳,检索时优先考虑新鲜且高置信度的。
    • 设计遗忘机制 :并非所有信息都需要永久记忆。可以设置TTL(生存时间)或基于重要性的遗忘策略。
  3. 隐私与安全

    • 数据加密 :确保存储在向量数据库和磁盘上的记忆数据是加密的。
    • 用户授权 :明确告知用户哪些数据会被记忆,并提供查看、编辑、删除个人记忆的入口。
    • 合规性 :遵循相关数据保护法规(如GDPR)。
  4. 系统可观测性

    • 记录检索日志 :记录每次检索的查询、返回的记忆以及最终LLM的回复,用于分析和优化记忆系统。
    • 监控记忆质量 :定期抽样检查记忆的准确性和相关性。
  5. 与现有架构集成

    • 作为微服务 :可以将Cognee封装成独立的记忆服务,通过gRPC或REST API供多个AI应用调用。
    • 事件驱动 :用户行为事件(如购买、点赞、长时间阅读)可以自动触发记忆的添加或更新。

Cognee代表了一个重要的方向:为AI赋予持续学习和个人化的能力。通过本文的拆解和实战,你应该已经掌握了为其AI应用添加“记忆层”的核心思路与方法。从简单的用户偏好记忆开始,你可以逐步探索更复杂的记忆结构、更高效的检索算法以及与知识图谱的结合,最终打造出真正“懂你”的、具备长期陪伴感的智能应用。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐