Skip to content

向量数据库配置

向量数据库是 AnythingLLM 实现语义搜索和检索增强生成(RAG)的核心组件。本指南详细介绍如何配置和优化各种向量数据库解决方案。

支持的向量数据库

云端解决方案

  • Pinecone: 完全托管的向量数据库服务
  • Weaviate Cloud: 托管的 Weaviate 实例
  • Qdrant Cloud: 托管的 Qdrant 服务

自托管解决方案

  • Chroma: 轻量级的开源向量数据库
  • Weaviate: 开源的向量搜索引擎
  • Qdrant: 高性能的向量相似性搜索引擎
  • Milvus: 大规模向量数据库
  • LanceDB: 嵌入式向量数据库

传统数据库扩展

  • pgvector: PostgreSQL 向量扩展
  • Redis Search: Redis 向量搜索模块

Pinecone 配置

基础配置

javascript
// Pinecone 环境变量
PINECONE_API_KEY=your-pinecone-api-key
PINECONE_ENVIRONMENT=us-west1-gcp
PINECONE_INDEX=anythingllm-index

// 高级配置
PINECONE_NAMESPACE=default
PINECONE_TOP_K=10
PINECONE_INCLUDE_METADATA=true

索引创建和管理

javascript
// Pinecone 索引配置
const pineconeConfig = {
  apiKey: process.env.PINECONE_API_KEY,
  environment: process.env.PINECONE_ENVIRONMENT,
  
  // 索引配置
  index: {
    name: "anythingllm-index",
    dimension: 1536,  // OpenAI ada-002 嵌入维度
    metric: "cosine", // cosine, euclidean, dotproduct
    pods: 1,
    replicas: 1,
    podType: "p1.x1"  // p1.x1, p1.x2, p1.x4, p1.x8
  },
  
  // 命名空间配置
  namespaces: {
    default: "default",
    workspace: (workspaceId) => `workspace-${workspaceId}`,
    user: (userId) => `user-${userId}`
  },
  
  // 查询配置
  query: {
    topK: 10,
    includeMetadata: true,
    includeValues: false,
    filter: {}
  }
};

// 索引创建示例
async function createPineconeIndex() {
  const pinecone = new PineconeClient();
  await pinecone.init({
    apiKey: process.env.PINECONE_API_KEY,
    environment: process.env.PINECONE_ENVIRONMENT
  });
  
  await pinecone.createIndex({
    createRequest: {
      name: "anythingllm-index",
      dimension: 1536,
      metric: "cosine",
      pods: 1,
      replicas: 1,
      pod_type: "p1.x1"
    }
  });
}

性能优化

javascript
// Pinecone 性能优化
const pineconeOptimization = {
  // 批量操作
  batching: {
    upsertBatchSize: 100,
    queryBatchSize: 10,
    deleteBatchSize: 1000
  },
  
  // 连接池
  connectionPool: {
    maxConnections: 10,
    keepAlive: true,
    timeout: 30000
  },
  
  // 缓存策略
  caching: {
    enabled: true,
    ttl: 3600,  // 1小时
    maxSize: 1000
  },
  
  // 索引优化
  indexOptimization: {
    podType: "p1.x2",  // 更高性能的 pod
    replicas: 2,       // 增加副本提高可用性
    shards: 1          // 分片配置
  }
};

Chroma 配置

基础配置

javascript
// Chroma 环境变量
CHROMA_ENDPOINT=http://localhost:8000
CHROMA_COLLECTION=anythingllm_collection
CHROMA_AUTH_TOKEN=your-chroma-token  // 可选

// 持久化配置
CHROMA_PERSIST_DIRECTORY=./chroma_db
CHROMA_ALLOW_RESET=false

集合配置

