Dify 集成-向量数据库

1. 集成概述

Dify 支持 28+ 向量数据库,用于实现 RAG (Retrieval-Augmented Generation) 功能。向量数据库是知识库系统的核心组件,负责存储文档的向量表示并提供高效的相似度检索能力。

核心价值

  • 多样化选择: 支持从云服务到自建方案的多种向量数据库
  • 统一接口: 提供一致的向量操作 API,简化开发
  • 性能优化: 针对不同场景选择最优的向量数据库
  • 灵活部署: 支持本地部署和云服务部署

2. 支持的服务/产品

2.1 开源向量数据库

服务名称 版本 状态 说明
Milvus 2.x ✅ 支持 高性能向量数据库,支持大规模数据
Qdrant Latest ✅ 支持 高性能 Rust 实现,支持过滤
Weaviate Latest ✅ 支持 GraphQL 接口,支持多模态
Chroma Latest ✅ 支持 轻量级,易于部署
PGVector Latest ✅ 支持 PostgreSQL 扩展,易于集成
PGVecto.rs Latest ✅ 支持 PostgreSQL 扩展,Rust 实现
Elasticsearch 7.x/8.x ✅ 支持 支持向量搜索的全文检索引擎
OpenSearch Latest ✅ 支持 Elasticsearch 分支,支持向量

2.2 云服务向量数据库

服务名称 状态 说明
阿里云 AnalyticDB ✅ 支持 阿里云托管向量数据库
阿里云 MySQL ✅ 支持 MySQL 向量扩展
阿里云 Lindorm ✅ 支持 多模数据库,支持向量
阿里云 TableStore ✅ 支持 NoSQL 数据库,支持向量
腾讯云 TencentVectorDB ✅ 支持 腾讯云向量数据库
百度 VectorDB ✅ 支持 百度云向量数据库
火山引擎 VikingDB ✅ 支持 字节跳动云向量数据库
华为云 GaussDB ✅ 支持 华为云数据库向量扩展
Oracle Database ✅ 支持 Oracle 23ai 向量功能
Upstash Vector ✅ 支持 Serverless 向量数据库

2.3 专用向量数据库

服务名称 状态 说明
TiDB Vector ✅ 支持 TiDB 向量搜索
TiDB on Qdrant ✅ 支持 TiDB + Qdrant 混合方案
MyScale ✅ 支持 ClickHouse 向量扩展
Couchbase ✅ 支持 NoSQL 数据库,支持向量
OceanBase ✅ 支持 分布式数据库,支持向量
OpenGauss ✅ 支持 企业级数据库,支持向量
Vastbase ✅ 支持 基于 PostgreSQL 的数据库
MatrixOne ✅ 支持 超融合数据库,支持向量
Relyt ✅ 支持 PostgreSQL 兼容向量数据库
ClickZetta ✅ 支持 云原生数据仓库,支持向量

3. 集成方式

3.1 架构设计

复制代码
┌─────────────────────────────────────────────────────┐
│                 RAG Application                      │
├─────────────────────────────────────────────────────┤
│              Retrieval Service                       │
│  ┌───────────────────────────────────────────────┐  │
│  │          Vector Factory                        │  │
│  │  - 根据配置创建向量数据库实例                  │  │
│  │  - 管理数据库连接                              │  │
│  └───────────────────────────────────────────────┘  │
├─────────────────────────────────────────────────────┤
│            Base Vector Interface                     │
│  ┌───────────────────────────────────────────────┐  │
│  │  - create(texts, embeddings, metadatas)       │  │
│  │  - add_texts(texts, embeddings)               │  │
│  │  - delete_by_ids(ids)                         │  │
│  │  - search_by_vector(query_vector, top_k)     │  │
│  │  - search_by_full_text(query, top_k)         │  │
│  └───────────────────────────────────────────────┘  │
├─────────────────────────────────────────────────────┤
│         Vector Database Implementations              │
│  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐       │
│  │Milvus  │ │Qdrant  │ │Weaviate│ │Chroma  │ ...   │
│  │Vector  │ │Vector  │ │Vector  │ │Vector  │       │
│  └────────┘ └────────┘ └────────┘ └────────┘       │
└─────────────────────────────────────────────────────┘

