跳转至

长期记忆与向量数据库

引言

当信息超出上下文窗口的容量,Agent 需要一种持久化的长期记忆机制。向量数据库(Vector Database)通过将文本转化为高维向量并进行相似性搜索,成为当前 Agent 长期记忆的核心基础设施。

派系视角:向量检索(embedding similarity + ANN)是 Domingos 五学派中类比派 (Analogizers) 在大模型时代的复兴 —— RAG = 现代 CBR。从派系视角看推荐系统、协同过滤、矩阵分解、HNSW/IVF/LSH 算法对比、RAG vs 经典 CBR,见 The Master Algorithm — 推荐系统与现代检索

向量嵌入(Embedding)

什么是嵌入

嵌入是将离散的文本(词、句子、段落)映射到连续的高维向量空间中,使得语义相近的文本在向量空间中距离更近。

\[\text{embed}: \text{Text} \rightarrow \mathbb{R}^d\]

其中 \(d\) 是嵌入维度(通常 384-3072)。

主流嵌入模型

模型 维度 提供者 特点
text-embedding-3-small 1536 OpenAI 性价比高
text-embedding-3-large 3072 OpenAI 精度最高
text-embedding-ada-002 1536 OpenAI 经典模型
BGE-large-en-v1.5 1024 BAAI 开源最佳之一
BGE-M3 1024 BAAI 多语言、多粒度
E5-large-v2 1024 Microsoft 开源高质量
voyage-3 1024 Voyage AI 代码/文档专优
Cohere embed-v3 1024 Cohere 多语言优化

嵌入代码示例

from openai import OpenAI

client = OpenAI()

def get_embedding(text, model="text-embedding-3-small"):
    response = client.embeddings.create(input=text, model=model)
    return response.data[0].embedding

# 示例
embedding = get_embedding("Agent 的记忆系统非常重要")
print(f"维度: {len(embedding)}")  # 1536
# 使用开源模型(sentence-transformers)
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("BAAI/bge-large-en-v1.5")
embeddings = model.encode(["memory systems for agents", "向量数据库"])

相似性度量

余弦相似度

最常用的相似性度量:

\[\cos(\theta) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \|\mathbf{b}\|} = \frac{\sum_{i=1}^{n} a_i b_i}{\sqrt{\sum_{i=1}^{n} a_i^2} \cdot \sqrt{\sum_{i=1}^{n} b_i^2}}\]
  • 值域:\([-1, 1]\),1 表示完全相同,0 表示正交,-1 表示完全相反
  • 优势:对向量长度不敏感,适合文本相似度

其他度量

度量 公式 适用场景
欧氏距离 \(d = \sqrt{\sum(a_i - b_i)^2}\) 绝对距离敏感
点积 \(s = \sum a_i b_i\) 已归一化的向量
Manhattan 距离 \(d = \sum \|a_i - b_i\|\) 高维稀疏数据

近似最近邻搜索(ANN)

精确的最近邻搜索复杂度为 \(O(nd)\)\(n\) 为向量数,\(d\) 为维度),在大规模数据下不可行。ANN 算法牺牲少量精度换取大幅加速。

HNSW(Hierarchical Navigable Small World)

当前最流行的 ANN 算法:

graph TB
    subgraph "HNSW 多层图结构"
        subgraph "Layer 2(稀疏)"
            A2((A)) --- B2((B))
        end
        subgraph "Layer 1(中等)"
            A1((A)) --- B1((B))
            A1 --- C1((C))
            B1 --- D1((D))
        end
        subgraph "Layer 0(密集)"
            A0((A)) --- B0((B))
            A0 --- C0((C))
            B0 --- D0((D))
            C0 --- E0((E))
            D0 --- F0((F))
            E0 --- F0
        end
    end

    Q[查询向量 q] -.->|从顶层开始| A2
    A2 -.->|下沉到下层| A1
    A1 -.->|细化搜索| E0

原理

  1. 构建多层图结构,上层稀疏、下层密集
  2. 搜索时从顶层入口开始,贪心搜索最近邻
  3. 逐层下沉,在每层细化搜索结果
  4. 搜索复杂度:\(O(\log n)\)

IVF(Inverted File Index)

  1. 先用聚类(如 K-Means)将向量空间分区
  2. 搜索时只在最近的几个分区(nprobe)内搜索
  3. 搜索复杂度:\(O(n \cdot \text{nprobe} / K)\)

Product Quantization(PQ)

将高维向量分段量化,压缩存储空间(可压缩 4-64 倍),同时支持近似距离计算。

主流向量数据库

对比表

