你可能不训练模型,但大概率已经在用它:接一个大模型 API、做一个知识库问答、算一次 token 账单、给上下文长度设一个上限。这些决策背后站着同一个东西——Transformer

这篇文章不推导公式,也不追求把论文讲全。它只回答一个问题:一个主要写 Java 后端的人,理解 Transformer 的哪些部分,能让自己在用大模型时少踩坑、少花冤枉钱、少做无效优化。

先用一句话把结论摆出来:Transformer 的本质是把「按顺序一步步算」换成了「一次性把所有位置两两算一遍」。它用一次矩阵乘法,把序列中任意两点的距离压缩成 1 步,代价是计算量随序列长度平方增长、推理时显存随长度线性增长。你后面会遇到的所有「贵、慢、上下文不够」的问题,几乎都能从这句话里找到根因。


一、它到底解决了什么问题

1.1 RNN 时代的三个结构性缺陷

在 2017 年之前,处理序列(句子、日志、时间序列)的标准解法是 RNN 及其改进版 LSTM。它们的共同点是一步一步递推:算完第 1 个词,才能算第 2 个词。

缺陷 本质原因 直观表现 后果
无法并行 第 t 步必须等第 t-1 步算完 一个句子里 512 个词,就得排 512 次队 GPU 再强也吃不满,训练慢到无法规模化成今天的样子
长依赖难学 信息要穿过几百次递推才能从开头传到结尾 像传话游戏,传的人越多,原意丢得越多 长句、长文档里远距离的关联学不到
信息瓶颈 整句话被压进一个固定长度的向量 不管原文多长,解码时只能看同一个摘要 长文本翻译质量断崖式下降

一个类比:RNN 像一个人在会议室里从头读到尾,边读边记笔记,但笔记本只有一页,写满了就得覆盖。 位置越靠前的信息,被覆盖得越彻底。

1.2 一个容易被忽略的前史

注意力机制不是 Transformer 发明的。2015 年 Bahdanau 等人为了缓解「信息瓶颈」,让 RNN 的解码器每一步都能回头看一眼编码器的全部状态——这就是最早的注意力。

Transformer 的历史贡献不是发明注意力,而是做了一个极端决定:既然注意力能直接建模任意两个位置的关系,那 RNN 是不是可以整个删掉?

删掉递推之后,剩下的计算全是矩阵乘法。矩阵乘法是 GPU 最擅长的事情。这就是标题《Attention Is All You Need》的字面意思,也是后面八年一切变化的起点。

对你的意义:你不必理解 RNN,但要知道「串行」和「并行」的区别决定了今天模型的能力边界。凡是需要严格按顺序、无法并行的计算,在大规模场景下都会被淘汰。


二、真正需要理解的几个机制

这一节只讲「理解了会对你有用」的部分。不讲梯度推导,不讲初始化理论。

2.1 Q/K/V:把它当成一次「带权重的搜索」

Transformer 里最容易被讲玄乎的就是 Q、K、V。其实它就是一个可微的检索过程,用图书馆找书来类比最清楚:

符号 图书馆类比 在做什么
Query(查询) 你心里的检索需求 当前这个 token「想问什么」
Key(键) 每本书封面上的标签、索引卡 每个 token「能被怎么找到」
Value(值) 书里的实际内容 每个 token「实际提供什么信息」
匹配分数 需求与标签的相似度 谁跟谁相关
注意力权重 按相似度分配注意力 归一化成 0 到 1 的权重
输出 按权重把所有书的内容混合起来 加权求和的结果

关键区别在于:它不是「命中一条返回一条」的硬检索,而是「按相似度给所有内容分配权重再混合」的软检索。 硬检索不可导、没法训练;软检索完全可导,所以模型能自己学会「该怎么提问、该怎么贴标签」。

对你的意义:这就是 RAG 排障时最有用的一个直觉。模型检索到的内容和它「真正注意到」的内容不是一回事——检索给你证据,注意力告诉你模型看没看那些证据。当你遇到「文档明明检索到了,模型却答错」时,问题往往出在注意力被别的内容分散了,而不是检索失败。

2.2 注意力:一行公式,四步操作

整个自注意力的核心就是下面这一行:

1
Attention(Q, K, V) = softmax( Q · Kᵀ / √d_k ) · V