3.2 核心接口

python 复制代码
class BaseVector:
    """Base class for vector database"""
    
    def create(
        self,
        texts: list[Document],
        embeddings: list[list[float]],
        **kwargs
    ):
        """
        Create collection and add texts with embeddings
        
        :param texts: list of documents
        :param embeddings: list of embeddings
        """
        raise NotImplementedError
    
    def add_texts(
        self,
        texts: list[Document],
        embeddings: list[list[float]],
        **kwargs
    ):
        """
        Add texts with embeddings to collection
        
        :param texts: list of documents
        :param embeddings: list of embeddings
        """
        raise NotImplementedError
    
    def delete_by_ids(self, ids: list[str]):
        """
        Delete vectors by ids
        
        :param ids: list of ids
        """
        raise NotImplementedError
    
    def search_by_vector(
        self,
        query_vector: list[float],
        top_k: int = 4,
        **kwargs
    ) -> list[Document]:
        """
        Search by vector
        
        :param query_vector: query vector
        :param top_k: top k results
        :return: list of documents
        """
        raise NotImplementedError
    
    def search_by_full_text(
        self,
        query: str,
        top_k: int = 4,
        **kwargs
    ) -> list[Document]:
        """
        Search by full text
        
        :param query: query text
        :param top_k: top k results
        :return: list of documents
        """
        raise NotImplementedError

3.3 配置方式

环境变量配置
bash 复制代码
# 向量数据库类型
VECTOR_STORE=milvus

# Milvus 配置
MILVUS_HOST=localhost
MILVUS_PORT=19530
MILVUS_USER=root
MILVUS_PASSWORD=Milvus
MILVUS_SECURE=false

# Qdrant 配置
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY=your_api_key

# Weaviate 配置
WEAVIATE_ENDPOINT=http://localhost:8080
WEAVIATE_API_KEY=your_api_key

# Chroma 配置
CHROMA_HOST=localhost
CHROMA_PORT=8000
CHROMA_TENANT=default_tenant
CHROMA_DATABASE=default_database

# PGVector 配置 (使用主数据库)
# 无需额外配置,使用主数据库连接

# ElasticSearch 配置
ELASTICSEARCH_HOST=localhost
ELASTICSEARCH_PORT=9200
ELASTICSEARCH_USERNAME=elastic
ELASTICSEARCH_PASSWORD=your_password

4. 代码实现

4.1 核心代码路径

复制代码
api/core/rag/datasource/vdb/
├── vector_base.py              # 向量数据库基类
├── vector_factory.py           # 向量数据库工厂
├── vector_type.py              # 向量类型枚举
├── field.py                    # 字段定义
├── milvus/                     # Milvus 实现
│   └── milvus_vector.py
├── qdrant/                     # Qdrant 实现
│   └── qdrant_vector.py
├── weaviate/                   # Weaviate 实现
│   └── weaviate_vector.py
├── chroma/                     # Chroma 实现
│   └── chroma_vector.py
├── pgvector/                   # PGVector 实现
│   └── pgvector.py
├── elasticsearch/              # Elasticsearch 实现
│   └── elasticsearch_vector.py
└── .../                        # 其他实现

4.2 向量类型枚举

python 复制代码
# api/core/rag/datasource/vdb/vector_type.py
from enum import StrEnum

class VectorType(StrEnum):
    ALIBABACLOUD_MYSQL = "alibabacloud_mysql"
    ANALYTICDB = "analyticdb"
    CHROMA = "chroma"
    MILVUS = "milvus"
    MYSCALE = "myscale"
    PGVECTOR = "pgvector"
    VASTBASE = "vastbase"
    PGVECTO_RS = "pgvecto-rs"
    QDRANT = "qdrant"
    RELYT = "relyt"
    TIDB_VECTOR = "tidb_vector"
    WEAVIATE = "weaviate"
    OPENSEARCH = "opensearch"
    TENCENT = "tencent"
    ORACLE = "oracle"
    ELASTICSEARCH = "elasticsearch"
    ELASTICSEARCH_JA = "elasticsearch-ja"
    LINDORM = "lindorm"
    COUCHBASE = "couchbase"
    BAIDU = "baidu"
    VIKINGDB = "vikingdb"
    UPSTASH = "upstash"
    TIDB_ON_QDRANT = "tidb_on_qdrant"
    OCEANBASE = "oceanbase"
    OPENGAUSS = "opengauss"
    TABLESTORE = "tablestore"
    HUAWEI_CLOUD = "huawei_cloud"
    MATRIXONE = "matrixone"
    CLICKZETTA = "clickzetta"

