基于 FAISS 的 AI 长期记忆系统示例

FAISS(Facebook AI Similarity Search)是 Meta 开源的高性能向量检索库,专为海量高维向量数据的快速近似搜索而设计。基于 FAISS 构建的 AI 长期记忆系统,本质上是为 AI 模型(尤其是大语言模型)提供持久化、可检索的"外部大脑"。

该系统通常采用"向量索引 + 元数据存储"的双存储架构:

  • 向量化(Embedding):利用嵌入模型(如 OpenAI text-embedding-ada-002、Sentence-BERT)将文本、图像等非结构化数据转换为高维向量(例如 1536 维)。
  • 索引构建(Indexing):使用 FAISS 将向量构建成高效的索引结构(如 FlatL2、IVFFlat、HNSW),支持毫秒级近似最近邻(ANN)搜索。
  • 元数据关联:为每个向量附加原始文本、时间戳、来源等元数据(通常存储在 JSON 或 SQLite 中)。
  • 检索增强生成(RAG):当用户提问时,系统将查询文本向量化,通过 FAISS 召回最相关的历史记忆,并将其作为上下文注入 LLM 的 Prompt,实现"记忆唤醒"。

核心优势:

  • 高性能:针对 GPU 和批量查询高度优化,能在百万级向量中实现亚秒级检索。
  • 可扩展性:支持从本地小文件到分布式集群的平滑扩展。
  • 灵活性:提供多种索引算法(精确搜索 vs. 近似搜索)和距离度量(L2、内积、余弦相似度),可根据数据规模和精度需求灵活配置。

典型应用场景:

  • 对话记忆持久化:跨会话记住用户的偏好、习惯和重要对话历史。
  • 知识库问答(KBQA):将企业文档、技术手册向量化,构建私有知识库。
  • 智能助理:实现基于历史交互的个性化推荐和上下文感知服务。

需求分析

本文示例代码实现了一个AI长期记忆系统,其核心需求源于当前AI应用对上下文记忆和历史交互保持能力的迫切需求。随着大型语言模型的普及,人们发现单次会话的AI虽然能提供即时响应,但缺乏持续的学习和记忆能力,导致每次对话都像是"重新开始"。这个记忆系统旨在解决这一痛点,为AI提供类似人类长期记忆的功能,使其能够跨会话保持知识、学习用户偏好、积累经验,从而提供更加个性化、连贯和智能的服务。

具体需求包括:向量化存储和检索技术文档、会议记录、用户交互历史等非结构化信息;支持高效的相似性搜索,快速找到相关历史信息;提供数据持久化机制,确保记忆不因系统重启而丢失;具备可扩展的架构,能够适应不同规模的数据集和多样的应用场景。

设计架构

该系统采用经典的知识库检索架构,以FAISS向量数据库为核心,结合元数据管理实现完整的记忆生命周期管理。系统设计分为三层:存储层使用FAISS索引进行高维向量的高效相似性搜索,这是系统的性能基础;业务层管理记忆的增删改查操作,包括向量的添加、相似性检索、元数据更新和软删除;持久化层负责将内存中的索引和元数据序列化到磁盘。系统采用模块化设计,索引类型可配置(FlatL2用于精确搜索,HNSW用于近似大规模搜索),维度可调节以适配不同的嵌入模型。元数据与向量通过索引位置隐式关联的设计简化了数据一致性维护,但需要注意删除操作只能软删除的局限性。系统还包含一个简单的文本向量化示例,展示了如何将文本转化为向量,尽管实际应用中需要替换为更专业的嵌入模型。

代码实现

复制代码
# -*- coding: utf-8 -*-
"""
Created on Wed Jul  9 09:11:42 2025

@author: liguo
"""
import faiss
import numpy as np
from typing import List, Dict, Any
import json
import os

