RAG 学习之向量嵌入(Embedding)知识总结

目录


一、什么是向量嵌入

向量嵌入是将文本、图片等非结构化数据转换为固定长度的数值向量的过程。嵌入后的向量在高维空间中保留了原始数据的语义信息——语义相近的内容,其向量距离也更近。

"猢狲施展烈焰拳" → [0.023, -0.117, 0.089, ..., 0.041]  (1536维)
"猴子使用火拳攻击" → [0.019, -0.108, 0.092, ..., 0.038]  (1536维)
                        ↑ 语义相近 → 向量距离近

在 RAG 流水线中,嵌入是连接"文本切块"和"向量检索"的关键桥梁:

原始文档 → 文本切块 → 【向量嵌入】→ 存入向量数据库 → 检索 → LLM 生成回答

二、嵌入的三种基本类型

2.1 密集嵌入(Dense Embedding)

  • 原理:将文本压缩为固定长度的稠密实数向量(如 768 维、1024 维、1536 维)
  • 特点:每一维都有非零值,信息高度压缩,适合语义相似度计算
  • 代表模型:OpenAI text-embedding-3-small、Jina jina-embeddings-v3、BGE 系列
  • 相似度计算:余弦相似度(Cosine Similarity)
# 余弦相似度公式
cosine_similarity(A, B) = (A · B) / (||A|| × ||B||)

# 值域 [-1, 1],越接近 1 表示越相似

2.2 稀疏嵌入(Sparse Embedding)

  • 原理:基于词频统计生成高维但大部分维度为零的向量
  • 特点:保留了精确的词汇匹配能力,对关键词检索友好
  • 代表算法:BM25(TF-IDF 的改进版本)
  • BM25 核心公式
BM25(q, d) = Σ IDF(qi) × (f(qi, d) × (k1 + 1)) / (f(qi, d) + k1 × (1 - b + b × |d| / avgdl))

参数说明:
  f(qi, d)  — 词 qi 在文档 d 中的词频(TF)
  |d|       — 文档 d 的长度
  avgdl     — 所有文档的平均长度
  k1        — 词频饱和参数(通常 1.2~2.0),控制词频增长对分数的影响上限
  b         — 文档长度归一化参数(通常 0.75),b=0 忽略长度,b=1 完全归一化
  IDF(qi)   — 逆文档频率,衡量词的稀有程度

2.3 多向量嵌入(Multi-Vector Embedding / ColBERT)

  • 原理:为文本中的每个 Token 都生成一个向量,而不是将整段文本压缩为单个向量
  • 特点:保留 Token 级别的细粒度语义信息,检索精度更高
  • 代表模型:BGE-M3 的 ColBERT 模式
密集嵌入:  "猢狲施展烈焰拳" → [1个向量]    (整体语义)
多向量嵌入:"猢狲施展烈焰拳" → [5个向量]     (每个 Token 一个)
                              ↑ 猢狲 ↑ 施展 ↑ 烈焰 ↑ 拳

三、本项目涉及的嵌入模型

3.1 OpenAI Embedding — 推荐系统应用

📄 对应代码:01-openai-embedding-recomendation-system.py

模型text-embedding-3-small(1536 维)

应用场景:游戏推荐系统

核心流程

1. 获取每个游戏的描述文本 → 调用 OpenAI API 生成嵌入向量
2. 对每个用户:将其评价过的所有游戏的嵌入向量 → 取平均值 → 作为用户偏好向量
3. 计算用户偏好向量与目标游戏向量的余弦相似度
4. 按相似度排序 → 推荐最可能喜欢该游戏的用户

关键代码模式

# 获取嵌入
response = openai.embeddings.create(input=[text], model="text-embedding-3-small")
embedding = response.data[0].embedding

# 用户画像 = 历史偏好的平均向量
user_vector = np.mean(user_game_vectors, axis=0)

# 相似度计算
similarity = cosine_similarity(user_vector.reshape(1, -1), target_vector.reshape(1, -1))

要点:用嵌入向量的平均值作为用户画像,是一种简单但有效的协同过滤替代方案。


3.2 Jina Embeddings v3 — 聚类分析应用

📄 对应代码:02-jina-embeddings-v3-clustering.py

模型jina-embeddings-v3(支持 1024 维,可调)

应用场景:游戏描述文本聚类

核心流程

1. 批量获取游戏描述的嵌入向量
2. 使用 KMeans 进行聚类(K=3)
3. 同一簇内的游戏语义相近

Jina v3 的特色参数

{
    "model": "jina-embeddings-v3",
    "task": "text-matching",       # 任务类型:文本匹配
    "dimensions": 1024,            # 输出维度可调
    "normalized": True,            # 自动归一化(L2 范数 = 1)
    "input": texts                 # 支持批量输入
}
参数说明
task可选 text-matchingclassificationretrieval.queryretrieval.passage 等,针对不同任务优化
dimensions支持降维(Matryoshka 套娃表示),灵活权衡精度与存储
normalized归一化后余弦相似度 = 点积,计算更快

要点:Jina v3 支持任务感知嵌入——同一个模型,指定不同 task 会生成针对该任务优化的向量。


3.3 BM25 — 稀疏检索(手写实现)

📄 对应代码:03-BM25.py

模型:BM25(从零手写实现,不依赖外部库)

核心流程

1. 分词 → 构建词表
2. 计算 IDF(逆文档频率):衡量词的稀有程度
3. 对每条文本计算 TF(词频)
4. 代入 BM25 公式生成稀疏嵌入(只保留非零维度的字典表示)

稀疏嵌入的特点

# 稀疏嵌入用字典存储,key=词表索引,value=BM25 分数
sparse_embedding = {
    0: 1.234,    # "猢狲" 的 BM25 分数
    5: 0.891,    # "烈焰拳" 的 BM25 分数
    12: 0.567,   # "妖怪" 的 BM25 分数
    # 其余几千维全是 0,不存储
}