拆成四步,每一步都有明确的工程含义:

步骤 做什么 要记住的点
① 打分 Q 乘以 K 的转置 算出「每对位置之间有多相关」,得到一个 n×n 的矩阵
② 缩放 除以 √d_k 数值稳定性修正,见下
③ 归一化 沿最后一维做 softmax 每行和为 1,即「这个位置把注意力怎么分配出去」
④ 聚合 权重乘以 V 得到加权混合后的新表示

第 ② 步为什么必须缩放? 不用记推导,记结论就够:向量维度越大,点积的数值就越大;数值一大,softmax 就会输出接近「非 0 即 1」的结果——注意力全都压在一个位置上,其余全是 0。这样一来模型就没法「综合考虑多个信息源」,训练也会因为梯度接近 0 而停滞。除以 √d_k 就是把数值拉回正常范围。

一个实用的副产品:注意力权重是一个 n×n 的矩阵,天然记录了「每个位置看了哪些位置」。这是大模型可解释性最主要的抓手——想知道模型凭什么这么答,看它的注意力分布比看参数有用得多。

2.3 多头注意力:同时用多套视角看同一句话

单个注意力头只能产出一套「平均化」的关联关系,会把不同的模式互相抹平。多头的做法是并行跑好几套独立的注意力,最后拼起来。

单头 多头(一般 8 到 128 个头)
视角 一套 多套,每个头在不同子空间里关注不同模式
计算量 n² × 维度 基本相同(每个头维度按比例缩小)
参数量 相同量级 相同量级
实际观察 有的头盯前一个词、有的盯句法结构、有的负责代词指代

注意那个「基本相同」:多头不是「多花几倍算力买效果」,它买到的是表示能力,成本几乎不变。这是 Transformer 设计里性价比最高的一处。

2.4 位置编码:顺序必须专门喂进去

自注意力有一个反直觉的性质:它对位置是置换等变的。把一句话的词序打乱,输出只是跟着打乱,数值完全不变。因为它只关心「谁和谁相关」,不关心「谁在前」。

所以不加位置信息,Transformer 就是一个词袋模型。 位置必须显式注入。方案演进如下:

方案 做法 现状
正弦固定编码(2017 原论文) 用三角函数生成绝对位置,加到词向量上 论文实测与可学习编码几乎无差别
可学习绝对位置 每个位置一个可训练向量 有最大长度上限,超出就无定义
相对位置偏置 在注意力分数上加与距离有关的偏置 T5 等使用
RoPE 旋转位置编码 让注意力内积只依赖两个位置的相对距离 当今大模型的主流(Llama 3 等)
ALiBi 按距离对注意力分数线性衰减 外推性好,但采用度较低

对你的意义:上下文长度不是「把参数调大」就能变长的能力。它靠位置编码方案 + 训练时的长度扩展共同决定——这也解释了为什么很多模型要专门做「长上下文版本」,以及为什么超出训练长度的部分表现会明显退化。

2.5 残差连接与归一化:为什么能堆到 100 多层

每个子层外面都套了一层「残差 + 归一化」。两句话说明白:

  • 残差连接(把输入直接加到输出上):给梯度留了一条直通车道。没有它,网络一深梯度就衰减,6 层都难训。
  • 归一化:把每层的数值范围拉回稳定区间,防止层数一多数值就漂移。

几个需要知道的名词:

名词 一句话解释 现状
LayerNorm 沿特征维归一化,与 batch 大小无关 原论文用的是它
BatchNorm 沿 batch 维归一化 不适合序列:变长序列与 padding 会污染统计量
Pre-LN 先归一化再进子层 现代主流,训练更稳,可以不用预热
Post-LN 先算子层再归一化 原论文方案,训练更脆弱,需要预热
RMSNorm LayerNorm 的简化版,去掉去均值步骤 现代主流,更快,质量相当

对你的意义:这些细节不会影响你怎么调 API,但它们解释了「为什么模型能堆到 100 多层、几千亿参数」。稳定性工程做得好,规模才上得去。

2.6 FFN:参数和「知识」的真正大头

每个位置还会独立过一个两层的小型全连接网络(FFN),中间维度会扩张 3 到 4 倍。这里有一个多数人不知道的事实:

