当前位置:首页 > AI > 正文内容

向量数据库实战完全指南:从零构建高效向量检索系统

廖万里14小时前AI2

向量数据库是 AI 时代的核心基础设施,它让计算机能够"理解"语义相似性,是实现智能搜索、推荐系统和 RAG 应用的关键技术。本文将深入讲解向量数据库的核心原理、主流方案对比,以及从零构建向量检索系统的完整实战。

一、为什么需要向量数据库?

在传统数据库中,我们使用精确匹配来查找数据——比如搜索关键词"苹果",只能找到包含"苹果"二字的内容。但这种搜索方式存在明显缺陷:

  • 语义鸿沟:搜索"水果"找不到"苹果"相关内容
  • 同义词问题:"手机"和"移动电话"无法关联
  • 多模态需求:无法处理图片、音频等非文本数据

向量数据库的出现解决了这些问题。它将所有数据转换为高维向量(通常是几百到几千维的浮点数数组),通过计算向量之间的"距离"来衡量相似度。这使得:

  • 语义相似的内容在向量空间中距离更近
  • 可以跨模态检索(用文字搜索图片)
  • 支持模糊匹配和相似推荐

1.1 向量嵌入原理

向量嵌入是将离散数据转换为连续向量的过程。以文本为例:

# 使用 OpenAI 的 text-embedding-3-small 模型生成向量嵌入
import openai

def get_embedding(text):
    """
    将文本转换为向量嵌入
    返回 1536 维的浮点数数组
    
    参数:
        text: 输入文本字符串
    
    返回:
        embedding: 1536维向量 (list[float])
    """
    response = openai.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return response.data[0].embedding

# 示例:将句子转换为向量
text1 = "苹果是一种水果"
text2 = "香蕉是热带水果"
text3 = "Python 是编程语言"

emb1 = get_embedding(text1)
emb2 = get_embedding(text2)
emb3 = get_embedding(text3)

1.2 相似度计算

向量数据库最常用的相似度计算方法是余弦相似度欧氏距离

import numpy as np

def cosine_similarity(vec_a, vec_b):
    """
    计算两个向量的余弦相似度
    值范围 [-1, 1],越大越相似
    
    公式: cos(θ) = (A · B) / (||A|| * ||B||)
    """
    dot_product = np.dot(vec_a, vec_b)
    norm_a = np.linalg.norm(vec_a)
    norm_b = np.linalg.norm(vec_b)
    
    return dot_product / (norm_a * norm_b)

def euclidean_distance(vec_a, vec_b):
    """
    计算两个向量的欧氏距离
    值范围 [0, +∞),越小越相似
    
    公式: d = √(Σ(Ai - Bi)²)
    """
    return np.linalg.norm(np.array(vec_a) - np.array(vec_b))

二、主流向量数据库对比

目前市面上有多款优秀的向量数据库,各有特点:

数据库 类型 优势 适用场景
Milvus 开源分布式 高性能、可扩展、支持多种索引 大规模生产环境
Pinecone 云端托管 零运维、即开即用 快速原型、中小规模
Chroma 轻量级开源 Python 友好、易于集成 本地开发、原型验证
Weaviate 开源云原生 内置向量化、GraphQL API 语义搜索、知识图谱
Qdrant 开源高性能 Rust 实现、过滤能力强 需要复杂过滤的场景

2.1 Chroma 快速入门

Chroma 是最适合入门的向量数据库,安装简单、API 直观:

# 安装: pip install chromadb

import chromadb
from chromadb.utils import embedding_functions

# 初始化客户端(数据存储在本地)
client = chromadb.PersistentClient(path="./chroma_db")

# 使用 OpenAI 嵌入函数
embedding_function = embedding_functions.OpenAIEmbeddingFunction(
    api_key="your-api-key",
    model_name="text-embedding-3-small"
)

# 创建集合(类似于数据库表)
collection = client.create_collection(
    name="documents",
    embedding_function=embedding_function,
    metadata={"description": "我的文档向量库"}
)

# 添加文档
documents = [
    "Python 是一种解释型编程语言",
    "机器学习是人工智能的子领域",
    "向量数据库用于存储高维向量",
    "深度学习使用神经网络进行特征学习"
]

collection.add(
    documents=documents,
    ids=["doc1", "doc2", "doc3", "doc4"]
)

# 语义搜索
results = collection.query(
    query_texts=["编程语言有哪些"],
    n_results=2
)

print(results["documents"][0])

2.2 Milvus 生产级部署

Milvus 是面向生产环境的高性能向量数据库:

# 使用 Docker 启动 Milvus
# docker run -d --name milvus -p 19530:19530 milvusdb/milvus:latest

from pymilvus import (
    connections, 
    Collection, 
    FieldSchema, 
    CollectionSchema, 
    DataType
)

# 连接 Milvus 服务器
connections.connect(
    alias="default",
    host="localhost",
    port="19530"
)

# 定义 Schema
fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536),
    FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=200),
    FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=5000)
]

schema = CollectionSchema(
    fields=fields,
    description="文档向量集合"
)

# 创建集合
collection = Collection(name="documents", schema=schema)

# 创建向量索引
index_params = {
    "metric_type": "COSINE",
    "index_type": "IVF_FLAT",
    "params": {"nlist": 128}
}

collection.create_index(
    field_name="embedding",
    index_params=index_params
)