要点:BM25 是稀疏嵌入的经典算法,无需神经网络,纯统计方法,计算极快,精确匹配能力强。


3.4 LangChain BM25 + Chroma — 混合检索

📄 对应代码:03-LangChain-BM25.py

核心思想:将 BM25(稀疏检索)与向量检索(密集检索)结合,互补各自短板。

查询:"猢狲有什么装备和招数?"
                │
    ┌───────────┴───────────┐
    ▼                       ▼
 BM25 检索              Chroma 向量检索
 (关键词匹配)          (语义匹配)
    │                       │
    │  找到:"猢狲身披锁子甲"  │  找到:"猢狲使用铜云棒抵挡"
    │  ("装备"关键词命中)    │  (语义相近,但缺关键词)
    │                       │
    └───────────┬───────────┘
                ▼
         混合检索结果(去重合并)
                ▼
            LLM 生成回答

关键代码

# 稀疏检索
bm25_retriever = BM25Retriever.from_texts(battle_logs)
bm25_response = bm25_retriever.invoke(request)

# 密集检索
chroma_vs = Chroma.from_documents(docs, embedding=OpenAIEmbeddings())
chroma_response = chroma_vs.as_retriever().invoke(request)

# 混合 = 简单去重合并
hybrid_response = list({doc.page_content for doc in bm25_response + chroma_response})
检索方式能找到可能漏掉
BM25 稀疏检索包含查询关键词的文档语义相关但用词不同的文档
向量密集检索语义相关的文档关键词精确匹配但语义距离远的文档
混合检索两者都能找到

要点:混合检索是 RAG 工程实践中的最佳实践,兼顾精确匹配和语义理解。


3.5 BGE-M3 — 多功能嵌入模型

📄 对应代码:04-BGE-M3.py

模型BAAI/bge-m3(BAAI 北京智源人工智能研究院出品)

三大能力(M3 = Multi-lingual, Multi-granularity, Multi-Function)

passage_embeddings = model.encode(
    passage,
    return_sparse=True,       # 稀疏嵌入(类 BM25)
    return_dense=True,        # 密集嵌入(传统向量)
    return_colbert_vecs=True  # 多向量嵌入(ColBERT,Token 级别)
)
输出类型维度用途
dense_vecs(1024,)整体语义相似度
lexical_weights{词索引: 权重}精确词匹配(稀疏)
colbert_vecs(seq_len, 1024)Token 级别精细匹配

BGE-M3 的核心价值:一个模型同时输出三种嵌入,天然支持混合检索,无需分别部署 BM25 + 密集嵌入两个系统。

BGE-M3 一个模型 → 同时产出:
  ├─ 密集向量 → 语义检索
  ├─ 稀疏向量 → 关键词检索
  └─ ColBERT 多向量 → 精细匹配

3.6 Visualized-BGE — 多模态嵌入

📄 对应代码:05-多模态嵌入.py

模型BAAI/bge-visualized(基于 BGE 的视觉扩展)

核心能力:将图片编码为与文本同一向量空间的嵌入向量。

model = Visualized_BGE(model_name_bge="BAAI/bge-base-en-v1.5", model_weight=model_path)

# 纯图片嵌入
image_embedding = model.encode(image=image_path)

# 图片+文本联合嵌入
multimodal_embedding = model.encode(image=image_path, text="这是一张悟空战斗示例图片")

多模态嵌入的意义

传统 RAG:只能处理文本
多模态 RAG:可以跨模态检索
  "孙悟空的战斗画面"(文本查询)
        ↓ 余弦相似度
  [图片A的向量] → 0.92 ✅ 高度匹配
  [图片B的向量] → 0.31 ❌ 不相关

四、嵌入模型对比总览

模型嵌入类型维度部署方式特色
OpenAI text-embedding-3-small密集1536API 调用稳定可靠,适合通用场景
Jina jina-embeddings-v3密集可调(最高 1024)API 调用任务感知,维度可调
BM25稀疏词表大小本地计算无需模型,精确匹配
BGE-M3密集 + 稀疏 + ColBERT1024本地模型一个模型三种嵌入
Visualized-BGE多模态密集768本地模型支持图片编码

五、关键概念总结

5.1 稠密 vs 稀疏 vs 多向量

特性密集嵌入稀疏嵌入多向量嵌入(ColBERT)
向量形式每维非零大部分为零多个向量
存储开销低(只存非零)
语义理解✅ 强❌ 弱✅ 最强
精确匹配❌ 弱✅ 强✅ 强
计算速度较慢
代表OpenAI EmbeddingBM25ColBERT / BGE-M3

5.2 检索策略选择

只需要语义搜索?
  └─ 是 → 密集嵌入(OpenAI / Jina)
  └─ 否 → 需要关键词精确匹配?
              └─ 是 → 稀疏嵌入(BM25)
              └─ 否 → 需要同时兼顾?
                          └─ 是 → 混合检索
                                  ├─ 方案A:BM25 + 密集嵌入(两套系统)
                                  └─ 方案B:BGE-M3(一个模型搞定)
                          └─ 否 → 需要跨模态?
                                      └─ 是 → 多模态嵌入(Visualized-BGE)

5.3 实践建议

  1. 起步阶段:用 OpenAI Embedding + Chroma 快速搭建原型
  2. 优化检索:引入 BM25 做混合检索,显著提升召回率
  3. 进阶部署:用 BGE-M3 替代分离的 BM25 + 密集嵌入方案,一个模型统一管理
  4. 多模态需求:涉及图片/表格检索时,使用 Visualized-BGE 等多模态模型
  5. 降本策略:Jina v3 的可调维度 + 任务感知能力,可以在精度和成本间灵活权衡

六、词向量嵌入技术发展历史

时间线总览

1950s        1970s       2013      2014      2016      2018         2019       2022        2023+
 │           │           │         │         │         │            │          │           │
