游乐游手机版
首页/AI教程/文章详情

嵌入与向量数据库深度解析:核心原理与实战案例

时间:2026-06-01 12:27
一、什么是Embedding? 聊向量数据库之前,得先把这事儿讲清楚。不少朋友第一次接触这个概念时,可能会觉得“Embedding”是个挺抽象的术语。其实,它没那么复杂。 1 1 通俗理解 简单来说,Embedding 就是给文字配上一组数字——专业的说法叫“向量”。好让计算机能够理解不同文字之间在

一、什么是Embedding?

聊向量数据库之前,得先把这事儿讲清楚。不少朋友第一次接触这个概念时,可能会觉得“Embedding”是个挺抽象的术语。其实,它没那么复杂。

1.1 通俗理解

简单来说,Embedding 就是给文字配上一组数字——专业的说法叫“向量”。好让计算机能够理解不同文字之间在语义上是亲近还是疏远。

Embedding 与向量数据库

人类理解语义: "猫" 和 "狗" 很相似(都是宠物)
             "猫" 和 "汽车" 很不同

计算机怎么理解?→ 把文字变成数字!
"猫" → [0.2, 0.8, 0.1, 0.9, ...]   ← 一组数字(向量)
"狗" → [0.3, 0.7, 0.2, 0.8, ...]   ← 和"猫"的数字很接近
"汽车" → [0.9, 0.1, 0.8, 0.2, ...] ← 和"猫"的数字差很远

1.2 一个直观的比喻

想象一下二维地图(实际的 Embedding 是几百维,但原理是一样的):

↑ "动物属性"
│
1.0│?猫?狗
0.8│   ?兔子
0.5│
│✈️飞机
0.2│    ?汽车
│      ?火车
0.0├───────────────────→ "交通工具属性"
  0.0    0.2    0.5    0.8    1.0

"猫"和"狗"在地图上离得很近 → 语义相似
"猫"和"汽车"离得很远 → 语义不同

1.3 Embedding 的维度

实际场景中的 Embedding 不是二维,而是几百到几千维不等。维度越高,能表达更细微的语义差异,计算量自然也更大:

┌─────────────────────┬──────────────────────┐
│Embedding 模型       │向量维度               │
├─────────────────────┼──────────────────────┤
│OpenAI text-ada-002 │1536 维                │
│OpenAI text-3-small │1536 维                │
│OpenAI text-3-large │3072 维                │
│BGE-large-zh        │1024 维                │
│Jina Embeddings v3  │1024 维                │
│Cohere Embed v3     │1024 维                │
└─────────────────────┴──────────────────────┘

二、如何生成Embedding?

知道了概念,怎么动手拿到这个向量呢?下面介绍两种最典型的路径。

2.1 使用 OpenAI Embedding API

最省事的办法,直接用 OpenAI 的接口:

from openai import OpenAI
client = OpenAI(api_key="sk-xxx")

# 生成单个文本的 Embedding
response = client.embeddings.create(
    model="text-embedding-3-small",
    input="今天天气真好"
)
vector = response.data[0].embedding
print(f"维度:{len(vector)}")  # 1536
print(f"前5个数字:{vector[:5]}")
# [0.012, -0.034, 0.056, ...]

2.2 使用开源 Embedding 模型

如果你的数据不能外传,或者想省点 API 费用,完全可以用开源方案本地跑:

# 使用 sentence-transformers 库(免费、可本地运行)
# pip install sentence-transformers
from sentence_transformers import SentenceTransformer

# 加载模型(首次运行会自动下载)
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')  # 中文最佳

# 生成 Embedding
sentences = ["今天天气真好", "天气不错适合出门", "我要买一辆汽车"]
embeddings = model.encode(sentences)
print(f"形状:{embeddings.shape}")  # (3, 1024) → 3个句子,每个1024维

三、向量相似度计算

有了向量的肉身,还得知道怎么度量向量的“亲疏远近”。最常见的手段是余弦相似度。

3.1 余弦相似度(最常用)

衡量两个向量的方向是否一致,不关心长度:

余弦相似度的直觉理解:
两个向量方向完全相同 → 相似度 = 1(完全相似)
两个向量方向垂直  → 相似度 = 0(不相关)
两个向量方向相反  → 相似度 = -1(完全相反)

               ↑ B
             ╱
           ╱ θ = 小角度 → cos(θ) 接近 1 → 很相似
         ╱
       ──────→ A
import numpy as np