三、实战案例:构建 RAG 知识问答系统

RAG(Retrieval-Augmented Generation)是当前最热门的 AI 应用架构,它将向量检索与大语言模型结合,实现了"基于私有知识库的智能问答"。

3.1 系统架构

用户提问 → 向量化 → 向量检索 → 获取相关文档 → 构建 Prompt → LLM 生成回答

3.2 核心代码实现

"""
RAG 知识问答系统核心实现
"""

import chromadb
from chromadb.utils import embedding_functions
import openai
from typing import List, Dict

class RAGSystem:
    """RAG 知识问答系统"""
    
    def __init__(self, openai_api_key: str, db_path: str = "./rag_db"):
        openai.api_key = openai_api_key
        self.client = chromadb.PersistentClient(path=db_path)
        
        self.embedding_function = embedding_functions.OpenAIEmbeddingFunction(
            api_key=openai_api_key,
            model_name="text-embedding-3-small"
        )
        
        self.collection = self.client.get_or_create_collection(
            name="knowledge_base",
            embedding_function=self.embedding_function
        )
    
    def chunk_text(self, text: str, chunk_size: int = 500) -> List[str]:
        """将长文本分割成适合检索的块"""
        chunks = []
        start = 0
        
        while start < len(text):
            end = start + chunk_size
            if end < len(text):
                for sep in ["。", "!", "?", ".", "!", "?"]:
                    last_sep = text.rfind(sep, start, end)
                    if last_sep != -1:
                        end = last_sep + 1
                        break
            
            chunk = text[start:end].strip()
            if chunk:
                chunks.append(chunk)
            start = end
        
        return chunks
    
    def add_documents(self, documents: List[Dict[str, str]]):
        """批量添加文档到知识库"""
        all_chunks = []
        all_ids = []
        all_metadatas = []
        
        for doc_idx, doc in enumerate(documents):
            chunks = self.chunk_text(doc["content"])
            
            for chunk_idx, chunk in enumerate(chunks):
                chunk_id = f"doc_{doc_idx}_chunk_{chunk_idx}"
                all_chunks.append(chunk)
                all_ids.append(chunk_id)
                all_metadatas.append({
                    "title": doc["title"],
                    "source": doc.get("source", "unknown")
                })
        
        if all_chunks:
            self.collection.add(
                documents=all_chunks,
                ids=all_ids,
                metadatas=all_metadatas
            )
    
    def retrieve(self, query: str, top_k: int = 5) -> List[Dict]:
        """检索与查询最相关的文档片段"""
        results = self.collection.query(
            query_texts=[query],
            n_results=top_k,
            include=["documents", "metadatas", "distances"]
        )
        
        retrieved = []
        for i in range(len(results["documents"][0])):
            retrieved.append({
                "content": results["documents"][0][i],
                "metadata": results["metadatas"][0][i],
                "distance": results["distances"][0][i]
            })
        
        return retrieved
    
    def generate_answer(self, query: str, context: List[Dict]) -> str:
        """基于检索结果生成回答"""
        context_text = "\n\n".join([
            f"【相关资料 {i+1}】\n{item['content']}"
            for i, item in enumerate(context)
        ])
        
        prompt = f"""你是一个专业的知识问答助手。请根据以下参考资料回答用户问题。

参考资料:
{context_text}

用户问题:{query}

请给出你的回答:"""

        response = openai.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "你是一个专业的知识问答助手。"},
                {"role": "user", "content": prompt}
            ],
            temperature=0.3,
            max_tokens=1000
        )
        
        return response.choices[0].message.content
    
    def ask(self, question: str, top_k: int = 3) -> Dict:
        """完整的问答流程"""
        context = self.retrieve(question, top_k)
        answer = self.generate_answer(question, context)
        
        return {
            "question": question,
            "answer": answer,
            "sources": [item["metadata"]["title"] for item in context]
        }

四、性能优化技巧

4.1 索引选择

向量数据库支持多种索引类型,选择合适的索引能大幅提升检索性能:

  • FLAT:暴力搜索,精度最高但速度最慢,适合小数据集
  • IVF_FLAT:倒排文件索引,平衡精度和速度
  • HNSW:层次导航小世界图,查询速度最快

4.2 批量处理

向量化操作是 I/O 密集型任务,批量处理能显著提升效率:

def batch_embed(texts: List[str], batch_size: int = 100) -> List[List[float]]:
    """批量生成向量嵌入,减少 API 调用次数"""
    embeddings = []
    
    for i in range(0, len(texts), batch_size):
        batch = texts[i:i + batch_size]
        response = openai.embeddings.create(
            model="text-embedding-3-small",
            input=batch
        )
        embeddings.extend([item.embedding for item in response.data])
    
    return embeddings

总结

向量数据库是 AI 应用开发的核心组件,掌握它对于构建智能应用至关重要:

  1. 理解原理:向量嵌入将语义转化为数学表示
  2. 选对工具:Chroma 适合入门,Milvus 适合生产
  3. 优化性能:选择合适的索引、批量处理
  4. 实战应用:RAG 是最典型场景

随着大模型的发展,向量数据库的应用场景只会越来越广。现在就动手实践,构建你的第一个向量检索系统吧!

本文链接:https://www.kkkliao.cn/?id=929 转载需授权!

分享到:

版权声明:本文由廖万里的博客发布,如需转载请注明出处。


发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。