One-Hot    TF-IDF     Word2Vec   GloVe    FastText   ELMo      Sentence    OpenAI     BGE-M3
                        CBOW    全局共现    子词      BERT      -BERT     Embedding   多模态
                       Skip-Gram  矩阵分解  n-gram   GPT                 v3         嵌入

6.1 第一阶段:离散表示(1950s — 2000s)

One-Hot 编码

最早的词表示方法,每个词对应词表中唯一的一个位置:

词表 = ["猢狲", "施展", "烈焰拳", "妖怪"]

"猢狲" → [1, 0, 0, 0]
"施展" → [0, 1, 0, 0]
"烈焰拳"→ [0, 0, 1, 0]
"妖怪" → [0, 0, 0, 1]

致命缺陷

  • 维度灾难:词表多大,向量就多长(几万到几十万维)
  • 完全稀疏:只有一个 1,其余全 0
  • 无语义信息:任意两个词的"距离"完全相同,"猢狲"和"妖怪"的距离 = "猢狲"和"施展"的距离
TF-IDF(1972)

在 One-Hot 基础上引入了统计权重:

TF-IDF(t, d) = TF(t, d) × IDF(t)

TF(词频):词 t 在文档 d 中出现的频率
IDF(逆文档频率):log(总文档数 / 包含词 t 的文档数)

→ 高频常见词("的"、"是")权重低
→ 稀有但信息量大的词("烈焰拳")权重高

进步:区分了词的重要性
局限:仍然是稀疏向量,词与词之间没有语义关系

TF-IDF 的改进版 BM25(1980s-1990s)加入了文档长度归一化和词频饱和机制,成为稀疏检索的黄金标准,至今仍是搜索引擎的基石。本项目中 03-BM25.py 就是用它实现的。

6.2 第二阶段:静态词向量(2013 — 2017)

Word2Vec(2013)

里程碑事件:Mikolov 等人在 Google 发表论文,证明用简单的神经网络可以从海量文本中学习到有意义的词向量。

两种训练架构

CBOW(连续词袋模型):上下文 → 预测中心词
  输入:"猢狲" "施展" [?] "击退" "妖怪"
  输出:预测 [?] = "烈焰拳"

Skip-Gram(跳字模型):中心词 → 预测上下文
  输入:"烈焰拳"
  输出:预测周围可能出现 "猢狲" "施展" "击退" "妖怪"

核心思想上下文相似的词,语义也相似(分布假设/Distributional Hypothesis)

经典成果——词向量代数运算

king - man + woman ≈ queen
巴黎 - 法国 + 中国 ≈ 北京

局限

  • 一词一向量:无法区分多义词。"苹果"无论是水果还是公司,都是同一个向量
  • 窗口太小:只看局部上下文(通常 ±5 个词),缺少全局信息
GloVe(2014)

Stanford 的 Pennington 等人提出,结合了全局统计局部上下文

Word2Vec:基于局部上下文窗口 → 只看"邻居"
GloVe:   基于全局共现矩阵 → 看所有文档中的共现统计

核心公式:w_i · w_j + b_i + b_j = log(X_ij)

  w_i, w_j:词 i 和词 j 的向量
  X_ij:词 i 和词 j 在语料库中共现的次数

优势:利用了全局统计信息,训练更快,在小语料上效果更好。

FastText(2016)

Facebook 的 Joulin 等人提出,在 Word2Vec 基础上引入**子词(subword)**表示。

Word2Vec: "烈焰拳" → 1 个向量(整词)
FastText: "烈焰拳" → "烈" + "焰" + "拳" → 3 个子词向量的和

优势:
  1. 能处理未登录词(OOV):"火焰拳" 没见过,但 "火"+"焰"+"拳" 都见过
  2. 天然适合形态丰富的语言(德语、土耳其语等)
  3. 对中文也有效——汉字本身就是有意义的子词单元

Word2Vec / GloVe / FastText 三者统称为静态词向量(Static Embedding),它们的特点是:训练完成后,每个词的向量就固定不变了。

6.3 第三阶段:上下文词向量(2018)

ELMo(2018.02)

Allen AI 的 Peters 等人提出,首次实现了一词多义的动态表示。

静态词向量:
  "苹果" 永远是 [0.23, -0.11, ...]
  无论上下文是 "吃了一个苹果" 还是 "苹果发布了新手机"

ELMo:
  "吃了一个 苹果"  → "苹果" 的向量 = [0.15, 0.32, ...]  ← 偏向食物语义
  "苹果 发布新手机" → "苹果" 的向量 = [0.41, -0.08, ...] ← 偏向公司语义

原理:双向 LSTM,根据整个句子的上下文动态生成词向量

突破:同一个词在不同语境下有不同的向量表示。

BERT(2018.10)

Google 的 Devlin 等人发表,彻底改变了 NLP 领域

ELMo:双向 LSTM → 串行处理,速度慢
BERT:双向 Transformer → 并行处理,效果好

预训练任务:
  1. MLM(掩码语言模型):随机遮住 15% 的词,让模型预测
     输入:"猢狲施展 [MASK] 击退妖怪"
     目标:预测 [MASK] = "烈焰拳"

  2. NSP(下一句预测):判断两个句子是否相邻

如何从 BERT 中提取嵌入

方法1:取 [CLS] token 的向量作为整个句子的表示
方法2:取所有 token 向量的平均值作为句子表示

问题:BERT 的句子嵌入质量并不好(各向异性问题,向量分布在高维空间的狭窄锥形区域)
GPT 系列(2018 — 至今)
GPT-1 (2018) → GPT-2 (2019) → GPT-3 (2020) → ChatGPT (2022) → GPT-4 (2023)

与 BERT 的区别:
  BERT:双向编码器 → 理解语言(适合分类、检索、嵌入)
  GPT: 单向解码器 → 生成语言(适合对话、写作、推理)

注意:GPT 系列本身是生成模型,不是嵌入模型。但 OpenAI 后来基于类似的 Transformer 架构推出了专门的嵌入模型(text-embedding-ada-002、text-embedding-3-small 等)。