def cosine_similarity(a, b):
    """计算两个向量的余弦相似度"""
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# 示例
emb_cat = model.encode("一只可爱的猫咪")
emb_dog = model.encode("一只可爱的狗狗")
emb_car = model.encode("一辆红色的汽车")

print(f"猫 vs 狗:{cosine_similarity(emb_cat, emb_dog):.3f}")   # ~0.85 高相似
print(f"猫 vs 车:{cosine_similarity(emb_cat, emb_car):.3f}")   # ~0.25 低相似

3.2 其他距离度量

除了余弦相似度,还有一些其他选择:

┌──────────────────┬──────────────────────────────────────────┐
│度量方式          │适用场景                                   │
├──────────────────┼──────────────────────────────────────────┤
│余弦相似度        │最通用,推荐默认使用                       │
│(Cosine)          │不受向量长度影响                           │
├──────────────────┼──────────────────────────────────────────┤
│欧氏距离          │需要考虑"绝对距离"时                      │
│(Euclidean)       │值越小越相似                              │
├──────────────────┼──────────────────────────────────────────┤
│内积              │已归一化的向量                            │
│(Inner Product)   │等价于余弦相似度                          │
└──────────────────┴──────────────────────────────────────────┘

四、向量数据库

单个向量、少量向量还好处理,当你有成千上万的文档要做语义检索时,就轮到向量数据库出场了。

4.1 为什么需要向量数据库?

想象一下:你准备了 100 万篇文档的 Embedding,用户提了个问题。需要用最快的时间找出最相关的 10 篇文档。

  • 暴力搜索:逐一比较 100 万次 → 几分钟,太慢了。
  • 向量数据库:用特殊的数据结构 → 毫秒级返回!

4.2 主流向量数据库对比

┌──────────────┬──────────┬──────────┬──────────┬─────────────────┐
│数据库        │类型      │特点      │难度      │适合场景         │
├──────────────┼──────────┼──────────┼──────────┼─────────────────┤
│Chroma        │嵌入式    │最简单    │★☆☆☆☆   │学习、原型验证   │
│FAISS         │库(Meta)  │最快      │★★★☆☆   │研究、单机大规模 │
│Milvus        │分布式    │功能全    │★★★★☆   │企业级生产环境   │
│Qdrant        │服务端    │Rust写的  │★★★☆☆   │性能敏感场景     │
│Wea viate      │服务端    │多模态    │★★★☆☆   │图+文混合搜索   │
│Pinecone      │全托管    │免运维    │★★☆☆☆   │不想管运维       │
│PgVector      │PG扩展    │复用PG    │★★☆☆☆   │已有PostgreSQL   │
└──────────────┴──────────┴──────────┴──────────┴─────────────────┘

4.3 Chroma 快速上手(最简单)

如果你只想快速跑通、做原型验证,Chroma 绝对是最好的敲门砖:

# pip install chromadb
import chromadb

# 1. 创建客户端和集合
client = chromadb.Client()
collection = client.create_collection("my_docs")

# 2. 添加文档(Chroma 自动生成 Embedding!)
collection.add(
    documents=[
        "Python 是一种简单易学的编程语言",
        "Ja va 是一种面向对象的编程语言",
        "今天股市大涨,上证指数突破3500点",
        "机器学习是人工智能的一个子领域",
    ],
    ids=["doc1", "doc2", "doc3", "doc4"]
)

# 3. 搜索最相关的文档
results = collection.query(
    query_texts=["什么编程语言适合初学者?"],
    n_results=2  # 返回最相关的2条
)
print(results["documents"])
# [['Python 是一种简单易学的编程语言',
#   'Ja va 是一种面向对象的编程语言']]
# → 准确找到了编程相关的文档,没有返回股市新闻!

4.4 Milvus 生产级使用

而如果你要考虑生产环境,Milvus 是更成熟的选择:

# pip install pymilvus
from pymilvus import MilvusClient

# 1. 连接 Milvus
client = MilvusClient("https://localhost:19530")

# 2. 创建集合
client.create_collection(
    collection_name="articles",
    dimension=1024,  # 向量维度,需要与 Embedding 模型匹配
)

# 3. 插入数据
data = [
    {"id": 1, "vector": [0.1, 0.2, ...], "text": "Python 入门教程"},
    {"id": 2, "vector": [0.3, 0.4, ...], "text": "Ja va 设计模式"},
    # ...
]
client.insert(collection_name="articles", data=data)

# 4. 搜索
results = client.search(
    collection_name="articles",
    data=[query_embedding],   # 查询向量
    limit=5,                  # 返回 top 5
    output_fields=["text"]    # 同时返回文本
)

