Transformer 与注意力机制入门
Transformer 与注意力机制入门
你有没有在直播课上盯着 "Self-Attention"、"Q/K/V"、"Multi-Head" 这几个词,点头如捣蒜,回去自己一想——其实一个字没懂?
说实话,我第一次看 Transformer 那张经典架构图的时候也是这样。图上密密麻麻十几个框,箭头绕来绕去,配一堆矩阵公式,劝退感拉满。后来我发现:做 AI 工程根本不需要会推导那些公式,但你需要一个扎实到能撑住后面 RAG、Agent、微调的直觉——知道模型"读一句话"时脑子里到底发生了什么。这一篇就把这台发动机拆开给你看,带数字、带代码,但不带你去啃论文。
为什么要懂它?(不懂会怎样)
你完全可以不懂 Transformer 也调得通 OpenAI 的 API。但一旦往深走,这些问题会追上你:
- 为什么有 context window 限制?为什么 token 一多,又慢又贵?→ 答案在注意力的计算量上。
- 为什么模型会"中间遗忘"(lost in the middle),把长文档中段的信息漏掉?→ 跟注意力权重分配 + 位置编码有关。
temperature、top_p这些 API 参数到底在调哪一步?→ 调的是最后的采样层,不懂架构就只能背名词。- 微调、KV Cache、Flash Attention、量化……这些优化在优化哪个环节?→ 懂了架构,它们各归各位。
懂了这一层,后面很多"魔法"会变成"哦原来是这样"。
先破一个误解:LLM 不是"数据库"
术语:Transformer
- 一句话解释:一种靠"注意力"让每个词去看句子里其他词的神经网络结构。
- 形象比喻:开小组会。每个人(词)发言前,先扫一眼全桌其他人说了啥,再决定自己怎么说。
- 工作中怎么用:GPT、Claude、Llama、几乎所有主流 LLM 的底座都是它(准确说是它的 decoder 部分)。
- 最常踩的坑:以为它像数据库一样"存"了答案。它存的是词与词之间的关系权重,答案是现算出来的——这也是它会一本正经胡说(幻觉)的根源。
2017 年之前,处理文本的主力是 RNN/LSTM,它像排队念课文:一个字读完才能读下一个,前面的字读到后面就快忘光了。Transformer 那篇论文的名字很嚣张——《Attention Is All You Need》,意思是:排队那套不要了,让所有词一次性互相看就够了。
这一下解决了两件大事:①能并行(GPU 吃得饱,训练快);②再远的词也能直接"对上眼",不会读到后面忘了前面。
注意力到底在"看"什么
来看这句话:
那只猫没跳上桌子,因为它太累了。
"它"指谁?人一眼知道是"猫"。模型靠什么知道?靠注意力:处理"它"这个词时,模型会给句子里每个词打一个"我该多关注你"的分数,"猫"的分数最高,于是"它"的含义就被"猫"带跑了。
这就是 self-attention 的全部直觉:每个词,根据当前语境,动态决定该从其他哪些词身上吸收信息。
Q / K / V:别被吓到,就是"找资料"
模型给每个词算三样东西,用找资料来类比最好懂:
术语:Query / Key / Value (Q/K/V)
- 一句话解释:Query=我想问的问题,Key=每个词的"标签",Value=每个词真正的内容。
- 形象比喻:去图书馆。你的问题(Q)拿去跟每本书的书脊标签(K)比对,匹配上的书,就把它的正文(V)读进来。
- 工作中怎么用:注意力权重 = Q 和 K 的匹配程度;最终输出 = 按权重把各个 V 加权求和。
- 最常踩的坑:以为 Q/K/V 是三种不同的词。不是——它们是同一个词乘上三个不同权重矩阵后的三个"视角"。
一句话公式(看看就好,不用背):
注意力输出 = softmax( Q · Kᵀ / √d ) · V
└── 每个词该被关注多少 ──┘ └按权重取内容┘
Q · Kᵀ:算"问题"和每个"标签"的匹配分。/ √d:除一个数防止分值过大(否则 softmax 会变得非黑即白)。softmax:把一堆分数压成加起来等于 1 的权重。· V:按权重把内容混合出来。
上手算一遍:三个词的注意力(带数字)
光看公式没感觉,我们用"猫/累/它"三个词手算一次"它"该关注谁。假设经过一层网络后,算出"它"的 Query 和三个词的 Key 的匹配分是这样(数字我编的,只为演示):
"它" 对 "猫" 的原始分: 8.0
"它" 对 "累" 的原始分: 2.0
"它" 对 "它" 的原始分: 3.0
第一步 /√d 缩放(假设 d=64,√d=8):1.0 / 0.25 / 0.375。
第二步 softmax(把它们压成加起来=1 的权重),大致得到:
关注 "猫": 0.60 ← 最高,"它" 主要从 "猫" 吸收含义
关注 "累": 0.16
关注 "它": 0.24
第三步:最终"它"这个位置的新表示 = 0.60×V猫 + 0.16×V累 + 0.24×V它。"它"就这样被"猫"带跑了 60%,指代消解在数学上就是这么发生的。这一整套,GPT 每一层、每个词、每次生成都在做。
不信手算?20 行 numpy 自己跑一遍
上面的数字是我给的,你可以用 numpy 把整个流程复现出来——不需要 GPU,不需要装深度学习框架,纯矩阵乘法:
# pip install numpy
import numpy as np
def softmax(x):
e = np.exp(x - x.max())
return e / e.sum()
# 3 个词:"猫" "累" "它",用 d=4 的迷你向量演示(数字是编的,逻辑是真的)
q_it = np.array([1.0, 0.5, 0.2, 0.8]) # "它" 的 Query
K = np.array([
[1.1, 0.4, 0.3, 0.9], # "猫" 的 Key —— 故意设计得跟 q_it 很像
[0.1, 0.9, 0.1, 0.0], # "累" 的 Key
[0.3, 0.2, 0.6, 0.3], # "它" 的 Key
])
V = np.array([
[10.0, 0.0, 0.0, 0.0], # "猫" 的 Value(用好认的整数)
[0.0, 10.0, 0.0, 0.0], # "累" 的 Value
[0.0, 0.0, 10.0, 0.0], # "它" 的 Value
])
scores = K @ q_it / np.sqrt(4) # Q·Kᵀ / √d
weights = softmax(scores)
output = weights @ V # 按权重混合 Value
print("注意力权重:", weights.round(3)) # ≈ [0.503 0.237 0.260]
print("『它』的新表示:", output.round(2)) # ≈ [5.03 2.37 2.6 0. ]
跑出来你会看到"猫"拿走了约 0.5 的权重,"它"的新表示里第一个维度("猫"的成分)也明显最大。整个 self-attention 的核心,就是这三行矩阵运算——scores、softmax、加权求和。真实模型只是把 d=4 换成 d=上万、3 个词换成几万 token、单头换成几十个头、再叠几十层而已。就这些。跑通这个,你就懂了注意力的 80%。
Multi-Head:同一句话,派好几组人各看各的
Multi-Head Attention(多头注意力):与其派一个人看整句,不如派 8 组、16 组人同时看,每组盯不同的关系——一组盯语法(主谓宾),一组盯指代(它=猫),一组盯时态或情绪……最后把各组结论拼起来再过一个线性层融合。这样一层就能同时抓住多种关系,信息远比单头丰富。GPT-3 有 96 个头,不是拍脑袋,是"分工看"的并行度。
这个"图书馆/分工"比喻帮你理解检索这层,但和真实系统有一处不同:图书馆的书是固定的,而这里的 Q/K/V 每过一层都会被重新计算、重新混合,越往上越抽象。
一个完整的 Transformer Block 里发生了什么
注意力只是一层里的一半。真实的一层(block)是这样,从下往上:
输入向量(每个 token 一串数字)
│
┌──────────▼───────────┐
│ Multi-Head Attention │ ← 词互相看,吸收上下文
└──────────┬───────────┘
│ + 残差(把输入原样加回来) → LayerNorm
┌──────────▼───────────┐
│ Feed-Forward (FFN) │ ← 每个词各自过一个小型两层网络,加工信息
└──────────┬───────────┘
│ + 残差 → LayerNorm
▼
输出向量 → 喂给上面一层,重复 N 次
三个你一定会听到的名词,一次说清:
- FFN(前馈网络):注意力负责"词之间互相看",FFN 负责"每个词自己再想想"。它是一个先放大(如 4 倍维度)再压回来的两层网络,模型很大一部分"知识"其实存在这里。
- 残差连接(Residual):把这一层的输入原封不动加到输出上。为什么?网络堆到几十上百层,梯度会消失、信息会走丢;残差留了一条"高速公路",让信息和梯度能直通到底。没有它,深层网络根本训不动。
- LayerNorm(层归一化):把每层数值拉回一个稳定范围,防止越算越离谱。可以理解成每层之间的"稳压器"。
GPT-3 就是把这样的 block 叠了 96 层。"大模型"的"大",一大半是层数 × 每层宽度堆出来的。
顺手记一组数,讲课或面试都用得上:GPT-3(175B 参数)= 96 层 × 96 头 × 12288 维隐藏层。而微调里常听到的 LoRA/PEFT,动的主要就是注意力那几个投影矩阵——为什么"只训 1% 参数也有效",等你学到微调那一章会回来感谢这张架构图。
位置编码:模型本来分不清词序
注意力有个尴尬的先天缺陷:它是"一次性看全部"的,天生没有顺序概念。对纯注意力来说,"猫追狗"和"狗追猫"里的词集合一模一样,它分不清谁先谁后。
术语:位置编码 (Positional Encoding)
- 一句话解释:给每个位置加一个独特的"数字指纹",让模型知道谁在第几位。
- 形象比喻:剧院座位号。同样一批观众,有了排号座号,才知道谁挨着谁、谁在前排。
- 工作中怎么用:早期(原版 Transformer)用固定的正弦/余弦波形当指纹;现在主流(如 RoPE 旋转位置编码)把位置信息直接编进 Q/K 里,长文本外推更好。
- 最常踩的坑:以为 context window 想开多大开多大。位置编码的设计决定了模型能可靠处理多长,超出训练长度太多,效果会掉——这也是"长 context 模型"们真正在卷的技术点之一。
一句话:词序信息全靠位置编码补进去。 去掉它,GPT 会变成一个不懂语序的词袋子。
从文本到"下一个词":完整流水线
拿 "猫太累了" 喂进 GPT,大致流程:
文本
│ ① 分词 Tokenize:切成 token(不完全等于"字")
▼
[那只][猫][太][累][了]
│ ② Embedding:每个 token 变成一串数字(向量),含"语义坐标"
│ ③ 位置编码:告诉模型谁在前谁在后
▼
│ ④ 堆叠 N 层 Block(Attention+FFN,各带残差/LayerNorm)
▼
│ ⑤ 输出层:把最后一层向量投影成"每个候选 token 的分数(logits)"
│ ⑥ 采样:按分数挑下一个 token
▼
下一个词 → 接回输入末尾 → 再跑一遍 → 循环,逐字吐出来
图解说明(对着流程图看):
- 这张图在讲什么:一句话从文本到"预测下一个词"要过的完整工序,以及为什么它是"逐字接龙"。
- 先看哪里:先看①②③理解"文字先变数字+补位置";再看④,那是重复几十次的核心;最后⑤⑥解释它为什么会"编"。
- 工作中的关键判断:第⑤⑥步只是"挑下一个词",所以 LLM 本质是超强的文字接龙,不是查答案——这解释了它为什么流畅但会幻觉。
第⑥步就是 temperature / top_p 在管的地方
输出层给出的是一串候选词的分数,怎么从里面挑一个,就是采样策略——这正是你天天调的 API 参数:
| 参数 | 在干什么 | 调高会怎样 | 一句话记忆 |
|---|---|---|---|
temperature | 把分数分布"抹平"或"拉尖" | 越高越随机、越有创意也越容易胡说;=0 近似永远挑最高分 | 创意/确定性的旋钮 |
top_p (核采样) | 只在"累计概率前 p"的候选里挑 | p 越小越保守,只从最可能的几个里选 | 砍掉长尾垃圾选项 |
top_k | 只在分数最高的 k 个里挑 | 同上,按个数截断 | 另一种截断方式 |
所以"要稳定输出就 temperature=0"这句经验,在架构上就是"每步都选分数最高的词"。
顺带说清:token ≠ 字
第①步补一个最常踩的坑:token 不是字也不是单词。"ChatGPT" 可能被切成 2 个 token,一个中文字常占 1–2 个 token。你按 token 付费、context window 也按 token 算,所以"字数"和"token 数"永远对不上,别用字数估成本。
第②步的主角:Embedding
术语:Embedding(词嵌入)
- 一句话解释:把每个 token 变成一串数字(向量),意思相近的词,数字也相近。
- 形象比喻:给每个词发一张"语义坐标"的地图定位——"猫"和"狗"住得近,"猫"和"发票"隔着十条街。
- 工作中怎么用:LLM 输入的第一步;RAG 里的向量检索、语义搜索、推荐系统,用的全是这套"距离=语义相似度"的思路。
- 最常踩的坑:以为 embedding 是固定查表就完事。查表只是起点——过完注意力层之后,同一个词在不同句子里的向量是不一样的("苹果发布会"和"苹果真甜"里的"苹果"),这正是 Transformer 比老式词向量强的地方。
上手代码:亲眼看看分词和注意力
# pip install transformers torch
from transformers import AutoTokenizer, AutoModel
import torch
tok = AutoTokenizer.from_pretrained("bert-base-chinese")
model = AutoModel.from_pretrained("bert-base-chinese", output_attentions=True)
text = "那只猫没跳上桌子因为它太累了"
enc = tok(text, return_tensors="pt")
print("token 切分:", tok.convert_ids_to_tokens(enc["input_ids"][0]))
# ['[CLS]','那','只','猫','没','跳',... ,'它','太','累','了','[SEP]'] ← 每个字≈1个token
with torch.no_grad():
out = model(**enc)
# out.attentions: (层数) 个张量,每个 shape = [batch, 头数, seq, seq]
att = out.attentions[-1][0] # 最后一层,去掉 batch 维 → [头数, seq, seq]
att = att.mean(0) # 对所有头取平均 → [seq, seq]
tokens = tok.convert_ids_to_tokens(enc["input_ids"][0])
it_idx = tokens.index("它")
scores = att[it_idx] # "它" 这一行 = 它对每个词的注意力权重
top = torch.topk(scores, 3)
print("『它』最关注:", [(tokens[i], round(float(scores[i]),3)) for i in top.indices])
# 通常你会看到 "猫" 排在前面 —— 亲眼验证指代
图解说明:
- 这段在干嘛:加载一个真实模型,把注意力权重掏出来,看"它"到底关注了谁。
- 先看哪里:先看
att.shape的四个维度(层、头、词×词),这就是前面讲的多头注意力矩阵;再看最后打印的"它最关注"。 - 关键判断:不同的头会关注不同东西,所以我们
mean(0)取平均看整体倾向;想研究"哪个头管指代",就别取平均,逐头看。
KV Cache:为什么第一个 token 慢,后面的快
生产环境有个现象你迟早会撞上:调 API 时,第一个 token 等得最久,后面哗哗地吐。我第一次给客户查"响应慢"的工单时就栽在这——盯着日志看了半天总耗时,后来才发现该拆开看两个指标:首 token 延迟(time to first token)和吐字速度(tokens/s)。这俩背后是两个完全不同的阶段:
- Prefill(预填充):把你的整个 prompt 一次性过完所有层,算出每个 token 的 K 和 V。prompt 越长这步越慢——这就是首 token 延迟的大头。
- Decode(逐字生成):之后每生成一个新 token,理论上要重新算前面所有 token 的 K/V——但它们根本没变过!所以推理框架把算好的 K/V 缓存起来,每步只算新 token 自己的 Q/K/V,再去查缓存。这就是 KV Cache。
没有 KV Cache 会怎样?算笔账:1000 token 的 prompt 生成 500 token 回复,第 500 步要重算 1500 个 token 的 K/V,整个生成过程的重复计算量是缓存方案的几百倍。KV Cache 是空间换时间——代价是显存:以 7B 模型(fp16)为例,每个 token 的 K/V 缓存约占 0.5 MB,一条 4096 token 的对话就是约 2 GB 显存。为什么长对话的 API 又慢又贵、为什么本地部署跑长 context 显存爆炸,账就在这里。
一句话记住:Prefill 决定首 token 快不快,KV Cache 决定后面吐字快不快,显存决定你能缓存多长。 这三个词以后在部署与成本优化里还会反复出现。
为什么这架构又贵又有 context 限制
注意力要让每个词看所有词,n 个词就是 n×n 次比对。文本翻倍,计算量翻四倍(O(n²))。这个平方有多凶?代进数字看:
1,000 token → 100 万次比对
10,000 token → 1 亿次比对 (文本 ×10,计算 ×100)
100,000 token → 100 亿次比对 (文本 ×100,计算 ×10000)
这就是为什么:
| 现象 | 根因 | 一句话记忆 |
|---|---|---|
| context window 有上限 | n 越大,注意力矩阵 n² 吃爆显存 | 不是不想给你长,是平方级烧钱 |
| token 多就慢就贵 | 计算量按平方涨 | 长 prompt 是真金白银 |
| 长文档"中间遗忘" | 注意力被稀释 + 位置外推变弱 | 重点别塞文档正中间 |
后来的 Flash Attention(把注意力算得更省显存)、稀疏/滑窗注意力(不让每个词看全部)、KV Cache(生成时缓存已算过的 K/V,不重算)全是在跟这个 O(n²) 死磕。你现在不用会,但知道"瓶颈在注意力"就够了。
这也是做 RAG 的第一性原理:与其把 10 万 token 全塞进 context 让注意力稀释,不如先检索出最相关的 2000 token 再喂进去——又准又便宜。等你到 RAG 那一章,会发现整套方案就是在绕这个 n² 走。
这些权重是从哪来的?训练一分钟版
看到这你可能会问:Q/K/V 的那些投影矩阵、FFN 里的参数,数值是谁定的?答案简单到让人意外——全是"猜下一个词"猜出来的:
1. 拿一大段真实文本,如 "那只猫没跳上桌子因为它太累了"
2. 遮住后半截,让模型预测下一个 token:"那只猫没跳上桌子因为它太___"
3. 模型输出每个候选 token 的概率,跟正确答案 "累" 对比,算出差距(loss)
4. 反向传播:把所有权重朝 "下次更可能猜对" 的方向微调一点点
5. 换下一段文本,回到第 2 步 —— 重复几万亿个 token
所谓"预训练"(pretraining)就是这个循环跑上几个月。没有人给模型标注"它=猫"这种规则——指代、语法、常识,全是为了把下一个词猜得更准而"顺便"学会的。这也解释了两件事:
- 为什么微调有效:预训练已经把语言规律压进了那些矩阵,微调只是在现成基础上小幅调向。LoRA 敢只训 1% 参数,赌的就是"底子不用动"。
- 为什么幻觉治不断根:训练目标从头到尾是"猜得像",不是"说得对"。像与对高度相关,但不是一回事。
就这些。训练的数学细节(梯度下降、优化器)留给机器学习基础那章,这里你只需要这个直觉。
三种 Transformer:GPT 只是其中一款
《Attention Is All You Need》原版有 encoder 和 decoder 两半,后来分化成三种用法:
| 类型 | 代表 | 怎么看词 | 擅长 | 一句话记忆 |
|---|---|---|---|---|
| Encoder-only | BERT | 双向,能看前后文 | 理解类:分类、检索、抽取 | 做阅读理解的 |
| Decoder-only | GPT / Llama / Claude | 单向,只能看左边(前文) | 生成类:对话、写作、代码 | 做文字接龙的,你天天用的这种 |
| Encoder-Decoder | T5 / 原版翻译模型 | 先读懂再生成 | 翻译、摘要等"输入→输出"任务 | 先读后写的 |
为什么 GPT 只能看左边?因为它的任务是"预测下一个词",训练和推理时不能偷看答案(右边),所以用了带掩码的注意力(masked attention)把右边挡住。这也是为什么它天然是"从左往右逐字生成"。
顺便一提:RAG 里管检索的 embedding 模型,多数是 encoder 系的后代;你天天聊天用的是 decoder 系。同一套注意力机制,两种吃法——一个用来"读懂",一个用来"接龙"。
⚠️ 常见陷阱
| 陷阱 | 实际情况 | 一句话记忆 |
|---|---|---|
| "参数越多越聪明" | 大致相关但不绝对。数据质量、训练方法、对齐同样关键,调好的 7B 能吊打没调好的更大模型 | 参数是身材,训练是本事 |
| "Transformer = ChatGPT" | Transformer 是架构,GPT 是基于它的 decoder-only 模型;BERT 也是 Transformer,干的却是理解类的活 | 架构是发动机,产品是整车 |
| "context window 越大越好、随便塞" | 受位置编码和 O(n²) 成本双重制约,塞满长 context 既贵又可能触发"中间遗忘" | 塞得进 ≠ 记得住 |
| "位置编码可有可无" | 去掉它,"猫追狗"和"狗追猫"在模型眼里一模一样 | 没座位号,全场大乱 |
| "LLM 会查答案,错了就是没查到" | 它从头到尾只做"预测下一个 token",没有查询这个动作,幻觉是机制自带的 | 接龙选手,不是图书管理员 |
| "temperature=0 就绝对可复现" | 只是每步近似挑最高分,浮点并行计算、服务端批处理仍可能带来细微差异 | =0 是很稳,不是公证处 |
| "Q/K/V 是三种不同的输入" | 同一个词向量乘三个不同矩阵得到的三个"视角",源头是同一个 token | 一人分饰三角 |
| "多头 = 多算几遍一样的注意力" | 每个头有独立的投影矩阵,学到的关系各不相同(语法/指代/位置……) | 分工不同,不是复读机 |
🔧 动手练习
练习 1:亲手复现"它 → 猫"的注意力(约 20 分钟)
- 把上面那段 numpy 代码原样跑通(本地
pip install numpy或直接开一个 Colab)。 - 改
K矩阵第二行("累"的 Key),把它改成跟q_it很像的向量(比如[1.0, 0.5, 0.2, 0.8]),重跑——看权重怎么从"猫"倒向"累"。 - 把
scores那行的/ np.sqrt(4)删掉,再把 K 的数值全体 ×10 重跑——观察 softmax 输出变得多"非黑即白",这就是公式里/√d存在的理由。 - 进阶:跑 transformers 那段 BERT 代码,把句子换成"律师把文件交给助理因为他快迟到了",看"他"的注意力落在"律师"还是"助理"——模型的判断跟你的直觉一致吗?
练习 2:用 API 参数验证"采样层"(约 15 分钟)
- 打开 OpenAI Tokenizer,把 "人工智能" 和 "Artificial Intelligence" 分别粘进去,数各占几个 token,体会"中文更费 token"。
- 同一个 prompt(建议用"给这款耳机写一句广告语"这类开放题),分别用
temperature=0和temperature=1.2各生成 3 次,对比稳定性和"胡说"程度,把结果和本文"采样层"那段对上。 - 找一段 500 字资料,把一个关键结论分别放在正中间和结尾,各问一次模型,观察哪次答得准——亲手复现"中间遗忘"。
- 记录每次调用返回的 token 用量(
usage字段),对照第 1 步的分词结果,验证"按 token 计费"到底怎么算的。
📚 小结
- Transformer 靠注意力让每个词一次性看全句,取代 RNN 的排队式处理——又快又不忘;Q/K/V = 拿问题比标签再按匹配度取内容,multi-head 是"派好几组人各看各的关系",核心就是
softmax(QKᵀ/√d)·V三步矩阵运算,20 行 numpy 就能复现。 - 一个 block = 注意力 + FFN,各配残差 + LayerNorm;残差是深层网络能训起来的"高速公路",FFN 存了模型大半知识,大模型的"大"主要是层数×宽度(GPT-3 = 96 层 × 96 头)。
- 注意力天生没有词序,位置编码把顺序补进去,它的设计也决定了 context 能可靠多长。
- LLM 本质是逐字接龙(⑤输出 logits→⑥采样),
temperature/top_p/top_k调的就是采样这一步;token≠字,成本和 context 都按 token 算;生成分 Prefill(决定首 token 延迟)+ Decode(KV Cache 加速吐字) 两阶段,KV Cache 用显存换速度(7B 模型约 0.5 MB/token)。 - 注意力是 O(n²)(文本 ×100 = 计算 ×10000),这是 context 限制、长文本又慢又贵、"中间遗忘"的共同根源,也是 RAG"先检索再喂"的第一性原理;GPT 是 decoder-only(只看左边、逐字生成),和 BERT(encoder,理解)、T5(encoder-decoder)分工不同。
相关阅读
下一步:机器学习 / 深度学习基础速通 →
- LLM API 入门 — temperature/top_p、token 计费、streaming,这章讲的采样层在 API 侧长什么样
- Context 基础 — context window 的工程用法,接住本章的位置编码和 n² 根因
- Context 退化模式 — "中间遗忘"在真实系统里的各种表现和对策
- RAG 系统入门 — 绕开 n² 的正解:先检索再喂
- 微调:PEFT / QLoRA — LoRA 动的就是本章讲的注意力投影矩阵
- 部署与成本优化 — KV Cache、显存、首 token 延迟在生产环境的账本
📚 相关资源
❓ 常见问题
关于本章主题最常被搜索的问题,点击展开答案
为什么 LLM 有 context window 限制?
注意力要求每个 token 和所有 token 两两比对,n 个 token 就是 n² 次计算,文本翻倍计算量翻四倍,显存和成本按平方烧;同时位置编码只在训练长度附近可靠,超出太多效果会掉。两个因素叠加,context 就有了上限。
注意力的计算量为什么是 n² 的?
self-attention 让每个词对句子里所有词各打一次「该多关注你」的分数,n 个词就是 n×n 次比对。1,000 token 是 100 万次,100,000 token 就是 100 亿次——文本长 100 倍,计算量涨 1 万倍,这就是长 prompt 又慢又贵的根因。
「lost in the middle」(中间遗忘)是怎么回事?
长文档里塞在中段的信息最容易被模型漏掉:一方面 token 越多,注意力权重被稀释得越薄;另一方面位置编码对超长距离的外推变弱。实践对策是把关键结论放在开头或结尾,或者用 RAG 先检索出相关片段再喂给模型。
temperature 调的到底是哪一步?
模型每步先输出一串候选 token 的分数(logits),temperature 作用在最后的采样层:调高把分数分布抹平,更随机更有创意也更容易胡说;调低把分布拉尖,更确定。设为 0 近似每步都挑最高分,跟注意力、位置编码这些环节无关。
KV Cache 优化了什么?
逐字生成时前面所有 token 的 K/V 其实没变,KV Cache 把它们缓存起来,每步只算新 token 自己的 Q/K/V,省掉几百倍的重复计算——代价是显存,7B 模型约每 token 0.5 MB。它决定吐字速度,首 token 延迟则由 prefill 阶段决定。