6.4 第四阶段:句子/文档嵌入(2019 — 2021)

Sentence-BERT(2019)

专门解决 BERT 句子嵌入质量差的问题。

BERT 原始方案:
  句子A → BERT → 向量A
  句子B → BERT → 向量B
  计算相似度
  问题:需要在 GPU 上跑 BERT,且效果不如简单的 GloVe 平均

Sentence-BERT:
  用孪生网络(Siamese Network)对 BERT 做微调
  训练目标:让相似句子的向量靠近,不相似的远离

  "猢狲施展烈焰拳" → SBERT → [0.23, -0.11, ...]  ← 高质量的句子向量
  "猴子使用火拳攻击" → SBERT → [0.21, -0.09, ...]  ← 语义相近,向量也近
SimCSE(2021)

Stanford 提出,用**对比学习(Contrastive Learning)**进一步提升句子嵌入质量。

核心思想:同一个句子经过两次 Dropout,生成两个"正样本"
  "猢狲施展烈焰拳" → Encoder(Dropout¹) → 向量 v1
  "猢狲施展烈焰拳" → Encoder(Dropout²) → 向量 v2

  训练目标:拉近距离 (v1, v2),推远距离 (v1, 其他句子的向量)

  无监督、不需要标注数据!

6.5 第五阶段:现代嵌入模型(2022 — 至今)

OpenAI Embedding(2022)
text-embedding-ada-002    (2022) — 1536 维,统一文本搜索、代码搜索、相似度
text-embedding-3-small    (2024) — 1536 维,性能提升
text-embedding-3-large    (2024) — 3072 维,支持可调维度(Matryoshka)

本项目 01-openai-embedding-recomendation-system.py 使用的就是 text-embedding-3-small

BGE 系列(2023 — 2024)

北京智源人工智能研究院(BAAI)出品,开源嵌入模型的标杆。

BGE-base-en-v1.5   (2023) — 英文,768 维
BGE-large-zh-v1.5  (2023) — 中文,1024 维
BGE-M3             (2024) — 多语言 + 多功能(密集 + 稀疏 + ColBERT)
Visualized-BGE     (2024) — 多模态(图片 + 文本)

BGE-M3 在本项目 04-BGE-M3.py 中演示,同时输出三种嵌入。Visualized-BGE 在 05-多模态嵌入.py 中演示图片编码。

Jina Embeddings v3(2024)
特色:
  ├─ 任务感知(Task-Aware):指定 retrieval.query / retrieval.passage / text-matching 等
  ├─ 可调维度(Matryoshka Representation):128/256/512/1024 自由选择
  ├─ 8192 token 长文本支持
  └─ 多语言

本项目 02-jina-embeddings-v3-clustering.py 演示了 Jina v3 用于文本聚类。

6.6 演进脉络总结

离散表示                    静态词向量                  上下文词向量              现代嵌入模型
─────────────────────────────────────────────────────────────────────────────────────────
One-Hot (1950s)                                                      OpenAI Embedding (2022)
  ↓                          Word2Vec (2013)                        BGE 系列 (2023)
TF-IDF (1972)                  ↓                                    Jina v3 (2024)
  ↓       没有语义    →    GloVe (2014)      ELMo (2018.02)         多模态嵌入
BM25 (1990s)                    ↓                   ↓
  ↓                        FastText (2016)    BERT (2018.10)         核心进步:
稀疏    ─────────────→     静态,一词一向量  →  动态,看上下文   →   多功能统一
                          ─────────────────→  ─────────────→        长文本支持
                          第一次飞跃:          第二次飞跃:           多模态融合
                          有了语义空间          有了上下文理解         维度可调

三次关键飞跃

飞跃时间从 → 到本质变化
第一次2013离散稀疏 → 连续稠密词有了语义空间中的位置
第二次2018静态 → 上下文感知同一个词在不同语境有不同表示
第三次2022+单一密集 → 多功能统一一个模型同时支持密集/稀疏/多向量/多模态

七、关键词匹配 vs 语义嵌入

传统关键词匹配(如 BM25)和语义嵌入(Embedding)各有优劣,实际系统中通常两者结合使用:

关键词匹配局限Embedding 解决方式
同义词不匹配语义相近即可匹配
多义词无法区分上下文感知,一词多义
语义相关但无共同词向量距离衡量语义关系
否定/修饰语理解不了深层语义理解
跨语言不行多语言向量空间统一
拼写错误找不到向量相似度容忍噪声
关键词匹配:字面匹配,速度快、可解释,但无法理解语义
语义嵌入:语义匹配,能理解含义,但计算成本高
最佳实践:两者结合(混合检索)

八、余弦相似度与欧氏距离的区别

核心区别

余弦相似度 = "方向一样吗?"   → 衡量方向的相似性,忽略向量长度
欧氏距离   = "离得多远?"     → 衡量绝对距离,受向量长度影响
指标衡量内容受长度影响适合场景
余弦相似度方向夹角❌ 不受文本、Embedding 等语义场景
欧氏距离绝对距离✅ 受影响物理空间、坐标等场景

为什么文本场景选余弦相似度?

向量 A = [1, 1]       → 方向东北
向量 B = [100, 100]   → 方向东北

欧氏距离:很远!(因为长度差很多)
余弦相似度:= 1(完全同方向,因为夹角为 0°)

文本 Embedding 关注的是"语义方向是否一致",而非向量绝对大小,因此余弦相似度更适合。

夹角与相似度对应关系

夹角cos 值含义
1完全相同方向
60°0.5有点像
90°0无关
120°-0.5有点相反
180°-1完全相反

九、维度选择的权衡

维度越高能捕捉越细微的差别

128 维:能分辨 "猫" vs "汽车" ✅
512 维:能分辨 "开心" vs "快乐" ✅
1536 维:能分辨 "开心" vs "愉悦" vs "欣喜" ✅
3072 维:能分辨更细微的差别

但边际效益递减:384 → 1536 提升明显,1536 → 3072 提升有限,3072 → 6144 几乎没区别。

