Embedding 将语义转化为向量实现跨词匹配,向量数据库通过近似最近邻索引在精度与速度间取得平衡,是每个 RAG 系统的技术基石。
你给文档加了一个搜索框。用户输入"how do I reset my password",结果什么都没有——因为你的帮助文章标题是"Account recovery steps"。意思相同,却没有匹配的词。关键词搜索只能找到共享字面 token 的文档;它完全不知道"reset password"和"account recovery"是同一个意思。
Embeddings 解决了这个问题。它们把文本转换成数字,用数字编码语义,这样"reset my password"和"account recovery"即使没有任何共同词汇也会靠得很近。Vector search 就是用来快速找到这些相近语义的,它是每个 RAG 系统底层的检索引擎。
📌 谁适合看这篇文章: 工程师看过 RAG 教程里提到 embeddings,但一直不明白向量到底是什么、为什么 cosine similarity 到处出现、为什么"HNSW"很重要。如果你调用了一个 embedding API,返回了一大串浮点数数组,然后想"然后呢?",从这篇文章开始。不需要线性代数学位。
一个 embedding 就是一个数字列表(一个 vector),它把一段文本表示为高维空间中的一个点,位置安排使得语义相近的文本彼此靠近。
就这样。你把文本交给 embedding 模型,它返回一个固定长度的浮点数数组,通常是 384、768 或 1536 个数字。每个数字是一个坐标。"The cat sat on the mat"可能变成[0.021, -0.118, 0.337, ...]。这些单个数字对你来说没有意义;重要的是它们描述的位置,以及这个位置与其他位置的接近程度。
模型是通过阅读大量文本学习到这些坐标的。它发现用在相似上下文中的词和句子应该落在相似的地方。结果就是这样一个空间:几何距离成为语义差异的代理。
可以把 embedding 想象成一张语义地图。
在真实地图上,巴黎和里昂很近,东京则离两者都很远。在 embedding 空间中,"reset password"和"account recovery"很近,两者都远离"export invoice as PDF"。搜索变成了几何问题:找相关文本,就是找最近的点。

