前言

大家好,我是mr_pyx。最近在做RAG相关项目时,发现不少同学对向量数据库的理解还停留在“会用API调一调”的阶段。趁着周末,我把向量数据库的核心知识点梳理了一下,希望能帮助大家建立一个更系统的认知。


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

1.1 传统数据库的困境

先来看一个实际场景:假设你有一个电商平台,用户上传了一张红色连衣裙的照片,想要找到同款或相似的商品。

  • MySQL:只能通过标签(“红色”、“连衣裙”)做精确匹配,但无法理解“丝绸质感”、“A字版型”这类抽象特征

  • Elasticsearch:基于关键词匹配,搜“苹果手机”会出现“苹果”和“手机”,但分不清你到底是想要水果还是手机

根本问题:传统数据库处理的是结构化数据,而现实世界70%以上是非结构化数据(图片、文本、音频、视频)。

1.2 向量的诞生

Embedding(嵌入)技术的出现改变了这一切。通过深度学习模型,我们可以将任何事物转换成一个“语义向量”:

text

“国王” → [0.25, -0.13, 0.87, 0.04, ...]  # 假设768维
“王后” → [0.24, -0.12, 0.86, 0.05, ...]  # 与国王非常接近
“苹果” → [-0.62, 0.33, 0.01, -0.45, ...] # 完全不同

相似的事物在向量空间中距离较近,这不就是我们想要的“语义搜索”吗?


二、向量数据库的核心原理

2.1 相似度计算的三种方式

假设有两个向量 A 和 B,如何判断它们的相似度?

方法 公式 特点
余弦相似度 cos(θ) = (A·B) / ( A B ) 关注方向而非长度,最常用
欧氏距离 √Σ(Ai - Bi)² 关注绝对位置差异
点积 Σ Ai × Bi 需要向量已归一化

💡 实践经验:文本搜索一般用余弦相似度,图像检索有时用欧氏距离效果更好。具体用哪个,建议做A/B测试。

2.2 暴力搜索 vs 近似最近邻

暴力搜索:逐条计算,时间复杂度 O(n)。1亿条数据,假设每条计算1微秒,需要100秒。

ANN算法:牺牲少量精度换取百倍甚至千倍的性能提升。

主流的ANN索引算法:

text

┌─────────────────────────────────────────────┐
│  HNSW (Hierarchical Navigable Small World) │ ← 目前综合最优
│  - 跳表+图结构                               │
│  - 查询速度快,构建慢,内存占用高             │
├─────────────────────────────────────────────┤
│  IVF (Inverted File Index)                  │
│  - 聚类+倒排                                 │
│  - 内存友好,适合大规模数据                   │
├─────────────────────────────────────────────┤
│  PQ (Product Quantization)                  │
│  - 向量压缩                                 │
│  - 大幅降低内存,精度有一定损失               │
└─────────────────────────────────────────────┘

2.3 HNSW 原理简析(图文并茂版)

HNSW 的思想很有趣:借鉴了跳表的多层结构。

text

第2层: o ------ o                (节点很少)
第1层: o -- o -- o -- o          (节点较多)
第0层: o-o-o-o-o-o-o-o-o-o-o-o-o (所有节点)

搜索时从上往下:
1. 在第2层找到最近节点
2. 跳到第1层继续找
3. 最后到第0层精确搜索

这也是为什么 HNSW 的查询复杂度可以达到 O(log N)。


三、主流向量数据库对比

3.1 产品矩阵

数据库 类型 特点 适合场景
Milvus 专用 功能最全,社区活跃 生产级大规模应用
Qdrant 专用 Rust编写,性能优秀 对性能有极致要求
Pinecone 云服务 全托管,免运维 快速验证MVP
Chroma 嵌入式 轻量级,Python友好 本地开发/小项目
pgvector 插件 复用PostgreSQL生态 不想引入新组件

3.2 选型建议

python

# 根据不同场景的决策树
if 数据量 < 100万:
    if 不想加新组件:
        选 pgvector
    else:
        选 Chroma
elif 100万 < 数据量 < 1亿:
    if 团队有运维能力:
        选 Qdrant / Milvus
    else:
        选 Pinecone (云服务)
else:  # > 1亿
    选 Milvus (分布式集群)

