外观
向量数据库
约 1878 字大约 6 分钟
2025-04-07
一、定义与核心作用
向量数据库是RAG(检索增强生成)系统的核心组件,专门用于存储和检索高维向量数据。这些向量由嵌入模型(如BERT、BGE-M3等)将文本、图像等非结构化数据转换而来,能够捕捉语义特征和上下文关系。在RAG中,向量数据库通过高效的相似性搜索,从海量知识库中快速召回与用户查询语义最相关的片段,为生成模型提供精准的上下文支持。
二、技术原理与核心能力
高维向量处理
支持存储千亿级向量,通过HNSW、IVF等索引算法优化高维空间中的相似性计算,实现毫秒级响应。例如,Milvus通过分布式架构支持水平扩展,而FAISS则专注于单机高性能检索。近似最近邻搜索(ANN)
牺牲少量精度以换取检索效率,支持余弦相似度、欧氏距离等计算方式。部分数据库(如Qdrant)支持GPU加速,进一步提升吞吐量。混合查询优化
结合向量相似度与元数据过滤(如文档来源、时间戳),通过条件筛选缩小检索范围。例如,HybridRAG架构中同时使用向量数据库和图数据库,提升复杂关系推理能力。动态更新与压缩
支持增量数据插入与索引自动优化,部分系统(如腾讯云向量数据库)通过量化技术将向量维度从768压缩至64,存储成本降低80%。
三、主流产品对比
数据库 | 核心优势 | 适用场景 |
---|---|---|
Milvus | 分布式架构支持千亿级数据,集成HNSW/IVF索引,适合大规模企业级应用 | 金融风控、跨模态搜索 |
FAISS | Facebook开源库,GPU加速优化,易于与PyTorch/TensorFlow集成 | 学术研究、轻量级原型开发 |
Chroma | 轻量级设计,内置嵌入模型,支持本地快速部署 | 小型知识库、个人开发者项目 |
Qdrant | 支持多模态混合检索,提供RESTful API和动态负载均衡 | 多语言客服系统、电商推荐 |
Pinecone | 全托管云服务,自动索引优化,提供99.9% SLA保障 | 初创企业、快速迭代的AI应用 |
四、代码示例
import os
from openai import OpenAI
import matplotlib.pyplot as plt
import numpy as np
from typing import Dict, List, Optional, Tuple, Union
import ollama
class BaseEmbeddings:
"""
向量化的基类,用于将文本转换为向量表示。不同的子类可以实现不同的向量获取方法。
"""
def __init__(self, path: str, is_api: bool) -> None:
"""
初始化基类。
参数:
path (str) - 如果是本地模型,path 表示模型路径;如果是API模式,path可以为空
is_api (bool) - 表示是否使用API调用,如果为True表示通过API获取Embedding
"""
self.path = path
self.is_api = is_api
def get_embedding(self, text: str, model: str) -> List[float]:
"""
抽象方法,用于获取文本的向量表示,具体实现需要在子类中定义。
参数:
text (str) - 需要转换为向量的文本
model (str) - 所使用的模型名称
返回:
list[float] - 文本的向量表示
"""
raise NotImplementedError
@classmethod
def cosine_similarity(cls, vector1: List[float], vector2: List[float]) -> float:
"""
计算两个向量之间的余弦相似度,用于衡量它们的相似程度。
参数:
vector1 (list[float]) - 第一个向量
vector2 (list[float]) - 第二个向量
返回:
float - 余弦相似度值,范围从 -1 到 1,越接近 1 表示向量越相似
"""
dot_product = np.dot(vector1, vector2) # 向量点积
magnitude = np.linalg.norm(vector1) * np.linalg.norm(vector2) # 向量的模
if not magnitude:
return 0
return dot_product / magnitude # 计算余弦相似度
class OpenAIEmbedding(BaseEmbeddings):
"""
使用 OpenAI 的 Embedding API 来获取文本向量的类,继承自 BaseEmbeddings。
"""
def __init__(self, path: str = '', is_api: bool = True) -> None:
"""
初始化类,设置 OpenAI API 客户端,如果使用的是 API 调用。
参数:
path (str) - 本地模型的路径,使用API时可以为空
is_api (bool) - 是否通过 API 获取 Embedding,默认为 True
"""
super().__init__(path, is_api)
if self.is_api:
# 初始化 OpenAI API 客户端
from openai import OpenAI
self.client = OpenAI()
self.client.api_key = os.getenv("OPENAI_API_KEY") # 从环境变量中获取 API 密钥
self.client.base_url = os.getenv("OPENAI_BASE_URL") # 从环境变量中获取 API 基础URL
def get_embedding(self, text: str, model: str = "mxbai-embed-large") -> List[float]:
"""
使用 OpenAI 的 Embedding API 获取文本的向量表示。
参数:
text (str) - 需要转化为向量的文本
model (str) - 使用的 Embedding 模型名称,默认为 'mxbai-embed-large'
返回:
list[float] - 文本的向量表示
"""
if self.is_api:
# 去掉文本中的换行符,保证输入格式规范
text = text.replace("\n", " ")
# 调用 OpenAI API 获取文本的向量表示
return self.client.embeddings.create(input=[text], model=model).data[0].embedding
else:
return ollama.embeddings(model=model, prompt=text).embedding
class VectorStore:
def __init__(self, document: List[str] = None) -> None:
"""
初始化向量存储类,存储文档和对应的向量表示。
:param document: 文档列表,默认为空。
"""
if document is None:
document = []
self.document = document # 存储文档内容
self.vectors = [] # 存储文档的向量表示
def get_vector(self, EmbeddingModel: BaseEmbeddings) -> List[List[float]]:
"""
使用传入的 Embedding 模型将文档向量化。
:param EmbeddingModel: 传入的用于生成向量的模型(需继承 BaseEmbeddings 类)。
:return: 返回文档对应的向量列表。
"""
# 遍历所有文档,获取每个文档的向量表示
self.vectors = [EmbeddingModel.get_embedding(doc) for doc in self.document]
return self.vectors
def persist(self, path: str = 'storage'):
"""
将文档和对应的向量表示持久化到本地目录中,以便后续加载使用。
:param path: 存储路径,默认为 'storage'。
"""
if not os.path.exists(path):
os.makedirs(path) # 如果路径不存在,创建路径
# 保存向量为 numpy 文件
np.save(os.path.join(path, 'vectors.npy'), self.vectors)
# 将文档内容存储到文本文件中
with open(os.path.join(path, 'documents.txt'), 'w') as f:
for doc in self.document:
f.write(f"{doc}\n")
def load_vector(self, path: str = 'storage'):
"""
从本地加载之前保存的文档和向量数据。
:param path: 存储路径,默认为 'storage'。
"""
# 加载保存的向量数据
self.vectors = np.load(os.path.join(path, 'vectors.npy')).tolist()
# 加载文档内容
with open(os.path.join(path, 'documents.txt'), 'r') as f:
self.document = [line.strip() for line in f.readlines()]
def get_similarity(self, vector1: List[float], vector2: List[float]) -> float:
"""
计算两个向量的余弦相似度。
:param vector1: 第一个向量。
:param vector2: 第二个向量。
:return: 返回两个向量的余弦相似度,范围从 -1 到 1。
"""
dot_product = np.dot(vector1, vector2)
magnitude = np.linalg.norm(vector1) * np.linalg.norm(vector2)
if not magnitude:
return 0
return dot_product / magnitude
def query(self, query: str, EmbeddingModel: BaseEmbeddings, k: int = 1) -> List[str]:
"""
根据用户的查询文本,检索最相关的文档片段。
:param query: 用户的查询文本。
:param EmbeddingModel: 用于将查询向量化的嵌入模型。
:param k: 返回最相似的文档数量,默认为 1。
:return: 返回最相似的文档列表。
"""
# 将查询文本向量化
query_vector = EmbeddingModel.get_embedding(query)
# 计算查询向量与每个文档向量的相似度
similarities = [self.get_similarity(query_vector, vector) for vector in self.vectors]
# 获取相似度最高的 k 个文档索引
top_k_indices = np.argsort(similarities)[-k:][::-1]
# 返回对应的文档内容
return [self.document[idx] for idx in top_k_indices]
# 初始化文档列表
documents = [
"机器学习是人工智能的一个分支。",
"深度学习是一种特殊的机器学习方法。",
"监督学习是一种训练模型的方式。",
"强化学习通过奖励和惩罚进行学习。",
"无监督学习不依赖标签数据。",
]
# 创建向量数据库
vector_store = VectorStore(document=documents)
# 使用 OpenAI Embedding 模型对文档进行向量化
embedding_model = OpenAIEmbedding("", False)
# 获取文档向量并存储
vector_store.get_vector(embedding_model)
# 持久化存储到本地
vector_store.persist('storage')
# 模拟用户查询
query = "什么是深度学习?"
result = vector_store.query(query, embedding_model)
print("检索结果:", result)
loaded_array = np.load('./storage/vectors.npy')
print(loaded_array)
版权所有
版权归属:NateHHX