TECH ARTICLES
Embedding 向量检索 RAG

向量模型底层原理:文字怎么变成一串数字,又怎么"懂"了语义?

Jackie Zhan 2026-06-27
目录
一、文字怎么变成数字:从"查字典"到"画坐标" 二、模型到底学了什么:让"上下文"出卖一个词 三、为什么语义近的会"挤"到一起:对比学习的拉与推 四、向量空间里的"近"到底怎么算:余弦、点积、欧氏距离 五、写在最后:你今天就能做的一个实验

做一个思想实验。

我给你三个词:"猫"、"狗"、"法律"。我让你按"相近程度"排个序,你一秒钟就知道答案——猫和狗是一伙的,法律是另一伙的。

但你有没有想过,计算机凭什么知道这件事?在它眼里,"猫"和"狗"不过是两串编码,"猫"是 0x732B,"狗"是 0x72D7,"法律"是 0x6CD5 0x5F8B。论字节,猫和狗差了 0x05,猫和法律的第一个字差了 0x59。难道说……猫和狗更近,是因为它们的 Unicode 编号挨得更近?

当然不是。这只是巧合。如果换成"猫"和"锚",编码挨得更近,但语义八竿子打不着。

这就是整个 AI 检索时代最底层的那个问题:怎么让一台只认数字的机器,理解"意思上的远近"?答案,就藏在"向量模型"(Embedding) 这四个字里。今天我们就一层层把它拆开——不堆公式,但每一步都让你真的"看见"它在干什么。读完你会明白:所谓 RAG、所谓语义搜索、所谓向量数据库,本质上都建立在同一个朴素到惊人的想法上。


一、文字怎么变成数字:从"查字典"到"画坐标"

要把文字喂给计算机,第一步永远是变成数字。最笨的办法,叫 One-Hot(独热编码)

它的逻辑简单到可爱:假设世界上一共有 5 万个词,那就准备一个 5 万维的向量。"猫"是第 1024 个词,那"猫"的向量就是——第 1024 位是 1,其余 49999 位全是 0。"狗"是第 2048 个词,就第 2048 位是 1。

问题来了。在这套表示法里,"猫"和"狗"的距离,跟"猫"和"法律"的距离,一模一样。

为什么?因为任意两个 One-Hot 向量都是"正交"的——它们各自只在一个位置亮灯,且永不重叠。你算它们的相似度,结果恒等于 0。在 One-Hot 的世界里,所有词都是孤岛,谁跟谁都没关系。这显然不是我们要的。

常见误解
很多人以为"把字变成数字"就已经是 Embedding 了。不是的。One-Hot 也是数字,但它没有任何语义——它只是给每个词发了一个工号。Embedding 的关键不在"变成数字",而在"变成有意义的、彼此可比较的数字"。

那怎么办?聪明的做法是换一个思路:不要给每个词发工号,而是给每个词画一组坐标。

想象一张地图。我们不再用 5 万维去标记"是不是第 1024 个词",而是用比如 768 个维度去描述这个词的"属性"。第 1 维也许隐约对应"是不是动物",第 2 维也许对应"是不是抽象概念",第 88 维也许对应"和权力有关吗"……(注意,真实模型里这些维度并没有这么清晰的人类标签,但精神是这样的。)

于是"猫"可能是 [0.91, 0.02, 0.05, ...],"狗"是 [0.88, 0.03, 0.07, ...],"法律"是 [0.01, 0.95, 0.89, ...]。猫和狗在"动物"那一维都很高、在"抽象"那一维都很低,它们的坐标自然就挨得近;法律则飘到了地图的另一个角落。

这种"密集的、低维的、用坐标描述语义"的向量,就叫 Embedding(嵌入向量)。"嵌入"这个词很传神——它是把离散的词语,嵌入到一个连续的几何空间里。从此,"意思相近"这件抽象的事,被翻译成了一件具体到可以用尺子量的事:空间里的距离