五、向量索引类型

5.1 为什么需要索引?

没有索引(暴力搜索 Flat):
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ... ┌──┐
│  │ │  │ │  │ │  │ │  │     │  │
└──┘ └──┘ └──┘ └──┘ └──┘     └──┘
逐一比较所有向量 → 准确但慢

有索引(近似搜索):
先把向量分组/建树,搜索时只看相关的组 → 快但可能遗漏

5.2 常见索引类型

┌───────────┬──────────────────────────────────────────────┐
│索引类型   │通俗解释                                       │
├───────────┼──────────────────────────────────────────────┤
│Flat       │暴力搜索,逐一比较                           │
│(平坦)     │最准确但最慢。数据少时可以用                 │
│           │                                              │
│IVF        │先把向量分成若干个"簇"                      │
│(倒排)     │搜索时只在最相近的几个簇中找                  │
│           │类比:先确定在哪个书架,再在书架上找书        │
│           │                                              │
│HNSW       │建一个多层图结构(像跳表)                    │
│(层次图)   │从粗到细逐层搜索                              │
│           │类比:先看世界地图,再看国家地图,再看城市地图│
│           │目前最流行的索引类型                          │
│           │                                              │
│PQ         │把向量压缩(量化),用更少的空间存储          │
│(乘积量化) │牺牲一点精度换取大幅减少内存占用              │
└───────────┴──────────────────────────────────────────────┘
HNSW 索引示意图:
Layer 2 (最顶层,最稀疏):
A ─────────── D
│             │
Layer 1 (中间层):
A ── B ──── C ── D
│    │      │    │
Layer 0 (最底层,最密集):
A─B─E─F─C─G─H─D─I

搜索过程:
1. 从顶层开始,找到大致方向(A → D)
2. 下一层细化(A → B → C)
3. 底层精确搜索(找到最近邻)

六、混合检索

6.1 向量检索的局限

纯粹依赖向量检索并非万能,尤其在需要精确匹配关键词的场景下,它的短板也很明显。

问题:用户搜索 "Python 3.12 新特性"

纯向量搜索可能返回:
1. "Python 最新版本的功能介绍"  ← 相关但不精确
2. "编程语言的新特性总结"       ← 相关但太宽泛
✗ 可能没有精确匹配 "3.12" 这个版本号

纯关键词搜索(BM25)可能返回:
1. "Python 3.12 发布说明"       ← 精确匹配 ✓
2. "Python 3.12 变更日志"       ← 精确匹配 ✓
✗ 但如果用户搜 "最新Python有啥变化",关键词匹配不到

6.2 混合检索 = 向量 + 关键词

所以,一个很自然的改进方向,就是把两者结合起来:

┌────────────────────────────────────────────────────────┐
│                     混合检索流程                      │
│                                                        │
│                 用户查询:"Python 3.12 新特性"        │
│                         │                              │
│                     ┌────┴────┐                        │
│                     ▼          ▼                       │
│               向量检索      BM25 关键词检索            │
│              (语义理解)    (精确匹配)                  │
│                     │          │                       │
│                     ▼          ▼                       │
│              结果集A        结果集B                    │
│                     │          │                       │
│                     └────┬────┘                        │
│                          ▼                             │
│                 融合排序(RRF / 加权融合)              │
│                          │                             │
│                          ▼                             │
│                     最终排序结果                       │
└────────────────────────────────────────────────────────┘
# 混合检索的简化实现
def hybrid_search(query, documents, alpha=0.7):
    """alpha: 向量检索的权重(0-1)
       1-alpha: 关键词检索的权重"""
    # 向量检索得分
    vector_scores = vector_search(query, documents)
    # BM25 关键词检索得分
    bm25_scores = bm25_search(query, documents)

    # 融合得分
    final_scores = {}
    for doc_id in set(vector_scores) | set(bm25_scores):
        v_score = vector_scores.get(doc_id, 0)
        b_score = bm25_scores.get(doc_id, 0)
        final_scores[doc_id] = alpha * v_score + (1 - alpha) * b_score

    return sorted(final_scores.items(), key=lambda x: x[1], reverse=True)

七、Reranker 重排序

7.1 为什么需要重排序?

向量检索本质上是“粗筛”。对于前 10 名或者前 20 名的结果,它给出的排序未必完全精准。Reranker 就是用来做“精排”的,在候选集上重新打分:

检索流程:
百万文档 ──向量检索──→ Top 20 候选 ──Reranker──→ Top 5 精排结果
            (粗筛:快但粗略)           (精排:慢但精准)

7.2 使用 Reranker

