2.1 向量基础:Embedding、余弦相似度、欧氏距离、向量检索

如果说 LLM 是大脑,那向量就是它的「神经信号编码」。人类用文字交流,计算机用数字计算,而 Embedding 是连接这两个世界的桥梁。不懂向量,就不懂 RAG;不懂 RAG,就没法让 LLM 真正落地到实际业务中。

📑 目录


Embedding(文本嵌入):文字变数字的魔法

一句话定义

把任意长度文本转换成固定长度的数字数组(向量)。语义相似的文本,向量在空间中的距离也更近。

本质大白话

复制代码
Embedding = 文字的 GPS 坐标

想象一个多维空间(比如 1536 维):

「猫」  → [0.12, -0.34, 0.56, ...]  ← 附近聚集着「小狗」「萌宠」
「狗」  → [0.15, -0.31, 0.52, ...]  ← 跟「猫」很近!(都是宠物)
「汽车」→ [-0.45, 0.78, -0.23, ...]  ← 离「猫」「狗」很远
「公交车」→ [-0.42, 0.75, -0.20, ...]  ← 跟「汽车」很近!(交通工具)

关键洞察:
Embedding 不是简单的编码,而是把语义关系映射到几何空间!
语义近 = 空间距短  |  语义远 = 空间距长

Embedding 模型对比

模型 维度 语言 特点 场景
text-embedding-3-small 1536 多语 效果好,付费 通用首选
BGE-large-zh 1024 中英 开源免费效果好 中文首选
M3E-base 768 中文 轻量快速 中文轻量
E5-mistral 1024 多语 多语言强 国际化
Cohere embed-v3 1024 多语 搜索专用 搜索引擎
python 复制代码
from openai import OpenAI
import numpy as np

client = OpenAI()

def get_embedding(text, model="text-embedding-3-small"):
    response = client.embeddings.create(model=model, input=text)
    return response.data[0].embedding  # 1536维向量

# 语义相似的文本,向量接近
texts = ["今天天气不错", "天气很好", "Python 编程教程"]
embs = [get_embedding(t) for t in texts]