One-Hot:5万维,全是 0 和 1 猫 = [0, …, 1, …, 0] 第1024位亮 狗 = [0, …, 1, …, 0] 第2048位亮 任意两词距离都相等 → 无语义 学习 Embedding:768维,连续坐标 猫 = [0.91, 0.02, 0.05, …] 狗 = [0.88, 0.03, 0.07, …] ≈猫 法律 = [0.01, 0.95, 0.89, …] 远
从"发工号"的 One-Hot,到"画坐标"的 Embedding

但问题只是被推后了一步:这些坐标,是谁定的?总不能让语言学家坐下来,给每个词的 768 个维度一个个手填吧。这才是真正的魔法所在。

One-Hot 给词发工号,Embedding 给词画坐标——前者让词彼此孤立,后者让词彼此相邻。

二、模型到底学了什么:让"上下文"出卖一个词

坐标不是人填的,是模型从海量文本里"猜"出来的。而它能猜出来,靠的是一条朴素到近乎哲学的原理,叫 分布式假设(Distributional Hypothesis)

这句话出自语言学家 J.R. Firth 1957 年的一句名言:

你想知道一个词的意思,就看它跟哪些词在一起出现。
(You shall know a word by the company it keeps.)
—— J.R. Firth, 1957

什么意思?我换个生活化的说法你立刻就懂。

假设你在读一本全是生词的外语书,里面反复出现一个你不认识的词,姑且叫它"bvar"。但你发现:每次"bvar"出现,旁边总是跟着"喝、口渴、倒一杯、冰镇、解渴"。读了三十遍之后,就算没人告诉你,你也敢打赌——bvar 八成是某种"饮料"或者干脆就是"水"

你看,你根本没查字典,只是观察了它的"社交圈",就反推出了它的意思。一个词的意义,被它周围的词出卖了。

模型干的就是这件事,只不过把它做成了一道填空题。最经典的范式 Word2Vec(2013 年)就是这么训练的:把一句话挖个空,让模型猜中间该填什么。

输入上下文: "今天好热,我想喝一杯 ___ 的可乐"
让模型预测: 冰镇 / 冰的 / 加冰  ← 这些词的坐标会被往一起拉

训练的细节是这样的:模型一开始把每个词的坐标随机乱撒,预测当然全错。但每错一次,它就根据误差微调一点点所有相关词的坐标——让"冰镇"的坐标朝着"在这种上下文里更容易被选中"的方向挪一小步。一句话挪一点,一万句挪一万点,几十亿句话喂下去……

奇迹发生了。那些总是出现在相似上下文里的词,会被反复往同一个方向拉,最后自然而然地聚到了一起。"冰镇""冰的""加冰"挤成一团,"国王""女王""王室"挤成另一团。没有人教过模型"冰镇和加冰是近义词",是它们共同的上下文,把它们推到了一起。

动手算一算
Word2Vec 最著名的"彩蛋":把学出来的向量做加减法,居然能完成类比推理。
vec("国王") − vec("男人") + vec("女人") ≈ vec("女王")
为什么?因为"国王→女王"和"男人→女人"在训练语料里走的是同一种上下文差异(都是"性别"那条线),于是这个差异在空间里被编码成了同一个方向的位移。语义关系,变成了几何向量——这是第一次让人直观感到"向量真的装下了意义"。

到了今天的 BERT、BGE、OpenAI 的 text-embedding 这一代模型,机制更复杂(用的是 Transformer,能根据整句话动态地理解一个词),但内核没变:还是"用上下文预测、用预测误差反推坐标"。区别只在于——Word2Vec 给每个词一个固定坐标,而现代模型能给"苹果手机"的"苹果"和"吃苹果"的"苹果"算出不同的坐标。后者更聪明,但它们站在同一条地基上。

