Codex 教程
按顺序阅读,循序渐进掌握相关 AI 工具与实战方法。
向量数据库(Vector Database)是一种专门用于存储、索引和检索高维向量数据的数据库系统。
你可以把它理解为:把意思相近的东西存在一起,并能快速找到和这个最像的那些东西。
与传统数据库通过精确匹配来查询(WHERE name = 'Alice')不同,向量数据库通过相似度来查询(找到和这张图最相似的 10 张图)。
想象一个图书馆的场景:
| 数据库类型 | 检索方式 | 类比 |
|---|---|---|
| 传统数据库 | 按书号、书名精确检索 | 找一本指定编号的书 |
| 向量数据库 | 按内容相关性检索 | 找"所有和《三体》风格类似的科幻小说" |
这种语义上的相似,正是向量数据库解决的核心问题。
在深入技术细节之前,我们先理解向量数据库解决了什么问题。
传统关系型数据库(MySQL、PostgreSQL)非常擅长处理结构化数据,但在面对以下需求时力不从心:
这些问题的共同特征是:需要理解内容的"含义",而不是做字面匹配。
用 LIKE '%苹果%' 搜索 → 找不到 "iPhone"、"Apple" 用全文索引搜索 → 找不到语义相关但用词不同的内容
下面的图表直观展示了传统数据库和向量数据库在查询方式上的根本差异。
理解向量和嵌入是掌握向量数据库的第一步。
在数学上,向量就是一组有序的数字。
[0.12, -0.54, 0.87, 0.03, ..., 0.61] ← 这就是一个向量
在机器学习中,这组数字代表某个对象的语义特征,维度通常在 128 到 4096 之间。
嵌入(Embedding)是将现实世界的对象(文字、图片、音频等)转换成向量的过程和结果。
这个转换由嵌入模型完成,其核心思想是:语义相近的对象,其向量在空间中的距离也更近。
用一个 2D 简化示例来理解(实际是几百至几千维):
关键理解:向量空间中距离近的两个向量,其原始内容在语义上也更相近。这是向量数据库所有能力的基础。
找到"最相似的向量"的核心是计算两个向量的距离或相似度。以下是三种最常用的方法。
余弦相似度衡量两个向量的方向角,忽略长度。这是最常用的方法,尤其适合文本场景。
公式:
\[
\text{CosineSimilarity}(A, B)
=
\frac{A \cdot B}
{\|A\|\|B\|}
=
\frac{\sum_{i=1}^{n} A_i B_i}
{\sqrt{\sum_{i=1}^{n} A_i^2}\sqrt{\sum_{i=1}^{n} B_i^2}}
\]
欧氏距离衡量两点之间的直线距离,距离越小越相似。
公式:
\[
d(A,B)
=
\sqrt{\sum_{i=1}^{n}(A_i-B_i)^2}
\]
点积是向量相乘求和,结合了方向和长度信息。
公式:
\[
A \cdot B
=
\sum_{i=1}^{n} A_i B_i
\]
以下示例演示了三种相似度计算方法的 Python 实现:
import numpy as np
# 余弦相似度:衡量方向相似性
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# 欧氏距离:衡量绝对位置差异
def euclidean_distance(a, b):
return np.linalg.norm(a - b)
# 点积:结合方向与长度
def dot_product(a, b):
return np.dot(a, b)
# 示例向量
v1 = np.array([0.12, -0.54, 0.87, 0.03])
v2 = np.array([0.10, -0.50, 0.90, 0.05])
v3 = np.array([-0.80, 0.20, -0.30, 0.70])
print(f"v1 vs v2 余弦相似度: {cosine_similarity(v1, v2):.4f}") # 约 0.9997(非常相似)
print(f"v1 vs v3 余弦相似度: {cosine_similarity(v1, v3):.4f}") # 约 -0.55(不相似)
v1 vs v2 余弦相似度: 0.9997 v1 vs v3 余弦相似度: -0.5512
数据量大时(百万、亿级),对每一条数据做相似度计算(暴力检索)太慢。向量数据库使用专门的索引算法来加速查询。
暴力检索遍历所有向量,逐一计算相似度。
| 维度 | 说明 |
|---|---|
| 原理 | 遍历所有向量,逐一计算相似度 |
| 优点 | 结果 100% 精确 |
| 缺点 | 数据量大时极慢,O(n) 复杂度 |
| 适用 | 数据量小于 10 万,对精度要求极高 |
IVF 执行步骤:
HNSW 是目前最主流的向量索引算法,兼顾速度和精度。
HNSW 核心思路:
| 索引类型 | 特点 | 适用场景 |
|---|---|---|
| Flat(暴力) | 精确但慢 | 小数据集、精度优先 |
| IVF_Flat | 聚类后精确搜索,速度快 | 中大规模,内存充足 |
| IVF_PQ | 量化压缩,节省内存 | 超大规模,内存受限 |
| HNSW | 速度快、精度高,内存占用高 | 最常用,推荐首选 |
| ScaNN | Google 出品,优化吞吐量 | 高并发生产环境 |
以下是当前最主流的向量数据库横向对比,帮助你在不同场景下做出选择。
新手建议:从 Chroma 或 pgvector 起步,前者适合 AI 应用原型,后者适合已有 PostgreSQL 的项目。
下面用 Chroma(最易入门)演示完整的增删改查流程。
pip install chromadb openai
以下代码从头到尾演示了如何使用 Chroma 构建一个基于语义的文档搜索系统。
import chromadb
from chromadb.utils import embedding_functions
# ─── 1. 初始化客户端 ───────────────────────────────────────────
# 持久化到本地(推荐)
client = chromadb.PersistentClient(path="./my_vector_db")
# 使用 OpenAI 嵌入模型(也可换成本地模型)
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="your-openai-api-key", # 必填:替换为你的 API Key
model_name="text-embedding-3-small" # 1536 维,性价比高
)
# ─── 2. 创建集合(类似关系库里的"表")────────────────────────
collection = client.get_or_create_collection(
name="my_documents", # 集合名称
embedding_function=openai_ef, # 绑定嵌入函数
metadata={"hnsw:space": "cosine"} # 使用余弦相似度
)
# ─── 3. 插入文档 ──────────────────────────────────────────────
documents = [
"Python 是一种面向对象的解释型编程语言,广泛用于数据科学和 AI 开发",
"机器学习是人工智能的子领域,让计算机从数据中学习规律",
"深度学习使用多层神经网络,在图像识别和 NLP 任务中表现优异",
"向量数据库专门存储高维向量,支持语义相似度搜索",
"PostgreSQL 是功能强大的开源关系型数据库",
"Redis 是基于内存的高性能键值数据库,常用于缓存",
"Docker 容器化技术让应用可以在任何环境中一致运行",
"Git 是分布式版本控制系统,是现代软件开发的基础工具",
]
ids = [f"doc_{i}" for i in range(len(documents))]
# 批量插入(Chroma 自动调用嵌入模型转为向量后存储)
collection.add(
documents=documents,
ids=ids,
metadatas=[{"source": "tutorial", "index": i} for i in range(len(documents))]
)
print(f"已插入 {len(documents)} 条文档")
已插入 8 条文档
# ─── 4. 语义搜索 ──────────────────────────────────────────────
query = "如何用 Python 做人工智能"
results = collection.query(
query_texts=[query],
n_results=3, # 返回最相似的 3 条
include=["documents", "distances", "metadatas"]
)
print(f"\n查询:{query}")
print("-" * 50)
for i, (doc, dist) in enumerate(zip(
results["documents"][0],
results["distances"][0]
)):
similarity = 1 - dist # 余弦距离转相似度
print(f"第 {i+1} 名(相似度 {similarity:.4f}):")
print(f" {doc}")
print()
查询:如何用 Python 做人工智能 -------------------------------------------------- 第 1 名(相似度 0.9231):Python 是一种面向对象的解释型编程语言... 第 2 名(相似度 0.8874):机器学习是人工智能的子领域... 第 3 名(相似度 0.8612):深度学习使用多层神经网络...
# ─── 5. 带过滤条件的搜索(元数据过滤)───────────────────────
results_filtered = collection.query(
query_texts=["数据库技术"],
n_results=2,
where={"source": "tutorial"}, # 只在 source=tutorial 的文档里搜索
include=["documents", "distances"]
)
# ─── 6. 更新文档 ──────────────────────────────────────────────
collection.update(
ids=["doc_0"],
documents=["Python 是目前最流行的编程语言,在 AI、数据分析、Web 开发中均有广泛应用"],
metadatas=[{"source": "tutorial", "index": 0, "updated": True}]
)
# ─── 7. 删除文档 ──────────────────────────────────────────────
collection.delete(ids=["doc_7"]) # 删除 Git 相关文档
# ─── 8. 查看集合统计 ──────────────────────────────────────────
print(f"当前集合文档数:{collection.count()}")
如果你不想使用 OpenAI API,可以用本地嵌入模型完全离线运行。
import chromadb
from sentence_transformers import SentenceTransformer
# 使用本地嵌入模型(无需 API Key,完全离线)
model = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2") # 支持中文
client = chromadb.Client()
collection = client.create_collection("local_demo")
texts = ["今天天气很好", "阳光明媚,适合出门", "股市大涨了", "明天可能会下雨"]
# 手动生成向量后插入
embeddings = model.encode(texts).tolist()
collection.add(
embeddings=embeddings,
documents=texts,
ids=[f"id_{i}" for i in range(len(texts))]
)
# 查询
query_embedding = model.encode(["今天天气怎么样"]).tolist()
results = collection.query(query_embeddings=query_embedding, n_results=2)
print(results["documents"])
# 输出: [['今天天气很好', '阳光明媚,适合出门']]
如果你的项目已经使用 PostgreSQL,pgvector 是最轻量的接入方式。
-- 安装扩展
CREATE EXTENSION IF NOT EXISTS vector;
-- 建表:存储文章标题及其向量(1536维)
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
embedding vector(1536) -- 向量列,1536 维
);
-- 创建 HNSW 索引加速查询
CREATE INDEX ON articles
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- 插入数据(向量由应用层生成后传入)
INSERT INTO articles (title, embedding)
VALUES ('Python 入门指南', '[0.12, -0.54, 0.87, ...]'::vector);
-- 语义搜索:找最相似的 5 篇文章
SELECT id, title,
1 - (embedding <=> '[0.10, -0.50, 0.90, ...]'::vector) AS similarity
FROM articles
ORDER BY embedding <=> '[0.10, -0.50, 0.90, ...]'::vector
LIMIT 5;
注意: 是 pgvector 提供的向量距离运算符,用于计算余弦距离。用 1 减去余弦距离即得到余弦相似度。
向量数据库在 AI 时代的应用场景非常广泛,以下是六个最典型的场景概览。
RAG 是目前向量数据库最主要的应用场景之一。下面是其核心工作流程:
根据你的具体情况,按照以下决策树选择合适的向量数据库:
你的情况是什么?
│
├─── 已有 PostgreSQL,且数据量 < 500 万
│ └──> 用 pgvector,无缝集成,零额外运维
│
├─── 做 AI/LLM 应用原型,快速验证
│ └──> 用 Chroma,几行代码跑起来
│
├─── 需要生产级部署,性能优先,数据量 500 万 ~ 1 亿
│ └──> 用 Qdrant,Rust 实现,性能强
│
├─── 超大规模(> 1 亿),有 K8s 运维能力
│ └──> 用 Milvus,分布式,功能最全
│
└─── 团队没有运维能力,愿意付费
└──> 用 Pinecone 云服务,开箱即用
选择合适的嵌入模型是向量数据库应用的关键第一步。
| 需求 | 推荐模型 |
|---|---|
| 中英文文本(高质量) | OpenAI text-embedding-3-small |
| 中文文本(本地离线) | BAAI/bge-large-zh-v1.5 |
| 多语言通用 | paraphrase-multilingual-MiniLM-L12-v2 |
| 图文多模态 | OpenAI CLIP 系列 |
1. 批量插入:一次插入多条,避免频繁单条写入。
# 推荐:批量插入 collection.add(documents=docs_list, ids=ids_list) # 不推荐:循环单条(每次都重新索引,效率极低) # for doc, id in zip(docs_list, ids_list): # collection.add(documents=[doc], ids=[id])
2. 向量归一化:使用余弦相似度前,提前归一化向量可加速计算。
import numpy as np
def normalize(v):
"""对向量做 L2 归一化,使模长为 1"""
return v / np.linalg.norm(v)
3. 合理设置 n_results:不要无脑设置很大的 top_k,一般 RAG 场景 3~10 条足够。
4. 善用元数据过滤:在搜索时配合 where 条件,缩小搜索范围。
# 只在"技术文档"分类里搜索,缩小范围提升精度
collection.query(
query_texts=["Python 异常处理"],
where={"category": "tech_doc"},
n_results=5
)
5. 定期重建索引:数据量增长后,适时重建 HNSW 索引以维持查询性能。
以下是初学者使用向量数据库时最容易遇到的问题及解决方案。
| 问题 | 说明 | 解决方案 |
|---|---|---|
| 嵌入模型要统一 | 插入和查询必须用同一个模型 | 在配置文件中固定模型版本 |
| 维度不匹配 | 换了模型但没重建集合 | 换模型时删除重建集合 |
| 文本过长 | 大多数模型有 token 限制(512~8192) | 超长文本先分块(chunking) |
| 相似度不准确 | 文本没有分块,语义被稀释 | 按段落或固定长度切分文档 |
| 冷启动慢 | 数据量大时首次加载索引耗时 | 提前预热,或使用持久索引 |
让我们回顾本教程的核心知识点:
向量数据库是 AI 时代基础设施的重要一环。
它解决了传统数据库无法处理的语义相似性搜索问题,是构建 RAG 系统、推荐系统、多模态搜索的核心组件。