



























本文基于 0xkato 的英文文章 "How LLMs Actually Work" 改写整理,用于中文读者学习参考。
原文:https://www.0xkato.xyz/how-llms-actually-work
标签:Machine Learning · Transformers · LLM · Neural Networks · AI
现代主流大语言模型(LLM)几乎都是把同一种结构——Transformer block——一层一层堆起来的。所以只要把一个 Transformer 内部的几个零件理解透,就能看懂绝大部分主流 LLM 的论文和 model card。
模型与模型之间的区别,主要在于三件事:
下面按 9 个主题,把 LLM 的"内部机器"从输入到输出走一遍。
模型并不直接读文字,它读的是整数 ID。把字符串切成整数序列的过程叫 tokenization(分词 / 切分 token)。
token 通常不是完整单词,而是子词(subword)片段:
tokenization 可能会切成 ["token", "ization"]running 可能会切成 ["run", "ning"]为什么用子词?
经典坑:问 LLM "strawberry 里有几个 r",早期模型常答错。不是模型不会数数,而是它根本看不到字母——它看到的是几个 token ID,"strawberry" 也许只是 1~2 个 token,里面的字母被打包了。
不同家族用不同分词器:GPT 系列用 BPE(Byte Pair Encoding) 的变体,LLaMA 系常用 SentencePiece。算力消耗、多语种覆盖会受影响,但本质都是:文字进,整数出。
1024 这样一个 token ID 本身没有任何含义,它只是一个行号。让它有意义的,是一张巨大的查找表——embedding matrix(词嵌入矩阵)。
Vector(向量):就是一串数字。Transformer 内部一切运算都是向量与矩阵的乘法。
模型拿到 token ID 后,会去 embedding 表里查出对应的那一行,后面的所有计算都用这个向量进行。
有趣的性质:训练完成后,语义相似的 token 在向量空间里也接近。
king − man + woman ≈ queen。这种几何结构没人手写过,是模型为了把"下一个 token 预测"做好,自己把它学出来的。
⚠️ 注意:到这一步,每个 token 已经变成向量了,但向量本身不带"位置信息"。"dog"无论排在第 1 个还是第 5 个,查表得到的是同一个向量。这就需要下一步的位置编码来补上。
纯粹的 self-attention 天生不区分顺序,需要额外注入"位置信号",否则模型分不清是 "dog bites man" 还是 "man bites dog"。
给每个位置一组固定的数字(不同频率的 sin/cos 组合),直接加到 token 的 embedding 上。位置 1 加一个模式,位置 5 加另一个模式。
优点:可以外推到训练时没见过的更长序列。
但随着模型变大,加性方案有两个问题:
Su et al. 2021 提出,目前 LLaMA、Mistral、Gemma、Qwen 等几乎所有开源模型都用它。
直觉:不再"加"位置向量,而是按位置旋转 Query 和 Key 向量。
优点:
Liu et al. 2023 报告:即使位置编码足够好,LLM 在长 prompt 中对开头和结尾的信息利用得更好,对中间的反而会"忘"。这也是"重要内容放开头/结尾"这条 prompt 工程经验的科学依据——模型并不是均匀使用你的 prompt 的每一部分。
Attention(注意力) 是 Transformer 名字的来源,也是它最核心的机制。每一层 Transformer 里,attention 做一件事:让每个 token 看一眼它被允许看到的其他 token,决定哪些对自己接下来的表示更重要。
为此,每个 token 同时扮演三个角色,被映射成三个新向量:
| 角色 | 含义 |
|---|---|
| Query (Q) | 我想从别的 token 那里找什么? |
| Key (K) | 我能给别的 token 提供什么"标签"用来匹配? |
| Value (V) | 一旦匹配上,我会传出去什么内容? |
Q、K、V 是同一个 token 经过三个不同的、可学习的线性变换得到的。
Dot product:衡量两个向量"对齐程度"的最简单方式。
Softmax:把任意一组分数变成像概率一样、加起来等于 1 的权重。
句子:"The cat that I saw yesterday was sleeping."
模型处理 was 时,要搞清楚"是谁在 sleeping"。was 的 Query 与所有可见 token 的 Key 做点积:
cat 的点积很高(动词需要主语,cat 这种主语恰好提供匹配的 Key);yesterday 的点积很低;cat 拿到大权重,yesterday 拿到小权重;was 的新向量主要由 cat 的 Value 决定——这就是"指代"在数学上是怎么实现的。GPT 类模型是从左到右生成的,所以位置 5 的 token 只能看到位置 1~5,不能看到 6、7、8(那些还没生成出来)。
做法很简单:把"未来"位置的匹配分数设成极小的负数,softmax 之后权重几乎为 0。
Anthropic 在 2022 年发现的一类专门化注意力头:会识别 prompt 里 A B … A 这种模式,遇到第二个 A 时,回头看上一次 A 后面跟的是 B,于是预测下一个就是 B。
这是目前已知最清晰的 in-context learning(上下文学习) 机制之一——为什么你在 prompt 里给几个示例,模型就能照着续写。
完整 attention 中,每个 token 要和所有可见 token 比较,因此 prompt 长度翻倍,计算量大约翻 4 倍(O(n²))。这就是长 prompt 又慢又贵的根因,也是 FlashAttention、稀疏注意力、线性注意力等优化方向的存在意义。
一次 attention 只能给模型一种"谁该关注谁"的判断。但语言里同时存在很多种关系:主谓一致、代词指代、跨句长程引用、局部短语……一种视角不够。
多头注意力:并行跑多次 attention,每次走自己一小块空间,叫一个 head(头)。
很多教程说"把 token 向量切成几段,每段一个头"——错的。
正确做法是:每个头有自己一套可学习的投影矩阵,把完整的 token 向量投影到自己的小空间里得到 Q、K、V。
例如:模型 hidden=4096,32 个头,每个头的工作空间是 128 维。但这 128 维是从完整 4096 维投影出来的,不是固定的某 128 个分量。所以每个头是同一个 token 的"不同视角",不是它的"碎片"。
W_o)混合回完整的 hidden 维度。混合矩阵也是学出来的——模型自己决定该怎么把多个视角融合起来。
Transformer block 里除了 attention,还有一个逐 token 的前馈网络(FFN,也叫 MLP)。流程通常是:
hidden → 线性升维(4×)→ 非线性激活(GELU / SwiGLU)→ 线性降维 → hidden
要点:
直觉:Attention 负责"调动信息",FFN 负责"加工信息"。
Transformer block 不是"输入 → attention → FFN → 输出"这种串行的线,而是:
x ──► LayerNorm ──► Attention ──► + ──► LayerNorm ──► FFN ──► + ──► 下一层
└───────────────────────────────────┘ └─────────────────────────┘
residual(残差) residual
每个子模块输出加回它的输入。好处:
把每个 token 向量按通道归一化(减均值除标准差,再用一对可学习参数缩放/偏移),让数值分布稳定。
现代模型几乎都用 Pre-LN(先归一化再进子模块)而非原始 Transformer 的 Post-LN——更利于深层稳定训练。
许多新模型(LLaMA 系)用 RMSNorm——比 LayerNorm 更省、效果相当。
记住一个口诀:残差让深度可训,归一化让数值不爆。
走完所有 Transformer 层之后,每个位置都会得到一个最终的 hidden 向量。模型最关心的是最后一个位置的那个向量——它要根据这个向量预测"下一个 token 是什么"。
最后一层 hidden 向量乘上一个矩阵(通常和输入 embedding 矩阵共享权重,叫 weight tying),得到一个长度等于词表大小的向量,叫 logits。
拿到概率分布后怎么选?常见几种:
| 策略 | 含义 |
|---|---|
| Greedy(贪心) | 永远选概率最高的那个。确定性高,但容易死板、循环。 |
| Temperature | 把 logits 除以 T 再 softmax。T<1 更"自信",T>1 更"发散"。 |
| Top-k | 只在概率最高的 k 个 token 里抽样。 |
| Top-p / Nucleus | 选累计概率 ≥ p 的最小集合后抽样,更自适应。 |
| Min-p | 按相对最大概率的比例阈值过滤,抗噪声。 |
1. 把 prompt token 序列喂进模型
2. 取最后一个位置的 logits → softmax → 采样得到下一个 token
3. 把这个 token 拼到序列尾部
4. 回到第 1 步,直到遇到 EOS 或达到最大长度
这就是"AI 在打字"背后的全部秘密——它一次只生成一个 token,每个 token 都是基于前面所有 token 重新算一遍。
KV Cache:实际部署时,前面 token 的 Key/Value 会缓存下来,每生成新 token 只算它自己那一份注意力,避免 O(n²) 重复计算。这是推理加速的关键技巧。
读完前 8 节,你会发现 GPT、Claude、Gemini、LLaMA、Mistral、Qwen、DeepSeek……架构上几乎完全是同一套东西:
那为什么模型之间能力差这么多?区别主要在四件事上:
什么语种、什么领域、什么质量、是否经过严格清洗、是否包含代码、是否包含数学推理过程——这是"模型最终知道什么、擅长什么"的根源。
层数、隐藏维度、头数、上下文窗口长度、词表大小、稀疏 vs 稠密(MoE)……这些都是"骨架的尺寸"。
量化(FP16 / BF16 / FP8 / INT4)、KV cache、推理引擎(vLLM、TensorRT-LLM、SGLang)、并行策略(TP / PP / EP)等——这些不改架构,但决定速度和成本。
一句话总结:架构决定能力上限的形状,数据和后训练决定模型实际把这块上限"刻"成什么样子。
文字 prompt
│
▼ Tokenizer
整数 ID 序列
│
▼ Embedding 矩阵(查表)
每个 token 一个向量
│
▼ + Positional Encoding(RoPE 是旋转 Q/K)
带位置的向量
│
▼ ┌─ LayerNorm ─► Multi-Head Attention ─► + (残差)
│ │ │
│ └─ LayerNorm ─► Feed-Forward (FFN) ──────► +
│ │
│ ←─── 同样结构再堆 N 层(Llama-7B = 32 层) ──┘
│
▼ 最后一层 LayerNorm + LM Head
词表上的 logits
│
▼ softmax + 采样(greedy / top-p / temperature)
下一个 token
│
└──► 拼回序列,循环生成
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。