一、为什么我们需要“向量化”文本?

我们每天都在处理文本,比如搜索引擎查找网页、电商平台推荐商品、或者在一堆文档里找最相关的段落。最直觉的方法可能是关键词匹配,比如搜索“苹果”时,直接找包含这两个字的文档。但这存在明显问题:它无法理解“苹果”既可能是水果,也可能是科技公司;也分不清“机器学习”和“深度学习”虽是不同词汇,但语义高度相关。关键词匹配缺乏对“语义”——即语言背后含义——的理解。

为了解决这个问题,我们需要一种方法,将任意长度、结构复杂的文本(如一个词、一句话、一个段落)转换成一个固定长度、稠密、连续的数值向量。这个过程就是 0(嵌入)。这个向量就像是文本在数学空间中的一个“身份证”或“指纹”,它能够以一种机器可计算的方式,浓缩并表达文本的语义信息。当两个文本的语义相似时,它们的向量在空间中的距离(如余弦距离)就会很近。

提示:你可以把 Embedding 模型想象成一个“语义翻译器”,它将人类自然语言“翻译”成了计算机擅长处理的数学语言——向量。

二、Embedding 向量是如何生成的?

现代高质量的 Embedding 主要由深度学习模型,尤其是基于 Transformer 架构的模型(如 BERT、GPT 的编码器部分)生成。这些模型在海量文本数据上进行了“预训练”,学习到了丰富的语言规律和知识。当我们输入一段文本时,模型内部的多层注意力机制会协同工作,捕捉词语之间复杂的上下文依赖关系。

具体来说,输入文本首先会被分词器(Tokenizer)拆分成子词单元(如“学习”可能被拆分为“学”和“习”)。这些子词会查找一个初始的向量表示,然后经过 Transformer 编码器的多层变换。每一层都会结合上下文信息,更新每个子词的向量。最终,我们通常取特定层(如最后一层)的输出,并按照某种策略(如取所有子词向量的平均值,或直接使用第一个特殊标记 [CLS] 的向量)聚合为一个固定长度的向量,这就是该文本的 Embedding。

# 这是一个概念性示例,展示使用预训练模型生成Embedding的典型流程
from transformers import AutoTokenizer, AutoModel
import torch

# 1. 加载预训练模型和分词器(以'sentence-transformers/all-MiniLM-L6-v2'为例)
model_name = "sentence-transformers/all-MiniLM-L6-v2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)

# 2. 输入文本
sentences = ["如何学习编程?", "怎样开始写代码?", "今天天气怎么样?"]

# 3. 分词与编码
encoded_input = tokenizer(sentences, padding=True, truncation=True, return_tensors='pt')

# 4. 前向传播,获取模型输出
with torch.no_grad():
    model_output = model(**encoded_input)

# 5. 聚合输出为句子向量(这里使用平均池化)
# 注意:实际使用时,最好参考模型文档推荐的池化方法
def mean_pooling(model_output, attention_mask):
    token_embeddings = model_output.last_hidden_state
    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)

sentence_embeddings = mean_pooling(model_output, encoded_input['attention_mask'])
# sentence_embeddings 的形状将是 [3, 384],即3个句子的384维向量

三、向量空间与语义相似性

生成的 Embedding 向量存在于一个高维的“语义空间”中。这个空间有一个极其重要的特性:语义相似的文本,其向量在空间中的位置也相近。这种“相近”可以通过计算向量间的距离或相似度来量化,最常用的指标是余弦相似度。它的值范围在-1到1之间,1表示方向完全一致(语义完全相同),0表示正交(无关),-1表示完全相反。

例如,在理想情况下,“如何学习编程?”和“怎样开始写代码?”这两个问题的 Embedding 向量会指向非常相似的方向,它们的余弦相似度会接近1。而“今天天气怎么样?”这个句子的向量则会与它们的方向差异较大,相似度较低。正是这种数学化的表示,使得计算机能够进行“语义检索”——根据意思而非字面来查找相似内容。

