总成|Attention 到底在算什么

Attention 到底在算什么
前面十来篇探针,注意力(attention)这个词出现过无数次。
探针 4 讲 Claude Code 凭什么自己干活时,我说模型靠注意力才读得懂工具说明,但「具体在算什么,留到总成」。探针 5 讲 AI 为什么会忘事时,我说模型每生成一个字都要把整个窗口从头看一遍,这个「看」就是注意力,但「具体在算什么,留到总成」。
这篇就是那个总成。一口气把注意力从里到外挖透。
为什么值得专门拆?因为注意力是大模型理解语言的根。前几篇你看到的几乎所有本事——读工具说明、记上下文、看懂图、消歧义词——底下都是它在干活。但前面为了不跑题,每次都只用一句话带过。这篇不省了,把它三步流程、为什么平方爆炸、凭什么越答越快,一次讲清。
这篇只讲注意力这一个零件。它和 FFN、残差连接、LayerNorm、位置编码怎么拼成整个 Transformer,留给下一篇「总成 Transformer」。这里专注一件事:注意力本身在干什么。
三个角色:Q、K、V
注意力的全部秘密,藏在一个叫 Q/K/V 的设计里。
每个 token(对,又是 token,探针 2 讲过)进到注意力这一层,会拿自己的向量(一串数字,探针 3 讲过,模型只认数字)乘以三个不同的矩阵,投影出三样东西:
- Q(Query,查询):这个 token 「在找什么样的信息」
- K(Key,键):这个 token 「自称能提供什么」
- V(Value,值):这个 token 「实际携带的信息」
打个比方,一场聚会上你想找人聊天。你心里揣着自己的提问(Q:「我在找懂 AI 的人」);每个人胸前挂着胸牌(K:「我是搞 AI 的」/「我是搞法律的」);找到对的人后,你从他那儿取走的是他的实际发言(V)。
注意力的核心动作,就是让每个 token 拿着自己的 Q,去和所有人的 K 配对,看谁匹配,匹配度高的就把对方的 V 多拿一点过来,加权混合到自己身上。
一句话先压住全局:Q·K 点积算相关性 → softmax 归一化 → 加权求和 V。 注意力就这三步,没别的。下面一步步拆。
想亲手走一遍这三步?打开 Attention 三步可视化:点「我想吃苹果」里的任一个词,看它的 Q·K 点积 → softmax 权重 → 加权求和,看「苹果」怎么被上下文钉成水果。
第一步:点积打分——Q 和 K 方向越一致,越相关
拿「我想吃苹果」举例。切完 token 是 [我][想][吃][苹果],我们聚焦到「苹果」。
「苹果」要搞清楚自己在当前语境下到底是水果还是公司,得看上下文。它拿着自己的 Q(在找「谁吃我、怎么描述我」),去挨个看其他 token 的 K(胸牌):
Q(苹果) · K(我) = 0.5 ← 方向差得远,弱相关
Q(苹果) · K(想) = 0.2 ← 方向差得远,弱相关
Q(苹果) · K(吃) = 2.5 ← 方向接近,强相关 ★
Q(苹果) · K(苹果) = 3.0 ← 自己看自己,最高
这里算相关性的操作叫点积(dot product),就是中学数学里那套:两串数字对应位相乘,再全部加起来,得一个数。这个数有个直观含义——在向量长度差不多时,它衡量两串向量的「方向一致程度」。方向越一致,点积越大;方向相反,点积小甚至为负。
「苹果」的 Q 和「吃」的 K 指向相近的方向(都和「进食」「水果」的语义沾边),点积就大;「苹果」的 Q 和「我」的 K 方向八竿子打不着,点积就小。
这一步算出来的数字,行话叫注意力分数(attention score)。它回答的是:「苹果」该多关注谁。

第二步:softmax 归一化——把分数变成权重
上一步算出来的是一批原始分数(0.5、0.2、2.5、3.0……),数字有大有小,加起来也不等于 1。直接拿来用不方便。
所以接一个叫 softmax 的操作,把这批分数归一化成一组「权重」——让它们全部变成 0 到 1 之间的小数,且加起来正好等于 1。
原始分数: softmax 归一化后:
0.5 → 0.05 (≈ 5%)
0.2 → 0.03 (≈ 3%)
2.5 → 0.35 (≈ 35%)
3.0 → 0.57 (≈ 57%)
└──── 加起来 = 1.00
softmax 有个关键特性:它会让强相关的更突出、弱相关的更微弱。看上面这组:强相关的「吃」「苹果」原本点积就大,softmax 后占了 35% + 57% = 92% 的权重;弱相关的「我」「想」原本就小,softmax 后被压到 5% + 3% = 8%。归一化既把分数变成了好用的权重(加起来等于 1),又强化了「相关的多看、不相关的几乎不看」这个分布。
(工程上还有个细节:算点积之前会先除以一个数缩放一下,防止维度一高、softmax 分布太尖导致训练出问题。这不影响核心机制,知道有这回事就行。)
第三步:加权求和——把别人的 V 按权重拿过来
拿到归一化后的权重,「苹果」就按这组权重,把所有 token 的 V 加权混合到自己身上:
新向量(苹果) = 0.05 × V(我) + 0.03 × V(想) + 0.35 × V(吃) + 0.57 × V(苹果)
结果,「苹果」的向量被更新了:它大量吸收了「吃」的语义(权重 0.35)和自己原本的信息(0.57),只沾了一丁点「我」「想」的。更新后的「苹果」向量,现在「知道」自己在这个句子里是被吃的那个水果,而不是苹果公司。
这就是注意力最妙的本事:靠上下文,把一个词的多重含义收敛到正确的那一个。一个词在词典里有一堆意思,但放在具体句子里,注意力通过「看周围谁跟它相关」把它钉死成当下的含义。消歧义,就这么自动完成了。
到这里,标准注意力的全部三步就走完了:点积算相关性 → softmax 归一化 → 加权求和 V。一个 token 看完一圈上下文,把自己的向量更新一遍,注意力这一层就完事了。

