(三)先把地基打好:注意力到底在算什么

上一篇挖了个坑,这篇来填
上一篇我把整个行业的长上下文路线铺成了一张地图:Llama 靠改位置编码,Gemini 靠堆 TPU,GLM 和 DeepSeek 靠改架构。地图画完,我留了这么一句话:
要真正看懂路线二(改造注意力)和路线三(KV 压缩),你得先搞清楚标准注意力到底在算什么、为什么是 N²、KV Cache 到底是个什么东西。这些是地基。
这篇就是来打地基的。
我故意没在这篇里塞任何 GLM-5.2 的”创新”。如果你期待看到 DSA、MLA 怎么变魔术,先忍一下——不懂标准注意力,后面那些花活都是空中楼阁。这一篇不破任何墙,但它是理解后面四道墙为什么难的全部前提。
进度感:本篇是地基层,不对应任何一道墙
(后面按由易到难拆,不按墙号顺序)
墙 1(算不动 N²)→ 第 5 篇 DSA
墙 2(放不下 KV Cache)→ 第 4 篇 MLA
墙 3(推不动 千亿参数)→ 第 6 篇 MoE
墙 4(蹦得慢 自回归)→ 第 7 篇 MTP
一个 token 的诞生:文字怎么变成数字
模型不认识”字”,它只认识数字。所以第一步是翻译。
**分词器(Tokenizer)**把句子切成一个个 token。这里有个反直觉的点:token 不是字,也不是词,而是介于两者之间的”片段”。看个例子:
"我喜欢吃苹果"
→ 可能切成: [我] [喜欢] [吃] [苹果] ← 4 个 token
"喜欢" 常见,整体打包成 1 个 token
"我喜欢吃凤梨"
→ 可能切成: [我] [喜欢] [吃] [凤] [梨] ← 5 个 token
"凤梨" 不够常见,拆成两个字符 token
同样是 6 个字,“苹果”版本 4 个 token,“凤梨”版本 5 个。这就是为什么你数模型”生成了 100 个字”,它实际可能跑了 80 个 token——字数和 token 数经常对不上,中英文混排、词组打包都会让两者错位。GLM-5.2 的词表是 vocab_size: 154880,也就是它总共认识约 15.5 万种 token 片段。
切完 token,下一步是查表。每个 token 去翻一张叫 **Embedding(嵌入)**的大表,变成一串数字——一个向量。拆 GLM-5.2 的 config.json,这一串数字的长度写得很清楚:
hidden_size: 6144
每个 token 变成 6144 个数字。你可以把它想象成每个 token 背后挂着一个有 6144 个刻度的”身份证”,每个刻度都是训练学出来的。
为什么是 6144 个、不是一个?因为这些数字编码的是意思。训练让”意思相近的 token,数字串也长得像”——“猫”和”狗”的向量方向接近,“猫”和”汽车”差得远。怎么衡量”像不像”?看两串数字指向的方向夹角,本质就是中学几何里的余弦。6144 维给得足够细,能把 token 之间的微妙差别都摊开编码。

这对你用 AI 意味着什么: 同样一段话,不同模型的 token 数可能差很多——有的模型词表对中文友好(“喜欢”算一个),有的不友好(拆成单字)。你按 token 付费时,模型选谁直接影响账单。这也是为什么现在国产模型(Qwen、GLM、DeepSeek 等)都在扩中文词表:少切几个 token,既省钱又省上下文额度。
78 层的”接龙工厂”:Transformer 在干什么
变成 6144 维向量后,这些 token 进入一座加工厂。GLM-5.2 的层数同样是 config 写死的:
num_hidden_layers: 78
78 层。每一层做两件事,循环往复:
一个 token 进入一层
│
├─ 第一步: 注意力(Attention) ← 看一眼上下文,搞清楚"我是谁"
│
└─ 第二步: 前馈网络(MLP) ← 消化信息,做特征变换
│
▼
输出 → 进下一层 ...(重复 78 层)
- 注意力:让当前 token 扫一眼句子里其他 token,搞清楚自己在当前语境下到底是个什么角色。这是这篇的主角。
- MLP:把注意力收集来的信息做进一步加工变换,可以理解成”消化吸收”。
78 层叠完,每个 token 都拿到了一个”吃透了全部上下文”的向量。最后一步,拿最后一个 token的输出向量,过一层叫 lm_head 的,转成”下一个 token 是词表里每个候选的概率”,选概率最高的——下一个字就蹦出来了。然后用这个新字再跑一遍 78 层,再蹦下一个……这就是”接龙”:用已生成的 token 预测下一个 token,循环往复。