def cosine(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

print(f"'今天天气不错' vs '天气很好': {cosine(embs[0], embs[1]):.4f}")  # ~0.92
print(f"'今天天气不错' vs 'Python': {cosine(embs[0], embs[2]):.4f}")   # ~0.15

❌ 常见误区

  • ❌ Embedding 模型越大越好 --- text-embedding-3-small 很多场景优于大模型
  • ❌ 同一 Embedding 通用所有任务 --- 搜索和分类需要不同的 Embedding
  • ❌ 中文必须专用中文模型 --- 多语言模型在中文上已经很出色

余弦相似度:衡量「方向一致性」

一句话定义

计算两个向量夹角的余弦值,范围 -1, 1。越接近 1 表示方向一致(语义越相似)。

本质大白话

复制代码
余弦相似度 = 忽略长度,只看方向

两个人朝同一个方向走:
A 走了100米,B 走了1000米
方向一样 → 余弦 ≈ 1.0

A 往东走,B 往西走
方向相反 → 余弦 ≈ -1.0

文本场景:方向相同 = 语义相近(不管文章长短)
→ 这就是为什么余弦成为文本相似度的默认选择!

cos_sim ( A , B ) = A ⋅ B ∣ ∣ A ∣ ∣ ⋅ ∣ ∣ B ∣ ∣ \text{cos\_sim}(A,B) = \frac{A \cdot B}{||A|| \cdot ||B||} cos_sim(A,B)=∣∣A∣∣⋅∣∣B∣∣A⋅B

python 复制代码
import numpy as np

def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

vec_cat = get_embedding("可爱的小猫")
vec_dog = get_embedding("可爱的狗狗")
vec_car = get_embedding("一辆汽车")

print(f"猫 vs 狗: {cosine_similarity(vec_cat, vec_dog):.4f}")  # ~0.85
print(f"猫 vs 车: {cosine_similarity(vec_cat, vec_car):.4f}")  # ~0.20

❌ 常见误区

  • ❌ 余弦 > 0.9 就意思一样 --- 不同模型阈值不同,不要迷信绝对数值
  • ❌ 余弦适用于所有场景 --- 图像特征场景可能需要欧氏距离

欧氏距离:衡量「直线距离」

一句话定义

两个向量在多维空间的直线距离。越小越相似。

余弦 vs 欧氏

余弦 欧氏
关注点 方向 实际距离
受长度影响
范围 -1,1 [0,+∞)
文本场景 默认首选 少数
图像场景 可能失效 常用
python 复制代码
import numpy as np

def euclidean(a, b):
    return np.linalg.norm(a - b)

# 直观对比
short = get_embedding("你好")
long_text = get_embedding("你好" * 20)

print(f"余弦: {cosine_similarity(short, long_text):.4f}")  # ~0.95 (方向一样)
print(f"欧氏: {euclidean(short, long_text):.4f}")       # 可能很大(长度不同)
# 结论:文本用余弦,特征考虑欧氏

向量检索:从语义匹配到实际查询

一句话定义

给定查询文本转为向量后,在向量库中找到 Top-K 条最相似记录的过程。RAG 的核心操作。

检索流程

复制代码
用户提问:「如何优化 MySQL 查询性能?」
       ↓
   [Embedding 模型]
       ↓
   查询向量: [0.21, -0.15, 0.33, ...]
       ↓
┌────────────────────────────────┐
│          向量数据库             │
│  doc1 [0.20,-0.14,0.35,...] → 0.012 ★1 │
│  doc2 [0.55, 0.72,-0.11,...] → 0.892  │
│  doc3 [0.22,-0.13,0.31,...] → 0.025 ★2 │
│  doc4 [-0.81,0.33, 0.55,...] → 1.203  │
└────────────────────────────────┘
       ↓
   返回 Top-K (doc1, doc3) 作为 LLM 上下文
python 复制代码
from typing import List
import numpy as np

class VectorRetriever:
    def __init__(self, embedding_func):
        self.embed_fn = embedding_func
        self.vectors = []
        self.documents = []
    
    def add_document(self, text, metadata=None):
        vec = self.embed_fn(text)
        self.vectors.append(vec)
        self.documents.append({"text": text, "metadata": metadata or {}})
    
    def search(self, query, top_k=5) -> List[dict]:
        q_vec = self.embed_fn(query)
        scores = []
        for v in self.vectors:
            scores.append(np.dot(q_vec, v) / (
                np.linalg.norm(q_vec) * np.linalg.norm(v)))
        top_idx = np.argsort(scores)[::-1][:top_k]
        return [{"doc": self.documents[i], "score": scores[i]} for i in top_idx]

# 使用
retriever = VectorRetriever(get_embedding)
retriever.add_document("MySQL 索引优化策略:...")
retriever.add_document("Redis 缓存使用指南:...")
results = retriever.search("数据库太慢了怎么办", top_k=3)

❌ 常见误区

  • ❌ 向量检索 = 完美语义搜索 --- 找不到精确关键词匹配(型号编号、专有名词)
  • ❌ Top-K 越大越好 --- K 太大引入噪音,K 太小漏信息。一般 3-10 合理
  • ❌ 只要向量就够了 --- 生产环境通常需要混合检索(详见 2.2)

什么时候用什么度量?

场景 推荐 原因
文本语义检索 余弦 忽略长度,关注方向
图像特征比对 欧氏 特征幅度有意义
归一化后的向量 两者等效 归一化后余弦=欧氏
异常检测 欧氏 远离聚类中心的点易识别
推荐系统 余弦 关注偏好方向而非强度

📊 本节知识地图

复制代码
┌────────────────────────────────────────────────────┐
│              向量基础 --- RAG 的地基                  │
│                                                    │
│  ┌────────────┐    ┌──────────────────────────┐   │
│  │ Embedding  │──→ │     相似度计算            │   │
│  │ 文本→向量  │    │  余弦 ★ / 欧氏 ☆         │   │
│  └────────────┘    └──────────┬───────────────┘   │
│                              │                     │
│                              ↓                     │
│                    ┌──────────────────┐           │
│                    │   向量检索        │           │
│                    │  Top-K 返回       │           │
│                    └────────┬─────────┘           │
│                             ↓                     │
│                    ┌──────────────────┐           │
│                    │  2.2 RAG体系     │ ← 下节详解  │
│                    └──────────────────┘           │
│                                                    │
│  一句话:                                          │
│  Embedding转数字 → 相似度找最相关 → 检索返回       │
└────────────────────────────────────────────────────┘

🔗 关联推荐

  • 📖 1.1 模型本源 → Token 是 Embedding 的输入单元
  • 📖 1.3 交互基础 → 检索结果是 Context 的重要来源
  • 🔜 2.2 RAG 体系 → 向量检索是 RAG 的第一步
  • 🔜 2.3 向量数据库 → 向量存在哪里?怎么选型?
相关推荐
Black蜡笔小新3 小时前
自动化AI算法训练服务器DLTM训推一体工作站赋能多行业智能化升级
人工智能·算法·自动化
怪兽学LLM3 小时前
LeetCode 438 找到字符串中所有字母异位词(Python 固定滑动窗口+字符计数解法)
python·算法·leetcode
满怀冰雪3 小时前
第04篇-双指针算法-从有序数组到回文判断的高频解法
java·算法
CC数学建模3 小时前
2026年江西省研究生数学建模竞赛1题:空间数据分析中的过拟合识别完整思路、代码、模型、文章,全网首发高质量分享!
python·算法·数学建模
leo__5203 小时前
MATLAB实现牧羊人算法
开发语言·算法·matlab
Gauss松鼠会3 小时前
【GaussDB】GaussDB SMP特性调优详解
java·服务器·前端·数据库·sql·算法·gaussdb
Tisfy3 小时前
LeetCode 3689.最大子数组总值 I:What The Medium
算法·leetcode·题解·贪心·模拟·脑筋急转弯
葬送的代码人生3 小时前
JavaScript 数组完全指南:从入门到实战
前端·javascript·算法
春日见4 小时前
决策规划控制面经汇总
人工智能·深度学习·算法·机器学习·自动驾驶