数据库 类型 ANN 算法 特点 适用场景
Pinecone 云托管 自研 全托管、简单易用 快速上手、生产级
Weaviate 开源/云 HNSW 多模态、GraphQL 复杂查询、混合搜索
ChromaDB 开源 HNSW 嵌入式、Python 优先 原型开发、本地
Milvus 开源/云 IVF/HNSW 大规模、高性能 十亿级数据
Qdrant 开源/云 HNSW Rust 实现、过滤优 需要复杂过滤
pgvector 扩展 IVF/HNSW PostgreSQL 扩展 已有 PG 基础设施
FAISS 多种 Meta 开源库 研究、自定义

ChromaDB 示例(本地开发)

import chromadb

# 创建客户端
client = chromadb.Client()

# 创建集合
collection = client.create_collection(
    name="agent_memory",
    metadata={"hnsw:space": "cosine"}
)

# 添加记忆
collection.add(
    documents=[
        "用户偏好:喜欢简洁的回答",
        "任务记录:完成了数据分析报告",
        "学习笔记:掌握了 Python 装饰器",
    ],
    ids=["mem_1", "mem_2", "mem_3"],
    metadatas=[
        {"type": "preference", "timestamp": "2024-01-01"},
        {"type": "task", "timestamp": "2024-01-02"},
        {"type": "knowledge", "timestamp": "2024-01-03"},
    ]
)

# 检索相关记忆
results = collection.query(
    query_texts=["用户喜欢什么样的回答风格?"],
    n_results=2,
    where={"type": "preference"}  # 可选的元数据过滤
)
print(results["documents"])

Pinecone 示例(生产环境)

from pinecone import Pinecone

pc = Pinecone(api_key="your-api-key")
index = pc.Index("agent-memory")

# 写入(upsert)
index.upsert(vectors=[
    {
        "id": "mem_1",
        "values": embedding_vector,  # 1536维向量
        "metadata": {
            "text": "用户偏好:简洁回答",
            "type": "preference",
            "timestamp": 1704067200
        }
    }
])

# 查询
results = index.query(
    vector=query_embedding,
    top_k=5,
    include_metadata=True,
    filter={"type": {"$eq": "preference"}}
)

pgvector 示例(PostgreSQL)

-- 启用扩展
CREATE EXTENSION vector;

-- 创建表
CREATE TABLE agent_memory (
    id SERIAL PRIMARY KEY,
    content TEXT,
    embedding vector(1536),
    memory_type VARCHAR(50),
    created_at TIMESTAMP DEFAULT NOW()
);

-- 创建 HNSW 索引
CREATE INDEX ON agent_memory 
USING hnsw (embedding vector_cosine_ops);

-- 相似性搜索
SELECT content, 1 - (embedding <=> query_embedding) AS similarity
FROM agent_memory
WHERE memory_type = 'preference'
ORDER BY embedding <=> query_embedding
LIMIT 5;

向量搜索管线

graph LR
    A[原始文本] --> B[文本分块<br/>Chunking]
    B --> C[嵌入模型<br/>Embedding]
    C --> D[(向量数据库<br/>Index)]

    E[查询] --> F[查询嵌入]
    F --> G[ANN 搜索]
    D --> G
    G --> H[Top-K 结果]
    H --> I[重排序<br/>Reranking]
    I --> J[最终结果]

单纯的向量搜索可能遗漏关键词匹配的结果。混合搜索结合向量搜索和传统关键词搜索:

\[\text{score}_{\text{hybrid}} = \alpha \cdot \text{score}_{\text{vector}} + (1-\alpha) \cdot \text{score}_{\text{keyword}}\]
# Weaviate 混合搜索示例
result = client.query.get("Memory", ["content", "type"]).with_hybrid(
    query="Python 装饰器",
    alpha=0.7  # 0=纯关键词, 1=纯向量
).with_limit(5).do()

实践建议

嵌入模型选择

  • 通用场景:OpenAI text-embedding-3-small(性价比最佳)
  • 高精度:OpenAI text-embedding-3-large 或 Cohere embed-v3
  • 私有部署:BGE-M3 或 E5-large-v2
  • 代码场景:Voyage Code 或 CodeBERT

分块策略

  • 固定大小:简单但可能切断语义
  • 语义分块:基于段落/章节分割
  • 递归分块:先按大结构分,再递归细分
  • 推荐 chunk size:256-512 tokens,overlap 50-100 tokens

性能优化

  • 使用 batch 操作减少 API 调用
  • 对热点数据建立缓存层
  • 选择合适的 ANN 参数(如 HNSW 的 M 和 efConstruction)
  • 考虑向量维度压缩(Matryoshka embeddings)

延伸阅读

  • RAG 增强记忆 - 基于向量检索的完整 RAG 管线
  • Johnson, J., Douze, M., & Jégou, H. (2019). "Billion-scale similarity search with GPUs" (FAISS)
  • Malkov, Y. A., & Yashunin, D. A. (2020). "Efficient and robust approximate nearest neighbor search using HNSW"

评论 #