四、从向量到检索:近似最近邻搜索

当我们为数据库中的所有文档(如商品描述、FAQ问题、新闻标题)预先计算好 Embedding 向量后,语义检索就变成了一个在向量空间中查找“最近邻”的问题。给定一个用户查询(Query),我们首先将它编码为查询向量,然后在文档向量库中,找出与之余弦相似度最高的那几个文档向量,它们对应的原始文档就是最相关的检索结果。

然而,当文档库规模巨大(如上亿条)时,进行精确的暴力搜索(逐一计算查询向量与所有文档向量的相似度)计算成本过高,无法满足实时性要求。因此,工程上普遍采用近似最近邻(ANN, Approximate Nearest Neighbor)搜索算法。ANN 通过牺牲一小部分精度(例如召回率99%而非100%),来换取数量级的速度提升。常见的 ANN 库包括 Faiss(Facebook开源)、Annoy(Spotify开源)以及商业化的向量数据库如 Pinecone、Milvus 等。

五、实战:一个简单的语义检索流程

下面是一个简化的代码示例,演示如何构建一个最基本的语义检索管道。它结合了前面提到的 Embedding 模型和 ANN 搜索库 Faiss。

import numpy as np
import faiss
from sentence_transformers import SentenceTransformer

# 1. 加载一个为句子嵌入优化的模型
model = SentenceTransformer('all-MiniLM-L6-v2')

# 2. 准备我们的文档库(示例)
documents = [
    "机器学习是人工智能的一个子领域。",
    "深度学习是机器学习的一个分支,主要基于神经网络。",
    "神经网络是一种模仿动物大脑结构的算法模型。",
    "苹果公司是一家知名的科技企业。",
    "红富士是一种很甜的苹果品种。",
    "今天北京的天气是晴天。"
]

# 3. 批量计算所有文档的向量
doc_embeddings = model.encode(documents)
# doc_embeddings 的形状是 (6, 384)

# 4. 构建 Faiss 索引 (这里使用L2距离索引,需将余弦相似度转换为距离)
dimension = doc_embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)  # 精确的L2距离搜索索引(小数据量可用)
# 对于大数据量,应使用 `IndexIVFFlat` 或 `IndexHNSW` 等近似索引
# 将向量转为float32并添加到索引
index.add(doc_embeddings.astype('float32'))

# 5. 定义查询
query = "什么是深度学习?"
query_embedding = model.encode([query]).astype('float32')

# 6. 执行检索:查找最相似的2个文档
k = 2
distances, indices = index.search(query_embedding, k)

# 7. 输出结果
print(f"查询: {query}")
print("最相关的文档:")
for i in range(k):
    doc_index = indices[0][i]
    distance = distances[0][i]
    similarity = 1 / (1 + distance)  # 简单将L2距离转换为0-1间的相似度
    print(f"  {i+1}. {documents[doc_index]} (相似度: {similarity:.4f})")

运行结果可能会显示,“机器学习是人工智能的一个子领域。”和“深度学习是机器学习的一个分支,主要基于神经网络。”是最相关的两个文档,这正是语义检索的威力所在。

六、应用场景与局限性

基于 Embedding 的语义检索技术已经渗透到众多领域:

然而,这项技术也有其局限性:

七、总结与展望

Embedding 向量与语义检索的核心思想,是将非结构化的自然语言映射到结构化的高维向量空间,利用空间中的几何关系(距离、相似度)来表达语义关系。它从根本上超越了基于关键词的检索范式,实现了更接近人类理解的“概念检索”。

随着大语言模型的发展,Embedding 模型本身也在快速进化,变得更准确、更高效、支持更长的文本。同时,专为向量数据设计的向量数据库正在成为新的基础设施,为大规模、低延迟的语义检索提供支撑。理解并掌握这项技术,无疑是构建下一代智能应用的重要基石。