模型 注意力占参数比例 FFN 占参数比例
原论文 base(d=512) 33.3% 66.7%
Llama 3 8B 19.2% 80.8%
Llama 3 405B 17.9% 82.1%

(这两行不是估算,是我按官方配置逐项算出来的,见 5.3 节。)

有研究把 FFN 解释成一层可微的键值记忆:前半部分负责「识别出什么模式」,后半部分负责「识别到之后往输出里写什么」。模型中存储事实性知识的主要位置就是 FFN,这也解释了为什么知识编辑技术针对的都是 FFN 层。

对你的意义:模型的参数量主要买的是知识容量,而不是「推理能力」。这个结论直接支撑了后面 5.7 节的决策——补充知识优先用 RAG(便宜、可更新、可溯源),改变说话方式和输出格式才考虑微调。


三、和 RNN 的对比:为什么它赢了,代价是什么

3.1 三个维度看差异

原论文用三个维度对比了几种层类型,这张表是理解所有取舍的钥匙:

维度 RNN Transformer
每层的计算量 随序列长度线性增长,但系数大 随序列长度平方增长
必须串行的步骤 与序列长度同阶(一步一递推) 常数级(整层一次矩阵乘法)
信息传递路径 从开头传到结尾要经过整条链 任意两点都是 1 步直达

三句话解读:

  1. 路径短意味着长距离依赖好学——这是 Transformer 质量更高的根本原因。
  2. 串行步骤少意味着能并行——这是它能被训练到几千亿参数的根本原因。
  3. 计算量是平方的意味着序列一长就贵——这是今天所有长上下文问题的根源。

3.2 平方复杂度:什么时候开始变贵

以 d=512 为例,把两者的计算量算出来(这里只列数量级,理解趋势即可):

序列长度 谁更省 差距
128 注意力更省 约 4 倍
256 注意力更省 约 2 倍
512 打平 转折点
1024 RNN 更省 约 2 倍
2048 RNN 更省 约 4 倍
8192 RNN 更省 约 16 倍
131072 RNN 更省 约 256 倍

规律:序列长度每翻一倍,注意力的成本翻 4 倍。 这就是为什么 8K 上下文和 128K 上下文的成本差距不是 16 倍,而是 256 倍(算力维度)。

所以在 512 个 token 以内(大多数句子、段落),注意力在算力上并不亏;一旦超过,账就开始难看。今天所有的长上下文优化——分块计算、稀疏注意力、滑窗注意力、状态空间模型——本质都是在跟这个平方项讨价还价。

3.3 推理阶段的账要重算:KV Cache

训练时 Transformer 完胜,但推理时的成本结构完全反转,这段是工程上最要命的:

维度 RNN 推理 Transformer 推理
需要保留的状态 常数:一个固定长度的隐状态 KV Cache,随序列长度线性增长
每步计算 矩阵乘向量 读取全部权重 + 全部缓存
显存压力 固定 随上下文长度和并发数线性增长
瓶颈 参数带宽 参数带宽 + 缓存带宽

KV Cache 是什么?自回归生成是一步一个 token 往外吐的。如果不做缓存,每生成一个新 token 都要把前面所有 token 的中间结果重算一遍,复杂度会从平方恶化到立方。KV Cache 就是把已经算过的键和值存下来复用——代价是显存占用随上下文长度线性增长。

用 Llama 3 8B 的配置实算一遍(fp16):

配置 每 token 8K 上下文 128K 上下文
假设不做优化(每个注意力头各存一份) 512 KiB 4 GiB 64 GiB
实际做法(分组共享,下节解释) 128 KiB 1 GiB 16 GiB
再加 8 路并发 128 KiB 8 GiB 128 GiB

这张表能读出三个直接可用的结论:

  1. 128K 上下文下,单个请求的 KV Cache 就有 16 GiB,和 8B 模型本身的权重差不多大。 「上下文从 8K 扩到 128K」在显存账单上不是多备一点,而是要多备一整套同量级的显存。
  2. 8 路并发就是 128 GiB,已经超出一张 H100(80 GB)。 也就是说,长上下文服务的并发上限,是被显存卡住的,不是被算力卡住的。
  3. 这解释了一个常见现象:为什么有些服务「短问题很快,长文档就很慢甚至排队」——不是模型变笨了,是显存不够、只能排队。