说到这你可能已经看出一个微妙的问题了:填空题训练出来的是"词"的向量。可我们做检索,要比的是"一整句话"甚至"一整段文档"的相似度。从词到句,中间还差一道工序——而正是这道工序,才让"语义相近就距离更近"这件事真正落地。

模型从没被告诉过任何词的意思,它只是看了几十亿遍"谁和谁总在一起",然后让物以类聚自己发生。

三、为什么语义近的会"挤"到一起:对比学习的拉与推

把一句话变成一个向量,最简单的办法是把句子里所有词的向量取个平均(叫"平均池化")。能用,但很糙——它会把"我爱你"和"你爱我"算成几乎一样,因为词都一样。

真正让现代向量模型"开窍"的,是一种叫 对比学习(Contrastive Learning)的训练方式。它的思想,比上面那道填空题还要直白:与其教模型每个句子的绝对坐标,不如直接教它"谁该挨着谁、谁该离谁远"。

怎么教?给模型看一堆"三元组":

训练目标只有一句话:把锚点和正样本的向量往一起拉,把锚点和负样本的向量往两边推。拉近正样本、推远负样本——这个"一拉一推",就是对比学习的全部精髓。

训练前:随机散落 问题 正样本 负样本 拉 + 推 训练后:物以类聚 问题 正样本 负样本
对比学习:把语义相关的拉到一起,把无关的推开

这里有个反直觉但极其关键的点,请你停下来想三秒:"语义相近,所以距离近"这个结论,不是模型某种天赋,而是被训练目标直接定义出来的。

换句话说,我们并不是先有了一个"懂语义的空间",然后惊喜地发现相近的东西恰好挨得近。恰恰相反——我们是拿着几亿对"该相近"的样本,用拉推这把锤子,硬生生把空间敲打成了"相近的就该挨近"的形状。语义的远近和几何的远近能对齐,是几亿次拉推的结果,不是巧合。

insider 视角
对比学习里有个魔鬼细节叫"批内负样本"(in-batch negatives):训练时一个 batch 里其他所有句子,都被顺手当成当前问题的负样本。这等于让模型在"一大群干扰项里精准认出唯一的正确答案"——这跟你做检索时"在一百万篇文档里捞出最对的那几篇"是同一件事。模型练的,就是它将来要考的。这也是为什么 batch 越大、负样本越多,训练出的向量模型往往越强。

明白了这一点,你就拿到了理解向量检索的钥匙。模型已经把世界铺成了一张"语义地图",意思相近的内容在图上就是邻居。剩下的问题只有一个,也是最实际的一个——"邻居"这件事,到底用什么尺子来量?

不是相近的东西恰好挨得近,而是我们用几亿次拉推,把空间硬掰成了"相近即相邻"的样子。

四、向量空间里的"近"到底怎么算:余弦、点积、欧氏距离

现在每段文字都是空间里的一个点(一个向量)。问"哪两段意思最近",就是问"哪两个向量离得最近"。怎么量?三把常见的尺子,我们一把把上手。

第一把尺:欧氏距离——最符合直觉的"两点间直线长度"

这就是你初中学的两点距离公式,在高维空间里的推广。两个向量对应位置相减、平方、求和、开根号。距离越小,越近。直觉满分,但它有个软肋:它同时关心"方向"和"长度"。在文本检索里,一段长文档的向量往往"模长"更大,哪怕它和查询的方向高度一致,欧氏距离也可能被模长拉开。我们其实更在乎"聊的是不是一回事"(方向),而不是"说了多少话"(长度)。

第二把尺:余弦相似度——只看方向,不看长短

这是文本向量检索的默认选择。它不量两个点的距离,而是量两个向量之间夹角的余弦值

原点 国王 女王 法律 θ 小 → cos≈1 θ 大 → cos≈0
余弦相似度量的是夹角:方向越一致,越相似(与向量长短无关)