javascript
// Chroma 集合配置
const chromaConfig = {
  endpoint: process.env.CHROMA_ENDPOINT || "http://localhost:8000",
  
  // 集合配置
  collection: {
    name: "anythingllm_collection",
    metadata: {
      "hnsw:space": "cosine",
      "hnsw:construction_ef": 200,
      "hnsw:M": 16
    },
    embeddingFunction: "openai"  // openai, sentence-transformers, custom
  },
  
  // 查询配置
  query: {
    nResults: 10,
    includeMetadata: true,
    includeDocuments: true,
    includeDistances: true
  },
  
  // 过滤配置
  filtering: {
    enabled: true,
    operators: ["$eq", "$ne", "$gt", "$gte", "$lt", "$lte", "$in", "$nin"]
  }
};

// 集合创建示例
async function createChromaCollection() {
  const { ChromaClient } = require('chromadb');
  const client = new ChromaClient({
    path: process.env.CHROMA_ENDPOINT
  });
  
  const collection = await client.createCollection({
    name: "anythingllm_collection",
    metadata: {
      "hnsw:space": "cosine",
      "hnsw:construction_ef": 200,
      "hnsw:M": 16
    }
  });
  
  return collection;
}

Docker 部署

yaml
# docker-compose.yml for Chroma
version: '3.8'
services:
  chroma:
    image: ghcr.io/chroma-core/chroma:latest
    ports:
      - "8000:8000"
    volumes:
      - chroma_data:/chroma/chroma
    environment:
      - CHROMA_SERVER_HOST=0.0.0.0
      - CHROMA_SERVER_HTTP_PORT=8000
      - CHROMA_SERVER_CORS_ALLOW_ORIGINS=["*"]
    command: ["uvicorn", "chromadb.app:app", "--host", "0.0.0.0", "--port", "8000"]

volumes:
  chroma_data:
    driver: local

Weaviate 配置

基础配置

javascript
// Weaviate 环境变量
WEAVIATE_ENDPOINT=http://localhost:8080
WEAVIATE_API_KEY=your-weaviate-api-key  // 可选
WEAVIATE_CLASS_NAME=AnythingLLMDocument
WEAVIATE_SCHEME=http  // http 或 https

模式定义

javascript
// Weaviate 模式配置
const weaviateSchema = {
  class: "AnythingLLMDocument",
  description: "AnythingLLM document storage",
  vectorizer: "text2vec-openai",
  moduleConfig: {
    "text2vec-openai": {
      model: "ada",
      modelVersion: "002",
      type: "text"
    }
  },
  properties: [
    {
      name: "content",
      dataType: ["text"],
      description: "Document content",
      moduleConfig: {
        "text2vec-openai": {
          skip: false,
          vectorizePropertyName: false
        }
      }
    },
    {
      name: "title",
      dataType: ["string"],
      description: "Document title"
    },
    {
      name: "source",
      dataType: ["string"],
      description: "Document source"
    },
    {
      name: "workspaceId",
      dataType: ["string"],
      description: "Workspace identifier"
    },
    {
      name: "metadata",
      dataType: ["object"],
      description: "Additional metadata"
    }
  ]
};

// 创建 Weaviate 类
async function createWeaviateClass() {
  const weaviate = require('weaviate-ts-client').default;
  
  const client = weaviate.client({
    scheme: 'http',
    host: 'localhost:8080',
    apiKey: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY)
  });
  
  await client.schema
    .classCreator()
    .withClass(weaviateSchema)
    .do();
}

查询配置

javascript
// Weaviate 查询配置
const weaviateQuery = {
  // 向量搜索
  nearVector: {
    vector: [], // 查询向量
    certainty: 0.7,
    distance: 0.3
  },
  
  // 文本搜索
  nearText: {
    concepts: ["search query"],
    certainty: 0.7,
    distance: 0.3
  },
  
  // 混合搜索
  hybrid: {
    query: "search query",
    alpha: 0.5,  // 0 = 纯关键词搜索, 1 = 纯向量搜索
    vector: []
  },
  
  // 过滤器
  where: {
    path: ["workspaceId"],
    operator: "Equal",
    valueString: "workspace-123"
  },
  
  // 返回字段
  fields: "content title source metadata _additional { id certainty distance }"
};

Qdrant 配置

基础配置