4.3 向量工厂实现

python 复制代码
# api/core/rag/datasource/vdb/vector_factory.py
class VectorFactory:
    @staticmethod
    def create(
        vector_type: str,
        collection_name: str,
        config: dict,
        **kwargs
    ):
        """
        Create vector instance
        
        :param vector_type: vector type
        :param collection_name: collection name
        :param config: vector configuration
        :return: vector instance
        """
        if vector_type == VectorType.MILVUS:
            from .milvus import MilvusVector
            return MilvusVector(
                collection_name=collection_name,
                config=config
            )
        elif vector_type == VectorType.QDRANT:
            from .qdrant import QdrantVector
            return QdrantVector(
                collection_name=collection_name,
                config=config
            )
        # ... 其他向量数据库
        else:
            raise ValueError(f"Unsupported vector type: {vector_type}")

5. 使用示例

5.1 创建知识库

python 复制代码
from core.rag.datasource.vdb.vector_factory import VectorFactory
from core.rag.models.document import Document

# 准备文档
documents = [
    Document(
        page_content="Paris is the capital of France.",
        metadata={"source": "doc1", "page": 1}
    ),
    Document(
        page_content="London is the capital of England.",
        metadata={"source": "doc2", "page": 1}
    ),
]

# 获取 embeddings
from core.model_manager import ModelManager
model_manager = ModelManager()

texts = [doc.page_content for doc in documents]
embeddings = model_manager.text_embedding.invoke(
    tenant_id="tenant_id",
    provider="openai",
    model="text-embedding-ada-002",
    credentials={"openai_api_key": "sk-xxx"},
    texts=texts,
)

# 创建向量数据库
vector = VectorFactory.create(
    vector_type="milvus",
    collection_name="my_knowledge_base",
    config={
        "host": "localhost",
        "port": 19530,
        "user": "root",
        "password": "Milvus",
    }
)

# 添加文档
vector.create(texts=documents, embeddings=embeddings)

5.2 向量检索

python 复制代码
# 查询文本
query = "What is the capital of France?"

# 获取查询向量
query_embedding = model_manager.text_embedding.invoke(
    tenant_id="tenant_id",
    provider="openai",
    model="text-embedding-ada-002",
    credentials={"openai_api_key": "sk-xxx"},
    texts=[query],
)

# 向量检索
results = vector.search_by_vector(
    query_vector=query_embedding[0],
    top_k=3,
)

for doc in results:
    print(f"Content: {doc.page_content}")
    print(f"Score: {doc.metadata.get('score')}")
    print(f"Source: {doc.metadata.get('source')}")

5.3 全文检索

python 复制代码
# 某些向量数据库支持全文检索
results = vector.search_by_full_text(
    query="capital of France",
    top_k=3,
)

for doc in results:
    print(f"Content: {doc.page_content}")

5.4 删除文档

python 复制代码
# 删除指定 ID 的文档
vector.delete_by_ids(ids=["doc1", "doc2"])

# 删除整个集合
vector.delete()

5.5 混合检索

python 复制代码
from core.rag.retrieval.retrieval_methods import RetrievalMethod

# 混合检索(向量 + 全文)
retrieval_service = RetrievalService(
    dataset_id="dataset_id",
    top_k=5,
    score_threshold=0.5,
    reranking_model={
        "provider": "cohere",
        "model": "rerank-english-v2.0",
    }
)