这对你用 AI 意味着什么: 为什么大模型”思考”要那么久?因为每蹦一个字,都要把上面这套 78 层从头跑一遍(这点第 7 篇讲 MTP 时会重点拆)。模型不是一次性想好整句,而是真的一个字一个字往出蹦——所以你能看到它打字一样的”流式输出”。这也是”蹦得慢”那道墙的根源。
注意力的核心:Q / K / V 三角色
现在进正题:注意力到底怎么”看上下文”?
答案藏在三个角色里:Q(Query,查询)、K(Key,键)、V(Value,值)。每个 token 都会拿自己的向量,乘以三个训练好的矩阵,投影出这三样东西。
用”我想吃苹果”举例
拆 token 后是 [我] [想] [吃] [苹果],我们聚焦到「苹果」。
「苹果」会向句子里每个 token 发起一次”注意力”,看谁跟自己相关。这个过程可以想象成**「苹果」在挨个问句子里每个字一个问题**:“你跟我有关系吗?关系多大?”
"我" → 相关度 0.10 (弱)
"想" → 相关度 0.05 (弱)
"吃" → 相关度 0.85 ★ 强!"吃苹果"强烈暗示这是水果
"苹果" → 相关度 1.00 (自己,最高)
然后「苹果」按相关度做加权混合:大量吸收「吃」的信息,弱吸收「我」「想」。结果,「苹果」的向量被更新了,它现在”知道”自己是被吃的那个水果,而不是苹果公司。靠上下文把一个词的多重含义收敛到正确的那一个,注意力就是这么消歧义的。
Q / K / V 分别扮演什么
那”相关度”具体怎么算?这就是 Q/K/V 的核心。打个比方:
| 角色 | 含义 | 比喻 |
|---|---|---|
| Q(Query) | 当前 token “在找什么样的信息” | 你举手提问:“我在找懂 X 的人” |
| K(Key) | 每个 token “自称能提供什么” | 每人胸前挂的胸牌:“我是 X 方面的” |
| V(Value) | 每个 token “实际携带的信息” | 那个人的实际发言内容 |
「苹果」拿着自己的 Q(在找”谁吃我 / 描述我”),去看其他 token 的 K(胸牌)。Q 和 K 方向越一致,点积越大,相关性越高:
Q(苹果) · K(我) = 0.10 ← 苹果的 Q 和"我"的 K 方向差得远
Q(苹果) · K(吃) = 0.85 ← 苹果的 Q 和"吃"的 K 方向接近 ★
Q(苹果) · K(苹果) = 1.00 ← 自己看自己,最高
算出一批相关度后,用 softmax 把它们归一化成”权重”(加起来等于 1),再按权重加权混合所有 token 的 V(实际信息):
新向量(苹果) = 0.10×V(我) + 0.05×V(想) + 0.85×V(吃) + 1.00×V(苹果)
└─ 大量吸收"吃"的动作语义
一句话概括标准注意力的全部:Q·K 点积算相关性 → softmax 归一化 → 加权混合 V。 就这三步,没有别的。
这对你用 AI 意味着什么: 注意力的本质是”按相关性分配注意力”——和你问题语义相关的上下文,权重高、被认真读;无关的,权重低、几乎被忽略。 所以写 prompt 时,把关键信息和你的问题放近、放相关,比堆一堆背景废话更管用。模型不是逐字精读整篇,而是在做相关性筛选。

三个容易踩的坑
讲到这里,有三个点必须澄清,否则后面 DSA 的逻辑接不上。
第一,注意力是非对称的——是”有向图”,不是无向图。
「苹果」关注「吃」的程度(0.85),不一定等于「吃」关注「苹果」的程度(可能是 0.30,也可能是 0.90)。因为 Q 和 K 是两套不同的投影矩阵,“我找你”和”你找我”用的是不同的尺子,两个方向的注意力是独立算出来的。这就像暗恋是单向的,你盯着某人看,不代表对方也在看你。
这直接推出一个关键结论:N 个 token 要算的不是 N(N−1)/2 次(无向图),而是 N×N 次(有向图)。 每个方向的注意力都得单独算一遍。后面讲 N² 时这个细节会回来。
第二,注意力是”全员对照”,不是”接力赛”。
「苹果」不是只看相邻的「吃」,而是和句子里每一个 token 都算一次。哪怕隔得很远——“小明去了很远的银行”里,「银行」要直接看到句首的「小明」,中间隔了几个 token 也得直线关联。
这是注意力区别于老一代 RNN(循环神经网络)的核心优势:RNN 像传话游戏,信息要一个挨一个往下传,传远了就失真;注意力是全员大合影,任意两个 token 都能直接对上眼,不管隔多远。代价就是——人人都得对一遍,于是有了 N²。