Text becomes a vector, lands in a vector space, and a query finds its nearest neighbors.
对你的文档做 embedding: 把语料库的每个 chunk 跑一遍 embedding 模型,离线完成。每个 chunk 得到一个向量。
把向量存到索引里: 加载到向量数据库(Pinecone、Qdrant、pgvector、Weaviate)。数据库会构建一个索引,通常是 HNSW,让搜索变快。
对用户查询做 embedding: 查询时,把用户的问题通过同一个模型,得到一个同空间中的查询向量。
找最近邻: 索引返回与查询向量最接近的 top-k 个向量,按 cosine 等相似度度量排序。
使用结果: 作为搜索结果返回,或者作为上下文塞进 LLM prompt——第二条路径就是 RAG。
⚠️ 两边用同一个模型: 文档和查询必须用同一个模型做 embedding。两个模型产生两个不兼容的坐标系,它们之间的距离是毫无意义的噪声。这是 vector search "返回垃圾"最常见的原因。
"最近"需要一个距离的定义。三种度量占主导,但它们回答的问题有微妙差异。选错了会悄悄降低结果质量。
选择模型训练时用的度量,通常是 cosine。
对于文本,cosine 几乎总是对的。两句关于同一主题的话,即使一个是一段话另一个是一个短语,方向也是相同的——cosine 关心的是方向,不是长度。一个有用的结论:如果先把向量归一化成单位长度,cosine similarity 和 dot product 是等价的,而 dot product 更便宜。很多向量数据库帮你做了这一步,所以它们的文档说"用 dot product 得到 cosine 结果"。
整个概念在一个可运行的脚本里:embed 两段文本,然后测量它们的向量对齐程度。换掉模型可以用任何 embedding API 或本地模型,数学是一样的。
import numpy as np
from openai import OpenAI
client = OpenAI()
def embed(text: str) -> np.ndarray:
resp = client.embeddings.create(
model="text-embedding-3-small",
input=text,
)
return np.array(resp.data[0].embedding)
def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
# dot product divided by the product of magnitudes
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
v1 = embed("how do I reset my password")
v2 = embed("steps to recover my account")
v3 = embed("export an invoice as a PDF")
print(round(cosine_similarity(v1, v2), 3)) # ~0.82 -> very similar
print(round(cosine_similarity(v1, v3), 3)) # ~0.21 -> unrelated
同一意图的两种说法得分很高(约 0.82);无关的任务得分很低(约 0.21),没有任何共同关键词。这个差距就是 embeddings 的全部价值。Vector search 就是在数百万个存储向量上做这个比较,然后返回得分最高的那些。
找最近邻的朴素方法是精确搜索:计算查询与每个存储向量的相似度,然后排序。这完全准确,也完全不可扩展。一万个向量?没问题。一千万个?每次查询现在要做一千万次比较。延迟完蛋。
近似最近邻(ANN)搜索用一点点准确度换来了数量级的速度提升。它不扫描所有内容,而是构建一个智能索引,让查询跳到正确的邻域,只和一小部分候选集比较。两大家族主导:
HNSW(Hierarchical Navigable Small World)构建一个分层图,每个向量链接到它的邻居。查询从顶层进入,贪心地跳向更近的节点,然后下降。召回率出色,查询非常快;代价是更高的内存使用。大多数向量数据库的默认选择。
IVF(Inverted File Index)通过 k-means 把向量聚类到桶中,查询时只搜索查询向量最近的几个桶。内存更低,适合超大数据集;召回率取决于你探测多少个桶(nprobe 旋钮)。
关键词是 approximate:ANN 可能错过真正的第 3 名而返回真正的第 4 名。我们用 recall 来衡量,即索引实际返回的 true top-k 占的比例。调优 ANN 就是在这条曲线上选一个点:把参数推高(HNSW 的 ef_search、IVF 的 nprobe)得到更高召回率和更慢查询,或者调低得到极致速度和几个漏掉的近邻。对大多数应用来说,以一小部分延迟换来 95-99% 的召回率,这个交换你很乐意接受。
💡 精确搜索也够用的情况: 向量少于 ~10k 个时,就用精确(暴力)搜索,pgvector 等做得很好,而且你省掉了所有索引调优。只有当你的语料库和延迟预算真正需要 ANN 时才用它,不是之前。
Embedding 模型不匹配。 用一个模型对文档做 embedding,用另一个模型对查询做 embedding,会把它们放到不同的坐标系中。结果看起来是随机的。两边锁定同一个模型,如果要换就重新 embed 所有内容。
距离度量用错。 在为 cosine 训练的向量上用 Euclidean(或者反过来),会悄悄地把错误的东西排到前面。查看模型卡,它会告诉你训练用的度量是什么,配置你的索引去匹配。
没有归一化。 如果你用 dot product 但期望 cosine 行为,却没有归一化成单位长度,较长的文档会因其更大的幅度被不公平地提升。归一化,或者使用忽略幅度的度量。
Embedding 原始的、过大的 chunk。 把一篇 4000 字的文章塞进一个向量,会把很多想法模糊成一个平均点。切成连贯的段落(见 RAG architecture),让每个向量代表一个想法。
追求 100% 召回率。 要求完美的 ANN 召回率等于抛弃了全部速度优势。设定一个召回率目标(比如 98%),调优到目标,然后继续。
Embeddings 和 vector search 是现代 AI 应用的检索半部分。下一步自然是把它们接进生成循环,这正是 RAG 做的事。如果这里的几何让你觉得神奇,理解产生这些向量的模型是如何训练的,会解开其余的谜团。
RAG Architecture Explained, retrieved chunks 如何变成有依据的 LLM 回答。
How LLMs Actually Work,embeddings 和生成背后模型的工作原理。
AI Engineer career path,从基础到生产 AI 系统的完整路径。
Originally published on TheSimplifiedTech, where this guide is interactive, with in-browser terminal labs and diagrams. Learn cloud and DevOps by doing, no videos.