嵌入与向量搜索:入门路线图
你想为应用添加语义搜索——用户输入查询后,根据含义而非精确关键词返回结果。但你不确定从何入手:什么是嵌入?需要向量数据库吗?如何衡量相似度?这份路线图用实用步骤和可立即运行的代码来回答这些问题。
什么是嵌入?
嵌入是一个由浮点数组成的稠密向量,用来表示输入(文本、图像、音频等)的含义。对于文本,像 text-embedding-3-small 这样的模型或开源替代方案(例如 all-MiniLM-L6-v2)会把一个句子转换成比如 384 维的向量。含义相近的词或句子在这个向量空间中彼此靠近。
例如:"cat" 和 "kitten" 的向量会比 "cat" 和 "airplane" 更接近。这一特性使语义搜索成为可能:你为文档和查询生成嵌入,然后找到最近的文档向量。
向量搜索如何工作
向量搜索(也称相似度搜索)是在数据集中找到与查询向量最相似的向量。相似度通常用余弦相似度或点积来衡量。对于归一化向量,余弦相似度和点积是等价的。
暴力搜索会将查询与每个向量逐一比较——对几千个向量来说没问题,但对数百万个就太慢了。这正是近似最近邻(ANN)算法的用武之地,例如 HNSW(分层可导航小世界)或 IVF(倒排文件索引)。它们用极小的精度损失换取巨大的速度提升。
分步指南:构建语义搜索原型
- 选择嵌入模型。对于英文文本,可以从 Sentence Transformers 的小型快速模型如
all-MiniLM-L6-v2(384 维)开始。生产环境可考虑 OpenAI 的text-embedding-3-small(1536 维)或text-embedding-3-large(3072 维)。 - 为文档生成嵌入。将长文本切分成块(例如 200–500 词),让每个块包含一个连贯的想法。将原始文本与向量一起存储。
- 选择向量存储。快速上手可用内存库如 FAISS 或简单的 NumPy 数组。生产环境则选择专用向量数据库(见下表)。
- 为查询生成嵌入。使用同一个模型为用户搜索查询生成嵌入。
- 搜索。计算查询向量与所有文档向量的相似度(或使用 ANN 索引),返回前 k 个结果。
- 迭代。评估结果,调整块大小、模型或相似度度量。
使用 Sentence Transformers 和 FAISS 的最小 Python 示例
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# 1. Load model
model = SentenceTransformer('all-MiniLM-L6-v2')
# 2. Sample documents
docs = [
"The cat sat on the mat.",
"A kitten is playing with yarn.",
"The stock market crashed today.",
"Investors are worried about inflation."
]
# 3. Create embeddings
embeddings = model.encode(docs, convert_to_numpy=True)
# 4. Build FAISS index
dim = embeddings.shape[1]
index = faiss.IndexFlatL2(dim) # L2 distance; for cosine, normalize first
index.add(embeddings)
# 5. Search
query = "feline resting"
query_vec = model.encode([query], convert_to_numpy=True)
D, I = index.search(query_vec, k=2)
print([docs[i] for i in I[0]])
# Output likely: ['The cat sat on the mat.', 'A kitten is playing with yarn.']
选择向量数据库
对于小型项目,你可以将向量存储在简单文件或内存索引中。随着规模增长,专用向量数据库提供持久化、过滤和 ANN 索引。以下是快速对比:
| 数据库 | 类型 | 最适合 |
|---|---|---|
| FAISS | 库 | 原型开发、本地实验 |
| Chroma | 嵌入式 / 客户端-服务器 | 中小型应用、易于设置 |
| Pinecone | 托管云 | 生产环境、无服务器扩展 |
| Weaviate | 开源 / 云 | 混合搜索、GraphQL API |
| Qdrant | 开源 / 云 | 高性能、过滤 |
| pgvector | PostgreSQL 扩展 | 现有 Postgres 技术栈 |
最佳实践与常见陷阱
- 如果使用余弦相似度,归一化向量——许多库假设点积使用单位向量。
- 合理切块:太大则失去特异性;太小则失去上下文。尝试不同的重叠程度。
- 文档和查询使用同一模型。混用模型会破坏相似度。
- 仅在存储或速度至关重要时考虑降维(如 PCA);它可能损害精度。
- 混合搜索(结合关键词和向量)通常能改善精确匹配的结果。
常见问题
小型项目需要向量数据库吗?
不需要。对于最多几千个向量,你可以使用内存库如 FAISS 甚至 NumPy 数组。当你需要持久化、过滤或超出内存的规模时,向量数据库才有用。
如何选择嵌入模型?
原型开发时从 all-MiniLM-L6-v2 这样的小型快速模型开始。如果需要更高精度且能承担 API 成本,可以尝试 OpenAI 的 text-embedding-3-small 或 text-embedding-3-large。始终在你自己的数据上评估。
余弦相似度和欧几里得距离有什么区别?
余弦相似度衡量向量之间的夹角,忽略大小。欧几里得距离衡量直线距离。对于归一化向量,它们给出相同的排名。余弦在文本嵌入中很常见,因为它关注方向(含义)而非长度。
下一步
现在你已经了解了基础知识,试着在你自己的笔记或文档上构建一个小型语义搜索。尝试不同的块大小和模型。随着规模增长,迁移到托管向量数据库并添加混合搜索。这个领域发展迅速,但这些基础将保持相关。
当你需要格式化 API 响应或调试来自嵌入服务的 JSON 载荷时,JSON Formatter 可以帮助你快速检查和验证数据。