class AIMemory:
    def __init__(self, dim: int = 1536, index_type: str = "FlatL2", storage_path: str = "ai_memory"):
        """
        初始化AI长期记忆系统
        
        Args:
            dim: 向量维度
            index_type: 索引类型,支持FlatL2、HNSW等
            storage_path: 数据存储路径
        """
        self.dim = dim
        self.index_type = index_type
        self.storage_path = storage_path
        self.metadata = []  # 存储向量对应的元数据
        
        # 创建存储目录
        if not os.path.exists(storage_path):
            os.makedirs(storage_path)
            
        # 初始化索引
        self._init_index()
        
        # 加载已保存的数据
        self._load_memory()
    
    def _init_index(self):
        """根据指定类型初始化FAISS索引"""
        if self.index_type == "FlatL2":
            self.index = faiss.IndexFlatL2(self.dim)
        elif self.index_type == "HNSW":
            self.index = faiss.IndexHNSWFlat(self.dim, 32)
            self.index.hnsw.efConstruction = 40
        else:
            raise ValueError(f"不支持的索引类型: {self.index_type}")
    
    def _load_memory(self):
        """从磁盘加载已保存的记忆"""
        index_path = os.path.join(self.storage_path, "index.faiss")
        metadata_path = os.path.join(self.storage_path, "metadata.json")
        
        if os.path.exists(index_path) and os.path.exists(metadata_path):
            try:
                # 加载索引
                self.index = faiss.read_index(index_path)
                
                # 加载元数据
                with open(metadata_path, "r", encoding="utf-8") as f:
                    self.metadata = json.load(f)
                
                print(f"已从 {self.storage_path} 加载记忆: {len(self.metadata)} 条记录")
            except Exception as e:
                print(f"加载记忆失败: {e}")
                # 重新初始化索引
                self._init_index()
    
    def save_memory(self):
        """保存记忆到磁盘"""
        index_path = os.path.join(self.storage_path, "index.faiss")
        metadata_path = os.path.join(self.storage_path, "metadata.json")
        
        try:
            # 保存索引
            faiss.write_index(self.index, index_path)
            
            # 保存元数据
            with open(metadata_path, "w", encoding="utf-8") as f:
                json.dump(self.metadata, f, ensure_ascii=False, indent=2)
            
            print(f"已保存记忆到 {self.storage_path}")
        except Exception as e:
            print(f"保存记忆失败: {e}")
    
    def add_memory(self, vector: np.ndarray, data: Dict[str, Any]):
        """
        添加记忆条目
        
        Args:
            vector: 特征向量,numpy数组
            data: 相关元数据,字典格式
        """
        # 确保向量维度正确
        vector = vector.reshape(1, -1)
        if vector.shape[1] != self.dim:
            raise ValueError(f"向量维度不匹配,期望 {self.dim},实际 {vector.shape[1]}")
        
        # 添加到索引
        self.index.add(vector)
        
        # 保存元数据
        self.metadata.append(data)
        
        # 自动保存(可优化为定期保存)
        self.save_memory()
        
        return len(self.metadata) - 1  # 返回添加的记忆ID
    
    def search_memory(self, query_vector: np.ndarray, k: int = 5) -> List[Dict[str, Any]]:
        """
        搜索相似记忆
        
        Args:
            query_vector: 查询向量
            k: 返回结果数量
            
        Returns:
            包含相似度和元数据的列表
        """
        # 确保向量维度正确
        query_vector = query_vector.reshape(1, -1)
        if query_vector.shape[1] != self.dim:
            raise ValueError(f"向量维度不匹配,期望 {self.dim},实际 {query_vector.shape[1]}")
        
        # 搜索
        distances, indices = self.index.search(query_vector, k)
        
        # 构建结果
        results = []
        for i, idx in enumerate(indices[0]):
            if idx != -1:  # -1表示未找到
                results.append({
                    "similarity": float(distances[0][i]),
                    "metadata": self.metadata[idx],
                    "memory_id": idx
                })
        
        return results
    
    def update_memory(self, memory_id: int, new_data: Dict[str, Any]):
        """
        更新记忆元数据
        
        Args:
            memory_id: 记忆ID
            new_data: 新的元数据
        """
        if 0 <= memory_id < len(self.metadata):
            self.metadata[memory_id].update(new_data)
            self.save_memory()
            return True
        return False
    
    def delete_memory(self, memory_id: int):
        """
        删除记忆
        
        Args:
            memory_id: 记忆ID
        """
        if 0 <= memory_id < len(self.metadata):
            # 注意:FAISS不支持直接删除索引项,这里采用标记删除
            self.metadata[memory_id]["deleted"] = True
            self.save_memory()
            return True
        return False