javascript
// Qdrant 环境变量
QDRANT_ENDPOINT=http://localhost:6333
QDRANT_API_KEY=your-qdrant-api-key  // 可选
QDRANT_COLLECTION=anythingllm_collection
QDRANT_VECTOR_SIZE=1536

集合配置

javascript
// Qdrant 集合配置
const qdrantConfig = {
  endpoint: process.env.QDRANT_ENDPOINT,
  apiKey: process.env.QDRANT_API_KEY,
  
  // 集合配置
  collection: {
    name: "anythingllm_collection",
    vectors: {
      size: 1536,
      distance: "Cosine"  // Cosine, Euclid, Dot
    },
    optimizers_config: {
      deleted_threshold: 0.2,
      vacuum_min_vector_number: 1000,
      default_segment_number: 0,
      max_segment_size: null,
      memmap_threshold: null,
      indexing_threshold: 20000,
      flush_interval_sec: 5,
      max_optimization_threads: 1
    },
    wal_config: {
      wal_capacity_mb: 32,
      wal_segments_ahead: 0
    },
    hnsw_config: {
      m: 16,
      ef_construct: 100,
      full_scan_threshold: 10000,
      max_indexing_threads: 0,
      on_disk: false,
      payload_m: null
    }
  }
};

// 创建 Qdrant 集合
async function createQdrantCollection() {
  const { QdrantClient } = require('@qdrant/js-client-rest');
  
  const client = new QdrantClient({
    url: process.env.QDRANT_ENDPOINT,
    apiKey: process.env.QDRANT_API_KEY
  });
  
  await client.createCollection("anythingllm_collection", {
    vectors: {
      size: 1536,
      distance: "Cosine"
    },
    optimizers_config: {
      default_segment_number: 2
    },
    replication_factor: 2
  });
}

搜索配置

javascript
// Qdrant 搜索配置
const qdrantSearch = {
  // 基础搜索
  search: {
    collection_name: "anythingllm_collection",
    vector: [], // 查询向量
    limit: 10,
    score_threshold: 0.7,
    with_payload: true,
    with_vectors: false
  },
  
  // 过滤搜索
  searchWithFilter: {
    collection_name: "anythingllm_collection",
    vector: [],
    filter: {
      must: [
        {
          key: "workspaceId",
          match: {
            value: "workspace-123"
          }
        }
      ]
    },
    limit: 10,
    with_payload: true
  },
  
  // 批量搜索
  searchBatch: {
    collection_name: "anythingllm_collection",
    searches: [
      {
        vector: [],
        limit: 5,
        filter: {}
      }
    ]
  }
};

pgvector 配置

基础配置

javascript
// PostgreSQL + pgvector 配置
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=anythingllm
POSTGRES_USER=anythingllm
POSTGRES_PASSWORD=your-password
PGVECTOR_DIMENSION=1536

数据库设置

sql
-- 启用 pgvector 扩展
CREATE EXTENSION IF NOT EXISTS vector;

