LLM 基本原理
注意力是查字典,采样是带随机性的接龙,训练是先博览群书再上岗培训——不堆公式,把 LLM 从 Token 到 RLHF 讲透。
为什么要懂原理
你可能已经会调 API、会写 Prompt 了,那为什么还要回头学原理?因为不懂原理的人写 Prompt 靠玄学,懂原理的人写 Prompt 靠推理。
当你知道模型本质是「根据上文预测下一个 token」,你就能自己解释一堆现象:为什么关键要求放开头比埋在中间稳、为什么上下文太长模型会「忘事」、为什么 temperature 调高后输出开始胡说、为什么让模型「先想再答」反而更准。这一章不堆公式,只用直觉、类比和关键数字,帮你建立一个能指导工程实践的心智模型。
先记住全文最重要的一句话:
LLM 的全部工作 = 给定前面的 token 序列,预测下一个 token 的概率分布,然后从中挑一个。循环往复。
翻译成人话:LLM 是一个超大规模的「文字接龙」机器。它不会「思考」,它只是在极高维的概率空间里续写最可能接下去的文字。接下来所有概念,都是在解释这台接龙机器的内部构造、训练方式和使用注意事项。
Token:模型的「字」,计费的「单位」
模型看不到「字」或「词」,它看到的是 token——文本被分词器切碎后的最小单元。主流分词算法是 BPE(Byte Pair Encoding):从单字节开始,反复把语料中出现频率最高的相邻对合并成一个新符号,直到词表装满。GPT-4 使用的 cl100k_base 词表约 10 万个 token。因为底层从字节起步,任何语言、emoji、乱码都能被表示,不存在「词表外」的问题——代价是生僻内容会被拆得很碎。
大致规律:
- 英文:1 token ≈ 0.75 个单词,常见词整体一个 token
- 中文:1 token ≈ 1
2 个汉字。中文在训练语料中占比小、合并不充分,同样语义的一句话,token 数往往是英文的 1.52 倍——中文用户天然要多付钱 - 代码、空格、标点都占 token,换行和缩进都是钱
用 OpenAI 的 tiktoken 直观感受一下:
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
tokens = enc.encode("LLM 是文字接龙机器")
print(tokens) # 一串整数 ID,模型眼里只有它们
print(len(tokens)) # token 数量,计费就按它算
分词有个反直觉的后果:模型对「字符级」任务很笨。数 "strawberry" 里有几个 r、把单词倒过来拼,它经常翻车——因为它从没见过单个字母,只见过整块的 token。不是模型笨,是它的「视力」就到 token 这一层。
为什么按 token 计费? 因为计算量严格正比于 token 数:每处理一个输入 token、每生成一个输出 token,GPU 都要实打实做一次前向计算。token 就是 LLM 世界的「度」,像电费按度数收;输入和输出还分开计价,输出通常贵 3~5 倍(原因见「推理」一节)。
工程要点:控制成本 = 控制 token 数。 压缩 Prompt、精简历史消息、限制 max_tokens,都是最直接的省钱手段。
Transformer 与自注意力:查字典的艺术
2017 年《Attention Is All You Need》提出的 Transformer 是今天所有主流 LLM 的骨架。标题本身就是宣言:抛弃 RNN 逐词顺序处理的老路,只用注意力。核心创新是自注意力(Self-Attention)——序列里每个 token 都能直接「看到」其他所有 token,并决定该关注谁。RNN 像传话游戏,信息逐词传递、越传越糊;自注意力像开会,所有人直接对视,长距离依赖不再是问题。
直觉:查字典
注意力机制可以类比查字典。字典里有成对的「键」(Key)和「值」(Value),你拿着「查询」(Query)去匹配:
- Query:当前 token 想知道什么——「我是谁,我需要什么信息来理解自己」
- Key:每个 token 挂出来的索引牌——「我是什么,我能提供什么信息」
- Value:每个 token 实际携带的内容——「如果你真的关注我,这是你要拿走的东西」
流程是:每个 token 拿自己的 Query 去和所有人的 Key 算相似度(点积),softmax 归一化成一组和为 1 的权重,然后用这组权重对所有人的 Value 加权求和,作为自己的新表示。Q、K、V 都是同一个 token 表示乘上三个不同的权重矩阵得到的——模型训练学的就是这三组「怎么问、怎么挂牌、怎么给货」的参数。
举个具体例子,句子是「这只苹果很甜,因为它熟透了」。模型处理「它」时:
于是「它」不再是孤立的代词,而是融合了「苹果」语义的 token。这就是模型理解指代、长距离依赖的方式——不靠记忆,靠每步现场计算「谁和我最相关」。
一个注意力层用 NumPy 十几行就能写完(真实可跑):
import numpy as np
def softmax(x):
e = np.exp(x - x.max(axis=-1, keepdims=True))
return e / e.sum(axis=-1, keepdims=True)
d = 8 # 向量维度
X = np.random.randn(5, d) # 5 个 token,每个 d 维
Wq, Wk, Wv = (np.random.randn(d, d) for _ in range(3))
Q, K, V = X @ Wq, X @ Wk, X @ Wv
weights = softmax(Q @ K.T / np.sqrt(d)) # 5×5 矩阵:谁关注谁
out = weights @ V # 加权求和后的新表示
print(weights.round(2)) # 每行之和为 1
注意 Q @ K.T 的结果是一个 n×n 矩阵:n 个 token 两两算一次相似度。这就是注意力 O(n²) 复杂度的来源——长度翻倍,计算量和显存都变 4 倍。上下文窗口之所以有限,根子就在这里。FlashAttention(2022)用分块计算避免把 n×n 矩阵整体写进显存,训练提速 2~4 倍——它是数学上精确等价的改写而非近似,今天已是训练标配。
多头、多层与 FFN
实际 Transformer 把查字典并行做多份(多头注意力):有的头关注指代关系,有的头关注语法结构,有的头关注位置邻近,各查各的字典再拼起来。GPT-3(1750 亿参数)堆了 96 层、每层 96 个头。层数越深,表示越抽象:低层管局部语法,中层管句法语义,高层形成类似「世界知识」的东西。
每层注意力之后还有前馈网络(FFN):一个升维再降维的 MLP,参数量约占整层的 2/3。研究界一个流行的心智模型是:注意力负责「搬运」上下文里的信息,FFN 负责「存储」训练中学到的知识。 你不需要背结构图,只要记住:每一层,每个 token 都在用查字典的方式从上下文吸收信息;层数越深,理解越抽象。
位置编码:从死记位置到相对距离
注意力本身不区分顺序——「狗咬人」和「人咬狗」的 token 集合完全一样,所以必须显式注入位置信息。这个看似边角的组件经历了一轮重要演进:
- 正弦绝对位置编码(原始 Transformer):把位置编号直接「加」在 token 表示上,简单但外推差——训练见过多长,推理就基本只能多长
- RoPE(旋转位置编码,RoFormer 2021):不往表示里加位置,而是按位置把 Q/K 向量旋转一个角度。妙处在于两个向量旋转后的点积天然只依赖它们的相对距离——「相距 3 个 token」被编码进了几何。LLaMA、Qwen 等现代模型几乎全用 RoPE;把旋转频率「拉长」的外推技巧,还能把窗口从训练时的 4K 撑到 128K
- ALiBi(2021):更激进——完全不编码位置,只在注意力分数上按距离线性扣分,隔得越远扣得越多。训练只用 1K 长度、推理上 2K 也不崩,外推性极好
记结论即可:现代 LLM 的主流是 RoPE;位置编码的演进方向是从「绝对位置」走向「相对距离」,从「死记长度」走向「可以外推」。
MoE:稀疏激活的容量魔法
参数越多越聪明,但参数越多推理越贵——**MoE(混合专家)**就是为了绕开这个矛盾:把每层的 FFN 换成 N 个并行的「专家」网络,每个 token 进来由一个小型「路由器」挑其中 1~2 个专家计算,其余睡觉。
效果是总参数很大(知识容量高),激活参数很小(计算成本低):Mixtral 8×7B 总参数约 47B,每个 token 只激活约 13B,推理成本接近 13B 的稠密模型,效果却对标大几倍的模型;Switch Transformer 更是把总参数堆到 1.6 万亿。
代价也真实存在:
- 省算力不省显存:所有专家都得常驻显存,部署门槛没有降低
- 训练更难:路由器容易「负载塌缩」(所有 token 都挤向少数专家),需要额外的负载均衡损失
- 小批量推理不占便宜:只有高吞吐场景,稀疏激活的成本优势才兑现
上下文窗口:模型的工作记忆
注意力是「每个 token 看所有 token」,O(n²) 的代价决定上下文不可能无限长——这个上限就是上下文窗口,比如 128K token。
把上下文窗口理解成模型的工作记忆(短期记忆):
- 窗口内的所有内容(系统提示、历史对话、塞进去的资料)模型都能「看见」
- 窗口外的东西对模型来说不存在——它没有跨请求的记忆,每次调用都是全新的开始
- 对话太长溢出窗口时,最旧的内容被截掉,模型就「忘了你们之前说过什么」
两个工程上的坑,都有研究背书:
- 窗口大 ≠ 记得牢。《Lost in the Middle》(2023)的实验表明:关键信息放在长上下文开头或结尾时模型表现最好,放在中间时准确率明显下滑,极端情况下甚至低于完全不给资料的基线——呈 U 形曲线。关键指令放开头或结尾,别埋在中间。
- 窗口是要钱的,而且是双重贵。每轮对话都把全部历史重新发给模型;推理时为避免重复计算,会把历史 token 的 K/V 缓存起来(KV Cache),它随长度线性增长——一个 32 层、隐层 4096 的 fp16 模型,每 token 的 KV 缓存约 1MB,10 万 token 就是约 100GB 显存。注意力计算是平方级,KV Cache 是线性级,两头都烧钱。
长上下文 vs RAG 的争论也值得知道双方立场。正方:长窗口省事、能做全局理解(整个代码库、几百页合同一次读完),不用维护检索管线;反方:贵、慢、中间内容容易被忽略,塞得越多注意力越被稀释。实践中的答案往往是两者混用:RAG 负责从海量资料初筛,长窗口负责把筛出的内容读透。
模型权重 = 长期记忆(训练时固化,不可改),上下文窗口 = 短期记忆(每次调用临时组装,唯一可写的)。 你所有的 Prompt 工程,本质都是在经营这块昂贵又有限的短期记忆。
采样参数:接龙的随机性旋钮
模型每步输出的不是一个确定的词,而是一个概率分布——词表里每个 token 一个概率。从这个分布里「挑」一个出来,就是采样。
temperature:概率分布的「平滑度」
数学上,temperature 是作用在 softmax 之前的除法:softmax(logits / T)。假设模型对下一个 token 的原始预测是:「好」60%、「很」25%、「赞」10%、其他 5%。
- T → 0(实际实现为贪心):永远挑概率最高的「好」。输出稳定、基本可复现,但容易复读
- T = 1:按原始分布采样,60% 概率选「好」,但也有机会选别的
- T > 1:分布被「压平」,低概率词的机会被放大。更有创意,也更可能胡说八道
# OpenAI API 的典型用法
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "给咖啡店起个名字"}],
temperature=0.2, # 低:稳定保守,适合抽取、分类、代码
# temperature=1.2, # 高:发散有创意,适合头脑风暴
)
top_p 与 top_k:候选池的「截断线」
top_p(核采样) 换个思路:按概率从高到低排序,只保留累计概率达到 p 的那一小撮候选,其余归零后再采样。top_p = 0.1 只在最顶尖几个候选里挑;top_p = 0.9 保留主流候选、砍掉长尾奇怪选项;top_p = 1.0 不截断。top_k 更粗暴:只保留概率最高的 k 个。
temperature 和 top_p 的区别在于:T 改变分布的形状,top_p 改变候选的数量——一个是「把分数压平或拉尖」,一个是「直接剪掉尾巴」。经验法则:两者只调一个,另一个保持默认。 写代码、做抽取用低 temperature(0~0.3);写文案、做创意适度调高。两个同时调高,是「模型开始胡言乱语」的经典配方。
两个值得知道的边界事实:
- 为什么开放式生成不用束搜索(beam search)? 机器翻译时代靠它,但《The Curious Case of Neural Text Degeneration》(2019)发现:开放式文本里一味追求高概率,会得到极其平庸、不断复读的句子——人类的语言本身就是「不太可预测」的,适度随机反而更像人。
- temperature=0 不保证 100% 复现。 GPU 浮点加法不满足结合律,不同 batch 大小时计算顺序不同,极小概率下 argmax 会翻转。工程上要严格复现,得固定模型版本、seed,并把关键结果落库,而不是赌 API 的确定性。
训练与推理:先博览群书,再上岗培训
模型的能力不是一次炼成的,主流 pipeline 分三个阶段,外加一个持续烧钱的推理阶段。
1. 预训练(Pretraining):博览群书
把几万亿 token 的文本喂给模型,任务只有一个:预测下一个 token。梯度下降反复调整几千亿参数,直到续写得足够好。这个阶段学到的是「语言本身 + 世界知识」——语法、事实、推理模式,全是为了把接龙接好而顺带学会的副产品。但此时的模型是续写机器,不是助手:你问「怎么煮咖啡」,它可能续写成「怎么煮咖啡?怎么泡茶?」——语料里问题后面经常跟着更多问题。
预训练占了绝大部分算力:GPT-3 训练用了约 3000 亿 token、3640 petaflop/s-day 的算力,成本估计数百万美元;GPT-4 级别外界估计在数千万美元级。它决定了模型的能力上限。
模型到底该多大、数据该喂多少? 这里有一场影响行业走向的争论。OpenAI 的 Kaplan 缩放定律(2020)发现 loss 随参数量、数据量、算力呈平滑的幂律下降,并暗示「大模型优先」。DeepMind 的 Chinchilla(2022)修正了这个结论:给定算力预算,模型大小和数据量应该等比增长,最优比例约是每个参数配 20 个 token——据此训练的 70B 模型(喂了 1.4 万亿 token)全面超过了 4 倍于它参数的 280B Gopher。行业随即转向「数据饥渴」路线。
但 Chinchilla 也不是终局:它只优化训练成本,没算推理成本。 如果模型要服务几十亿次请求,把一个小模型「过度训练」(LLaMA 让 7B 模型吃 1 万亿 token)反而总账更划算。今天的主流实践是「训练时超标喂数据,部署时占小模型的便宜」。
2. SFT(监督微调):学会当助手
用人工编写的高质量「指令-回答」对继续训练,让模型学会:用户提问时应该直接给出有帮助的回答,而不是续写问题。 格式上也学会了对话的角色结构(system / user / assistant)。InstructGPT 只用了约 1.3 万条标注数据就改变了模型行为——数据量是预训练的零头,行为改变却巨大,花小钱办大事。
能省到什么程度?LIMA(2023)提出一个激进观点:只用 1000 条精心策划的样例就能对齐出不错的助手,并由此猜想「模型的知识和能力几乎全在预训练,对齐主要学的是表面格式」。这就是表面对齐假说。它有争议——反方证据是:复杂指令遵循、多语言能力、安全边界,靠 1000 条数据撑不起来。务实的解读是:SFT 数据的质量和多样性远比数量重要,但「1000 条就够」只在任务分布很窄时成立。
3. RLHF(人类反馈强化学习):对齐人类偏好
SFT 之后模型会回答了,但「好坏」还有很多维度:是否诚实、是否有害、是否啰嗦。RLHF 的做法:
- 让模型对同一问题生成多个回答
- 人工标注员给回答排序
- 用排序数据训练一个奖励模型,模仿人类口味
- 用强化学习(PPO)让模型在奖励模型的打分下不断调整
InstructGPT 论文里最关键的实验结果是:标注员明显更喜欢 13 亿参数的 InstructGPT 的回答,而不是 1750 亿参数的原始 GPT-3——参数差了 130 倍,靠对齐扳回来。这说明 RLHF 调的不是知识,是品味和边界。
RLHF 同样有争议。一是对齐税(alignment tax):过度对齐可能牺牲能力和多样性,模型变得过分谨慎、爱说正确的废话。二是路线之争:DPO(2023)跳过奖励模型和强化学习,直接拿偏好对做监督式优化,简单稳定、训练不易崩,迅速流行;但 PPO 系支持者认为在线探索(边生成边打分)上限更高,DPO 容易过拟合偏好数据。今天两条路线都在生产环境中大规模使用,没有公认赢家。
4. 推理(Inference):串行生成,一次一个
训练和推理的形态完全不同。训练是并行的:整个序列一起算,每个位置同时预测下一个 token。推理是串行的,分两个阶段:
- Prefill:并行处理你发来的全部输入,填好 KV Cache——快,按输入 token 计低价
- Decode:逐 token 生成,第 N 个 token 必须等前 N-1 个生成完,每步都要把几百 GB 的模型权重从显存搬过一遍——慢,且瓶颈在显存带宽而非算力
这解释了两个定价现象:输出 token 比输入贵 3~5 倍;以及为什么让模型「先想再答」(思维链)反而更准——前面生成的推理过程会成为后面答案的上下文,相当于模型给自己打草稿,多花的输出 token 买来了正确率。
常见误区
- 「模型记住了训练数据」:它存的是统计模式,不是数据库。同一事实换个问法可能答错,「记得」和「能稳定检索」是两回事
- 「temperature=0 就不会出错」:它只让输出基本确定,不让输出正确。事实错误照样犯,只是每次都犯一样的
- 「上下文窗口大就可以随便塞」:塞得越多越贵、越慢、关键信息越容易被淹没(U 形曲线)。窗口是稀缺资源,不是垃圾桶
- 「模型输出流畅 = 内容正确」:流畅是训练目标,正确是副产品。模型对「自信的胡说」没有任何内置刹车,这就是幻觉
- 「RLHF 让模型更聪明」:它让模型更「讨人喜欢」,知识能力在预训练阶段就基本定型了
- 「MoE 模型部署很便宜」:MoE 省的是计算,不是显存——全部专家都得常驻显存,47B 的 Mixtral 依然需要装下 47B 的内存
术语表
| 名词 | 定义 | 一句话直觉 | 常见混淆 |
|---|---|---|---|
| Token | 文本被分词器切碎后的最小单元,模型输入输出的基本计数 | 模型世界的「字」,计费世界的「度」 | 以为 1 token 等于 1 个字或 1 个词 |
| BPE 分词 | 从字节开始反复合并高频相邻对,构建词表的算法 | 像学语言时把常见搭配记成整块 | 以为分词按词典或空格切 |
| 自注意力 | 每个 token 与所有 token 算相似度并加权汇聚信息的机制 | 开会时每个人直接对视所有人 | 以为是「记住」前文,其实是每步现场重算 |
| Query / Key / Value | 注意力的三个角色:查询、索引、内容 | 查字典:拿问题(Q)对索引(K),取内容(V) | 把 K 和 V 搞反:K 决定「关不关注」,V 决定「关注后拿走什么」 |
| 多头注意力 | 并行做多份注意力再拼接 | 多个读者同时读一本书,各看各的角度 | 以为是多个模型投票 |
| RoPE | 按位置旋转 Q/K 向量的相对位置编码 | 把「相距多远」刻进向量的角度里 | 与绝对位置编码混淆:RoPE 编码的是相对距离 |
| 上下文窗口 | 单次请求模型能看到的最大 token 数 | 模型的工作记忆,出窗即不存在 | 以为是模型的「记忆容量」——它没有跨请求记忆 |
| KV Cache | 推理时缓存历史 token 的 K/V 以避免重复计算 | 接龙时把前面算过的笔记留着,不重算 | 以为它能扩大窗口——它只省算力,不扩容量 |
| temperature | 采样前对 logits 做除法的平滑度参数 | 随机性的「火候」:越低越保守 | 与 top_p 同时调高,输出失控 |
| top_p | 只保留累计概率达 p 的头部候选再采样 | 给候选池画一条及格线 | 与 temperature 混淆:T 改分布形状,top_p 改候选数量 |
| 预训练 | 在海量文本上做「预测下一个 token」的初始训练 | 博览群书,知识和能力在此定型 | 与微调混淆:预训练定能力上限,微调定行为风格 |
| SFT | 用指令-回答对继续训练,教模型当助手 | 上岗培训,学会「答」而不是「续写」 | 以为 SFT 能注入大量新知识——它主要教格式和风格 |
| RLHF | 用人类偏好排序训练奖励模型,再用强化学习对齐 | 请人类当评委,调品味和边界 | 以为 RLHF 让模型更聪明——它让模型更「讨人喜欢」 |
| MoE | 用路由器为每个 token 选少数专家计算的稀疏架构 | 大医院分诊:病人只看对应科室 | 混淆总参数与激活参数:省算力不省显存 |
参考材料
- Attention Is All You Need — Transformer 原始论文,一切的起点
- The Illustrated Transformer — Jay Alammar 的经典图解,注意力机制最好的可视化入门
- RoFormer (RoPE) — 旋转位置编码原始论文
- Train Short, Test Long (ALiBi) — 线性偏置位置编码,外推性研究
- Training Compute-Optimal Large Language Models (Chinchilla) — 修正缩放定律,20 token/参数的经验法则
- Lost in the Middle — 长上下文 U 形准确率的经典实验
- InstructGPT — RLHF 三阶段流程与「1.3B 胜过 175B」的关键实验
- LIMA: Less Is More for Alignment — 表面对齐假说的出处
- OpenAI Tokenizer — 在线把玩分词,直观感受 token 怎么切
- nanoGPT — Karpathy 的最小 GPT 实现,几百行代码看懂训练全流程
小结
把这一章压缩成五句话:
- LLM 是文字接龙机器:预测下一个 token,循环往复,这就是全部
- Token 是计量单位:模型用它看世界,账单按它收费,中文天然更贵
- 注意力是查字典:Q 去问、K 做索引、V 是内容,代价是 O(n²)——窗口、成本、KV Cache 全是它的推论
- 上下文窗口是工作记忆:唯一可写的「内存」,贵且有限,开头结尾最金贵
- 训练分三步:预训练定能力(数据量约 20 token/参数),SFT 教当助手,RLHF 调品味;推理则是逐 token 串行生成,贵在显存带宽
有了这个心智模型,后面学 Prompt 工程、RAG、Agent 时,你会发现它们全是这五句话的推论。