向量数据库实战完全指南:从零构建高效向量检索系统
向量数据库是 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 应用开发的核心组件,掌握它对于构建智能应用至关重要:
- 理解原理:向量嵌入将语义转化为数学表示
- 选对工具:Chroma 适合入门,Milvus 适合生产
- 优化性能:选择合适的索引、批量处理
- 实战应用:RAG 是最典型场景
随着大模型的发展,向量数据库的应用场景只会越来越广。现在就动手实践,构建你的第一个向量检索系统吧!
本文链接:https://www.kkkliao.cn/?id=929 转载需授权!
版权声明:本文由廖万里的博客发布,如需转载请注明出处。



手机流量卡
免费领卡
号卡合伙人
产品服务
关于本站