3.4 那 RNN 系什么时候仍然是对的

场景 更适合 原因
流式/实时(音频、传感器、边读边处理) RNN / 状态空间模型 状态固定,来一个 token 更新一次,不需要重算
超长序列(数十万 token) 状态空间模型 / 线性注意力 线性复杂度,绕开平方项
边缘设备、极低显存 RNN 或极小模型 没有 KV Cache,显存不随上下文增长
通用语言建模、大规模预训练 Transformer 及其混合变体 并行性 + 短路径 + 可扩展,三条无替代

结论:Transformer 不是「全面更优」,而是「在大规模通用场景下综合最优」。 它把长依赖从「优化难题」变成了「成本问题」——而成本问题通常比数学问题好解决。


四、三种编解码范式:决定你该调哪种模型

4.1 差别只在「谁能看谁」

Transformer 有三种用法,本质上是三种注意力可见性

注意力类型 谁能被看到 用在哪
编码器自注意力 全序列,双向 理解类任务
解码器自注意力 只能是已生成的部分(因果掩码) 生成类任务
交叉注意力 查询来自解码器,键值来自编码器 编码器和解码器之间的桥

三者共用同一个注意力函数,区别只在「谁被遮住」。所谓因果掩码,就是把每个位置右边的分数全部设为负无穷,确保模型在预测第 t 个词时看不到第 t 个词之后的内容——这是自回归生成能成立的前提。

4.2 三种范式对照

维度 Encoder-only Decoder-only Encoder-Decoder
擅长 理解、编码成向量 生成、续写 输入输出长度差异大的转换
训练目标 遮词还原 预测下一个 token 去噪还原
代表模型 BERT、各类 embedding 模型 GPT、Llama、DeepSeek 原始 Transformer、T5
典型用途 检索、分类、聚类、语义匹配 对话、写作、代码、Agent 翻译、摘要
你会怎么用到 搭 RAG 时的向量模型 你调的大模型 API 相对少见

这张表里最实用的一行是最后一行:

  • 你搭 RAG 用的 embedding 模型,几乎都是 Encoder-only。 它的产物是向量,不是文字,所以「让 embedding 模型回答问题」是方向性错误。
  • 你调的大模型 API,几乎都是 Decoder-only。 它天生是「给前缀、续写下去」,所有任务都要被你改写成「续写」的形式——这就是提示词工程存在的根本原因。

4.3 为什么大模型最终都收敛到 Decoder-only

原始 Transformer 是编码器-解码器结构,但今天几乎所有通用大模型都是 Decoder-only。这不是理论最优,而是工程上最省事:

理由 说明
目标统一 任何任务都能改写成「给前缀、续写」。翻译、分类、抽取共用一套目标函数,不用为每个任务设计结构
结构最简 只有一种注意力模式,没有编码器/解码器两套堆叠和交叉注意力,代码路径少、并行策略简单
推理最省 只有一套 KV Cache,且可以单调追加、天然支持前缀复用(系统提示词只算一次)
扩展最顺 加深、加宽、加数据就能按规律涨点,不需要额外设计
涌现了上下文学习 规模足够大时,模型能靠提示词里的几个示例学会新任务,不需要更新参数

一句话:Decoder-only 赢在工程,不是赢在理论。 它牺牲了双向注意力带来的表示效率,换来了极致的可扩展性。


五、大模型是怎么跑起来的

5.1 一次请求的完整流水线

下表是每一步「在干什么」和「对你的影响」:

步骤 在做什么 对你的影响
① 分词 把文本切成 token(子词),映射成数字 决定计费和上下文长度,见 5.2
② Prefill 一次性并行处理整个输入 输入越长,首字延迟(TTFT)越大
③ 写 KV Cache 把中间结果缓存下来 直接决定显存占用和并发上限,见 5.5
④ Decode 一个一个往外吐 token 决定吐字速度(TPOT),受显存带宽限制
⑤ 输出 logits 算出每个候选 token 的分数 词表越大,这一步越占显存
⑥ 采样 按策略挑出下一个 token 决定输出的稳定性和多样性,见 5.6
⑦ 循环 把新 token 追加后回到 ④ 整个链路是串行的,无法并行加速
⑧ 反分词 把 token 拼回文本 流式返回时要注意半个词被截断的问题