维度高的四项代价

代价计算示例
存储空间1536维 → 6KB/条,3072维 → 12KB/条;100万条差 6GB
计算速度维度翻倍 → 相似度计算量翻倍
内存占用1536维 100万条 ≈ 6GB,3072维 ≈ 12GB
模型费用OpenAI small $0.02/百万token vs large $0.13/百万token(贵 6.5 倍)

实际建议

场景推荐维度
简单搜索384 - 512
一般 RAG 应用1024 - 1536
精细语义区分2048 - 3072
大规模生产环境512 - 1024

维度是「精度」和「成本」的权衡。不确定时先用中等(1024-1536)。


十、模型选型补充

10.1 OpenAI small vs large

text-embedding-3-smalltext-embedding-3-large
维度15363072
价格$0.02 / 100万 token$0.13 / 100万 token
最大输入8191 token8191 token
适合大规模、简单任务高精度、复杂语义
small = 手机拍照:日常够用,传得快、存得多
large = 单反相机:细节更丰富,但文件大、处理慢、贵

10.2 Voyage AI

模型谁家的开源?语言支持特点
VoyageVoyage AI多语言检索专家,效果顶尖

Voyage 专注于检索场景,在多项检索基准测试中表现突出,适合追求最佳检索效果的项目。

10.3 模型选择决策树

你的需求是什么?
│
├─ 🇨🇳 中文为主 / 中英混合
│   └─ 选 BGE-M3(免费开源,多语言强)
│
├─ 💰 预算有限 / 想省钱
│   ├─ 能自己部署 → BGE-M3(免费)
│   └─ 要用 API → OpenAI small(最便宜)
│
├─ 🏆 追求最佳检索效果
│   └─ 选 Voyage(检索专业户)
│
├─ 🔒 数据敏感 / 不能外传
│   └─ 选 BGE / BGE-M3(本地运行)
│
├─ 🌍 多语言 / 跨语言检索
│   ├─ 免费 → BGE-M3
│   └─ 付费 → Voyage / OpenAI large
│
└─ 📱 已经在用 OpenAI 生态
    └─ 选 text-embedding-3(省事)

10.4 自建 vs API

自建(BGE-M3)API(OpenAI/Voyage)
优点🆓 免费、🔒 数据安全、⚡ 低延迟🚀 开箱即用、📈 自动扩容
缺点💰 GPU 成本、🔧 需要运维💰 长期成本高、🔒 数据外传

中文选 BGE-M3,英文选 Voyage,省事选 OpenAI,敏感选本地部署。


十一、常见误解

8 个常见误解与真相

#误解真相
1单个数字越大越好单个数字没意义,要看整体方向
2相似度高 = 内容一样只是语义接近,不是内容相同
3维度越高效果越好边际效益递减,够用就行
4Embedding 能理解一切有盲区:最新事件、专业术语、反讽
5不同模型的向量可以互相比较向量空间不同,不能跨模型比较
6相似度 0.9 就是匹配成功高相似度 ≠ 正确答案
7最相似 = 用户想要语义相似 ≠ 满足需求
8模型越大越好要看任务,小任务用小模型

误解 6 的典型例子

用户问:"iPhone 15 多少钱?"

文档 A:"iPhone 15 Pro Max 价格" → 相似度 0.91(更相似,但不是答案)
文档 B:"iPhone 15 售价 5999 元" → 相似度 0.89(虽然分数低,但才是答案)

误解 5 的关键提醒

OpenAI 的 [0.8, ...] 和 BGE 的 [0.3, ...]
就像华氏度和摄氏度,不能直接比较

要比较,必须用同一个模型生成所有向量!

Embedding 是工具,不是魔法。它能捕捉语义相似性,但不能替代真正的「理解」。


十二、实战问题与解决方案

12.1 相似度翻车案例

案例 1:反义词反而相似

"开心" vs "快乐" → 0.95 ✅ 符合预期
"开心" vs "难过" → 0.72 ❓ 为什么不是很低?

原因:它们都在讨论「情绪」,Embedding 捕捉的是语义空间中的关系。

案例 2:「不相关」的词反而相似

"苹果" vs "三星" → 0.88 ❓ 水果和韩国公司?
"小米" vs "华为" → 0.91 ❓ 谷物和建筑?

原因:模型学到的是「共现关系」,这些词经常在相似上下文出现(都是手机品牌)。

案例 3:同义词相似度反而不高

"买" vs "购买" → 0.85 ✅
"买" vs "下单" → 0.68 ❓ 怎么低了这么多?

原因:使用场景不同,上下文差异大 → Embedding 差异大。

12.2 翻车的核心原因

原因解释
学的是「共现」不是「定义」模型通过「这个词周围经常出现什么词」来学习
多义词无法区分“苹果” = 水果 + 手机品牌 + 电影公司,混在一起
缺乏上下文单独的词 vs 有上下文的句子,Embedding 不同
模型世界观 ≠ 你的世界观模型不知道你的微妙差异
领域知识缺失通用模型不懂专业领域的细微差别

12.3 解决方案

方法说明
用更大的上下文❌ 差:单独搜 “苹果”;✅ 好:搜 “苹果 手机 价格”
用专业领域模型医学 Embedding 模型懂 “感冒” vs “流感” 的区别
加关键词过滤先用 Embedding 召回,再用关键词精确筛选
用重排序模型Embedding 召回 → 粗筛;Reranker 重排 → 精筛

12.4 相似度阈值设定指南