# 执行检索
results = retrieval_service.retrieve(
    query="What is the capital of France?",
    retrieval_method=RetrievalMethod.HYBRID_SEARCH,
)

6. 错误处理

6.1 常见错误

python 复制代码
from core.rag.datasource.vdb.vector_base import VectorError

try:
    vector.create(texts=documents, embeddings=embeddings)
except VectorError as e:
    # 向量数据库操作错误
    logger.error(f"Vector operation failed: {e}")
except ConnectionError as e:
    # 连接错误
    logger.error(f"Connection failed: {e}")

6.2 重试策略

python 复制代码
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=4, max=10)
)
def add_texts_with_retry(vector, texts, embeddings):
    return vector.add_texts(texts=texts, embeddings=embeddings)

6.3 降级方案

python 复制代码
# 主向量数据库失败时使用备用方案
primary_vector_type = "milvus"
fallback_vector_type = "pgvector"

try:
    vector = VectorFactory.create(
        vector_type=primary_vector_type,
        collection_name=collection_name,
        config=primary_config,
    )
except Exception as e:
    logger.warning(f"Primary vector store failed: {e}, using fallback")
    vector = VectorFactory.create(
        vector_type=fallback_vector_type,
        collection_name=collection_name,
        config=fallback_config,
    )

7. 性能优化

7.1 批量插入

python 复制代码
# 批量插入文档
batch_size = 100
for i in range(0, len(documents), batch_size):
    batch_docs = documents[i:i + batch_size]
    batch_embeddings = embeddings[i:i + batch_size]
    vector.add_texts(texts=batch_docs, embeddings=batch_embeddings)

7.2 索引优化

python 复制代码
# Milvus 索引配置
index_params = {
    "metric_type": "COSINE",  # 或 "L2", "IP"
    "index_type": "IVF_FLAT",  # 或 "HNSW", "IVF_SQ8"
    "params": {"nlist": 1024}
}

# 创建索引
vector.create_index(index_params=index_params)

7.3 缓存策略

python 复制代码
from extensions.ext_redis import redis_client
import hashlib

def get_cached_search_results(query_vector, top_k):
    # 生成缓存键
    cache_key = f"vector:search:{hashlib.md5(str(query_vector).encode()).hexdigest()}:{top_k}"
    
    # 检查缓存
    cached = redis_client.get(cache_key)
    if cached:
        return json.loads(cached)
    
    # 执行检索
    results = vector.search_by_vector(query_vector=query_vector, top_k=top_k)
    
    # 缓存结果
    redis_client.setex(cache_key, 3600, json.dumps(results))
    return results

7.4 并发控制

python 复制代码
import asyncio
from concurrent.futures import ThreadPoolExecutor

async def batch_search(queries, embeddings):
    with ThreadPoolExecutor(max_workers=10) as executor:
        loop = asyncio.get_event_loop()
        tasks = [
            loop.run_in_executor(
                executor,
                vector.search_by_vector,
                embedding,
                5
            )
            for embedding in embeddings
        ]
        results = await asyncio.gather(*tasks)
    return results

8. 监控与日志

8.1 性能监控

python 复制代码
import time

start_time = time.time()
results = vector.search_by_vector(query_vector=query_vector, top_k=5)
end_time = time.time()

logger.info(f"Vector search latency: {end_time - start_time:.2f}s")
logger.info(f"Results count: {len(results)}")

8.2 连接监控

python 复制代码
# 监控连接状态
def check_vector_health():
    try:
        # 执行简单查询测试连接
        vector.search_by_vector(query_vector=[0.1] * 1536, top_k=1)
        return True
    except Exception as e:
        logger.error(f"Vector store health check failed: {e}")
        return False

9. 测试

9.1 单元测试

python 复制代码
import pytest
from unittest.mock import Mock, patch

@patch('pymilvus.Collection')
def test_milvus_create(mock_collection):
    vector = VectorFactory.create(
        vector_type="milvus",
        collection_name="test",
        config={"host": "localhost", "port": 19530}
    )
    
    documents = [Document(page_content="test", metadata={})]
    embeddings = [[0.1] * 1536]
    
    vector.create(texts=documents, embeddings=embeddings)
    
    assert mock_collection.called