# 使用 Cohere Reranker(API 方式)
import cohere
co = cohere.Client(api_key="xxx")

results = co.rerank(
    query="什么是向量数据库?",
    documents=[
        "向量数据库用于存储和检索高维向量数据",
        "关系数据库使用SQL进行查询",
        "向量搜索引擎可以进行语义搜索",
        "NoSQL数据库包括MongoDB等"
    ],
    top_n=2
)
for r in results.results:
    print(f"排名 {r.index}: 分数 {r.relevance_score:.3f}")
# 排名 0: 分数 0.95 → "向量数据库用于存储..."
# 排名 2: 分数 0.82 → "向量搜索引擎可以..."
# 使用开源 Reranker(本地运行,免费)
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('BAAI/bge-reranker-v2-m3')

pairs = [
    ["什么是向量数据库?", "向量数据库用于存储和检索高维向量数据"],
    ["什么是向量数据库?", "关系数据库使用SQL进行查询"],
]
scores = reranker.predict(pairs)
# [0.95, 0.12] → 第一个文档和查询更相关

八、Embedding 模型选择指南

选模型本质上是个“决策树”问题,看你的数据和场景来定:

┌──────────────────────────────────────────────────────────────┐
│                   Embedding 模型选择决策树                   │
│                                                              │
│  你的数据是什么语言?                                        │
│  │                                                           │
│  ├─ 中文为主 → BGE-large-zh / Jina Embeddings v3            │
│  │                                                           │
│  ├─ 英文为主 → OpenAI text-embedding-3-small                │
│  │             (付费但效果好)                                │
│  │             或 BGE-large-en (免费开源)                    │
│  │                                                           │
│  └─ 多语言   → Jina Embeddings v3 / Cohere Embed v3         │
│                                                              │
│  数据能否发送到云端?                                        │
│  │                                                           │
│  ├─ 可以     → OpenAI / Cohere API(简单省事)               │
│  └─ 不行     → BGE / Jina(本地部署)                       │
│                                                              │
│  数据规模多大?                                              │
│  │                                                           │
│  ├─ < 10万条  → 维度大一点没关系(1024-3072)               │
│  └─ > 100万条 → 考虑较小维度(512-768)节省存储             │
└──────────────────────────────────────────────────────────────┘

九、实战练习

完整示例:构建一个简易语义搜索引擎

"""
用 Chroma + Sentence Transformers 构建语义搜索引擎
无需 API Key,完全本地运行
"""
import chromadb
from sentence_transformers import SentenceTransformer

# 1. 初始化
embedding_model = SentenceTransformer('BAAI/bge-small-zh-v1.5')
chroma_client = chromadb.Client()

# 2. 创建集合,使用自定义 Embedding 函数
collection = chroma_client.create_collection(
    name="knowledge_base",
    metadata={"hnsw:space": "cosine"}  # 使用余弦相似度
)

# 3. 准备文档
documents = [
    "Python 是一种解释型、面向对象的高级编程语言",
    "Ja va 是一种广泛使用的编程语言,具有跨平台特性",
    "Ja vaScript 是网页开发的核心语言,可以在浏览器中运行",
    "机器学习是人工智能的一个分支,通过数据来学习规律",
    "深度学习使用多层神经网络来处理复杂的模式识别任务",
    "Docker 是一种容器化技术,可以将应用打包成轻量级容器",
    "Kubernetes 用于自动化部署、扩展和管理容器化应用",
    "Git 是一种分布式版本控制系统,用于跟踪代码变更",
    "REST API 是一种基于 HTTP 协议的接口设计风格",
    "微服务架构将应用拆分为多个独立的小服务",
]

# 4. 生成 Embedding 并存入数据库
embeddings = embedding_model.encode(documents).tolist()
collection.add(
    documents=documents,
    embeddings=embeddings,
    ids=[f"doc_{i}" for i in range(len(documents))]
)

# 5. 搜索
def search(query: str, top_k: int = 3):
    query_embedding = embedding_model.encode([query]).tolist()
    results = collection.query(
        query_embeddings=query_embedding,
        n_results=top_k
    )
    print(f"\n查询:{query}")
    print("=" * 50)
    for i, (doc, distance) in enumerate(zip(results["documents"][0], results["distances"][0])):
        similarity = 1 - distance  # Chroma 返回的是距离,转为相似度
        print(f"{i+1}. [{similarity:.2f}] {doc}")

# 测试
search("什么编程语言好学")
# 1. [0.78] Python 是一种解释型、面向对象的高级编程语言
# 2. [0.65] Ja va 是一种广泛使用的编程语言...
# 3. [0.61] Ja vaScript 是网页开发的核心语言...