经验阈值参考
相似度范围含义建议
> 0.9几乎相同直接用,置信度很高
0.8 - 0.9非常相关大多数场景够用
0.7 - 0.8比较相关需要人工确认
0.6 - 0.7有点关系可能噪音,看场景
< 0.6关系不大通常直接丢弃
不同场景的推荐阈值
场景推荐阈值策略
严格匹配(客服问答)0.85 - 0.90高于阈值才回答,否则说"没找到"
推荐系统0.65 - 0.75召回 Top 10-20,让用户自己筛选
知识库搜索0.70 - 0.80召回 Top 5-10,显示相似度分数
去重 / 聚类0.90 - 0.95高于 0.95 视为重复
更好的策略:不用硬阈值
策略说明
Top K 召回 + 重排序召回 Top 10,用 Reranker 重排序
动态阈值查询具体 → 阈值高;查询模糊 → 阈值低
显示分数让用户判断展示相似度分数,让用户自己决定
置信度区间>0.85 高置信;0.70-0.85 中置信;<0.70 低置信

从 0.75 开始,用你的数据测试调整。更好的做法:召回 Top K + 重排序,不要硬用阈值。


十三、面试题库

13.1 基础概念题

Q1:什么是 Embedding?用一句话解释。

Embedding 是将离散对象(如单词、图片、用户 ID)映射到连续向量空间的技术,使语义相近的对象在向量空间中距离接近。

加分展开(3 点)

  1. 核心思想:将离散符号或复杂数据,映射为固定长度的连续稠密向量,保留语义、结构或相似性关系
  2. 关键特性:语义保持(相似的输入 → 向量距离近)、可计算(可做数学运算)、可学习(通过训练自动优化)
  3. 应用场景:NLP(Word2Vec、句子嵌入)、推荐系统(用户/物品 Embedding)、搜索(语义搜索)、RAG(文档向量化检索)

加分项:“Embedding 的本质是表示学习(Representation Learning)——让模型自己学会什么是好的特征表示,而不是依赖人工设计特征。”


Q2:Embedding 和 One-Hot 编码有什么区别?

对比维度One-HotEmbedding
向量形式稀疏,只有一个 1,其余全 0稠密,每个维度都有非零值
维度等于词表大小(几万到几十万)固定长度(通常几百到几千)
语义信息❌ 任意两个词距离完全相同✅ 语义相近的词距离近
可计算性只能判断是否相同可以做加减法、相似度计算
存储开销极大较小
One-Hot:  "猫" → [0,0,0,1,0,0,0]  ← 无法表达"猫"和"狗"的相似性
Embedding:"猫" → [0.23, -0.45, 0.89, ...]  ← "猫"和"狗"的向量很接近

Q3:Embedding 的维度是什么意思?维度越高越好吗?

维度 = 描述一个对象需要几个数字。2 维描述平面位置,1536 维描述文本的语义特征。

不是越高越好,维度是精度与成本的权衡:

  • 高维度的好处:能捕捉更细微的语义差别(如"开心" vs “愉悦” vs “欣喜”)
  • 高维度的代价:存储翻倍、计算变慢、内存占用增大、模型费用更高
  • 边际效益递减:384→1536 提升明显,1536→3072 提升有限

一般 RAG 应用推荐 1024-1536 维,不确定时先用中等维度。


Q4:向量、维度、相似度这三个概念怎么理解?

概念通俗理解类比
向量一串有顺序的数字RPG 角色的属性面板 [攻击力, 防御力, 速度]
维度这串数字有几个了解一个人知道多少细节
相似度两个向量「有多像」的分数两个同学有多像

Q5:什么是向量数据库?和普通数据库有什么区别?

对比普通数据库向量数据库
存储内容结构化数据(表格)向量(高维数值)
查询方式精确匹配(WHERE name = ‘xxx’)相似度搜索(找最近的向量)
排列逻辑按索引/主键排列按「语义主题」排列
类比按书名排的图书馆按内容主题排的图书馆

常见的向量数据库:Chroma、Milvus、Pinecone、Weaviate、FAISS


13.2 原理深入题

Q6:余弦相似度和欧氏距离有什么区别?各自适合什么场景?

余弦相似度 = "方向一样吗?"  → 忽略长度,只看方向夹角
欧氏距离   = "离得多远?"    → 看绝对距离,受长度影响
指标衡量内容受长度影响适合场景
余弦相似度方向夹角文本/Embedding 语义场景
欧氏距离绝对距离物理空间/坐标场景

为什么文本场景选余弦? 因为 [1,1][100,100] 方向相同、语义一致,但欧氏距离会很远,余弦相似度 = 1。


Q7:余弦相似度的公式是什么?值域和含义?

cos(θ) = (A · B) / (||A|| × ||B||)

分子:点积(对应维度相乘再相加)
分母:两个向量的长度(模)相乘
值域:[-1, 1]
夹角含义
1完全相同方向
0.560°有点像
090°完全无关
-1180°完全相反

Q8:密集嵌入、稀疏嵌入、多向量嵌入(ColBERT)有什么区别?

特性密集嵌入稀疏嵌入(BM25)多向量嵌入(ColBERT)
向量形式每维非零大部分为 0每个 Token 一个向量
语义理解✅ 强❌ 弱(字面匹配)✅ 最强(Token 级精细)
精确匹配❌ 弱✅ 强✅ 强
存储开销
计算速度较慢
典型代表OpenAI EmbeddingBM25BGE-M3 ColBERT

最佳实践:混合检索(Dense + Sparse 互补),或用 BGE-M3 一个模型同时输出三种嵌入。


Q9:Word2Vec 是怎么训练的?它有什么局限性?

两种训练架构

CBOW:上下文 → 预测中心词    ("猢狲""施展"[?]"击退""妖怪" → 预测"烈焰拳")
Skip-Gram:中心词 → 预测上下文  ("烈焰拳" → 预测周围可能出现"猢狲""施展")

核心思想:上下文相似的词,语义也相似(分布假设)。

局限性

  1. 一词一向量:无法区分多义词(“苹果”=水果还是公司?)
  2. 窗口有限:只看局部上下文(±5 词),缺少全局信息
  3. 静态不变:训练完成后每个词的向量就固定了,不考虑当前语境

Q10:BERT 是如何解决多义词问题的?和 Word2Vec 有什么本质区别?

Word2Vec(静态):
  "苹果" → 永远是 [0.23, -0.11, ...]  ← 不管上下文