记住这个结构,后面调优就有方向了:「首字慢」是 prefill 的问题(输入太长),「吐字慢」是 decode 的问题(模型太大 / 显存带宽不够),「并发上不去」是 KV Cache 的问题。

5.2 token 与成本:为什么中文更贵

模型不认识「字」,只认识 token(子词)。不同模型的分词方案不同,中文、代码、JSON 的「字符数转 token 数」比例差异很大:

模型 词表大小
原论文(英德翻译) 约 37,000
BERT 30,522
GPT-3 约 50,257
Llama 3 论文称 128K
DeepSeek-V3 129,280

实际影响:同一个中文段落,在不同模型上可能相差 30% 以上的 token 数。这意味着

  • 按 token 计费时,换一个模型可能直接改变成本,不能只看单价;
  • 「上下文 128K」这个数字要换算成实际能放多少中文——按经验大约是 10 万汉字量级,但不同模型差异明显,上线前必须用真实业务文本实测
  • 存会话历史时按 token 而不是按字符来设阈值。

5.3 参数量与显存:自己算一遍就懂了

一个 Transformer 的参数量可以用几个简单规则算出来(现代大模型的配置):

1
2
3
4
每个注意力层  ≈ 2 × d²  +  2 × d × (KV 头数 × 每头维度)
每个 FFN 层 ≈ 3 × d × d_ff (门控结构需要三个矩阵)
每个词嵌入 ≈ 词表大小 × d
总参数 ≈ 层数 × (注意力 + FFN) + 嵌入 + 输出头

用这套规则去反推 Llama 3 的官方参数量,能精确到小数点后一位:

Llama 3 8B Llama 3 405B
每层注意力 41,943,040(19.2%) 570,425,344(17.9%)
每层 FFN 176,160,768(80.8%) 2,617,245,696(82.1%)
每层合计 218,103,808 3,187,671,040
乘以层数 × 32 = 6.98 B × 126 = 401.6 B
加嵌入与输出头 1.05 B 4.19 B
算出来 8.03 B 405.8 B
官方公布 8.03 B 405 B

对上了。这个练习的价值在于:你以后看到一个模型的配置表,就能自己估出它的部署成本,不用等别人告诉你。

部署一个模型需要多少显存?三部分相加:

部分 大小 说明
模型权重 参数量 × 每参数字节数 fp16 约 2 字节,int8 约 1 字节,int4 约 0.5 字节
KV Cache 见 5.5 节 随上下文长度和并发数线性增长,常常是真正的瓶颈
中间激活 与 batch 和序列长度有关 推理时通常占比最小

以 Llama 3 8B 为例:

精度 权重占用 能否放进单张 24 GB 消费级显卡
fp16 约 16 GB 勉强,但几乎没空间留给 KV Cache
int8 约 8 GB 可以,能留出上下文和并发的余量
int4 约 4 GB 宽裕

这也是量化技术存在的全部理由:它用很小的质量代价,把权重体积压到 1/2 到 1/4,从而让同样的显卡能跑更大的模型或更长的上下文。

5.4 Prefill 与 Decode:两种完全不同的性能特征

推理不是一个动作,而是两个特征相反阶段:

Prefill(处理输入) Decode(生成输出)
处理对象 整个提示词,可能几千 token 每次一个新 token
并行度 全并行 完全串行
瓶颈 算力 显存带宽
影响指标 首字延迟 TTFT 吐字速度 TPOT
优化方向 减少输入长度、分块预填充 量化、批处理、减少 KV Cache

Decode 为什么受带宽限制? 因为它每生成一个 token,都要把全部模型权重从显存里读一遍,却只做了极少的计算。实测推演:

模型(fp16) 权重体积 单 token 理论下限 单请求吞吐上限
Llama 3 8B 16.1 GB 约 4.8 ms 约 209 token/s
Llama 3 70B 141.2 GB 约 42 ms 约 24 token/s

(按 H100 的 3.35 TB/s 显存带宽估算,这是理论上限,实际还要打折。)

