Embedding 与向量数据库原理
RAG 背后的检索基础设施:从文本到向量,从暴力搜索到 ANN,从选型到落地
为什么重要:RAG 的效果 80% 取决于检索质量,而检索质量的基础就是 Embedding 和向量数据库。理解这层基础设施,才能在 RAG 出问题时知道该调什么——是换 Embedding 模型、换相似度算法、换向量库,还是调 Chunk 策略。
一、什么是 Embedding
Embedding 的本质是把文本(或图片、音频)转换成一组高维数字向量。语义相近的内容,在向量空间中的距离也相近。这就是机器"理解"语义的方式。
"狗啃骨头" → [0.15, -0.31, 0.52, ..., 0.75] (1536 维)
↑ 两个向量距离很近 —— 语义相似
维度
向量的维度由 Embedding 模型决定。OpenAI text-embedding-3-small 是 1536 维,text-embedding-3-large 是 3072 维。维度越高,表达能力越强,但计算和存储成本也越高。
语义相似
不是字面匹配,而是语义匹配。"如何退款"和"退货流程"字面不同,但向量距离很近。这正是 Embedding 比关键词搜索强大的地方。
应用基石
语义搜索、RAG 检索、推荐系统、聚类分析——所有这些应用的最底层都是 Embedding。选对 Embedding 模型,等于打好地基。
Embedding 模型的选择直接影响检索效果。常见选择:OpenAI text-embedding-3-small(性价比高)、text-embedding-3-large(精度最高)、BGE-M3(开源,中文优秀)、Cohere embed-v3(多语言强)。选型时务必用你自己的数据测试,不要只看榜单。
二、相似度计算:三种方法
有了向量,下一步就是计算"两个向量有多近"。有三种主流方法,适用场景各不相同:
余弦相似度
计算两个向量的夹角,关注方向而非大小。
- 最常用,绝大多数场景首选
- 对向量长度不敏感
- 值域 [-1, 1],越接近 1 越相似
- 适合文本语义搜索
欧氏距离
计算两个向量在空间中的直线距离。
- 关注向量的绝对位置
- 对向量长度敏感
- 值越小越相似(距离为 0 即相同)
- 适合图像 / 聚类场景
点积
最简单的计算方式,两个向量对应位相乘再求和。
- 计算最快
- 当向量已归一化时,等价于余弦相似度
- 很多向量库默认使用
- 适合对性能要求极高的场景
三、ANN 近似最近邻:为什么不能暴力搜索
当向量库有 100 万条数据时,每次查询都要和所有向量算一遍相似度?这就是暴力搜索(Brute Force),时间复杂度 O(N)。100 万条还能扛住,1 亿条就完全不可行了。
解决方案是 ANN(Approximate Nearest Neighbor,近似最近邻)——牺牲一点点精度,换取数量级的速度提升。核心思想是:不找绝对最近的,而是找"足够近"的。
| 算法 | 原理 | 速度 | 内存 | 适用场景 |
|---|---|---|---|---|
| HNSW | 图结构 | 最快 | 最多 | 对速度要求高,内存充足(最主流) |
| IVF | 聚类 | 中等 | 较少 | 数据量大、内存敏感、可调精度 |
| LSH | 哈希 | 快 | 少 | 理论价值高,实际工程中较少使用 |
| 暴力搜索 | 逐个比对 | 最慢 | 最少 | 数据量极小(<1 万),需要 100% 精确 |
HNSW · 分层小世界图
构建多层图结构,查询时从顶层快速定位区域,再逐层细化。查询最快,但内存占用最高(需要存图结构)。FAISS、Qdrant、Milvus 均支持。99% 的场景默认选它。
IVF · 倒排文件
先用 K-Means 把向量聚成若干簇,查询时只搜索最近的几个簇。nprobe 参数可调精度:搜的簇越多越精确但越慢。内存友好,适合超大规模数据。
LSH · 局部敏感哈希
把相近的向量哈希到同一个桶里。理论优雅但实际效果不稳定,工程中已被 HNSW 大幅取代。了解原理即可,不必深入实践。
四、向量数据库选型:六选一
向量数据库是 RAG 的存储和检索引擎。选型取决于数据规模、运维能力和功能需求。Reddit 等大型平台通过结构化评测从十余种方案中选出最终方案,以下是最主流的六个:
| 数据库 | 类型 | 规模 | 最适合 | 运维 | 亮点 |
|---|---|---|---|---|---|
| Chroma | 嵌入式 | <100 万 | 原型验证、POC、学习 | 零运维 | pip install 即用 |
| FAISS | 库 | 任意 | 极致速度、研究场景 | 手动持久化 | Meta 开源,最快 |
| Qdrant | 服务器 | 100 万-10 亿 | 最佳平衡、混合搜索 | Docker 单容器 | Rust 实现,推荐 |
| Milvus | 分布式 | 10 亿+ | 企业级、功能最全 | K8s,最重 | 支持 GPU 加速 |
| pgvector | PG 扩展 | <100 万 | 已有 PostgreSQL | 零额外运维 | SQL 查询,简单 |
| Weaviate | 服务器 | 100 万-10 亿 | 混合搜索、多模态 | Docker | 内置 Embedding |
五、选型决策树
不要被选项吓到。根据你的数据规模和现有技术栈,决策路径其实非常清晰:
快速启动
90% 的个人项目和早期产品,Chroma 或 pgvector 就够了。不要为了"以后可能需要"而一上来就搭 Milvus 集群。
规模化
数据过了百万级,Qdrant 是最佳选择——Rust 实现性能强,单 Docker 容器运维简单,原生支持混合搜索。
企业级
数据到了十亿级、需要高可用和水平扩展,才考虑 Milvus。它的运维复杂度最高,没有专职团队不要碰。
六、RAG 中的完整流程
把前面的所有概念串起来,就是 RAG 检索的完整管线。从文档到最终回答,每一步都有可调参数:
| 步骤 | 参数 | 说明 |
|---|---|---|
| 分块 | chunk_size: 500-1000 字符 | 太小会丢失上下文,太大会稀释相关性。中文建议 500-800 字,英文 500-1000 字符 |
| 重叠 | overlap: 10-20% of chunk_size | 相邻块之间重叠一部分,避免关键信息被切断在边界上 |
| Embedding | 模型选择 | 用同一模型编码文档和查询,不能混用不同模型 |
| 检索 | top_k: 5-20 | 先粗检索较多的候选,再用 Rerank 精排。top_k 太小会漏掉相关内容 |
| 重排 | Reranker 模型 | 用 Cross-Encoder 对候选重新打分,精度远高于 Embedding 相似度。常用 BGE-Reranker、Cohere Rerank |
| 生成 | context 注入 | 把检索到的 Top-K(重排后取前 3-5 条)作为上下文拼入 Prompt,让 LLM 基于上下文回答 |
参考资料:Reddit 工程博客向量数据库选型评测;FAISS 官方文档;Qdrant / Milvus / Weaviate 官方文档;HNSW 原始论文(Malkov & Yashunin);pgvector GitHub;LangChain RAG 最佳实践。