1. 先说结论:大语言模型其实是个"超级接龙游戏"
如果你只用一句话向别人解释大语言模型(LLM)是什么,我会说:它是一个不断预测"下一个词"的系统。这句话听起来简单到有点侮辱智商,但请允许我把它说完——所有你看到的惊艳能力,写诗、编程、解数学题、模拟对话,全部建立在这个看似朴素的机制之上。
我在刚接触LLM的时候,也犯过同样的错误:总以为模型内部有一套复杂的推理引擎,或者某种"理解"机制在驱动。但当你把GPT系列、开源社区的各类模型拆开看,绕来绕去都会回到同一个地方——next token prediction(下一个词元预测)。Transformer结构再精巧,最终目标也只是为了让这个预测变得更准。
这个认知转变非常重要。因为一旦你接受"LLM=接龙"这个设定,很多困惑都会迎刃而解:为什么模型会生成编造的答案?因为它只是在接龙,而不是在查询数据库。为什么同样的模型在不同温度下表现差异巨大?因为接龙时选择的随机性不同。为什么上下文窗口有长度限制?因为模型在接龙时能参考的前文长度是固定的。
这篇文章我就以这个核心认知为主线,把next token prediction和transformer结构彻底讲透。没有数学公式堆砌,没有故作高深,我会用尽量直白的话,配合我在实际使用和微调模型过程中积累的经验,把这两个概念讲明白。适合以下人群阅读:刚开始接触LLM的开发者、想深入理解模型原理的学生、以及那些已经用了一段时间API但始终觉得"隔了一层"的从业者。
2. next token prediction到底在预测什么
2.1 从"概率分布"开始理解
很多人第一次接触LLM时会被"神经网络""参数""嵌入"这些词吓住,但next token prediction的核心其实是一个很朴素的统计问题:给定一段前文,下一个词是什么?
比如你输入"今天天气",模型内部会计算一个概率分布,可能的结果是:
- "不错"——概率0.3
- "很好"——概率0.25
- "怎么样"——概率0.2
- "有点"——概率0.15
- 其他所有可能性——剩余概率
模型最后输出的是这个概率分布,而我们看到的文字,是从这个分布中采样得到的结果。
这里有一个很多人没意识到的重要事实:大语言模型本质上不"认识"文字,它只对"词元"(token)做运算。一个词元可能是完整单词、半个单词、甚至一个标点符号。模型的工作就是读入一串词元,然后从词表中挑选下一个最合适的词元。
我在训练一个小型模型做实验时,观察过一个很有趣的现象:当输入的上下文足够充分时,概率分布会非常尖锐(某个候选词的概率接近1),模型表现得像是"确信"答案;但上下文信息不足时,概率分布会变得平坦,模型开始"犹豫",这时候就会输出一些含糊的、来回绕的内容。这个观察对调试prompt很有帮助——当你觉得模型"答非所问"时,很多时候不是你问错了,而是上下文里提供的信息不足,导致概率分布太平坦。
2.2 为什么"预测下一个词"能带来智能
这是最容易被质疑的一点:一个只会接龙的系统,凭什么能写代码、做推理?我自己在深入理解这个机制后,得出的答案是:智能不是设计出来的,而是被"强制"出来的。
想象一下,如果你被要求预测一本推理小说的下一个词,你需要什么能力?首先你得理解前面所有的情节铺垫,你得知道每个角色之间的关系,你得掌握作者的行文风格,甚至要推测故事发展的内在逻辑。当一个系统被训练去预测海量文本中的下一个词时,它被迫学会了这些过程中的所有"隐含知识"——语法规则、事实常识、逻辑链条、写作风格、世界模型。
这就是为什么模型参数中实际存储的不是词频表,而是一个高度压缩的"世界模型"。OpenAI的研究者在一次展示中演示过:如果让模型预测"这个房间里有一把椅子,椅子的颜色是___",模型能答对,因为它从大量训练文本中学会了"椅子"和"颜色"之间的关联,虽然它从未"亲眼见过"椅子。
我经常用一个类比来说明这一点:next token prediction就像让一个孩子在大量阅读后复述下一句话。孩子刚开始只会模仿,但读得足够多之后,他开始理解句子的结构、语义的连贯性、甚至故事中的因果关系。这个"被迫理解"的过程,恰好就是LLM产生智能的路径。
2.3 采样、温度与"创造力"的真相
理解了概率分布之后,你就会明白为什么同一个模型可以被调成"严谨模式"或"创意模式"——关键在于采样策略。
在推理时,模型计算完概率分布后,不会直接把概率最高的词元输出(那样会得到非常死板、重复的文本),而是根据概率分布进行采样。这时候有一个关键参数叫温度(temperature):
- 温度趋近于0:采样基本等同于选择最高概率的词元,输出变得保守、确定
- 温度较高(如1.0):采样更随机,低概率词元也有机会被选中,输出变得多样、有"跳跃性"
这个参数直接影响所谓的"创造力",但其实它只改变了采样的随机程度,并没有改变模型内部的任何知识。
我在实际项目中的经验是:写代码任务最好把温度调低(0.1-0.3),因为代码需要精确性;写营销文案或头脑风暴时把温度调高(0.7-1.0),让输出更丰富。但要注意,温度过高会导致模型胡言乱语,本质上是因为它开始选择那些概率很低的词元,偏离了合理的语言模式。理解了这一点,你就不再会觉得"温度是个玄学参数",它完全可以用概率采样的逻辑来解释。
3. Transformer结构:让"接龙"能力飞升的关键
3.1 为什么循环神经网络不够用了
在transformer出现之前,处理序列数据(也就是文本)的主流方案是循环神经网络(RNN)。RNN的思路是"一个一个地读词",每读一个新词就更新一个"隐藏状态",这个状态试图携带前面所有信息的压缩摘要。
但RNN有个致命问题:它必须串行处理序列,无法并行计算,训练速度极慢。更麻烦的是,随着时间的推移,早期信息会在状态传递中逐渐丢失,导致模型"忘记"很久以前的内容。这就好比让你复述一篇长文,读到最后时已经想不起来第一段讲了什么。
Transformer结构的革命性在于它抛弃了"按顺序读"的思路,改为同时看整个序列。它不是按时间顺序逐个处理词元,而是把整句话的所有词元一次性输入到一个并行计算的架构中,让每个词元都能直接和所有其他词元交互。这个设计的选择直接解决了两个问题:并行训练效率大幅提升,序列中远距离的信息依赖也不再受距离限制。
3.2 自注意力机制:让每个词"看"所有词
Transformer的核心组件叫自注意力(Self-Attention),它的作用可以这样理解:当模型处理某个词时,它会计算这个词和句子中其他所有词之间的"关联权重",然后根据这些权重来聚合其他词的信息。
举一个具体的例子。处理"小明把苹果放在桌上,因为他觉得___"这句话时,模型要预测"觉得"之后的内容,需要知道"他"指代的是谁。自注意力机制会计算"他"和"小明"之间的高关联权重,于是"小明"的信息被共享给"他";同时"苹果""桌上"这些词也会贡献空间信息。通过这种方式,模型在预测下一个词时,实际上是在利用整个句子的全部信息,而不是像RNN那样只能依赖一个逐渐衰减的压缩状态。
我做的第一个自注意力可视化实验给我留下的印象非常深:把attention权重画出来之后,你会发现模型在处理动词时,总是倾向于关注它的主语和宾语;处理代词时,总是倾向于关注它指代的名词。这本应该是语言学家的研究对象,却在训练过程中被神经网络自己"发现"了,这不是巧合,而是预测下一个词这个任务的必然要求。
3.3 QKV机制:自注意力的实际计算逻辑
自注意力的实现细节中,最常被提到的就是**查询(Query)、键(Key)、值(Value)**这三个概念——它们通常被简称为Q、K、V。
可以用图书馆借书来理解这套机制:
- Query代表"我要找什么"
- Key代表"每本书的主题标签"
- Value代表"书的内容"
当模型处理一个词元时,它会先生成这个词元对应的Query向量,然后用这个Query去和序列中所有其他词元的Key做匹配计算——这个匹配分数决定了"哪些信息值得关注"。匹配之后,模型根据分数对Value向量做加权求和,得到当前词元的"增强表示"。
在这个机制中,匹配分数通常通过"点积相似度"计算,再除以向量维度的平方根做缩放。为什么要缩放?因为当向量维度较大时,点积结果会变得非常大,导致softmax后的注意力权重过于尖锐,不利于训练稳定性。这个细节我在面试候选人和带新人时经常考——能主动说出这个缩放原因的,说明对机制的理解比较扎实。
3.4 多头注意力:不同视角的并行关注
实际工程中的transformer不会只用一组QKV,而是会使用多头注意力。直观地说,一个头可能专门关注"语法依赖关系",另一个头可能关注"语义相似性",还有一个头可能关注"位置相邻关系"。
比如在上面那个"小明放苹果"的例子中,一个注意力头可能专注于代词与名词的指代关系,另一个头可能专注于动词与宾语之间的语义配合。模型通过多个注意力头并行捕获不同维度的关系,然后把各头的结果拼接起来,形成一个综合的、信息更丰富的表示。
"多头"这个设计被证明极其有效,但它的必要性并不是先验可知的——是一个在实践中被反复验证的经验性选择。我在尝试缩减某些维度来压缩模型时发现,减少头数会导致生成文本的连贯性明显下降,即使参数量变化不大。这说明多头注意力的价值不在于参数量,而在于它天然地提供了"分而治之"的并行建模能力。
3.5 位置编码:让模型知道"先来后到"
自注意力机制有个特点:它对序列中词元的顺序不敏感。如果把"小明打碎了花瓶"变成"花瓶打碎了小明",自注意力计算出的词元间关联权重完全一样——因为它们之间的两两关系没有变。但语义显然变了。
为了给模型注入顺序信息,transformer引入了位置编码。原始论文使用正弦和余弦函数的编码方式:不同的频率对应不同的位置,通过三角函数的叠加唯一标识每个位置。这个选择有一个不错的数学性质:任意两个位置的编码可以通过线性变换相关联,位置间的相对关系也能被模型捕获。
现代大模型通常改用可学习的绝对位置编码或旋转位置编码(RoPE),工程效果更好。特别是RoPE,它把位置信息直接编码进Query和Key的旋转角度中,让注意力分数自然地衰减远端位置的关联,这大大提升了模型处理长文本时的稳定性和外推能力。
你可能会疑惑:既然自注意力本来就能跨越任意距离关联信息,为什么还要额外分段地编码位置?我只能说,语言本身是强顺序的——"我打你"和"你打我"的区别只能靠顺序表达。Transformer既然把顺序信息的选择权交给了注意力机制,就必须为注意力提供位置线索,否则模型就只能假设所有词元完全无序了。
3.6 残差连接、归一化与前馈网络
多头注意力输出的结果,并不是直接送到下一层,而是经过一套固定的"加固流程":
- 残差连接:把输入加到输出上,即output = layer_input + attention_output。这样做的目的是给梯度提供高速公路,让深度模型(几十层甚至上百层)在训练时不容易梯度消失。
- 层归一化:对每一层的数据分布做标准化,保证激活值的尺度稳定,让训练更平滑。
- 前馈网络:对每个词元的表示做一次非线性变换,相当于对注意力整合后的信息进行"深度加工"。
这三者的组合看似繁琐,缺一不可。我在调优一个小模型时曾经试过去掉残差连接,结果模型在训练初期就出现了严重的损失震荡,根本训不动。这些结构不是理论推导出来的最优解,而是在无数实验中被留下、被验证的工程基石——每个组件的设计都有它应对的实际问题。
3.7 从编码器-解码器到仅解码器
一个值得注意的演进是:原始transformer是编码器-解码器结构,编码器负责读入源文本,解码器负责生成目标文本。这个结构非常适合机器翻译这类"转写"任务。
但现代的大语言模型几乎都采用了仅解码器结构。为什么?因为next token prediction任务本身只需要一个不断输出下一个词元的模块——你对模型输入一段文本,它自己就是"编码器",它输出的每个Token同时又在"解码"。这种简化带来了训练目标和模型架构的高度统一:一切只服务于"预测下一个词"这一个任务。
实际效果也证明了这个简洁设计的有效性。我在对比某些仅解码器和编码器-解码器模型在同一任务上的表现时发现,虽然编码器-解码器在翻译任务上有天然优势,但在开放域生成、对话、代码理解等任务上,仅解码器模型的表现更为灵活。因为它的建模目标更纯粹,不需要考虑"源文本"和"目标文本"的区分,任何输入都可以被看成"前文",预测输出就是"后文"。
从工程角度看,仅解码器结构也让部署和推理变得更简单:一个统一的生成循环,适用于所有任务类型。这也是为什么几乎所有主流开源模型(无论出自哪个团队)都不约而同地选择了这条路线。
4. 训练与推理:同一个机制下的两条岔路
4.1 训练阶段:一次性预测所有位置
训练时的next token prediction和推理时有一个关键区别需要特别注意:训练阶段是并行预测的,推理阶段是逐个生成的。
假设训练样本是"今天天气很好",模型在训练时会在内部看到完整句子(包括未来的词),然后让每个位置的输出都去预测它的下一个词——位置1预测位置2,位置2预测位置3,以此类推。这就是"Teacher Forcing"策略:训练时永远用真实的前文来预测后文,而不是用模型自己生成的词。
之所以要这样做,是因为并行可以大幅提升训练效率,同时给模型提供了大量训练信号——一句话,一次性产生多个预测任务,学习效率自然更高。但要注意的是,训练时的这种"全知视角"和推理时"只能看到自己已完成的部分"存在一种分布差异(业界叫exposure bias),这也是实际LLM生成质量与训练目标之间存在微妙差距的原因之一。
4.2 推理阶段:自回归生成,一次一个词
推理时模型进入自回归生成模式:先输入起始文本,得到一个预测结果和概率分布,采样出下一个词元,把它拼接到输入末尾,再作为新的输入进行一次前向计算,得到再下一个词元,如此循环。
这个过程看起来很美,但有一个工程上的大问题:每次生成新词都要对全部前文重新计算一遍关注,浪费严重。这也是为什么现代推理框架普遍采用KV Cache——把已经计算过的历史词元的Key和Value向量缓存起来,生成新词时只需计算新词元的注意力,而不是重新计算整体。这个优化是推理速度提升的关键因素,在实践中能让生成速度快几倍到十几倍。
我在调试一个本地部署模型的推理性能时,KV Cache的开与关对比下来,体验差异是决定性的。不夸张地说,没有KV Cache的transformer,在长对话场景中基本不适合实际部署。
4.3 上下文窗口与"长时记忆"的边界
最后一个绕不开的主题是上下文窗口。它定义了模型在进行next token prediction时最多能"看到"多长的前文。超过这个窗口的内容,模型是看不见的。
这个限制本质上是自注意力计算的复杂度决定的:每个词元需要对前面所有词元计算注意力,序列长度翻倍,计算量大约是平方倍增长。即便有KV Cache优化存储,算力消耗依然会随上下文长度快速上升。
更微妙的是"能看见"不等于"会注意"——即使上下文窗口内有足够信息,模型可能也不会有效地参考所有内容。很多文本摘要失败或信息遗漏的案例,根源不在模型"忘记",而在注意力权重分配的不均匀。我在做长文档问答时发现一个很实用的经验:关键信息如果要被模型准确发现,最好不要埋在长篇大论的中间位置,放在开头或结尾两端的被利用程度会显著更高。
5. 关于LLM的几句掏心窝子的话
如果你看到这里,应该已经对next token prediction和transformer结构有了较为完整的认知。最后我想根据自己的实际体会,再分享几个"明白了原理之后,工作方式会截然不同"的顿悟时刻。
第一,别再给LLM灌输"你要理解用户意图"这类废话。从原理上说,你的指令本身就是模型需要预测的前文的一部分。与其说"你要扮演一个资深律师",不如直接给出律师会看到的具体案件材料和问题——模型能从中提取的信息量,远远大于一个浮夸的角色设定。这是我在大量prompt调试后体会最深的一点:不要告诉模型"你是谁",让它直接从内容中判断该怎么做。
第二,复读机现象不是Bug,是概率分布的必然行为。模型在长文本生成中重复某个片段,通常是因为它陷入了概率的"局部高值"区域——重复循环词元的联合概率反而比跳出去更高。应对方法是调整采样参数(如repetition penalty),或者主动在prompt中引导模型走向新的方向。
第三,试图让一个LLM"100%准确"是违反它底层机制的。因为它的目标是预测最合理的下一个词,而不是查询事实。真实工程中需要把"知识记忆"和"推理生成"分开:需要事实准确性的部分,交给检索系统提供上下文;需要开放生成的部分,才交给LLM发挥。这是我维护生产级应用时最核心的原则。
如果你是从零开始接触这个领域,我建议你自己动手部署一个几亿参数的小模型玩一玩——不是为了追求效果,而是为了亲手感受"接龙"这个机制在不同参数配置下的行为差异。理论说得再多,都不如亲手看到一次概率分布变成文字的过程来得深刻。这东西的门槛比你想的低,但认知转变带来的收益,比你想的高得多。