search("如何部署应用")
# 1. [0.82] Docker 是一种容器化技术...
# 2. [0.75] Kubernetes 用于自动化部署...
# 3. [0.52] 微服务架构将应用拆分为...

search("怎么管理代码")
# 1. [0.80] Git 是一种分布式版本控制系统...
# 2. [0.45] ...

十、本章小结

┌────────────────────────────────────────────────────────┐
│                      本章知识地图                      │
│                                                        │
│  Embedding:把文字变成数字向量                         │
│  ├── 语义相似的文字 → 向量距离近                      │
│  ├── 余弦相似度 = 最常用的相似度计算方式              │
│  └── 主流模型:OpenAI / BGE / Jina                   │
│                                                        │
│  向量数据库:高效存储和搜索向量                        │
│  ├── 入门首选:Chroma(嵌入式,零配置)               │
│  ├── 生产首选:Milvus / Qdrant                        │
│  └── 索引类型:Flat / IVF / HNSW / PQ                 │
│                                                        │
│  检索增强:                                            │
│  ├── 混合检索 = 向量 + 关键词(互补)                 │
│  └── Reranker = 对初步结果精排                        │
└────────────────────────────────────────────────────────┘

十一、扩展学习资源

必读

  • Chroma 文档 —— 最简单的向量数据库入门
  • Sentence Transformers 文档 —— 开源 Embedding 模型库
  • MTEB 排行榜 —— Embedding 模型评测排行

推荐

  • Milvus 文档 —— 生产级向量数据库
  • Pinecone 学习中心 —— 优秀的向量数据库教程
  • What Are Embeddings?(Vicki Boykis) —— 深入理解 Embedding 的好文章

动手实践

  • 用 Chroma 构建一个简单的文档搜索系统
  • 对比不同 Embedding 模型在中文搜索上的效果
  • 试试在同一数据集上,纯向量检索 vs 混合检索的效果差异
来源:https://juejin.cn/post/7634396066286174218
上一篇可灵2.0三步实战创作AI故事短片电影与短剧教程 下一篇Trae生成小程序实测:MCP、Agent与上下文功能教程
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
AI如何从聊天能力进化到做事能力 Skill的实践之路
AI教程 · 2026-07-10

AI如何从聊天能力进化到做事能力 Skill的实践之路

让AI从“会聊天”转向“会做事”的关键在于Skill(技能包)。Skill由可执行代码、精确的说明书(如JSONSchema描述)及结果翻译器构成。通过精细定义参数与边界,AI能稳定调用接口完成重启服务、查询数据等操作,从而从空谈顾问变为可靠的数字员工。

零基础看懂Agent Skill MCP三层关系解读
AI教程 · 2026-07-10

零基础看懂Agent Skill MCP三层关系解读

智能体是自主执行任务的实体,技能是被封装的原子能力,MCP协议是智能体与技能间的标准化通信协议。智能体通过MCP协议发现并调用技能,灵活组合完成复杂任务。三者解耦,实现即插即用,降低了系统集成复杂度。

AI编码时代UI自动化测试智能化演进之路—中国平安人寿蔡雪
AI教程 · 2026-07-10

AI编码时代UI自动化测试智能化演进之路—中国平安人寿蔡雪

AI编码时代,UI自动化测试面临效率断层。平安人寿蔡雪基于自研“女娲”平台,分享从可视化录制到AI智能录制、基于EventDOM的智能感知与自愈机制的演进路径,实现用例创建降本、维护减负、执行提稳,推动测试工具从自动化向智能化升级。

一文讲清Agent、Skill、MCP到底什么关系:零基础小白三层拆解
AI教程 · 2026-07-10

一文讲清Agent、Skill、MCP到底什么关系:零基础小白三层拆解

Agent是自主执行任务的数字打工人,Skill为原子化能力函数,MCP是标准协议接口。Agent通过MCP发现并调用Skill,实现即插即用,解耦技能与智能体,让大模型能力安全、统一、可扩展地集成。

文生图同一提示词为何每次不同?随机性与可复现解析
AI教程 · 2026-07-10

文生图同一提示词为何每次不同?随机性与可复现解析

文生图每次结果不同源于从随机噪声开始去噪。固定种子(seed)可锁定初始噪声,但还需采样步数、引导强度、采样器、尺寸、提示词、模型等参数一致才能复现。通过控制变量法调参,先固定种子再逐一调整其他参数,可精确归因差异。