-- 创建向量表
CREATE TABLE IF NOT EXISTS document_embeddings (
    id SERIAL PRIMARY KEY,
    document_id VARCHAR(255) NOT NULL,
    workspace_id VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    metadata JSONB,
    embedding vector(1536),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 创建向量索引
CREATE INDEX IF NOT EXISTS idx_document_embeddings_vector 
ON document_embeddings USING ivfflat (embedding vector_cosine_ops) 
WITH (lists = 100);

-- 创建其他索引
CREATE INDEX IF NOT EXISTS idx_document_embeddings_workspace 
ON document_embeddings (workspace_id);

CREATE INDEX IF NOT EXISTS idx_document_embeddings_document 
ON document_embeddings (document_id);

查询优化

javascript
// pgvector 查询配置
const pgvectorConfig = {
  // 连接配置
  connection: {
    host: process.env.POSTGRES_HOST,
    port: process.env.POSTGRES_PORT,
    database: process.env.POSTGRES_DB,
    user: process.env.POSTGRES_USER,
    password: process.env.POSTGRES_PASSWORD,
    ssl: process.env.NODE_ENV === 'production'
  },
  
  // 向量搜索配置
  search: {
    // 设置搜索精度
    setSearchPath: "SET ivfflat.probes = 10;",
    
    // 相似性搜索查询
    similarityQuery: `
      SELECT 
        document_id,
        content,
        metadata,
        1 - (embedding <=> $1) as similarity
      FROM document_embeddings
      WHERE workspace_id = $2
      ORDER BY embedding <=> $1
      LIMIT $3;
    `,
    
    // 阈值过滤查询
    thresholdQuery: `
      SELECT 
        document_id,
        content,
        metadata,
        1 - (embedding <=> $1) as similarity
      FROM document_embeddings
      WHERE workspace_id = $2
        AND 1 - (embedding <=> $1) > $3
      ORDER BY embedding <=> $1
      LIMIT $4;
    `
  }
};

向量数据库选择指南

性能对比

javascript
// 向量数据库性能对比
const performanceComparison = {
  pinecone: {
    latency: "低",
    throughput: "高",
    scalability: "优秀",
    cost: "中等",
    maintenance: "无需维护",
    useCase: "生产环境,高并发"
  },
  
  chroma: {
    latency: "中等",
    throughput: "中等",
    scalability: "良好",
    cost: "低",
    maintenance: "简单",
    useCase: "开发测试,中小规模"
  },
  
  weaviate: {
    latency: "低",
    throughput: "高",
    scalability: "优秀",
    cost: "中等",
    maintenance: "中等",
    useCase: "企业级,复杂查询"
  },
  
  qdrant: {
    latency: "低",
    throughput: "高",
    scalability: "优秀",
    cost: "低",
    maintenance: "中等",
    useCase: "高性能,自托管"
  },
  
  pgvector: {
    latency: "中等",
    throughput: "中等",
    scalability: "良好",
    cost: "低",
    maintenance: "中等",
    useCase: "现有 PostgreSQL 环境"
  }
};

选择决策树

javascript
// 向量数据库选择决策
function selectVectorDatabase(requirements) {
  const {
    scale,           // small, medium, large
    budget,          // low, medium, high
    maintenance,     // minimal, moderate, high
    latency,         // low, medium, high
    features         // basic, advanced, enterprise
  } = requirements;
  
  // 大规模,高预算,低维护
  if (scale === 'large' && budget === 'high' && maintenance === 'minimal') {
    return 'pinecone';
  }
  
  // 中小规模,低预算,简单维护
  if (scale === 'small' && budget === 'low') {
    return 'chroma';
  }
  
  // 企业级功能需求
  if (features === 'enterprise') {
    return 'weaviate';
  }
  
  // 高性能,自托管
  if (latency === 'low' && maintenance === 'moderate') {
    return 'qdrant';
  }
  
  // 现有 PostgreSQL 环境
  if (requirements.existingPostgres) {
    return 'pgvector';
  }
  
  // 默认推荐
  return 'chroma';
}

数据迁移

跨数据库迁移

javascript
// 向量数据库迁移工具
class VectorDatabaseMigrator {
  constructor(source, target) {
    this.source = source;
    this.target = target;
  }
  
  async migrate() {
    console.log('开始迁移向量数据...');
    
    // 1. 导出源数据
    const data = await this.exportData();
    
    // 2. 转换数据格式
    const transformedData = await this.transformData(data);
    
    // 3. 导入目标数据库
    await this.importData(transformedData);
    
    // 4. 验证迁移结果
    await this.validateMigration();
    
    console.log('迁移完成');
  }
  
  async exportData() {
    const batchSize = 1000;
    let offset = 0;
    const allData = [];
    
    while (true) {
      const batch = await this.source.query({
        limit: batchSize,
        offset: offset
      });
      
      if (batch.length === 0) break;
      
      allData.push(...batch);
      offset += batchSize;
      
      console.log(`已导出 ${allData.length} 条记录`);
    }
    
    return allData;
  }
  
  async transformData(data) {
    return data.map(item => ({
      id: item.id,
      vector: item.embedding || item.vector,
      metadata: {
        content: item.content,
        source: item.source,
        workspaceId: item.workspaceId,
        ...item.metadata
      }
    }));
  }
  
  async importData(data) {
    const batchSize = 100;
    
    for (let i = 0; i < data.length; i += batchSize) {
      const batch = data.slice(i, i + batchSize);
      await this.target.upsert(batch);
      
      console.log(`已导入 ${Math.min(i + batchSize, data.length)} / ${data.length} 条记录`);
    }
  }
  
  async validateMigration() {
    const sourceCount = await this.source.count();
    const targetCount = await this.target.count();
    
    if (sourceCount !== targetCount) {
      throw new Error(`迁移验证失败: 源数据库 ${sourceCount} 条,目标数据库 ${targetCount} 条`);
    }
    
    console.log(`迁移验证成功: ${targetCount} 条记录`);
  }
}

// 使用示例
async function migratePineconeToQdrant() {
  const pinecone = new PineconeClient(/* config */);
  const qdrant = new QdrantClient(/* config */);
  
  const migrator = new VectorDatabaseMigrator(pinecone, qdrant);
  await migrator.migrate();
}

监控和维护

性能监控

javascript
// 向量数据库监控
const vectorDBMonitoring = {
  // 性能指标
  metrics: {
    queryLatency: {
      p50: 0,
      p95: 0,
      p99: 0
    },
    throughput: {
      queriesPerSecond: 0,
      insertsPerSecond: 0
    },
    storage: {
      totalVectors: 0,
      storageSize: 0,
      indexSize: 0
    },
    errors: {
      queryErrors: 0,
      insertErrors: 0,
      connectionErrors: 0
    }
  },
  
  // 健康检查
  healthCheck: async () => {
    try {
      const startTime = Date.now();
      await vectorDB.ping();
      const latency = Date.now() - startTime;
      
      return {
        status: 'healthy',
        latency: latency,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      return {
        status: 'unhealthy',
        error: error.message,
        timestamp: new Date().toISOString()
      };
    }
  },
  
  // 告警配置
  alerts: {
    highLatency: {
      threshold: 1000,  // 1秒
      action: 'email'
    },
    lowThroughput: {
      threshold: 10,    // 10 QPS
      action: 'slack'
    },
    storageLimit: {
      threshold: 0.8,   // 80%
      action: 'email'
    }
  }
};

维护任务

javascript
// 向量数据库维护
class VectorDBMaintenance {
  constructor(vectorDB) {
    this.vectorDB = vectorDB;
  }
  
  // 索引优化
  async optimizeIndex() {
    console.log('开始索引优化...');
    
    // 重建索引
    await this.vectorDB.rebuildIndex();
    
    // 压缩存储
    await this.vectorDB.compact();
    
    console.log('索引优化完成');
  }
  
  // 数据清理
  async cleanupData() {
    console.log('开始数据清理...');
    
    // 删除过期数据
    const expiredData = await this.vectorDB.findExpired();
    await this.vectorDB.delete(expiredData);
    
    // 删除重复数据
    const duplicates = await this.vectorDB.findDuplicates();
    await this.vectorDB.deduplicate(duplicates);
    
    console.log('数据清理完成');
  }
  
  // 备份数据
  async backupData() {
    console.log('开始数据备份...');
    
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const backupPath = `./backups/vectordb-${timestamp}`;
    
    await this.vectorDB.backup(backupPath);
    
    console.log(`数据备份完成: ${backupPath}`);
  }
  
  // 定期维护
  scheduleMaintenanceTasks() {
    // 每日索引优化
    cron.schedule('0 2 * * *', () => {
      this.optimizeIndex();
    });
    
    // 每周数据清理
    cron.schedule('0 3 * * 0', () => {
      this.cleanupData();
    });
    
    // 每日备份
    cron.schedule('0 1 * * *', () => {
      this.backupData();
    });
  }
}

选择合适的向量数据库并正确配置是实现高效语义搜索的关键。根据您的具体需求、预算和技术栈选择最适合的解决方案,并定期进行监控和维护以确保最佳性能。

AnythingLLM 是一个功能强大的开源 AI 知识管理平台,支持多种 LLM 模型,让您轻松构建智能对话系统和知识库。