第2章 大语言模型原理与工程化基石《AI Agent 开发平台资深技术专家 & AI Agent 应用架构师 & CTO 面试题库详解》
第2章 大语言模型原理与工程化基石
“所有大模型幻觉的本质,不是工程缺陷,而是概率拟合的宿命;理解这一点,是 Agent 架构师区别于调包侠的第一道分水岭。”
2.0 章首导读
本章是全书的地基。无论你是一名在 AI Agent 开发平台深耕多年的资深技术专家,还是一名在企业前线扛着交付压力的 AI Agent 应用架构师,抑或是一位需要在董事会里回答"我们到底用谁家模型、是否自主可控"的 CTO,你都绕不开一个根本命题:你必须真正理解大语言模型(LLM)的原理,才能在工程化层面做出正确决策。
很多人对 LLM 的理解停留在"调 API"的层次:传入一段 prompt,拿到一段回复,觉得这就是全部。这种理解深度,在 2023 年或许还够用,但在 2026 年的今天,当 Agent 系统开始承载政务审批、金融风控、医疗辅助决策等高风险任务时,停留在调 API 层次的工程师,注定会被淘汰。因为:
- 不懂得 Token 与计费模型,你无法压降 70% 的推理成本;
- 不懂得 Self-Attention 的本质,你无法理解为什么长上下文会出现"中间遗忘"现象;
- 不懂得 RLHF 与 DPO 的区别,你无法在模型选型时判断哪个基座更"听指令";
- 不懂得幻觉的概率本质,你无法设计出靠谱的 RAG + 工具调用架构来兜底;
- 不懂得 MoE 架构,你无法理解为什么 DeepSeek-V3 能用 1/5 的激活参数达到稠密模型的效果;
- 不懂得流式输出原理,你无法在 Agent 多轮编排中控制首字时延。
本章将带你从统计语言模型的源头出发,一路走到 Transformer、MoE、预训练三阶段、上下文窗口经济学、幻觉的概率推导、后训练对齐技术,最后落到面试题、选型对比和工程实践案例上。这是一章需要反复读三遍的章节——第一遍建立直觉,第二遍建立体系,第三遍建立判断力。
本章适合以下读者:
| 读者画像 | 核心关注点 | 本章对应章节 |
|---|---|---|
| 开发平台资深技术专家 | 后训练 SFT/RLHF/DPO、ASR/TTS 与 LLM 结合、流式输出 | 2.1-2.5, 2.8, 2.10 |
| AI Agent 应用架构师 | 模型选型、上下文管理、成本与时延权衡 | 2.4, 2.6, 2.7, 2.9, 2.11 |
| CTO / 技术负责人 | 模型供应链、自主可控、成本全局视角 | 2.6, 2.9, 2.11, 2.12 |
2.1 从统计语言模型到 Transformer:一段 40 年的技术长征
2.1.1 语言模型的本质:一句话的概率
语言模型(Language Model, LM)的核心定义极其简单:给定一段文字,计算这段文字出现的概率。 用数学语言表达:
P(w1, w2, ..., wn) = P(w1) × P(w2|w1) × P(w3|w1,w2) × ... × P(wn|w1,...,wn-1)
即:一段话的概率,等于每个词在前面所有词出现的条件下出现的概率的连乘。这个看似朴素到可笑的公式,却是过去 40 年自然语言处理领域所有技术演进的北极星——从 n-gram 到神经网络语言模型,从 RNN 到 Transformer,从 BERT 到 GPT,所有进步都是在更好地近似这个条件概率 P(wt|w1,…,wt-1)。
为什么这个公式如此重要? 因为一旦你能准确估计"给定前文,下一个词是什么"的条件概率分布,你就拥有了生成语言的能力——你只需从分布中采样或取最大概率的词作为输出,然后把它拼到上下文里,再预测下一个词,如此反复,就是"自回归生成"。今天所有 GPT 类大模型的生成机制,本质上就是这个循环。
金句:大语言模型不是"理解语言"的机器,而是"预测下一个 Token"的机器;但当你把"预测下一个 Token"这件事做到极致,涌现出的能力看起来就像理解——这就是涌现的魔法,也是幻觉的根源。
2.1.2 n-gram 时代:数词频的笨办法
1990 年代,语言模型的主流方法是 n-gram。其核心思想是:不要考虑太长的上下文,只看前 n-1 个词。比如 bi-gram(二元模型)只看前 1 个词:
P(wt|w1,...,wt-1) ≈ P(wt|wt-1) = count(wt-1, wt) / count(wt-1)
即在训练语料中数一数,"wt-1"后面跟"wt"出现了多少次,除以"wt-1"出现的总次数,就得到转移概率。这方法简单到可以用 Excel 实现,但问题也很明显:
- 数据稀疏:如果"wt-1, wt"这个组合在训练语料中没出现过,概率就是 0,整个句子的概率就坍缩为 0。解决方法是各种平滑技术(Good-Turing、Kneser-Ney 等),但终究是补丁。
- 上下文太短:bi-gram 只看 1 个词的上下文,tri-gram 看 2 个词,4-gram 看 3 个词……上下文越长,组合空间指数增长,语料再大也覆盖不了。
- 没有语义理解:n-gram 完全基于词频统计,它不知道"猫吃鱼"和"鱼吃猫"在语义上的区别——它只知道哪个在语料中出现更多。
2003 年,Bengio 等人提出了第一个神经网络语言模型(NNLM),用三层前馈神经网络学习词的分布式表示(Word Embedding),解决了 n-gram 的维度灾难问题。这是语言模型从"数词频"到"学语义"的关键转折。但 NNLM 用的是前馈网络,依然无法处理长序列——序列一长,输入维度就爆炸。
2.1.3 RNN/LSTM 时代:记住前文的尝试
1997 年,Hochreiter 和 Schmidhuber 提出了长短期记忆网络(LSTM),解决了普通 RNN 的梯度消失问题。LSTM 通过门控机制(输入门、遗忘门、输出门)来控制信息的保留与遗忘,能够处理较长的序列(几百个 Token)。
LSTM 语言模型的结构是:逐个 Token 输入,每一步更新一个隐状态 h_t,然后用 h_t 预测下一个 Token 的分布:
h_t = LSTM(x_t, h_{t-1})
P(w_{t+1} | w_1,...,w_t) = softmax(W × h_t + b)
LSTM 在 2015-2017 年间统治了 NLP 领域,机器翻译、文本分类、情感分析等任务都在用 LSTM 及其变体(Bi-LSTM、GRU 等)。但 LSTM 有一个致命缺陷:无法并行训练。因为 h_t 依赖 h_{t-1},必须按顺序逐个计算,无法像图像领域的 CNN 那样在 GPU 上大规模并行。这意味着训练一个大规模 LSTM 语言模型需要极长的时间。
此外,LSTM 的长程记忆能力仍然有限。虽然有门控机制,但在几百个 Token 之后,早期的信息仍然会被逐渐稀释。这就是所谓的"长程依赖"问题。
2.1.4 Transformer 的诞生:一次革命性的范式跃迁
2017 年 6 月,Google Brain 的 Ashish Vaswani 等人在 NeurIPS 上发表论文《Attention is All You Need》,提出了 Transformer 架构。这篇论文改变了 NLP 的一切——也改变了 AI 的一切。
Transformer 的核心创新只有一点:用 Self-Attention 替代 RNN 的循环结构,从而实现完全并行计算。 在 RNN 中,要计算第 100 个 Token 的隐状态,你需要先计算前 99 个 Token 的隐状态;而在 Transformer 中,所有 Token 的表示可以同时计算,因为每个 Token 都直接"看到"所有其他 Token(通过 Attention 机制)。
这听起来只是工程上的改进(并行 vs 串行),但其意义远超于此:
- 并行训练使得模型可以做得极大:GPT-3 有 1750 亿参数,BERT-base 只有 1.1 亿参数——如果没有并行训练,训练 1750 亿参数的 LSTM 在工程上几乎不可能(按当时的 GPU 算力,可能需要几十年)。
- 全局视野:RNN 只能通过隐状态间接"记住"前面的信息,而 Transformer 的每个 Token 可以直接attend到任意位置的 Token,信息通路是直接的,不存在"信息逐步稀释"的问题。
- 可扩展性:Transformer 的结构高度规整(堆叠相同的层、相同的 Attention Head),极其适合 GPU/TPU 的矩阵运算。这种规整性使得 Scaling Law 可以发挥作用——模型越大、数据越多、算力越多,效果就越好,且没有明显的饱和点。
金句:Transformer 之所以伟大,不是因为它"更聪明",而是因为它把语言建模从"串行记忆"变成了"并行全局视野"——这一个小小的改变,释放了 Scaling Law 的全部能量。
下面是一张从 n-gram 到 Transformer 的技术演进对比图:
╔══════════════════════════════════════════════════════════════════════════╗
║ 语言模型技术演进 40 年路线图 ║
╠══════════════════╦═══════════╦═══════════════╦══════════════════════════╣
║ 技术代际 ║ 年代 ║ 核心思想 ║ 致命局限 ║
╠══════════════════╬═══════════╬═══════════════╬══════════════════════════╣
║ n-gram ║ 1990s ║ 数词频统计 ║ 数据稀疏,无语义,上下文短 ║
║ NNLM(Bengio) ║ 2003 ║ 词向量+神经网络 ║ 前馈网络,无法处理长序列 ║
║ RNN/LSTM ║ 1997-2015 ║ 门控循环记忆 ║ 无法并行,长程依赖弱 ║
║ Seq2Seq+Attention║ 2014 ║ 编解码+注意力 ║ 编码器仍是RNN,瓶颈仍在 ║
║ Transformer ║ 2017 ║ 纯Self-Attn ║ (目前最优)算力消耗O(n²) ║
║ MoE Transformer ║ 2023+ ║ 稀疏专家路由 ║ 路由不稳定,训练复杂度高 ║
╚══════════════════╩═══════════╩═══════════════╩══════════════════════════╝
2.1.5 从 Encoder-Only 到 Decoder-Only:GPT 路线的胜利
Transformer 论文提出的是 Encoder-Decoder 架构(用于机器翻译),但后续的发展分化为三条路线:
- Encoder-Only(BERT 路线):只用 Transformer Encoder,适合"理解"类任务(分类、NER、相似度)。BERT 是典型代表,2018 年问世后横扫各种 NLP 基准。但 BERT 不是自回归的,不能直接生成文本。
- Encoder-Decoder(T5/BART 路线):保留完整 Encoder-Decoder 结构,用 text-to-text 框架统一所有 NLP 任务。T5 是典型代表,效果优秀但模型参数效率不如 Decoder-Only。
- Decoder-Only(GPT 路线):只用 Transformer Decoder,纯自回归生成。GPT 系列是典型代表。早期(2018-2020)被认为是"只会生成、理解不如 BERT"的路线,但随着模型规模增大,GPT-3 展现出了惊人的 few-shot 能力,证明了 Decoder-Only + 大规模 + 自回归预训练 是通向 AGI 的最优路径。
到 2024 年,Decoder-Only 已经成为绝对主流。GPT-4、Claude、Llama、Qwen、DeepSeek 等几乎所有主流大模型都采用 Decoder-Only 架构。BERT 路线的开创者 Google 也在 Gemini 系列中转向了 Decoder-Only(虽然官方说法是"原生多模态",但语言建模部分确实是 Decoder-Only)。
金句:BERT 教会了模型"理解",GPT 教会了模型"生成";但当模型足够大时,生成即理解——这就是为什么 Decoder-Only 最终赢了。不是因为 Decoder-Only 架构更优,而是因为自回归生成是语言建模最自然的任务形式,它天然支持 Scaling Law 的无限扩展。
2.1.6 Scaling Law:大模型世界的"物理定律"
2020 年,OpenAI 的 Jared Kaplan 等人发表了论文《Scaling Laws for Neural Language Models》,提出了大模型领域的"物理定律":
Loss(N, D, C) ≈ A / N^α + B / D^β + C / C^γ + L_inf
其中:
N = 模型参数量
D = 训练数据量(Tokens)
C = 计算量(FLOPs)
α, β, γ ≈ 0.5 左右(幂律指数)
L_inf = 不可约损失(数据本身的熵)
这个公式的含义是:Loss 随参数量、数据量、计算量的增加,呈幂律下降,且没有明显的饱和点。 也就是说,只要持续投入更多参数、更多数据、更多算力,模型就会持续变好——这就是"大力出奇迹"的理论基础。
DeepMind 的 Hoffmann 等人在 2022 年进一步提出了 Chinchilla 定律,指出当时大多数模型"过度参数化、训练不足":在给定计算预算下,最优策略是让参数量和数据量同步增长,比例约为 1:20(即 1 个参数对应 20 个 Token)。这个发现直接导致了 Llama-2 等模型采用"小模型+大数据"的训练策略,大幅降低了训练和推理成本。
金句:Scaling Law 不是一条建议,而是一条物理定律——在它被打破之前(即出现明确的饱和点之前),你做任何模型决策,都要先问自己:我的选择是否顺应了 Scaling Law?
2.2 Token、Embedding 与位置编码:大模型的"三原色"
2.2.1 Token:大模型的"原子"
大模型不直接处理文字,它处理的是 Token。Token 是文本的最小切分单元,介于"字符"和"词"之间。英文中,一个 Token 通常对应 3-4 个字符(约 0.75 个单词);中文中,一个汉字通常对应 1-2 个 Token(取决于分词器)。
Token 化(Tokenization)的过程可以用下图表示:
╔══════════════════════════════════════════════════════════════╗
║ Token 化处理流程 ║
╠══════════════════════════════════════════════════════════════╣
║ ║
║ 原始文本: "大语言模型很强大" ║
║ │ ║
║ ▼ ║
║ 分词器(BPE/SentencePiece/Tiktoken) ║
║ │ ║
║ ├──→ "大" → Token ID: 162 ║
║ ├──→ "语言" → Token ID: 5237 ║
║ ├──→ "模型" → Token ID: 8291 ║
║ ├──→ "很" → Token ID: 99 ║
║ └──→ "强大" → Token ID: 11203 ║
║ │ ║
║ ▼ ║
║ Token ID 序列: [162, 5237, 8291, 99, 11203] ║
║ │ ║
║ ▼ ║
║ Embedding 查表: 每个 Token ID → 一个 d维向量 ║
║ [162] → [0.12, -0.34, 0.56, ..., 0.78] (d=4096) ║
║ [5237] → [0.45, 0.23, -0.67, ..., 0.11] (d=4096) ║
║ ... ║
║ ║
╚══════════════════════════════════════════════════════════════╝
目前主流的分词算法有三种:
| 分词算法 | 提出者 | 代表模型 | 特点 |
|---|---|---|---|
| BPE (Byte Pair Encoding) | Sennrich 2016 | GPT 系列、Llama | 基于字节频率合并,通用性强,子词切分 |
| WordPiece | Schuster 2012 | BERT | 类似 BPE 但基于似然,概率最大化 |
| SentencePiece | Google 2018 | T5、Qwen、ChatGLM | 直接在 Unicode 字符层面操作,语言无关 |
| Tiktoken | OpenAI 2023 | GPT-4/Claude | BPE 的高效实现,100MB/s 级别 |
Token 与成本的关系极其重要。 在 API 计费模型中,你输入的每一个 Token 都要付费,输出的每一个 Token 都要付费(且输出通常更贵)。举个例子:假设你用 GPT-4 调用一次,输入 1000 Token 的 prompt,输出 500 Token 的回复:
成本 = 输入Token × 输入单价 + 输出Token × 输出单价
= 1000 × $0.03/1K + 500 × $0.06/1K
= $0.03 + $0.03
= $0.06
看起来不多,但如果你的 Agent 每天调用 10 万次,一个月就是:
月成本 = $0.06 × 100000 × 30 = $180,000/月
这就是为什么 Token 经济学 是 Agent 架构师必须精通的领域(详见 2.6 节)。
2.2.2 Embedding:从离散到连续的魔法
Token ID 是一个离散整数(比如 5237),它本身没有任何语义信息——5237 和 5238 之间在语义上没有任何关系。Embedding 的作用是将这些离散整数映射到连续的高维向量空间,使得语义相近的 Token 在向量空间中也相近。
Embedding 矩阵 E 的形状是 [V, d],其中 V 是词表大小(通常 3-10 万),d 是隐藏维度(通常 2048-12288)。每个 Token ID 查表得到一个 d 维向量:
embedding(token_id) = E[token_id] # 形状 [d]
这个 Embedding 矩阵是模型在预训练中学到的。训练过程中,模型会发现"猫"和"狗"的 Embedding 向量很近(因为它们在相似上下文中出现),"猫"和"汽车"的 Embedding 向量很远。
一个有趣的事实:Embedding 向量的维度 d 随模型规模线性增长:
GPT-2 Small: d = 768 (124M 参数)
GPT-2 Medium: d = 1024 (355M 参数)
GPT-2 XL: d = 1600 (1.5B 参数)
GPT-3: d = 12288 (175B 参数)
Llama-2 70B: d = 8192 (70B 参数)
Llama-3 405B: d = 16384 (405B 参数)
为什么维度越大越好? 因为高维空间能容纳更丰富的语义信息。在 768 维空间中,"猫"和"老虎"可能被迫挤在一起;但在 16384 维空间中,它们可以在某些维度上分离(比如"家养/野生"维度、"体型"维度等)。当然,维度越大,计算和存储成本也越高,这是工程权衡。
2.2.3 位置编码:让模型知道"顺序"
Transformer 的 Self-Attention 机制本身是置换不变的(permutation-invariant)——也就是说,打乱输入 Token 的顺序,Attention 的输出(集合意义上)不变。这显然不行:"猫吃鱼"和"鱼吃猫"的 Token 集合相同,但语义完全相反。
为了让模型感知 Token 的位置信息,需要引入位置编码(Positional Encoding, PE)。位置编码的主流方案有:
-
绝对正弦位置编码(原版 Transformer):用不同频率的正弦/余弦函数生成位置向量,加到 Token Embedding 上。
PE(pos, 2i) = sin(pos / 10000^(2i/d)) PE(pos, 2i+1) = cos(pos / 10000^(2i/d))优点:无需学习,可以外推到训练时未见过的更长序列。缺点:绝对位置信息对长序列效果有限。
-
可学习位置编码(BERT/GPT-2 使用):为每个位置学习一个位置 Embedding,直接加到 Token Embedding 上。优点:灵活。缺点:不能外推——训练时最大 1024,推理时就不能超过 1024。
-
RoPE 旋转位置编码(Llama/GPT-NeoX 使用):通过对 Query 和 Key 向量施加旋转矩阵来注入位置信息。核心思想是:两个 Token 的相对位置关系通过它们 Query-Key 内积的变化来编码。RoPE 的最大优点是天然支持相对位置编码,且通过 NTK-aware 插值可以扩展到更长的上下文。
╔══════════════════════════════════════════════════════════════════╗
║ 三种位置编码方案对比 ║
╠════════════════╦═══════════╦════════════╦═══════════╦════════════╣
║ 方案 ║ 是否可学习 ║ 相对/绝对 ║ 外推能力 ║ 代表模型 ║
╠════════════════╬═══════════╬════════════╬═══════════╬════════════╣
║ 正弦编码 ║ 否 ║ 绝对 ║ 较弱 ║ 原版Transformer║
║ 可学习编码 ║ 是 ║ 绝对 ║ 无 ║ BERT, GPT-2 ║
║ ALiBi ║ 否 ║ 相对(线性偏置)║ 强 ║ BLOOM, MPT ║
║ RoPE ║ 否 ║ 相对(旋转) ║ 强(需插值) ║ Llama, Qwen ║
╚════════════════╩═══════════╩════════════╩═══════════╩════════════╝
金句:位置编码是 Transformer 的"空间锚点"——没有它,Self-Attention 就像一个失忆的审稿人,能看到所有稿件却分不清哪段在先哪段在后。RoPE 的旋转之美在于:它不是给每个位置贴一个标签,而是让每个向量在空间中旋转一个角度——相对位置就编码在两个向量的夹角差里。
2.3 Self-Attention 与 Multi-Head Attention 的本质
2.3.1 Self-Attention:会议室里的"全局偷听"
Self-Attention 是 Transformer 的心脏。理解它,就理解了 Transformer 的一半。
类比:想象一个会议室里有 n 个人,每个人代表一个 Token。在 Self-Attention 机制下,每个人同时"偷听"所有人(包括自己)的发言,然后根据相关性加权整合信息,更新自己的"认知"。 相关性高的人说的话权重高,相关性低的人说的话权重低,最终每个人都得到了一个"融合了全局信息"的新表示。
用数学语言表达,Self-Attention 的计算过程如下:
给定输入序列 X ∈ R^{n×d}(n个Token,每个d维)
1. 线性变换生成 Q, K, V:
Q = X × W_Q # Query (查询) 形状 [n, d_k]
K = X × W_K # Key (键) 形状 [n, d_k]
V = X × W_V # Value (值) 形状 [n, d_v]
2. 计算注意力分数:
S = Q × K^T / sqrt(d_k) # 形状 [n, n] — 每对Token的相关性
3. 归一化:
A = softmax(S, dim=-1) # 形状 [n, n] — 每行加和为1
4. 加权聚合:
Output = A × V # 形状 [n, d_v] — 融合后的新表示
这里的 Query/Key/Value 命名来自信息检索领域:
- Query(查询):当前 Token 想要找什么信息。
- Key(键):每个 Token 能提供什么信息(用于匹配)。
- Value(值):每个 Token 实际提供的信息内容。
通俗比喻:你在图书馆找书。你的需求是 Query,每本书的标签是 Key,书的内容是 Value。你用 Query 去匹配所有书的 Key,匹配度高的书权重高,然后把所有书的内容按权重加权求和,得到你需要的"综合知识"。
在 Self-Attention 中,Query、Key、Value 都来自同一个输入序列 X(这就是"Self"的含义——自己 attend 自己)。在 Cross-Attention(交叉注意力,用于 Encoder-Decoder 架构)中,Query 来自 Decoder,Key 和 Value 来自 Encoder。
╔══════════════════════════════════════════════════════════════════════╗
║ Self-Attention 计算流程图 ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ 输入 X [n×d] ║
║ │ ║
║ ├──→ ×W_Q ──→ Q [n×d_k] ║
║ ├──→ ×W_K ──→ K [n×d_k] ║
║ └──→ ×W_V ──→ V [n×d_v] ║
║ ║
║ Q × K^T ║
║ ┌────────────────┐ ║
║ │ S [n×n] │ ← 注意力分数矩阵 ║
║ │ S_ij = Q_i·K_j│ (Token i 对 Token j 的关注程度) ║
║ └───────┬────────┘ ║
║ │ ÷sqrt(d_k) ║
║ ▼ ║
║ ┌────────────────┐ ║
║ │ softmax(dim=-1)│ ← 归一化,每行加和为1 ║
║ └───────┬────────┘ ║
║ │ ║
║ ▼ ║
║ ┌────────────────┐ ║
║ │ A [n×n] │ ← 注意力权重矩阵 ║
║ └───────┬────────┘ ║
║ │ ║
║ ▼ × V [n×d_v] ║
║ ║
║ ┌────────────────┐ ║
║ │ Output [n×d_v] │ ← 每个Token融合全局信息后的新表示 ║
║ └────────────────┘ ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
为什么除以 sqrt(d_k)? 这是为了控制注意力分数的方差。当 d_k 较大时,Q·K 的内积值会很大,导致 softmax 梯度趋近于 0(进入饱和区),训练不稳定。除以 sqrt(d_k) 将方差控制回 1,使梯度保持健康。
2.3.2 Multi-Head Attention:并行多视角审稿
Single-Head Self-Attention 只有一组 Q/K/V 变换,这意味着每个 Token 只能从"一个视角"来attend其他 Token。但语言的关系是多维的——"猫吃鱼"中,"猫"和"吃"有主谓关系,"吃"和"鱼"有动宾关系,"猫"和"鱼"有语义关系。一个 Head 可能只能捕捉一种关系。
Multi-Head Attention(MHA)的解决方案:同时运行多组 Self-Attention,每组用不同的参数,最后拼接结果。 类比:一间会议室里有多位审稿人,每人从不同角度(语法、语义、逻辑、风格)审稿,最后汇总各自的审稿意见。
数学表达:
MultiHead(X) = Concat(head_1, head_2, ..., head_h) × W_O
其中每个 head:
head_i = SelfAttention(Q = X×W_Q^i, K = X×W_K^i, V = X×W_V^i)
参数:
W_Q^i ∈ R^{d×d_k}, W_K^i ∈ R^{d×d_k}, W_V^i ∈ R^{d×d_v}, W_O ∈ R^{h×d_v × d}
通常 d_k = d_v = d / h
以 GPT-3(175B)为例,有 96 个 Attention Head,d = 12288,每个 Head 的维度 d_k = 12288/96 = 128。96 个 Head 各自计算 Self-Attention,然后拼接成 [n, 96×128] = [n, 12288] 的矩阵,再经过 W_O 线性变换回到 [n, 12288]。
╔══════════════════════════════════════════════════════════════════════╗
║ Multi-Head Attention 结构示意图 ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ 输入 X [n×d] ║
║ │ ║
║ ┌───────────────┼───────────────────┐ ║
║ │ │ │ ║
║ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ║
║ │ Head 1 │ │ Head 2 │ ··· │ Head h │ ║
║ │ Q,K,V │ │ Q,K,V │ │ Q,K,V │ ║
║ │ Attn │ │ Attn │ │ Attn │ ║
║ │[n,d_v] │ │[n,d_v] │ │[n,d_v] │ ║
║ └────┬────┘ └────┬────┘ └────┬────┘ ║
║ │ │ │ ║
║ └──────────────┼───────────────────┘ ║
║ │ Concat ║
║ ▼ ║
║ [n, h×d_v] ║
║ │ ║
║ × W_O [h×d_v, d] ║
║ │ ║
║ ▼ ║
║ Output [n×d] ║
║ ║
║ 类比: h 个审稿人从不同视角并行审稿,最后汇总意见 ║
║ Head 1: 语法关系 Head 2: 语义相似 Head 3: 指代消解 ... ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
一个关键洞察:Multi-Head Attention 的总计算量与 Single-Head(相同 d)相同,但表达能力更强。 因为 h 个 Head 各有 d_k = d/h 维,总维度 h × d_k = d,所以参数量和计算量不变,但多个 Head 可以学习不同的注意力模式,从多个视角建模序列内关系。
金句:Multi-Head Attention 的本质不是"更多注意力",而是"多视角注意力"——就像一个团队里需要法务、财务、技术三个视角的审稿人,单靠一个全能选手反而会漏掉细节。
2.3.3 Causal Mask:自回归的"防火墙"
在 Decoder-Only 模型(GPT 系列)中,Self-Attention 有一个关键约束:每个 Token 只能 attend 到它之前的 Token,不能 attend 到未来的 Token。 这是因为 Decoder 是自回归的——生成时从左到右逐个预测,如果训练时允许看到未来 Token,就是"作弊"。
实现方式是在注意力分数矩阵 S 上施加一个下三角掩码(Causal Mask):
Mask 矩阵(下三角为0,上三角为-∞):
┌ ┐
│ 0 -∞ -∞ -∞ ... -∞ -∞ │
│ 0 0 -∞ -∞ ... -∞ -∞ │
│ 0 0 0 -∞ ... -∞ -∞ │
│ ... │
│ 0 0 0 0 ... 0 -∞ │
│ 0 0 0 0 ... 0 0 │
└ ┘
S + Mask 后再 softmax:
-∞ 的位置 → softmax 后权重为 0
→ 未来 Token 的注意力权重为 0 → "看不到未来"
这个 Causal Mask 是 Decoder-Only 模型和 Encoder-Only 模型(如 BERT)的核心区别之一。BERT 用的是双向 Attention(所有 Token 互相可见),适合理解任务;GPT 用的是 Causal Attention(只看过去),适合生成任务。
2.3.4 Attention 的计算复杂度:O(n²) 的诅咒
Self-Attention 的计算复杂度是 O(n² × d),其中 n 是序列长度,d 是隐藏维度。这是因为注意力分数矩阵 S 的形状是 [n, n],需要计算 n² 个点积。
这个 O(n²) 复杂度是大模型长上下文的"阿喀琉斯之踵":
序列长度 n 注意力矩阵大小(n²) 显存占用(d=4096, fp16)
1,000 1M ~8 MB
4,000 16M ~128 MB
16,000 256M ~2 GB
65,000 4.2B ~33 GB
128,000 16.4B ~131 GB
1,000,000 1 Trillion ~8 TB !!!
当上下文从 4K 扩展到 128K,注意力矩阵的显存从 128MB 暴涨到 131GB——这就是为什么长上下文模型的训练和推理都极其昂贵,也是为什么各种"高效 Attention"方案层出不穷:
| 方案 | 复杂度 | 核心思想 | 代表实现 |
|---|---|---|---|
| 标准 Attention | O(n²) | 全局精确注意力 | 原版 Transformer |
| Sliding Window | O(n×w) | 局部窗口注意力 | Mistral (w=4096) |
| FlashAttention | O(n²) | IO 优化(不减少FLOPs) | FlashAttention-2/3 |
| Linear Attention | O(n) | 核函数近似 | Performer, Linformer |
| Sparse Attention | O(n×√n) | 稀疏注意力模式 | Longformer, BigBird |
| Ring Attention | O(n²) | 多卡环形分块 | Llama-3 1M 上下文 |
金句:Attention 的 O(n²) 复杂度,是大模型世界的"光速限制"——在突破它之前(或绕过它),长上下文永远是一个奢侈品,而非标配。FlashAttention 没有降低 FLOPs,它降低的是 HBM 读写次数——有时候,工程的突破不在于算得更快,而在于少去读写。
2.4 MoE 架构:稀疏激活的工程奇迹
2.4.1 为什么需要 MoE
Scaling Law 告诉我们:模型越大,效果越好。但"大"带来了一个致命问题:推理成本随参数量线性增长。 一个 700B 的稠密模型,每次前向传播都要激活全部 700B 参数,推理成本极高。
MoE(Mixture of Experts,混合专家)架构的核心思想是:用一个大模型的总参数量来获得更好的表达能力,但每次推理只激活其中一部分参数(稀疏激活),从而在不增加推理成本的情况下提升模型质量。
打个比方:稠密模型像一个"全科医生",什么病都自己看;MoE 模型像一家"综合医院",有眼科、内科、外科、骨科等多个科室(专家),每次来了病人,先由"分诊台"(Router/Gating)判断该去哪个科室,然后只有对应科室的医生出动,其他医生休息。
╔══════════════════════════════════════════════════════════════════════╗
║ MoE 架构原理图 ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ 输入 Token Embedding ║
║ │ ║
║ ▼ ║
║ ┌─────────────────┐ ║
║ │ Router (门控网络) │ ← 一个小的线性层 ║
║ │ W_gate [d, E] │ E = 专家数量 ║
║ └────────┬────────┘ ║
║ │ ║
║ gate_scores = softmax(X × W_gate) ║
║ [score_1, score_2, ..., score_E] ║
║ │ ║
║ 选出 Top-K 个得分最高的专家(通常 K=2) ║
║ │ ║
║ ┌──────────────┼──────────────┐ ║
║ │ │ │ ║
║ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ... ┌────────┐ ║
║ │Expert 1 │ │Expert 2 │ │Expert 3 │ │Expert E│ ║
║ │(FFN层) │ │(FFN层) │ │(FFN层) │ │(FFN层) │ ║
║ │ 激活 ✓ │ │ 休眠 ✗ │ │ 激活 ✓ │ │ 休眠 ✗ │ ║
║ └────┬────┘ └────────┘ └────┬────┘ └────────┘ ║
║ │ │ ║
║ └───────────┬────────────┘ ║
║ │ ║
║ 加权融合输出 ║
║ out = Σ(gate_i × expert_i(x)) ║
║ │ ║
║ ▼ ║
║ MoE 层输出 ║
║ ║
║ 关键:总参数量 = E × 单专家参数,但每次只激活 K 个专家 ║
║ → 表达力≈大模型,推理成本≈小模型 ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
2.4.2 MoE 的关键参数与代表模型
MoE 架构有几个关键参数:
- 总专家数 E:整个模型有多少个专家。DeepSeek-V3 有 256 个,Qwen2-MoE 有 60 个。
- 激活专家数 K:每次推理激活几个专家。通常 K=2 或 K=8。
- 稀疏比例 E/K:总专家/激活专家。比例越高,理论上的"性价比"越高。
- 共享专家(Shared Expert):有些 MoE 设计(如 DeepSeek-V3)保留少量"共享专家",每次都激活,用于处理通用知识,减少路由噪声。
| 模型 | 总参数 | 激活参数 | 专家数(E) | 激活数(K) | 稀疏比 |
|---|---|---|---|---|---|
| Mixtral 8×7B | 46.7B | 12.9B | 8 | 2 | 4× |
| DeepSeek-V2 | 236B | 21B | 160 | 6 | 26.7× |
| DeepSeek-V3 | 671B | 37B | 256 | 8 | 32× |
| Qwen2-57B-A14B | 57B | 14B | 64 | 8 | 8× |
| GPT-4(推测) | ~1.8T | ~220B | ~16 | ~2 | ~8× |
金句:DeepSeek-V3 用 671B 总参数、37B 激活参数,达到了接近 GPT-4 的效果——这就是 MoE 的魔法:用"人口基数"换"上场人数",用大水库的容量换小水管的流量。
2.4.3 MoE 的工程挑战
MoE 在理论上很美,但工程实现有一堆难题:
- 负载均衡问题:如果 Router 总是把 Token 送到少数几个专家,其他专家就"饿死"了,训练效率低下。解决方案是加辅助损失(auxiliary loss)来惩罚不均匀的分配,或用 Expert Choice 路由让专家反向选择 Token。
- 通信开销:在多卡训练中,不同专家分布在不同 GPU 上,Token 需要跨卡路由(All-to-All 通信),通信开销很大。
- 推理批效应:MoE 推理时,每个 Token 只激活 K 个专家,如果 batch size 小,每个专家的计算量不饱和,GPU 利用率低。需要通过 continuous batching 等技术来提高吞吐。
- 路由坍缩:训练过程中,Router 可能陷入局部最优,总是选择同样的几个专家。这是 MoE 训练不稳定的常见原因。
金句:MoE 不是免费的午餐——你用稀疏激活换来了低成本推理,但也换来了路由不稳定、通信开销和训练复杂度的三重诅咒。工程能力不够的团队,训 MoE 比训稠密模型难十倍。
2.5 预训练-指令微调-RLHF 三阶段:从"读万卷书"到"听指挥"
2.5.1 三阶段总览
大模型的生命周期分为三个阶段,就像一个人的成长:
╔══════════════════════════════════════════════════════════════════════╗
║ 大模型训练三阶段:从"读万卷书"到"听指挥" ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ 阶段1: 预训练 (Pre-training) ║
║ ───────────────────────────── ║
║ 类比: 一个人从小到大读了万亿字的书籍 ║
║ 目标: 学习语言规律和世界知识 ║
║ 数据: 海量无标注文本(网页、书籍、论文、代码) ║
║ 规模: 数万亿 Tokens ║
║ 成本: 数百万到数千万美元(GPU 集群运行数月) ║
║ 产出: 基座模型(Base Model),会"续写"但不会"对话" ║
║ ║
║ ──────→ Base Model 可以做"续写"但不懂"听指令" ──────→ ║
║ ║
║ 阶段2: 指令微调 (SFT - Supervised Fine-Tuning) ║
║ ───────────────────────────── ║
║ 类比: 给这个人上课,教他"问什么答什么" ║
║ 目标: 学会遵循指令,以问答形式输出 ║
║ 数据: 数万到数十万条(指令, 回答)对 ║
║ 规模: 数万到数十万条样本 ║
║ 成本: 数百到数千美元(单卡到几十卡,几小时到几天) ║
║ 产出: 指令模型(Instruct Model),会对话但可能不够安全/好用 ║
║ ║
║ ──────→ Instruct Model 会对话但风格/安全性未优化 ──────→ ║
║ ║
║ 阶段3: 人类偏好对齐 (RLHF / DPO) ║
║ ───────────────────────────── ║
║ 类比: 让这个人实习,有师傅打分反馈,逐步改进行为 ║
║ 目标: 使输出更安全、更有用、更符合人类偏好 ║
║ 数据: 人类标注的偏好对(A好于B) ║
║ 规模: 数万到数十万条偏好数据 ║
║ 成本: 数千到数万美元(训练+标注) ║
║ 产出: 对齐模型(Aligned Model),可以安全上线 ║
║ ║
║ ──────→ Aligned Model = 可上线的 ChatGPT/Claude/Qwen ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
2.5.2 阶段一:预训练——读万卷书
预训练是大模型成本最高、耗时最长的阶段。以 GPT-3 为例:
- 数据: 3000 亿 Token(WebText2、Common Crawl、书籍、Wikipedia)
- 参数: 1750 亿
- 算力: 约 3.14 × 10²³ FLOPs
- GPU: V100 × 1024 张,训练约 34 天
- 成本: 估算约 1200 万美元(按 2020 年云 GPU 价格)
预训练的目标函数极其简单:下一个 Token 预测(Next Token Prediction, NTP):
L = -Σ log P(w_t | w_1, ..., w_{t-1})
即:给定前 t-1 个 Token,预测第 t 个 Token 的对数似然的负值。在全部训练语料上求和(或分 batch 求平均),就是预训练的损失函数。
这个损失函数的精妙之处在于:它不需要任何人工标注——互联网上现成的文本就是训练数据,每个 Token 的"正确答案"就是它在语料中的下一个 Token。这就是为什么预训练可以用"万亿级"数据——因为数据是免费且无限的。
预训练出来的 Base Model 有一个特点:它会"续写"但不会"对话"。比如你给它输入"中国的首都是",它会续写"北京,人口约 2100 万,位于华北平原……“——它在续写一篇关于中国的文章,而不是在回答你的问题。如果你给它输入"请帮我写一首关于春天的诗”,它可能会续写"请帮我写一首关于夏天的诗 请帮我写一首关于秋天的诗……"——因为它没学过"问答"的格式。
金句:Base Model 是一个读过万亿字书籍的"书呆子"——知识渊博但不会对话。SFT 是教他学会"一问一答"的礼仪,RLHF 是教他学会"说人爱听的话"。三个阶段,缺一不可。
2.5.3 阶段二:指令微调(SFT)——学会听指挥
SFT(Supervised Fine-Tuning)的目标是让 Base Model 学会以"问答"形式输出。方法很简单:收集一批高质量的(指令, 回答)对,用监督学习的方式继续训练模型。
SFT 的数据格式通常是 ChatML 格式:
<|im_start|>system
你是一个有帮助的AI助手。
<|im_end|>
<|im_start|>user
请解释什么是量子计算。
<|im_end|>
<|im_start|>assistant
量子计算是一种利用量子力学原理...
<|im_end|>
SFT 的损失函数仍然是 Next Token Prediction,但只在 assistant 部分计算 loss(user 和 system 部分不参与 loss 计算,因为模型不需要学习"生成用户的问题"):
L_SFT = -Σ_{t ∈ assistant_tokens} log P(w_t | w_1, ..., w_{t-1})
SFT 的关键不在算法,而在数据质量。OpenAI 在 InstructGPT 论文中发现:少量高质量的 SFT 数据(几千条)效果优于大量低质量数据(几万条)。这就是"数据质量 > 数据数量"的原则。
SFT 数据的来源通常包括:
- 人工编写:雇佣专业人员编写高质量的指令-回答对。成本高但质量最高。
- 开源数据集:如 OpenOrca、Alpaca、ShareGPT 等。免费但质量参差不齐。
- 合成数据:用更强的模型(如 GPT-4)生成问答对,用于训练小模型。如 Alpaca 就是用 GPT-4 生成的 5.2 万条数据微调 Llama-7B。
- 领域数据:针对特定领域(医疗、法律、金融)收集或构造的问答对。
2.5.4 阶段三:人类偏好对齐(RLHF)——说人爱听的话
SFT 之后的模型已经能对话了,但它的回答可能:
- 不够安全:用户问"怎么制造炸弹",它可能直接回答。
- 不够有用:用户问"帮我写代码",它可能写了一段不能运行的代码。
- 风格不佳:回答冗长、跑题、或者语气不当。
RLHF(Reinforcement Learning from Human Feedback,人类反馈强化学习)的目标是:通过人类偏好反馈,让模型的输出更"好"——更安全、更有用、更符合人类偏好。
RLHF 的经典流程(InstructGPT/ChatGPT 方案)分为三步:
╔══════════════════════════════════════════════════════════════════════╗
║ RLHF 三阶段流程图 ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ Step 1: 训练奖励模型 (Reward Model, RM) ║
║ ─────────────────────────────────── ║
║ ║
║ SFT模型 ──→ 对同一个prompt生成多个回答(K个) ║
║ │ ║
║ ▼ ║
║ 人类标注员对K个回答排序: A > B > C > D ║
║ │ ║
║ ▼ ║
║ 训练奖励模型: 给定(prompt, response),输出一个标量奖励分 ║
║ 损失: L_RM = -log[exp(r(x,y_w)) / (exp(r(x,y_w)) + exp(r(x,y_l)))] ║
║ (y_w = 更好的回答, y_l = 更差的回答) ║
║ ║
║ ┌────────────────────────────────────────────────────┐ ║
║ │ Reward Model: 输入(prompt, response) → 输出分数 │ ║
║ │ 通常用SFT模型初始化,把最后一步的LM head换成标量输出│ ║
║ └────────────────────────────────────────────────────┘ ║
║ ║
║ Step 2: 用 PPO 强化学习优化策略模型 ║
║ ─────────────────────────────────── ║
║ ║
║ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ║
║ │ Policy Model│────→│ 生成回答 │───→│ Reward Model │ ║
║ │ (待优化的LLM)│ │ │ │ 打分 │ ║
║ └──────────────┘ └──────────────┘ └──────┬───────┘ ║
║ ↑ │ ║
║ │ ┌──────────────┐ │ ║
║ │←──更新策略 │ PPO 算法 │←──────────────┘ ║
║ │ │ 最大化奖励 │ ║
║ │ └──────────────┘ ║
║ │ │ ║
║ │ ┌──────────────┐ ║
║ │ │ Reference Model│ ← 冻结的SFT模型 ║
║ │ │ KL散度约束 │ → 防止策略偏离太远 ║
║ │ └──────────────┘ ║
║ │ │ ║
║ │ ┌──────────────┐ ║
║ └────────── │ KL Penalty │ ← β × KL(π || π_ref) ║
║ └──────────────┘ ║
║ ║
║ Step 3: 迭代 Step 2 直到收敛或奖励不再增长 ║
║ ║
║ 目标函数: ║
║ max E[r(x,y)] - β × KL(π_θ || π_ref) ║
║ 第一项: 最大化奖励(让回答更好) ║
║ 第二项: KL约束(不要偏离SFT模型太远,防止reward hacking) ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
RLHF 的核心难点:
- Reward Hacking(奖励黑客):模型可能学会"骗"奖励模型,输出一些 Reward Model 给高分但实际不好的回答。比如 Reward Model 可能偏好长回答,模型就拼命写长文,不管对不对。
- KL 散度约束的作用:为了防止 Reward Hacking,RLHF 引入了一个 KL 惩罚项,限制策略模型不能偏离 SFT 模型太远。这就像给实习生一个规矩:“你可以改进,但不能偏离基本功太远。”
- 训练不稳定:PPO 是一种 on-policy 强化学习算法,训练过程容易震荡。需要精细的超参调节(学习率、KL 系数 β、clip 范围等)。
- 标注成本高:人类偏好标注需要专业人员,成本约 $5-20/条,标注 10 万条就是 50-200 万美元。
金句:RLHF 的本质不是"教模型什么是对的",而是"教模型什么是人类偏好的"——偏好不等于正确,这也是为什么 RLHF 后的模型有时会"讨好"用户而非给出最准确的答案。
2.5.5 DPO:RLHF 的简化革命
2023 年,斯坦福大学的 Rafailov 等人提出了 DPO(Direct Preference Optimization),直接用偏好数据训练模型,不需要训练 Reward Model,也不需要 PPO 强化学习。DPO 的核心洞察是:最优的奖励函数可以解析地从策略模型中推导出来,因此可以跳过 Reward Model,直接用偏好数据优化策略模型。
DPO 的损失函数:
L_DPO = -log [ σ( β × (log π_θ(y_w|x)/π_ref(y_w|x) - log π_θ(y_l|x)/π_ref(y_l|x)) ) ]
其中:
y_w = 偏好回答(preferred)
y_l = 不偏好回答(rejected)
π_θ = 当前策略模型
π_ref = 参考模型(冻结的SFT模型)
β = 温度系数(控制偏离程度)
σ = sigmoid 函数
DPO 与 RLHF 的对比如下:
| 维度 | RLHF (PPO) | DPO |
|---|---|---|
| 是否需要 Reward Model | 是,需要单独训练 | 否,直接从策略模型推导 |
| 是否需要强化学习 | 是,PPO 算法 | 否,普通的分类损失 |
| 训练稳定性 | 差,PPO 容易震荡 | 好,类似于 SFT 的训练体验 |
| 训练成本 | 高(4个模型同时在显存中) | 低(2个模型:策略+参考) |
| 效果 | 略好(理论上限更高) | 接近RLHF(实际差距很小) |
| 工程复杂度 | 高 | 低 |
| 适合场景 | 大厂有充足资源 | 中小团队、快速迭代 |
到 2024-2025 年,DPO 及其变体(IPO、KTO、ORPO、SimPO)已经成为大多数开源模型对齐的首选方案。Llama-3、Qwen-2.5、DeepSeek-V3 等模型都采用了 DPO 或其变体进行后训练对齐。DeepSeek 还提出了 GRPO(Group Relative Policy Optimization),是 PPO 的简化版,去掉了 Critic 模型,用组内相对奖励来估计 baseline,在大模型推理能力训练(如 DeepSeek-R1)中表现优异。
金句:DPO 的伟大之处在于:它发现 RLHF 中的 Reward Model 和 PPO 都是"中间商",而中间商可以省掉——直接从偏好数据到策略优化,一步到位。这就像从"先翻译再润色"变成"直接用目标语言写作",少了一层转换,少了一层信息损失。
2.6 上下文窗口与长上下文:大模型的"工作记忆"
2.6.1 上下文窗口是什么
上下文窗口(Context Window)是指大模型一次推理能处理的最大 Token 数。它就像人的"工作记忆"——你能在脑子里同时记住多少信息,决定了你能处理多复杂的任务。
╔══════════════════════════════════════════════════════════════════════╗
║ 上下文窗口的演进历程 ║
╠══════════════╦═══════╦═══════════════════════════════════════════════╣
║ 模型 ║ 年代 ║ 上下文窗口 ║ 大约可容纳 ║
╠══════════════╬═══════╬═══════════════════════════════╬═════════════╣
║ GPT-2 ║ 2019 ║ 1,024 Token ║ 约 3页A4纸 ║
║ GPT-3 ║ 2020 ║ 2,048 Token ║ 约 6页 ║
║ GPT-3.5 ║ 2022 ║ 4,096-8,192 ║ 约 12-24页 ║
║ GPT-4 ║ 2023 ║ 8,192-32,768 ║ 约 24-96页 ║
║ Claude-2 ║ 2023 ║ 100,000 ║ 约 300页 ≈ 1本书║
║ GPT-4-Turbo ║ 2023 ║ 128,000 ║ 约 375页 ║
║ Gemini-1.5-Pro║ 2024 ║ 1,000,000 ║ 约 3000页 ≈ 10本书║
║ Llama-3.1 ║ 2024 ║ 131,072 ║ 约 390页 ║
║ Claude-3.5 ║ 2024 ║ 200,000 ║ 约 600页 ║
║ Gemini-2.0 ║ 2025 ║ 2,000,000+ ║ 约 6000页 ≈ 20本书║
╚══════════════╩═══════╩═══════════════════════════════╩═════════════╝
2.6.2 长上下文的工程挑战
扩展上下文窗口不是简单地把 max_seq_len 参数调大就行,它涉及一系列工程挑战:
- Attention 的 O(n²) 复杂度:如前所述,标准 Attention 的计算和显存随序列长度平方增长。128K 上下文的注意力矩阵是 4K 上下文的 1024 倍。
- 位置编码外推:如果模型训练时最长只见过 4K 序列,推理时给 128K 序列,位置编码会进入"未见过的区域",效果急剧下降。解决方案包括:
- NTK-aware 插值:对 RoPE 的频率做非线性插值,让高频部分保持原样(精细位置),低频部分压缩(粗略位置)。
- YaRN(Yet another RoPE extensioN):NTK 的改进版,Llama-3 用此方案扩展到 128K。
- 渐进式训练(Progressive Training):先在 4K 上训练,再逐步扩展到 32K、128K,让模型逐步适应长序列。
- 中间遗忘(Lost in the Middle):即使模型支持 128K 上下文,研究表明模型在长文本中,对开头和结尾的信息记忆较好,对中间的信息容易遗忘。这是 Attention 机制的一个已知偏置。
- 推理显存(KV Cache):长上下文推理时,KV Cache 会占用大量显存。128K 上下文、70B 模型的 KV Cache 约需 32GB 显存(详见 2.7 节)。
2.6.3 长上下文 vs RAG:永远的路线之争
一个永恒的架构问题是:当需要处理大量外部知识时,应该用长上下文(把所有知识塞进 prompt)还是用 RAG(检索增强生成,只塞相关片段)?
╔══════════════════════════════════════════════════════════════════════╗
║ 长上下文 vs RAG:架构路线对比 ║
╠═════════════════╦══════════════════════╦═════════════════════════════╣
║ 维度 ║ 长上下文(直接塞入) ║ RAG(检索增强) ║
╠═════════════════╬══════════════════════╬═════════════════════════════╣
║ 实现复杂度 ║ 低(直接拼prompt) ║ 高(需要向量库+检索+重排) ║
║ 知识更新成本 ║ 高(每次都要更新prompt)║ 低(只更新向量库) ║
║ 推理成本 ║ 高(每次付全部Token费) ║ 低(只付检索片段的Token费) ║
║ 知识规模上限 ║ 受上下文窗口限制 ║ 理论无限 ║
║ 信息精度 ║ 低(模型需自己"找") ║ 高(检索器精准定位) ║
║ 复杂推理 ║ 强(全局视野) ║ 弱(片段化,可能缺上下文) ║
║ 幻觉风险 ║ 中(有信息但可能记错) ║ 低(有明确出处) ║
║ 适合场景 ║ 少量文档深度分析 ║ 大规模知识库问答 ║
╚═════════════════╩══════════════════════╩═════════════════════════════╝
金句:长上下文和 RAG 不是二选一的关系,而是互补的——长上下文负责"深度理解少量文档",RAG 负责"广度覆盖大量知识",成熟的 Agent 系统永远是两者的融合:先 RAG 检索,再把检索结果放入长上下文中做深度推理。
2.7 幻觉的概率本质:LLM 是概率机器,必然幻觉
2.7.1 什么是幻觉
幻觉(Hallucination)是指大模型生成了看似合理但事实错误的内容。比如你问"林黛玉倒拔垂杨柳的故事出自哪里?“,模型可能回答"出自《红楼梦》第五回”——看似合理(林黛玉确实是《红楼梦》角色),但事实上"林黛玉倒拔垂杨柳"是网络恶搞梗,原作中根本没有这个情节。
幻觉是 LLM 在企业级应用中最大的信任障碍。一个会幻觉的模型,不能用于医疗诊断、法律咨询、政务审批等高风险场景。理解幻觉的本质,是 Agent 架构师设计兜底方案的前提。
2.7.2 从概率拟合演绎推导:为什么 LLM 必然幻觉
核心论证:LLM 的训练目标是 Next Token Prediction,即最大化 P(w_t | w_1, …, w_{t-1})。这个目标函数本身不包含"事实正确性"约束,只包含"统计似然性"约束。
详细推导:
-
LLM 学的是分布,不是事实:训练语料中,“巴黎是法国的首都"出现了 1000 次,“巴黎是中国的首都"出现了 0 次。模型学到的分布 P(巴黎|首都) 中,“法国"的概率远高于"中国”。但这只是统计规律,不是逻辑事实。如果训练语料中有足够的错误信息(比如网上有人说"巴黎是英国的首都”),模型也会学到一定概率的"英国”。
-
概率高 ≠ 事实对:即使"巴黎是法国的首都"的概率是 99.99%,模型在生成时仍有 0.01% 的概率输出错误答案——特别是在高温采样(temperature > 0)时。而且,对于训练语料中覆盖不足的事实,概率分布会更加平坦,错误概率更高。
-
长尾知识必然幻觉:训练语料是有限的,世界上的事实是无限的。对于训练语料中很少出现的事实(比如"某县某镇的某条路叫什么名字"),模型没有足够的统计证据,只能靠关联推理猜测——而猜测就可能错。
-
组合泛化必然幻觉:即使模型分别知道"A是B"和"B是C",也不保证它能正确推理出"A和C的关系"——因为 Next Token Prediction 不训练逻辑推理,只训练模式匹配。当需要多步推理时,每一步都有一个概率误差,误差累积导致最终结果出错。
-
指令与知识冲突时必然幻觉:当用户的问题前提是错误的(比如"林黛玉倒拔垂杨柳出自哪里"),模型可能不纠正前提,而是顺着错误前提"编造"一个看起来合理的答案——因为它学到的模式是"回答问题",而不是"质疑前提"。
金句:幻觉不是 bug,是 feature——LLM 本质上是一台"概率生成机",它的目标函数是"最可能的续写",不是"最正确的回答"。要求一台概率机器永远说真话,就像要求一个画家画出照片级精确的画作——他可以努力逼近,但本质上,画笔不是相机。
2.7.3 幻觉的分类与对策
| 幻觉类型 | 定义 | 典型案例 | 工程对策 |
|---|---|---|---|
| 事实性幻觉 | 生成与客观事实不符的内容 | “爱因斯坦生于1900年”(实为1879) | RAG + 事实核查 + 知识库约束 |
| 逻辑性幻觉 | 推理过程有逻辑错误 | “A>B, B>C, 所以 C>A” | CoT + 自我验证 + 多步推理验证 |
| 指令幻觉 | 不遵循用户指令 | 要求JSON格式但输出纯文本 | 结构化输出约束(JSON Mode) |
| 来源幻觉 | 编造不存在的引用/出处 | “根据Smith et al. (2023)…” | 引用验证 + RAG |
| 上下文幻觉 | 无视或曲解上下文信息 | 给了文档但回答与文档矛盾 | 上下文注入 + 引用标注 |
| 自我矛盾幻觉 | 同一回答中前后矛盾 | 前面说"是"后面说"不是" | 多轮自洽检查 |
2.7.4 Agent 架构师的防幻觉工具箱
作为 Agent 架构师,你不能指望模型自己不幻觉,你必须设计工程方案来兜底:
- RAG(检索增强生成):先从知识库检索相关事实,注入 prompt,让模型"看着资料回答"。
- 工具调用(Tool Use / Function Calling):让模型调用外部 API 获取实时数据,而非靠记忆。
- 结构化输出约束:用 JSON Mode / Constrained Decoding 强制模型输出结构化格式,减少自由发挥空间。
- 多模型交叉验证:用两个不同模型生成答案,比对一致性,不一致时触发人工审核或额外验证。
- 置信度估计:通过 logprob 或自洽性检查估计模型对答案的置信度,低置信度时拒绝回答或补充检索。
- 事实后验核查:用专门的 fact-checking 模型或规则引擎,对生成内容做事后核查。
- 人机协同(Human-in-the-Loop):高风险场景(如政务审批)设置人工审核环节,模型只做初筛。
金句:防幻觉不是消灭幻觉(那是不可能的),而是把幻觉控制在一个可接受的误差率内——就像自动驾驶不需要零事故才允许上路,而是要比人类驾驶员更安全。工程的意义,在于用不完美的零件构建足够可靠的系统。
2.8 Token 计费与成本模型:Agent 架构师的"财务报表"
2.8.1 Token 经济学基础
在 LLM API 计费模型中,成本由两部分组成:
总成本 = 输入Token成本 + 输出Token成本
= N_in × P_in + N_out × P_out
其中:
- N_in = 输入 Token 数(prompt + context + history)
- N_out = 输出 Token 数(模型生成的回复)
- P_in = 输入单价($/1K Token 或 $/1M Token)
- P_out = 输出单价(通常是输入的 2-3 倍)
为什么输出比输入贵?因为输入是一次性的矩阵乘法(可以高度并行),而输出是自回归的逐 Token 生成(每步依赖上一步,并行度低)。更关键的是,输出阶段需要维护 KV Cache,显存占用随序列长度增长,导致 GPU 利用率更低,单位成本更高。
2.8.2 主流模型价格对比(2025-2026 年)
以下价格仅供参考,实际价格以厂商官网为准:
| 模型 | 输入价格($/1M Token) | 输出价格($/1M Token) | 上下文窗口 | 备注 |
|---|---|---|---|---|
| GPT-4o | 2.50 | 10.00 | 128K | OpenAI 旗舰 |
| GPT-4o-mini | 0.15 | 0.60 | 128K | 高性价比 |
| GPT-4-Turbo | 10.00 | 30.00 | 128K | 旧旗舰 |
| Claude-3.5-Sonnet | 3.00 | 15.00 | 200K | Anthropic |
| Claude-3.5-Haiku | 0.80 | 4.00 | 200K | 轻量级 |
| Claude-3-Opus | 15.00 | 75.00 | 200K | Anthropic 旗舰 |
| Gemini-2.0-Pro | 1.25 | 5.00 | 2M | |
| Gemini-2.0-Flash | 0.075 | 0.30 | 1M | 极致性价比 |
| DeepSeek-V3 | 0.27 | 1.10 | 128K | 国产之光 |
| Qwen2.5-72B | 0.35 | 1.40 | 128K | 通义千问 |
| Llama-3.1-405B(自部署) | ~0.50(算力折算) | ~2.00 | 128K | 开源自部署 |
从上表可以看出:
- 价格差异巨大:最贵的 Claude-3-Opus 输出价格是最便宜的 Gemini-2.0-Flash 的 250 倍。
- 国产模型性价比突出:DeepSeek-V3 的价格只有 GPT-4o 的约 1/10,效果接近。
- 小模型/Flash 系列适合大规模调用:当你的 Agent 每天调用百万次时,$0.075/1M 和 $2.50/1M 的差距就是 $2400/天 vs $75/天。
2.8.3 Agent 系统的成本估算模型
一个 Agent 系统的单次任务成本,不只是"一次 API 调用"的成本,而是"整个任务链路所有 LLM 调用的成本之和":
C_task = Σ_i (N_in_i × P_in + N_out_i × P_out)
其中 i 遍历 Agent 执行任务过程中的所有 LLM 调用:
- 初始意图理解
- 工具选择
- 每一步推理/规划
- 工具调用结果的解读
- 多轮对话历史
- 最终回复生成
- 可能的自我反思/验证
一个典型的 Agent 任务可能涉及 5-20 次 LLM 调用,每次调用都包含不断增长的对话历史(因为 Agent 需要记住之前的步骤)。这意味着:
实际成本 ≈ 简单估算 × (5~20) × 历史膨胀因子(1.5~3)
这就是为什么很多团队在 POC 阶段觉得"LLM 成本可控",但上线后发现成本爆炸——因为他们只算了"一次调用"的成本,没算"一个完整任务链路"的成本。
金句:Agent 的成本不是一次 API 调用的成本,而是一条任务链路上所有调用的成本之和——这才是 CTO 视角下的真实账单。一个优秀的 Agent 架构师,必须在设计阶段就建好成本模型,否则上线即破产。
2.8.4 成本压降七板斧
基于以上分析,降成本的策略可以归纳为"七板斧":
- 模型分级路由(Model Routing):简单任务用小模型(GPT-4o-mini/Haiku),复杂任务才用大模型(GPT-4o/Sonnet)。用一个轻量分类器(甚至规则引擎)判断任务复杂度,路由到不同模型。可降成本 60-80%。
- Prompt 精简与缓存:删除 prompt 中的冗余信息,用 system prompt 缓存(OpenAI/Anthropic 都支持 prompt caching),减少重复输入成本。可降成本 30-50%。
- 上下文窗口管理:不要把完整对话历史每次都传入,用摘要 + 最近 N 轮的策略压缩历史。可降成本 40-60%。
- 输出长度控制:设置 max_tokens 限制输出长度,用 system prompt 指示"简洁回答"。输出 Token 更贵,控制输出比控制输入更有效。
- 批处理(Batch API):OpenAI/Anthropic 都提供 Batch API,50% 折扣,适合非实时场景。
- 自部署开源模型:对高频低复杂度任务,自部署 Llama/Qwen/DeepSeek 等开源模型,长期成本可降至 API 的 1/5-1/10。
- 结果缓存:对相同/相似 query 的结果做缓存(Semantic Cache),命中率 10-30% 可显著降本。
2.9 流式输出原理:首字时延与体验优化
2.9.1 为什么需要流式输出
大模型的生成是自回归的——逐个 Token 生成,每个 Token 依赖前序所有 Token。如果一个回复有 500 个 Token,非流式模式下用户需要等全部 500 个 Token 生成完才能看到回复,可能等 10-20 秒,体验极差。
流式输出(Streaming)的核心思想是:每生成一个(或几个)Token 就立即返回给前端,不等全部生成完。 这样用户几乎可以即时看到回复开始出现,然后像打字一样逐步显示完整内容。
2.9.2 流式输出的技术实现
流式输出通常基于 SSE(Server-Sent Events)协议实现:
╔══════════════════════════════════════════════════════════════════════╗
║ 流式输出技术架构 ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ 客户端(前端) API Gateway LLM 推理服务 ║
║ ║
║ ┌──────────┐ ┌──────────┐ ┌──────────┐ ║
║ │ EventSource│←─SSE──│ 反向代理 │←─SSE──│ vLLM/TGI │ ║
║ │ (浏览器) │ 连接 │(Nginx等) │ 连接 │(推理引擎) │ ║
║ └──────────┘ └──────────┘ └──────────┘ ║
║ │ │ │ ║
║ │ 1.发起POST请求 │ │ ║
║ │────stream:true─────→│ 2.转发请求 │ ║
║ │ │───────────────────→│ ║
║ │ │ │ 3.逐Token生成 ║
║ │ │ │ ║
║ │ │ 4. SSE: data: tok1 │←───────────────────│
║ │ 5. SSE: data: tok1 │←───────────────────│ ║
║ │←───────────────────│ │ ║
║ │ │ │ 6. 继续生成 ║
║ │ 7. SSE: data: tok2 │ │ ║
║ │←───────────────────│←───────────────────│ ║
║ │ ... │ ... │ ... ║
║ │ │ │ 8. 生成完毕 ║
║ │ 9. SSE: data: [DONE]│ │ ║
║ │←───────────────────│←───────────────────│ ║
║ │ │ │ ║
║ │ 10.关闭连接 │ │ ║
║ ║
║ SSE 数据格式: ║
║ data: {"choices":[{"delta":{"content":"你"}}]} ║
║ data: {"choices":[{"delta":{"content":"好"}}]} ║
║ data: {"choices":[{"delta":{"content":",世界"}}]} ║
║ data: [DONE] ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
2.9.3 首字时延(TTFT)与每 Token 时延(TPOT)
流式输出的体验质量由两个关键指标决定:
- TTFT(Time To First Token,首字时延):从用户发送请求到看到第一个 Token 的时间。理想 < 1 秒,可接受 < 3 秒。
- TPOT(Time Per Output Token,每 Token 时延):生成阶段,每两个 Token 之间的间隔。人类阅读速度约 5-10 Token/秒,所以 TPOT < 200ms 时体验流畅。
影响 TTFT 的主要因素:
- Prompt 处理(Prefill)时间:输入 prompt 越长,prefill 越慢。因为 prefill 阶段需要对所有输入 Token 计算一次前向传播。
- 网络延迟:客户端到 API Gateway 到推理服务的网络往返。
- 队列等待:如果推理服务繁忙,请求需要排队。
- 模型大小:大模型的前向传播更慢。
影响 TPOT 的主要因素:
- 模型大小与解码效率:大模型每个 Token 的生成时间更长。
- KV Cache 大小:上下文越长,KV Cache 越大,每步 Attention 计算越慢。
- 批处理大小:并发请求多时,GPU 可以批量并行 decode,但单请求 TPOT 可能略增。
金句:流式输出的本质是"用体验换容忍度"——用户愿意等 15 秒看完整回复,但如果 15 秒内一个字都没出现,用户会觉得系统卡死了。流式输出让用户"看到 AI 在思考",这种心理上的"在场感"比实际速度更重要。
更多推荐


所有评论(0)