第三,还有两处工程细节,不影响核心。
真实的 Q·K 点积还要做两件事:(a) 除以 √d 缩放,防止维度一高 softmax 分布过尖、梯度消失;(b) 多头并行——拆 GLM-5.2 的 config:
num_attention_heads: 64
head_dim: 192
64 个头,每个头独立算一遍注意力,各学一种不同的关系模式(语法、指代、长程依赖……)。这两点是工程优化,核心机制(Q·K 衡量方向一致性)一点没变。
这对你用 AI 意味着什么: 为什么 AI 能在一份长文档里”远距离”把第 1 页的设定和第 47 页的问题对上号?就是因为注意力是全员对照,不是接力赛——理论上任意两个 token 都能直接关联。但”理论上能”和”算得动”是两回事,这正是 N² 要逼出来的下一道墙。
为什么是 N²?长上下文的”原罪”
现在你能彻底看懂墙 1 了。
注意力的第二步(Q·K 算相关性)是这样的:每个 token 都要拿自己的 Q,去和所有其他 token 的 K 算一次点积。
N 个 token,每个都要算 N 次点积(跟所有人算一遍,含自己)
→ 总共 N × N = N² 次点积
序列长度一涨,计算量不是线性涨,是平方涨:
| 序列长度 | 注意力点积次数 |
|---|---|
| 100 个 token | 100 × 100 = 1 万次 |
| 1 万个 token | 1 亿 次 |
| 100 万 token(1M) | 1 万亿次 |
序列翻 10 倍,计算量翻 100 倍。1M 上下文的一次注意力,就是一万亿次点积——而这还只是一层的量,GLM-5.2 有 78 层,64 个头,全部叠起来是个让人头皮发麻的数字。

这就是 N²,长上下文的”原罪”。它不挑模型——任何用标准注意力的模型,只要把上下文拉到 1M,这一万亿次点积一个都躲不掉。
那 GLM-5.2 怎么躲的?靠的就是路线二:经验上,大部分注意力权重其实接近零(那个”的”字,真的需要和另外 100 万个 token 都算一遍吗?),那就别全员算,只挑相关的几个算,这是 DSA(分散稀疏注意力)的动机。但 DSA 具体怎么挑、怎么保证不挑错,我们留到第 5 篇深讲。这一篇你只要记住:标准注意力就是 N²,没有捷径。
KV Cache:为什么不用每次重算
讲完注意力,还有一个绕不开的概念——KV Cache。它是墙 2的来源,也是第 4 篇 MLA 要啃的骨头。
自回归生成的两个阶段
模型生成回复时,其实分两段:
阶段 1 Prefill(预填充):处理你的输入
一次性把你输入的所有 token 算一遍
→ 每个 token 在每一层都得到自己的 K 和 V
→ 把这些 K/V 存起来(进 KV Cache)
阶段 2 Decode(解码):一个字一个字蹦
每生成一个新 token:
- 用新 token 的 Q,和 Cache 里所有历史 K 算点积
- 按相关性加权混合历史 V
- 新 token 自己的 K/V 也存进 Cache
- Q 用完就扔
Q 扔、K/V 存——为什么这么设计?
| Q | K | V | |
|---|---|---|---|
| 存进 Cache 吗 | ❌ 扔 | ✅ 存 | ✅ 存 |
| 为什么 | Q 是”当前在找什么”,每个 token 不同,别人不会来查它,无复用价值 | 下次别的 Q 还要来查它,存了就免于重算 | 和 K 同理,是别人要取走的信息 |
用一个图书馆的比喻:你是读者(当前的新 token),带着自己的提问(Q);书架上每本书(历史 token)挂着书名(K,供你检索)和内容(V,你取走的部分)。书自己不需要”提问”——它们的 Q 早在当年就扔了——只需要持续提供书名和内容给后来的读者查。
这个设计的关键,在于把”重复计算”换成了”存储复用”。不然每蹦一个新字,都要把前面所有 token 的 K/V 重新算一遍,那生成一句话的成本会平方爆炸。
但存储本身,就是墙 2
聪明的代价是:K/V 得一直占着地方。算一笔账:
1M token × 每头 192 维 × 2(K,V) × 64 头 × 78 层 × 2 字节(bf16)
→ 约 3-4 TB(未压缩标准口径粗算)
→ 单张卡的显存,根本装不下
这就是 KV Cache 带来的第二道墙——算得动是一回事,存得下是另一回事。GLM-5.2 怎么把这几 TB 压到能在普通多卡上跑?答案在第 4 篇:把 K/V 用训练好的矩阵压成 512 维的”潜在向量”。具体怎么压、为什么不会压坏,留到 MLA 那篇。