3.3 pgvector 实战(代码示例)

不需要额外部署服务,直接在 PostgreSQL 中使用:

sql

-- 1. 安装扩展
CREATE EXTENSION vector;

-- 2. 创建表(1536维是OpenAI embeddings的维度)
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content TEXT,
    embedding VECTOR(1536)
);

-- 3. 创建索引(IVFFlat,需要先有数据)
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops);

-- 4. 相似度搜索
SELECT content, 1 - (embedding <=> '[0.1, 0.2, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 10;

⚠️ 坑点提醒:IVFFlat索引需要先插入一部分数据才能创建,否则效果很差。也可以选择HNSW索引(pgvector 0.5.0+支持)。


四、实战案例:基于RAG的智能客服

4.1 场景描述

我们有个800页的产品文档,用户每次提问都让大模型回答显然不现实(token成本高+信息可能过时)。用RAG方案:

python

# 整体架构
用户问题 → 向量化 → 检索相关文档 → 拼接Prompt → 大模型回答

4.2 代码实现

python

import chromadb
from sentence_transformers import SentenceTransformer

# 1. 初始化
client = chromadb.Client()
collection = client.create_collection("docs")
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')  # 中文embedding模型

# 2. 文档入库(离线阶段)
documents = ["产品A支持5G网络", "产品B电池容量5000mAh", ...]
embeddings = model.encode(documents)
collection.add(
    ids=[str(i) for i in range(len(documents))],
    documents=documents,
    embeddings=embeddings
)

# 3. 检索+生成(在线阶段)
def answer_question(question):
    # 检索
    q_embedding = model.encode([question])
    results = collection.query(query_embeddings=q_embedding, n_results=3)
    
    # 拼接上下文
    context = "\n".join(results['documents'][0])
    prompt = f"""基于以下信息回答问题:
    {context}
    问题:{question}
    回答:"""
    
    # 调用大模型
    return call_llm(prompt)  # 此处省略具体调用

4.3 效果对比

方式 准确率 平均延迟 Token消耗
直接问大模型 65% 2s 800/token
RAG (Top-3) 89% 1.5s 1200/token

准确率提升24%,而且回答有据可查,不会胡编乱造。


五、常见陷阱与最佳实践

5.1 几个容易被坑的点

❌ 坑1:忽视embedding模型选择

  • 用通用英文模型处理中文技术文档 → 效果惨不忍睹

  • ✅ 选择BGE、M3E等中文优化模型

❌ 坑2:小批量数据追求ANN索引

  • 数据集只有5000条,用HNSW反而比暴力搜索慢

  • ✅ 数据<1万时,暴力搜索足够

❌ 坑3:忽略索引重建

  • IVFFlat插入新数据后聚类失效,查询变慢

  • ✅ 定期执行 REINDEX 或设置自动重建阈值

5.2 性能优化的三板斧

python

# 1. 批量操作(单条插入vs批量)
collection.add(embeddings=all_data)  # ✅ 快
for d in all_data:                   # ❌ 慢
    collection.add(embeddings=[d])

# 2. 合理设置n_probe (IVFFlat查询时的聚类数)
index.nprobe = 10  # 默认1,调高提升召回但增加延迟

# 3. 降维(如果原始维度太高)
from sklearn.decomposition import PCA
pca = PCA(n_components=512)  # 从1536降到512
reduced = pca.fit_transform(embeddings)

六、未来趋势

  1. 多模态数据库:一张表同时存文本、图片、音频的向量,支持跨模态搜索

  2. 磁盘ANN:目前的索引大多依赖内存,未来会有更多磁盘友好型算法

  3. 与SQL深度融合SELECT * FROM products WHERE category='手机' AND embedding <-> query < 0.5


写在最后

向量数据库不是一个“银弹”技术,它解决的是特定的相似度搜索问题。在实际项目中,往往需要与传统数据库配合使用:向量数据库负责召回,传统数据库负责过滤和排序

纸上得来终觉浅,建议大家亲自跑一下代码。可以从docker启动一个Qdrant开始,10分钟就能跑通第一个相似度搜索demo。

本文代码已在GitHub开源github.com/xxxx/vector-db-demo (欢迎star)


参考阅读

如果觉得这篇文章对你有帮助,欢迎点赞+收藏+关注

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