为什么"只看方向"在文本里更合理?打个比方。一篇 200 字的短答案和一篇 2000 字的长文档,可能讲的是同一个主题,只是详略不同。它们的向量方向一致,但长度悬殊。余弦相似度会聪明地忽略长度差异,只认"你俩朝着同一个方向"——这正是我们想要的"主题是否一致"。

第三把尺:点积——方向和长度,它全都要

点积(内积)是把两个向量对应位置相乘再求和。它和余弦相似度的关系,一句话就能说清:

点积 = 余弦相似度 × |向量A的长度| × |向量B的长度|

看出来了吗?点积 = 余弦 × 两个模长。也就是说,余弦只管方向,点积在方向之外还把"长度"算了进去。一个向量越长,它在点积里的"嗓门"就越大。

这就引出了全篇最该记住的一个结论——很多人到这里会绕晕,其实简单:

关键区别
如果你先把所有向量都"归一化"(把长度统一缩放成 1),那么每个模长都等于 1,上面的公式里两个长度项消失——点积就完全等于余弦相似度

这就是为什么主流向量数据库默认用"点积"做计算:它比余弦少了一步除法(不用再除以模长),更快;而只要向量提前归一化过,结果和余弦一模一样。又快又等价,何乐不为。

所以你不必纠结"该选余弦还是点积"。绝大多数现代向量模型(BGE、E5、OpenAI 的 embedding 等)输出时就帮你归一化好了,此时余弦、点积、欧氏距离三者排出来的名次完全一致。真正需要你操心的,是别把没归一化的向量丢进按点积计算的索引里——那时长度会捣乱,召回结果会跑偏。

度量方式量的是什么适合场景
欧氏距离两点直线距离(含方向+长度)向量长度本身有意义时(如图像特征)
余弦相似度纯方向(夹角)文本语义检索的默认首选
点积方向 + 长度向量已归一化时=余弦,但计算更快

到这里,三把尺子你都拿到了。但还剩最后一个工程难题:一个向量库里动辄上亿条文档,难道每来一个查询,我都要和上亿个向量逐一算一遍相似度吗?

当然不能。所以真实系统里有一层近似最近邻(ANN,Approximate Nearest Neighbor)索引——用 HNSW 这类算法,把向量预先组织成一张"图"或"树",查询时只需探访极小一部分候选,就能以毫秒级找出最近的几个邻居。它牺牲了一点点精度("近似"),换来了成千上万倍的速度。整条链路因此跑通:

离线:建库 文档库 向量模型 在线:查询 用户问题 向量模型 ANN 索引(HNSW) 按余弦/点积排序 Top-K 最相近 交给大模型
一次语义检索的完整链路:文档与查询走同一个向量模型,在同一空间里比距离

这张图就是 RAG、语义搜索的骨架。注意一个常被忽略的前提:文档和查询必须用同一个向量模型来编码——只有进了同一张地图,比距离才有意义。用 A 模型编文档、B 模型编查询,相当于拿北京地图找上海的路,再精确的尺子也白搭。

选哪把尺子,决定的是"近不近怎么算";而归一化之后,余弦和点积本就是同一把尺子的两种握法。

五、写在最后:你今天就能做的一个实验

我们从"计算机凭什么知道猫和狗更近"出发,一路拆到了向量检索的骨头。把整条逻辑链收束成五句话:

但光看懂不算真懂。今天回去试一件事:随便找个 Embedding API(OpenAI、BGE、或本地一个 sentence-transformers),把这三句话各编码成向量——"我家的猫很可爱"、"我养了一只小狗"、"明天要开庭打官司"。然后亲手算一遍三两之间的余弦相似度。

你会亲眼看到:前两句的相似度明显高于它们和第三句。那一刻,"语义"这个虚无缥缈的词,会第一次以一个具体的小数,躺在你的屏幕上。

如果你愿意再往前一步,把向量归一化后改用点积再算一遍——你会发现数字分毫不差。那时候,这篇文章里所有的话,就都从"我说的"变成了"你验证过的"。这,才是真的懂了。