# 简单的文本向量化器示例(实际应用中应使用更强大的模型)
def simple_text_embedding(text: str) -> np.ndarray:
    """简单的文本向量化函数,实际应用中应替换为如OpenAI Embeddings等"""
    # 这里仅作示例,返回随机向量
    # 实际应用中应使用如sentence-transformers等模型
    return np.random.random(1536).astype('float32')

# 使用示例
if __name__ == "__main__":
    # 初始化记忆系统
    memory = AIMemory(dim=1536, index_type="FlatL2")
    
    # 添加记忆
    memory.add_memory(
        simple_text_embedding("机器学习是人工智能的一个分支"),
        {"text": "机器学习是人工智能的一个分支", "timestamp": "2023-05-15", "source": "教科书"}
    )
    
    memory.add_memory(
        simple_text_embedding("深度学习是机器学习的一个子领域"),
        {"text": "深度学习是机器学习的一个子领域", "timestamp": "2023-05-16", "source": "网络文章"}
    )
    
    # 搜索记忆
    query_vector = simple_text_embedding("人工智能的分支有哪些")
    results = memory.search_memory(query_vector, k=2)
    
    print("\n搜索结果:")
    for result in results:
        print(f"相似度: {result['similarity']:.4f}")
        print(f"内容: {result['metadata']['text']}")
        print(f"来源: {result['metadata']['source']}")
        print("-" * 40)
    
    # 更新记忆
    memory.update_memory(0, {"importance": "high"})
    
    # 删除记忆
    # memory.delete_memory(1)    

代码执行结果

C:\Users\xiayu\miniconda3\envs\langchain03\python.exe "C:\Users\xiayu\PyCharmMiscProject\AI-Agent-Dev-Practices-Code\第3章代码\3.18-实现了一个基于 FAISS 的 AI 长期记忆系统.py"

已从 ai_memory 加载记忆: 12 条记录

已保存记忆到 ai_memory

已保存记忆到 ai_memory

搜索结果:

相似度: 259.3894

内容: 机器学习是人工智能的一个分支

来源: 教科书


相似度: 260.8898

内容: 机器学习是人工智能的一个分支

来源: 教科书


已保存记忆到 ai_memory

Process finished with exit code 0

代码解析

代码实现展示了清晰的面向对象设计,AIMemory类封装了所有记忆管理功能。构造函数初始化向量维度、索引类型和存储路径,并调用_init_index()根据配置创建FAISS索引。add_memory()方法首先验证输入向量维度,然后将其添加到索引并关联元数据。search_memory()方法接收查询向量,通过FAISS的search方法找到最相似的k个记忆,返回包含相似度分数、元数据和内存ID的结果列表。持久化通过save_memory()_load_memory()方法实现,分别将FAISS索引和元数据JSON文件保存到磁盘。示例中使用的simple_text_embedding()函数只是随机向量生成器,实际部署时需要替换为真正的嵌入模型如Sentence-BERT或OpenAI Embeddings。主程序示例演示了完整的工作流程:初始化系统、添加记忆条目、执行搜索、更新和删除记忆,展示了系统的基本使用模式。

相关推荐
夜起叶落1 小时前
Claude Code 视觉桥接方案,全程 Agent 执行
人工智能
明月(Alioo)1 小时前
Agent 自主学习记忆:让 AI 从经验中成长的闭环系统
人工智能·ai
田井中律.1 小时前
知识图谱(知识融合)【第十三章】
人工智能·知识图谱
浔川python社1 小时前
视界新生,多模态破壁 ——DeepSeek 识图模式正式上线
人工智能·deepseek
云烟成雨TD1 小时前
Spring AI 1.x 系列【30】向量数据库:核心 API 和入门案例
java·人工智能·spring
wuxinyan1231 小时前
大模型学习之路01:提示工程从入门到精通(第一篇)
人工智能·学习·提示词
互联网推荐官1 小时前
上海物联网应用开发技术路径拆解:从协议选型到平台架构的工程实践
大数据·人工智能·软件工程
好运的阿财1 小时前
OpenClaw工具拆解之apply_patch+sandboxed_read
人工智能·python·ai编程·openclaw·openclaw工具
user29876982706542 小时前
四、深入 Claude Code CLI 源码:服务层的架构设计
人工智能