9.2 集成测试

python 复制代码
@pytest.mark.integration
def test_milvus_integration():
    # 使用真实 Milvus 实例测试
    vector = VectorFactory.create(
        vector_type="milvus",
        collection_name="test_integration",
        config={
            "host": os.getenv("MILVUS_HOST"),
            "port": int(os.getenv("MILVUS_PORT"))
        }
    )
    
    # 测试完整流程
    documents = [Document(page_content="test doc", metadata={})]
    embeddings = [[0.1] * 1536]
    
    vector.create(texts=documents, embeddings=embeddings)
    results = vector.search_by_vector(query_vector=[0.1] * 1536, top_k=1)
    
    assert len(results) > 0
    
    # 清理
    vector.delete()

10. 扩展新服务

10.1 实现向量类

python 复制代码
# api/core/rag/datasource/vdb/my_vector/my_vector.py
from core.rag.datasource.vdb.vector_base import BaseVector
from core.rag.models.document import Document

class MyVector(BaseVector):
    """My vector database implementation"""
    
    def __init__(self, collection_name: str, config: dict):
        self.collection_name = collection_name
        self.config = config
        self._initialize()
    
    def _initialize(self):
        """Initialize connection"""
        # 实现连接初始化
        pass
    
    def create(self, texts: list[Document], embeddings: list, **kwargs):
        """Create collection and add texts"""
        # 实现创建和插入
        pass
    
    def add_texts(self, texts: list[Document], embeddings: list, **kwargs):
        """Add texts to existing collection"""
        # 实现插入
        pass
    
    def search_by_vector(self, query_vector: list[float], top_k: int = 4, **kwargs):
        """Search by vector"""
        # 实现向量检索
        pass
    
    def delete_by_ids(self, ids: list[str]):
        """Delete by ids"""
        # 实现删除
        pass

10.2 添加到枚举

python 复制代码
# api/core/rag/datasource/vdb/vector_type.py
class VectorType(StrEnum):
    # ... existing types
    MY_VECTOR = "my_vector"

10.3 更新工厂

python 复制代码
# api/core/rag/datasource/vdb/vector_factory.py
if vector_type == VectorType.MY_VECTOR:
    from .my_vector import MyVector
    return MyVector(collection_name=collection_name, config=config)

11. 最佳实践

11.1 选择合适的向量数据库

  • 小规模 (<10万文档): Chroma, PGVector
  • 中规模 (10万-100万): Qdrant, Weaviate
  • 大规模 (>100万): Milvus, Elasticsearch
  • 云原生: 各云服务商托管方案

11.2 索引配置

  • 使用 HNSW 索引获得最佳查询性能
  • 使用 IVF 索引平衡性能和存储
  • 根据数据量调整索引参数

11.3 维度选择

  • OpenAI ada-002: 1536 维
  • Cohere: 1024 维或 768 维
  • 本地模型: 通常 384-768 维

12. 参考资源

相关推荐
月明长歌2 小时前
MySQL 视图:把复杂查询封装成表,并且还能控权限、做解耦
数据库·mysql
l1t2 小时前
postgresql 18版bytea 类型转换的改进
数据库·postgresql
小蒜学长2 小时前
python餐厅点餐系统(代码+数据库+LW)
数据库·spring boot·后端·python
岳麓丹枫0012 小时前
PostgreSQL 中 create database 中的注意事项
数据库·postgresql
梦想画家2 小时前
告别关键词!PostgreSQL+pgvector 玩转语义和图像检索
数据库·postgresql
爱潜水的小L3 小时前
自学嵌入式day41,数据库
jvm·数据库
橙汁味的风3 小时前
《数据库系统概论》陈红、卢卫 - 9 - 关系数据库存储管理
数据库·数据库系统概论
最贪吃的虎3 小时前
Redis 除了缓存,还能干什么?
java·数据库·redis·后端·缓存
u0131635513 小时前
Oracle 报错:PLS-00201: 必须声明标识符‘DBMS_LOCK‘的解决方法
数据库·oracle