当你调用 OpenAI 或 Claude 的 API 时,你发送的是字符串(string),返回的也是字符串。看起来模型在"处理文字"——但神经网络只能做数学运算。那么,文字是怎么变成数学的?
这是理解 LLM 的第一块基石。让我们从头开始。
LLM 不直接处理原始文字。它的第一步是把文字切分成 token(词元)—— 可以理解成模型的"阅读单位"。
一个 token 可能是:
"hello""un", "believ", "able"如果你用过编程,可以把 tokenization 想象成一个 parser:string → string[]。不同的模型使用不同的 tokenizer 算法(如 BPE、WordPiece),就像一个语言有不同的分词标准。
下面是一个简化的例子。假设我们有一个极简的 tokenizer:
text = "The cat sat on the mat"
# 假设的 tokenizer
tokens = ["The", " cat", " sat", " on", " the", " mat"]
# 6 个 tokens
实际模型使用的 tokenizer 要复杂得多,但原理相同:把连续的文本流切分成离散的单元。
切分出 token 后,下一步是把每个 token 变成一个整数 ID。模型维护了一个 vocabulary(词汇表)——一个从 token 到 ID 的映射表:
vocabulary = {
"The": 464,
" cat": 3797,
" sat": 1042,
" on": 318,
" the": 262,
" mat": 5128,
...
# 实际模型有 30,000 - 100,000+ 个词条
}
这就像一个 Map<String, Integer>。经过这一步,文本变成了整数序列:
"The cat sat on the mat"
→ [464, 3797, 1042, 318, 262, 5128]
现在我们有了数字。但这些数字有"意义"吗?
整数 ID 只是标签——ID 3797 并不比 ID 464 "大",它们之间没有数学关系。就像电话号码一样,数字本身不包含意义。
接下来是关键一步:模型通过一个 embedding table(嵌入表),把每个整数 ID 映射成一个向量(一组浮点数):
# 每个 token → 一个高维向量(例如 4096 维)
embedding_table = {
464: [0.12, -0.87, 0.34, ..., 0.56], # "The"
3797: [0.23, 0.45, -0.91, ..., 0.12], # " cat"
...
}
用编程的比喻:int → float[4096]。这就是一个巨大的查找表(lookup table),训练出来的。
经过 embedding,我们的一行文本变成了一个向量序列——这才是神经网络真正处理的东西:
"The cat sat on the mat"
→ [464, 3797, 1042, 318, 262, 5128] # integer IDs
→ [vec₁, vec₂, vec₃, vec₄, vec₅, vec₆] # 6 vectors, each 4096-dimensional
| 步骤 | 输入 | 输出 | 类比 |
|---|---|---|---|
| 1. Tokenization | "hello world" |
["hello", " world"] |
string → string[] |
| 2. Vocabulary Lookup | ["hello", " world"] |
[15496, 2159] |
string[] → int[] |
| 3. Embedding | [15496, 2159] |
[vec₁, vec₂] |
int[] → float[][] |
Q1. 一个 LLM 的 vocabulary 大小为 50,000。这意味着:
Q2. 为什么 embedding 比整数 ID 更有用?
Q3. "hello world" 被 tokenize 成 ["hello", " world"]。关于这两个 token,以下哪个说法是对的?
如果你看完这节课想进一步理解 embedding 的直觉,强烈推荐观看:
现在我们有了"意义的向量表示"。但 LLM 怎么理解句子中词与词之间的关系?"The cat sat on the mat" 中,"sat" 和 "cat" 的关系,跟 "sat" 和 "mat" 的关系是不同的。下一课我们来看 Self-Attention(自注意力机制)——LLM 最核心的魔法。