BERT(上下文感知):
  "吃了一个苹果" → "苹果" = [0.15, 0.32, ...]  ← 偏向食物
  "苹果发布新手机" → "苹果" = [0.41, -0.08, ...] ← 偏向公司

本质区别:Word2Vec 是静态词向量(一词一向量),BERT 是上下文词向量(同一词在不同语境有不同表示)。

原理:BERT 使用双向 Transformer,通过 MLM(掩码语言模型)预训练,能根据整个句子的上下文动态生成词向量。


Q11:从 BERT 中提取句子嵌入有哪些方法?各有什么问题?

方法做法问题
[CLS] token取 [CLS] 位置的向量效果一般
平均池化取所有 Token 向量的平均值略好,但仍有各向异性问题
Sentence-BERT用孪生网络微调 BERT✅ 专门优化,效果好
SimCSE对比学习(Dropout 数据增强)✅ 无需标注,效果优秀

各向异性问题:BERT 的向量分布在高维空间的狭窄锥形区域,导致所有句子的余弦相似度都偏高,区分度差。


13.3 模型与选型题

Q12:常见的 Embedding 模型有哪些?怎么选?

模型厂家开源特色适合场景
OpenAI smallOpenAI通用稳定快速验证、OpenAI 生态
OpenAI largeOpenAI3072 维高精度高精度复杂语义
BGE-M3北京智源三合一(Dense+Sparse+ColBERT)中文、混合检索、本地部署
VoyageVoyage AI检索效果顶尖追求最佳检索质量
Jina v3Jina AI任务感知、维度可调灵活权衡精度与成本

选择口诀:中文选 BGE-M3,英文选 Voyage,省事选 OpenAI,敏感选本地部署。


Q13:BGE-M3 的 M3 是什么意思?它为什么受欢迎?

M3 = Multi-Lingual(多语言)+ Multi-Functionality(多功能)+ Multi-Granularity(多粒度)

能力说明
多语言支持 100+ 种语言,跨语言检索强
多功能一个模型同时输出 Dense + Sparse + ColBERT 三种嵌入
多粒度句子、段落、长文档都能处理

受欢迎的原因:开源免费 + 一个模型替代 BM25+Dense 两套系统 + 中文效果好 + 支持本地部署(数据安全)。


Q14:自建 Embedding 模型和调用 API 各有什么优劣?

自建(如 BGE-M3)API(如 OpenAI/Voyage)
优点免费、数据安全不出域、低延迟(本地推理)开箱即用、自动扩容、无需运维
缺点需要 GPU 硬件成本、需要运维能力长期使用费用高、数据需发送到外部

建议

  • 数据敏感/企业内网 → 自建
  • 快速上线/MVP → API
  • 大规模 + 长期使用 → 自建(成本可控)

Q15:不同 Embedding 模型生成的向量可以直接比较吗?

绝对不行。

OpenAI 生成的 [0.8, ...] 和 BGE 生成的 [0.3, ...]
就像华氏度和摄氏度,不能直接比较

原因:不同模型的向量空间完全不同
- 维度可能不同(1536 vs 1024)
- 即使维度相同,每维的含义也完全不同
- 相似度的数值范围和分布也不同

规则:要比较,必须用同一个模型生成所有向量

13.4 RAG 与应用题

Q16:简述 RAG(检索增强生成)的核心流程。

【准备阶段 — 只做一次】
文档库 → 分块(Chunking)→ Embedding 向量化 → 存入向量数据库

【查询阶段 — 每次用户提问】
用户问题 → Embedding 向量化 → 向量相似度检索 → 找到相关文档片段 → LLM 生成回答

Embedding 在 RAG 中出现两次:① 把文档向量化存入数据库;② 把用户问题向量化进行检索。

三个关键作用

  1. 翻译:把人类语言翻译成计算机能理解的数字
  2. 压缩:把一段话压缩成一组数字,保留核心语义
  3. 连接:让问题和答案能在同一个数学空间里相遇

Q17:RAG 中为什么要对文档进行切分(Chunking)?常见策略有哪些?

为什么切分

  1. LLM 有输入长度限制(如 8K/128K token),无法一次处理整篇文档
  2. 文档太长时检索效率低,噪音多,相关内容被淹没
  3. 切分后能精准定位到最相关的段落

常见切分策略

策略原理优缺点
固定长度切分按 token/字符数切割简单,但可能截断句子
递归字符切分按分隔符层级递归切割最常用,兼顾语义完整性
按句子切分以句号/换行分段语义完整,但块大小不均
按语义切分用 Embedding 计算相邻句子相似度,在语义断裂处切分效果最好,但计算成本高

关键参数chunk_size(块大小)和 chunk_overlap(重叠部分)。overlap 太小会丢失上下文,太大则冗余。


Q18:为什么 RAG 中推荐混合检索?如何实现?

单一检索的局限

检索方式能找到可能漏掉
仅 BM25(关键词)包含查询关键词的文档语义相关但用词不同的文档
仅向量(语义)语义相关的文档关键词精确匹配但语义距离远的文档

混合检索 = 两者互补,能同时覆盖精确匹配和语义理解。

实现方案

方案做法优劣
双系统BM25 + Dense Embedding 分别检索,结果去重合并灵活但需维护两套系统
BGE-M3一个模型同时输出 Dense + Sparse + ColBERT✅ 推荐,统一管理

Q19:RAG 检索结果不相关,你会从哪些角度排查?

排查角度可能原因解决方法
文本切分chunk_size 太小、overlap 不够,上下文断裂调大 chunk_size,增加 overlap
Embedding 模型中文支持差,或未针对专有名词训练换用 BGE-M3 或领域模型
检索策略仅用向量检索,缺少关键词匹配引入混合检索
相似度阈值阈值过高导致漏召回,或过低导致噪音从 0.75 开始测试调整
查询理解用户问题表述模糊或过于简短优化 query(加上下文、扩展关键词)
文档质量文档本身内容混乱、格式不规范清洗文档、优化切分策略