这对你用 AI 意味着什么: 为什么你的长对话越聊越慢、越聊越卡?因为每多一轮,KV Cache 就多塞一层历史,显存越占越大,直到触发”清缓存”或截断——模型就开始”忘事”。这也是为什么很多产品有个上下文上限:不是模型不想记住,是显存放不下了。 懂了 KV Cache,你就懂了”为什么会忘”。
地基铺好了,后面要拆什么墙?
这一篇你没看到任何 GLM 的创新,但你掌握了三个地基概念,它们正是后面所有花活的着力点:
- 标准注意力:Q·K 点积算相关性 → softmax → 加权混合 V
- N² 问题:每个 token 和所有 N 个 token 算,序列一长平方爆炸
- KV Cache:K/V 存起来复用,免于重算,但体积大得撑爆显存
GLM-5.2 的四个架构创新,每一个都是对着 Transformer 的某个部件动刀——MLA 盯 KV Cache,DSA 盯注意力的 N²,这两个接着前面打的地基;MoE 动的是 MLP 层,MTP 动的是生成循环,这是 Transformer 另外两个部件。手术部位一一对应:
| 创新 | 对着哪个地基 | 怎么动刀 | 哪一篇拆 |
|---|---|---|---|
| MLA | KV Cache | 把 K/V 压成 512 维潜在向量 | 第 4 篇 |
| DSA | 注意力 N² | 每个 token 只算 top-2048 相关的 | 第 5 篇 |
| MoE | MLP 层 | 256 个专家选 8 个,只激活一小部分 | 第 6 篇 |
| MTP | 自回归生成 | MTP 头一次猜多个,主模型并行验证 | 第 7 篇 |

写在最后:地基就该打这么细
你可能觉得这篇啰嗦,讲个注意力至于吗?我的经验是:后面每一篇的爽点,都建立在这篇的扎实上。 当第 4 篇告诉你”MLA 把 K/V 从上万维压到 512 维”时,你得先知道 K/V 是什么、为什么要存它;当第 5 篇讲”indexer 粗筛 top-2048”时,你得先理解全员大合影的 N² 到底浪费在哪。
地基不打牢,后面全是名词的堆砌;地基打扎实了,后面的每一招你都能看懂它在动哪里、为什么这么动。
那我们就从最直观的一道墙开始:KV Cache 太大怎么办? 下一篇,MLA 登场。我们会回答一个很具体的问题:凭什么 GLM-5.2 敢把每个 token 的 K/V(64 个头合起来上万维)压到只存一个 512 维的潜在表示,还压不坏?答案藏在一个和 JPEG 图片压缩同源的数学技巧里,低秩分解。
下篇预告:《KV Cache 放不下?MLA 的低秩压缩》
本篇涉及的所有架构数字——hidden_size: 6144(每个 token 的向量维度)、num_hidden_layers: 78(层数)、num_attention_heads: 64 与 head_dim: 192(注意力头数与头维度)、vocab_size: 154880(词表大小)——均来自 GLM-5.2 公开的 config.json。Q/K/V、softmax、多头注意力、N²、KV Cache、Prefill/Decode 两阶段等为 Transformer 标准机制,描述基于公开论文与通用实现,无任何闭源或未公开信息。序列长度 100 / 1 万 / 100 万对应的点积次数(1 万 / 1 亿 / 1 万亿)是按 N² 直接计算的理论值,未计入常数与工程实现细节。