这张表说明三件事:

  1. 单请求的生成速度上限由显存带宽决定,和算力无关。 8B 模型在 H100 上的理论上限就是 200 token/s 左右,换更贵的卡也不会更快。
  2. 70B 的权重有 141 GB,单张 H100(80 GB)根本放不下,必须多卡切分或者量化到 int8/int4。
  3. 提高吞吐的唯一出路是批处理:权重读一次,服务多个请求。但批一开大,KV Cache 立刻成为新瓶颈。

对你的意义:如果一个服务的「吐字速度」达不到要求,加机器不如换更小的模型或量化;如果「首字延迟」达不到要求,先砍输入长度。

5.5 KV Cache:并发能力的真正上限

KV Cache 的大小可以用一句话概括:层数 × 缓存的键值头数 × 每头维度 × 序列长度 × 并发数 × 2(键和值各一份)

每一项都能优化,于是有了四代方案:

方案 做法 缓存规模 代表 代价
MHA 每个查询头各存一份键值 最大 原论文、BERT 显存压力最大
MQA 所有头共享一份 最小 PaLM、Falcon 质量有轻微下降
GQA 分组共享,折中 中等(常见 8 组) Llama 2/3 全系 基本无损
MLA 把键值压缩成低秩向量再缓存 最小(数量级下降) DeepSeek-V2/V3 实现复杂

GQA 的效果很直观:Llama 3 的查询头有 128 个,但只保留 8 组键值缓存——缓存直接压到 1/16,而质量几乎无损。这就是「为什么大家都用 GQA」的答案。

给你的三个可操作结论

  1. 评估长上下文能力时,不要只看「支持 128K」,还要问「在这个长度下能跑多少并发」——很多服务标称支持,实际并发只有个位数。
  2. 省显存的最有效手段通常是缩短输入,而不是换量化。因为 KV Cache 是按上下文长度和并发数线性叠加的,砍掉一半输入长度,等于白赚一倍并发。
  3. 前缀缓存(prompt caching)是性价比最高的优化之一:如果多个请求共享相同的系统提示词或长文档前缀,这部分只需计算一次,后续请求可以复用缓存。设计提示词时把固定的内容放前面、变化的内容放后面,能直接省掉重复的 prefill 成本。

5.6 采样参数:怎么调才不玄学

模型输出的是整个词表的概率分布,采样策略决定怎么从里面挑一个:

参数 作用 什么时候调
temperature 除以它再 softmax;越小越确定,越大越随机 抽取/分类类任务调到 0 到 0.3;创作类 0.7 到 1.0
top-p(核采样) 只在累积概率达到 p 的最小集合里采样 比 top-k 更自适应,通常比 top-k 更好用
top-k 只在概率最高的 k 个里采样 截断长尾,防止出现离谱词
重复惩罚 降低已出现 token 的分数 处理复读,但调太大会让输出变得不自然

最实用的经验做结构化抽取、分类、写代码时,temperature 直接设 0 或接近 0。 你要的是稳定复现,不是创造力。很多「模型输出格式不稳定」的问题,就是这么解决的。

5.7 补充知识该用哪一招

这是后端开发最常遇到的决策。三个选项不是互相替代,而是各有边界:

改提示词 RAG(检索增强) 微调
解决什么 输出格式、任务指令 补充知识、要求可溯源 固定风格、领域语感、特殊格式
知识更新 改文本即生效 改知识库即生效,分钟级 需重新训练,天级
成本 极低 中(存储 + 检索) 高(数据 + GPU)
可溯源 强,能给出引用原文 弱,知识混在参数里
适合 所有场景的第一步 知识密集、频繁更新的问答 风格与格式的一致性

决策顺序建议:先改提示词 → 不够就上 RAG → 还是不够(且问题是「说得不像」「格式总是跑偏」)才考虑微调。

一句总结:微调改变的是「怎么说」,RAG 补充的是「说什么」。 加上 2.6 节的结论(参数主要买的是知识容量),绝大多数企业知识问答场景,RAG 的性价比都远高于微调。

5.8 常见名词速查

看模型介绍时你会遇到一堆缩写,这张表一次说清:

名词 是什么 对你的影响
RMSNorm 简化版归一化,更快 只影响速度,不影响你怎么用
SwiGLU FFN 的门控激活方式 提升效果,是「现代模型标配」之一
RoPE 旋转位置编码,支持长上下文 决定长上下文能力上限
GQA / MQA / MLA 三种压缩 KV Cache 的方案 直接决定长上下文的并发和成本
FlashAttention 一种省显存、更快的注意力计算方式 不是近似算法,结果与标准算法等价
MoE(混合专家) 参数量很大但每次只激活一部分 总参数不等于部署成本,要看激活参数
Pre-LN 归一化的摆放位置 只影响训练稳定性
上下文长度 一次能处理多少 token(输入 + 输出) 直接决定成本、延迟和并发

关于 MoE 多说一句,因为它最容易误导预算评估:DeepSeek-V3 总参数 671B,但每个 token 只激活 37B。 部署时权重仍然要全部加载(671B),但计算量按 37B 算——所以它「能力接近超大模型,速度接近中等模型」,代价是显存占用高。


六、接进 Java 后端要注意什么

这一节是纯应用经验的归纳,和模型内部结构无关,但和前面所有机制都有关联。

关注点 建议做法 背后的原因
流式返回 用 SSE 逐 token 推给前端,不要等全文生成完 Decode 是串行的,等全文会让首字延迟等于总时长
超时设置 按「输出 token 数 × 单 token 时间」估算,不要沿用普通 HTTP 的 3 到 5 秒 生成是逐个 token 累积的,长回答天然耗时
限流维度 按 token 限流,不要只按请求数 一个 8 万 token 的请求和一个 50 token 的请求,成本差 3 个数量级
输入瘦身 会话历史做摘要裁剪,长文档做检索而不是全文塞 输入长度同时影响首字延迟、成本、并发三项
前缀复用 把固定内容(系统提示词、长文档)放前面,变化内容放后面 命中前缀缓存可以直接省掉重复的 prefill
并发控制 给长上下文请求单独排队,限制最大并发 KV Cache 是显存里的硬约束,超了就是 OOM 或排队
降级策略 准备好小模型/规则兜底,模型不可用时能降级 外部依赖 + 长耗时 = 必须考虑失败路径
可观测性 记录 token 数、首字延迟、吐字速度、重试次数 没有这些指标,成本和体验问题都无法定位
缓存边界 语义缓存要谨慎:相似问题可能答案不同 缓存命中错误比不缓存更伤用户体验
该不该用模型 能用规则、正则、检索解决的,不要上模型 大模型是最贵、最慢、最不确定的那个选项

一句总结:把它当成一个「慢、贵、不确定,但很聪明」的远程依赖来设计架构。 所有你对远程依赖做过的防护——超时、重试、熔断、降级、限流、缓存、监控——都需要再来一遍,而且阈值要重算。


七、总结

维度 RNN Transformer
核心操作 一步步递推 一次矩阵乘法,所有位置两两交互
能否并行 不能 能,这是它能做大的根本原因
长距离依赖 难学 好学,但从「优化难题」变成了「成本问题」
计算量 随长度线性增长 随长度平方增长
推理显存 固定 随上下文和并发线性增长
位置信息 结构自带 必须显式注入(现代用 RoPE)

六条可以直接拿去用的结论:

  1. 注意力就是一次带权重的软检索。 它同时解释了模型为什么有效,以及为什么 RAG 排障要看「模型注意到什么」而不只是「检索到什么」。
  2. 模型参数的大头在 FFN,主要在存知识。 所以补知识用 RAG,改风格才用微调。
  3. 三种范式对应三种用法:Encoder-only 出向量(你的向量模型)、Decoder-only 出文字(你调的大模型)、Encoder-Decoder 做长度差异大的转换。
  4. 首字慢、吐字慢、并发低是三件不同的事,分别对应输入长度、模型大小与显存带宽、KV Cache 占用,别混在一起优化。
  5. 显存账 = 权重 + KV Cache + 激活,其中 KV Cache 随上下文和并发线性增长,往往是真正的瓶颈。省显存先砍输入长度,其次才是量化。
  6. 温度调低能解决大部分「输出不稳定」的问题,在结构化抽取和代码场景尤其明显。

最后回到开头那句话:Transformer 把「按顺序一步步算」换成了「一次性两两算一遍」。 理解了这笔交易的收益(并行、可扩展、短路径)和代价(平方算力、线性显存),你在选模型、定上下文长度、估成本、排性能问题时,就有了判断依据,而不是只凭经验和传言。


参考