Q20:什么是 Reranker(重排序)?为什么需要它?

流程:Embedding 召回(粗筛 Top K)→ Reranker 重排(精筛 Top N)→ 送入 LLM

Embedding 召回:速度快,但只看整体语义相似度,精度有限
Reranker:用交叉编码器(Cross-Encoder)对 query 和 document 做深度交互,精度更高

为什么需要:Embedding 是双编码器(Query 和 Document 分别编码再算相似度),无法捕捉 Query-Doc 之间的细粒度交互。Reranker 将两者一起输入模型,能理解更精确的相关性。

类比:Embedding 是"看标题挑书",Reranker 是"翻开书细读再打分"。


13.5 实战与调优题

Q21:相似度阈值怎么定?有什么更好的做法?

经验参考

相似度含义建议
> 0.9几乎相同直接用
0.8 - 0.9非常相关大多数场景够用
0.7 - 0.8比较相关需确认
< 0.6关系不大通常丢弃

更好的做法——不要硬用阈值

  1. Top-K 召回 + Reranker:召回 Top 10 → 重排序 → 取 Top 3(最推荐)
  2. 动态阈值:查询具体时阈值高,查询模糊时阈值低
  3. 标注测试集:准备 100-200 个"问题-文档"对,人工标注,画分布图找分界线

⚠️ 不同模型的阈值标准不同,OpenAI 的 0.8 ≠ BGE 的 0.8,必须用自己的数据验证。


Q22:"开心"和"难过"的相似度竟然有 0.72,为什么?

这是 Embedding 的正常行为,不是 bug:

  • Embedding 捕捉的是语义空间中的关系,“开心"和"难过"都在讨论"情绪”
  • 模型学到的是共现关系,这些词经常在相似上下文出现
  • 它们比"开心"和"汽车"(≈0.1)相似得多,但比"开心"和"快乐"(≈0.95)差很多

本质:Embedding 学的是统计规律,不是人类定义

解决方法:如果业务需要区分情绪正负,应使用专业情感分析模型,而非通用 Embedding。


Q23:Embedding 有哪些"搞不定"的场景?

搞不定的场景例子解决方案
最新事件“昨天刚发生的新闻”结合实时搜索
专业术语医学/法律黑话用领域微调模型
反讽/讽刺“你真聪明啊”(实际骂人)加情感分析模块
精确匹配ID 号、订单号、邮箱混合 BM25 关键词检索
数值比较“价格低于 5000 的手机”结构化过滤 + Embedding 检索

Embedding 是工具,不是魔法。实际系统需要结合多种技术。


Q24:如何评估一个 Embedding 模型在自己业务上的效果?

方法 1:构建评测集

1. 准备 100-200 个「查询 - 相关文档 - 不相关文档」三元组
2. 用模型计算相似度
3. 计算 Recall@K(前 K 个结果中包含正确答案的比例)和 MRR(正确答案的排名倒数均值)

方法 2:A/B 测试

对比两个模型:用户满意度、检索命中率、回答质量评分

方法 3:可视化

用 t-SNE/UMAP 将向量降维到 2D,观察相似内容是否聚在一起

常见指标

指标含义
Recall@K前 K 个结果中正确答案的召回率
MRR正确答案排名倒数的均值
NDCG考虑排序位置的加权指标
Hit Rate至少包含一个正确答案的查询比例

13.6 场景设计题

Q25:如果要你设计一个客服 RAG 系统,文档是产品手册,你会怎么搭建?

1. 数据准备
   ├─ 清洗文档(去除无关格式、广告)
   ├─ 递归字符切分(chunk_size=500, overlap=100)
   └─ 用 BGE-M3 生成 Dense + Sparse 双重嵌入

2. 检索策略
   ├─ 混合检索(Dense 语义 + Sparse 关键词)
   ├─ Top-10 召回 → Reranker 精排 → 取 Top-3
   └─ 相似度阈值 0.75,低于阈值回答"未找到相关信息"

3. 生成策略
   ├─ 将 Top-3 文档片段 + 用户问题送入 LLM
   ├─ System Prompt 约束:只根据检索内容回答,不确定时说明
   └─ 加入引用来源(方便用户验证)

4. 优化方向
   ├─ 监控"未找到"的比例,补充缺失文档
   ├─ 收集用户反馈(有用/没用),持续优化切分和检索参数
   └─ 对高频问题缓存答案,减少 LLM 调用成本

Q26:如何构建一个"以图搜文"的多模态检索系统?

核心思路:图片和文本映射到同一个向量空间

技术方案:
  1. 用 Visualized-BGE / CLIP 等多模态模型
  2. 文档 → 文本 Embedding → 存入向量数据库
  3. 用户上传图片 → 图片 Embedding → 在同一空间检索最近文本

示例:
  用户上传一张"孙悟空战斗"的图片
       ↓ 图片 Embedding
  检索到:[0.92] "猢狲施展烈焰拳击退妖怪"
          [0.31] "唐僧骑白马西行取经"

关键:文本和图片必须用同一个多模态模型编码,确保在同一向量空间中可比。


Q27:公司有 100 万条商品描述要做语义搜索,你会怎么选型?

分析维度:
  ├─ 数据量:100 万条(中等规模)
  ├─ 语言:中文为主
  ├─ 精度要求:商品搜索需要区分细微差别(型号、规格)
  └─ 延迟要求:用户搜索需要 < 200ms 响应

选型方案:
  Embedding 模型:BGE-M3(免费、中文强、支持本地部署)
  向量数据库:Milvus(支持百万级、高性能)
  检索策略:Dense + Sparse 混合检索

  维度选择:1024 维(平衡精度和存储)
  存储:100 万 × 1024 × 4字节 ≈ 4GB(可控)

  如果预算充足追求效果:
    Embedding → Voyage(检索效果顶尖)
    数据库 → Pinecone(全托管,免运维)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值