你有没有想过,当你给 ChatGPT 发一句“中国的首都是”,它怎么就知道接“北京”而不是“上海”?明明它只是一个接收文本、输出文本的程序,内部到底发生了什么?

今天我们就钻进 LLM 的肚子里,从 Token 开始,一步步拆解它预测下一个词的全过程。读完这篇,你会对大模型“凭空生成”文本的能力有一个立体的认知——不再是黑盒,而是有迹可循的数学魔法。
我们人类看到的是“我爱人工智能”,但 LLM 不认识汉字。它只认识数字,所以第一步就是把自然语言切碎成词元(Token) 。
举个例子:unhappiness这个英文词,LLM 不会当做一个整体,而是切成["un", "happi", "ness"]。中文也是类似:"我爱人工智能,自然语言处理很有趣"→["我", "爱", "人工智能", ",", "自然语言处理", "很", "有趣"]。
为什么要切得这么碎?
每个 Token 在模型内部都有一个唯一的编号(Token ID),比如“你”可能是57668。你把 Prompt 发过去,模型收到的就是一堆 Token ID 的数组。
这就是输入:一串数字。
Token ID 是纯粹的数字索引,没有语义。57668和57669之间没有任何数学关系,你不能说“你”+1=“好”。
LLM 的第一步操作,就是把这个 ID映射成一个高维向量,这个过程叫Embedding。
每个 Token ID 都对应一个向量(例如 1024 维或 4096 维),这个向量可以理解为该 Token 在高维空间中的坐标。语义相近的词,它们的向量在空间里距离就近。比如“国王”和“王后”的向量距离就很近,而“苹果”离它们很远。
更有趣的是,向量之间还能做运算:国王 - 男性 + 女性 ≈ 王后
这说明模型通过训练,不仅学到了词义,还学到了语义关系。
LLM 内部有一个巨大的Embedding Matrix(嵌入矩阵) ,相当于一张“向量查找表”。当拿到 Token ID57668,它直接去这张表的第57668行,把对应的向量“抽出来”。
但到此为止,每个 Token 还是孤立的——它们只知道自己是什么,不知道自己在句子里的位置。
考虑这两句话:
它们的 Token 完全一样,但顺序不同,意思天差地别。Embedding 本身不携带顺序信息,所以必须给每个向量叠加一个位置编码(Position Encoding) 。
常见的做法是给每个位置生成一个固定的向量(比如用正弦余弦函数),然后直接加在 Embedding 上。这样,每个 Token 最终携带两类信息:
现在,模型有了一个个带坐标和顺序的向量,但它还是不知道词与词之间的依赖关系——比如“它”指代谁?这就要靠自注意力机制了。
这句英文:
这里的it指代的是animal还是street?人类一眼就懂是动物,因为“tired”常修饰动物,但模型怎么知道?
答案就是Self-Attention(自注意力) 。
对每个 Token 的向量,模型会通过三个不同的线性变换,生成三个新向量:
it要找个先行词;还是上面那个句子。假设我们只关注it和animal、street的关系:
token1:animal-> (Q1, K1, V1)token2:it-> (Q2, K2, V2)token3:street -> (Q3, K3, V3)
模型要做的是:用it的 Query 向量去和句子中每个词的 Key 向量做点积,得到一组注意力分数:
score_it_animal = Q2 · K1score_it_street = Q2 · K3
如果score_it_animal数值远大于score_it_street,就说明it和animal的相关性更强,模型会把更多注意力放到animal上。然后,这些分数经过 Softmax 归一化变成权重,再分别乘以对应词的 Value 向量,最后加权求和,得到it位置的新表示——这个新表示里就融合了animal的语义细节(比如“疲倦”这个属性),从而正确地让it指代动物而非街道。
同样的道理可以用在歧义场景里:
这就是上下文消歧的核心——不是靠词典硬查,而是靠 QKV 的动态加权。
你可能会问:Q、K、V 是怎么来的?它们都是通过模型训练学出来的权重矩阵,直接对原始向量做线性变换。我们不需要手动设计,模型自己会调整这些矩阵,让注意力分数最有利于预测下一个词。
经过多层自注意力(Transformer 里的 Decoder 部分),模型已经为当前序列中的每个位置生成了富含上下文信息的向量。接下来要做的事,就是预测下一个词。
对于最后一个位置(即当前输入序列的末尾),模型会取它的向量,通过一个线性层 + Softmax,映射成词表大小的概率分布。比如词表有 5 万个 Token,输出就是一个 5 万维的向量,每个维度代表对应 Token 成为下一个词的概率。
拿“中国的首都是”为例:
模型选择概率最高的那个(或者按温度采样),输出对应的 Token ID。然后,这个新 Token 会被追加到输入序列末尾,模型再继续预测下一个词。
这就是自回归生成:每次生成一个词,然后把新词加入上下文,再生成下一个,直到遇到结束标记或达到最大长度。
现在我们把所有步骤串起来,看看一次完整的生成到底经历了什么:
["中国", "的", "首都", "是"],转成 Token ID[123, 456, 789, 101]整个过程计算量极大,但核心思路就是不断重复步骤 5~7。
因为计费按 Token 数算,而不同模型的分词器(Tokenizer)切法不一样。比如英文中ChatGPT可能被切成一个 Token,也可能切成Chat+G+PT。所以相同的文本在不同模型上花费可能不同。而且切得越合理,模型理解越好——比如中文“人工智能”如果被切成“人工”和“智能”,就会丢失整体语义,所以现在主流中文模型都会把常用词保留为完整 Token。
早期用固定正弦编码,现在很多模型用可学习的位置编码,即把位置也当成参数来训练。还有 RoPE(旋转位置编码)等变体,本质都是给向量注入位置信息,只是实现方式不同。
理论上是,但实际上受限于上下文窗口(比如 8K、128K)。窗口之外的词完全看不见,这就是为什么长文本会丢失开头信息——因为注意力矩阵的计算量随窗口长度平方增长,模型只能截断。
说白了,LLM 的推理过程可以浓缩成一句话:
它没有“思考”,没有“理解”,只有大规模统计模式匹配。但正是这种模式匹配的深度和广度,让它看起来像有了智能。
作为开发者,了解这些底层细节至少能给你两个直接好处:
下次你再调用大模型 API 时,不妨想想那一串串向量在空间中跳舞的样子——你会发现,它其实没那么神秘,反而有点可爱。
祝你代码无 Bug,Token 永不浪费。