为什么是 N²——因为人人都得对一遍
现在能彻底看懂探针 5 没展开的那个 N² 了。
注意力的第一步(点积打分)是这样的:每个 token 都要拿自己的 Q,去和所有 token 的 K 算一次点积。 注意是「所有」——不是只看邻居,是全员对照。
N 个 token,每个都要算 N 次点积(跟所有人算一遍,含自己)
→ 总共 N × N = N² 次点积
序列长度一涨,计算量不是线性涨,是平方涨:
| 序列长度 | 注意力点积次数 |
|---|---|
| 100 个 token | 100 × 100 = 1 万次 |
| 1 万个 token | 1 亿次 |
| 100 万 token | 1 万亿次 |
序列翻 10 倍,计算量翻 100 倍。这就是探针 5 讲过的那个让上下文窗口不能无限大的「原罪」——「100 个字两两算就是 1 万次」,记住这个口径,N 个 token 两两算 = N×N 次。
为什么必须全员对照、不能偷懒只看邻居?因为信息可能隔得很远。「小明去了很远的银行」里,「银行」要直接看到句首的「小明」才能判断这是金融机构还是河岸——中间隔多少 token 都得能直线关联。注意力能做到任意两个 token 直接对上眼,这正是它取代老一代 RNN(循环神经网络)的关键优势。代价就是人人都得对一遍,于是 N²。

多头注意力——同时盯几种关系
光一套 Q/K/V 不够用。一句话里的关系不止一种:有语法关系(主谓宾)、有指代关系(「他」指代谁)、有长程依赖(句首设定、句末提问)。一套注意力头很难同时把这些都学好。
所以实际的大模型用的是多头注意力(multi-head attention):把 Q/K/V 拆成好几套,每套叫一个「头」,各学一种关系模式,并行算各自的注意力,最后把结果拼起来。
打个比方,读一句话时,你脑子里同时有好几个「频道」在工作:一个频道盯语法、一个频道盯指代、一个频道盯语义关联。多头注意力就是把这个并行读句子的过程显式拆开。每个头独立算一遍,最后汇总。这属于注意力机制本身的扩展,不改三步流程,只是多跑几路。
头数具体多少是模型自己定的。比如 GLM-5.2 用的是 64 个头(这个数字来自它公开的 config,探针 5 的素材里拆过)。每个头独立地学一种「谁该关注谁」的模式,64 个头叠起来,模型就能同时捕捉几十种不同的语言关系。头数越多,模型「看一句话的角度」越丰富,代价是算力和参数也跟着涨。
多个头之间是并行的,各自算各自的注意力、互不干扰,最后把结果拼起来送回给模型继续处理。
KV Cache——为什么越答越快
最后接上探针 5 讲过、但没展开的 KV Cache。
探针 5 说:模型每生成一个字,都要把整个窗口从头「看」一遍。如果每次都真的从头算所有 token 的 K 和 V,那生成一句话要重算无数遍,慢到没法用。
所以有个工程优化叫 KV Cache:把每个位置算出来的 K 和 V 存起来,下一次直接拿来用,不重算。
具体是分两阶段跑的:
阶段 1 Prefill(预填充):处理你的输入
一次性把输入的所有 token 算一遍
→ 每个位置的 K 和 V 算出来,存进 KV Cache
阶段 2 Decode(解码):一个字一个字蹦
每生成一个新 token:
- 用新 token 的 Q,和 Cache 里所有历史 K 算点积
- 按权重混合历史 V,得到新 token 的更新向量
- 新 token 自己的 K/V 也存进 Cache
- Q 用完就扔
这里有个关键设计:K 和 V 要存,Q 要扔。 为什么?因为下一次生成时,是「新的 Q 来查历史的 K/V」——历史的 K 还要被未来的 Q 反复查,所以得留着;V 是别人要取走的信息,也得留。而 Q 是「当前这个 token 在找什么」,每个新 token 的 Q 都不一样,老 Q 不会再被任何人查,存着没复用价值,所以用完即弃。
这个设计把「重复计算」换成了「存储复用」。代价是 KV Cache 会占内存(探针 5 讲过,窗口越长,存的越多,撑爆显存就是「忘事」的根源),但换来的是生成速度——这也是为什么你发一大段话给 AI,第一句回得慢(prefill 在算所有 K/V 填缓存),后面越答越快(缓存放那儿了,decode 直接复用)。

这篇挖到了什么
一个「注意力到底在算什么」的疑问,底下连着这些:
- Q/K/V 三角色:每个 token 拿 Query 找谁匹配、用 Key 自报家门、用 Value 携带实际信息
- 三步流程:点积算相关性 → softmax 归一化 → 加权求和 V
- N²:全员两两算,序列一长平方爆炸(100 字 1 万次,1 万字 1 亿次)
- 多头注意力:拆成多套头并行,各学一种关系
- KV Cache:K/V 存起来复用、Q 用完即弃,换来「越答越快」
记住一句话就够:注意力本质是「按相关性分配注意力」——和你问题相关的上下文,权重高、被认真读;无关的,权重低、几乎被忽略。模型不是逐字精读整段,而是在做相关性筛选。
下一篇是另一个总成:注意力只是 Transformer 里的一个零件,Transformer 整体长什么样、注意力怎么和 FFN、残差、LayerNorm 拼到一起,下回拆。