首页/Agent 核心/预训练、RLHF 与采样(KV Cache)
Agent 核心 · 第 04 章

预训练、RLHF 与采样(KV Cache)

第 3 章拼出了完整的架构,但一台随机初始化的模型只会输出乱码——把它变成能对话、能推理、能调用工具的助手,要经过一条两级流水线:预训练(学知识)+ 后训练(学做人)。这是模型的"前半生"。"后半生"则是每次你按下回车后…

约 18 分钟7,331 字12 个代码示例

第 3 章拼出了完整的架构,但一台随机初始化的模型只会输出乱码——把它变成能对话、能推理、能调用工具的助手,要经过一条两级流水线:预训练(学知识)+ 后训练(学做人)。这是模型的"前半生"。"后半生"则是每次你按下回车后发生的事:参数冻结,进入推理阶段,模型一个 token 一个 token 地把答案"吐"出来。本章把这两段一口气讲完——训练侧的预训练、SFT、RLHF/DPO、思维链、幻觉,推理侧的自回归循环、采样策略(温度到底在调什么)、K-V 缓存(为什么有"首 token 延迟"、为什么响应是逐字蹦出来的)。理解了这条完整链路,你就能解释日常开发中的一堆现象:为什么模型会编造事实、为什么换个问法结果天差地别、为什么"思维链"能提升效果。这是第一章「它是什么」的收官——原理的最后一块拼图,从下一章起,我们正式动手。

1. 预训练:读遍互联网

预训练的目标函数在第 1 章已经剧透过:预测下一个词。工程规模是这样的:

项 典型规模
数据 数万亿 token:网页、书籍、代码、论文
算力 数千张 GPU 跑数月
方法 第 2 章的梯度下降(工业级优化器 + 稳定技巧)

训练完成的产物叫基座模型(Base Model)。它的行为很"原始":你输入"中国的首都是",它接得很准;但你问"中国的首都",它可能接着补全"是哪个国家的问题吗?"——因为在语料里,这更像一个对话的开头。

基座模型的行为模式 = 互联网文本的续写统计

关键认知:预训练耗资巨大,但只做一次。 你每天用的各种模型,绝大多数共享少数几个开源基座(Qwen、Llama、DeepSeek 等)——差异主要来自下一步的后训练。这就是为什么"同一个基座的不同产品,性格迥异"。

一个常被问到的问题:预训练数据截止于某个时间点(knowledge cutoff),之后的事模型一无所知。模型没有"现在"的概念——这是 Agent 必须给模型配搜索工具的根本原因(第 9 章实战会用到)。

2. 后训练:从补全机器到助手

后训练(Post-training)让模型学会两件新事情:听懂指令 和 符合人类偏好。主流流程是三步走:

基座模型 ──SFT──→ 会聊天 ──RLHF/DPO──→ 乖巧有用 ──(可选)专项──→ Agent/推理模型

2.1 SFT:监督微调,照着示范学

SFT(Supervised Fine-Tuning)就是监督学习(第 1 章三大范式的第一员):

  • 数据:人工编写/审核的(指令, 理想回答)对,量级通常几万~百万条
  • 训练:和预训练完全相同的"预测下一个词",但只在"理想回答"部分计算损失
训练样本示例:
  用户:      总结这段文章
  助手:      <人类写的标准总结>     ← 只在这里算损失,让模型学会扮演"助手"

效果立竿见影:模型学会了"问-答"的行为模式。SFT 后的模型已经可以对话,但答案质量参差——因为"好的标准"很难用有限样本覆盖。

2.2 RLHF:从"模仿"到"偏好对齐"

RLHF(Reinforcement Learning from Human Feedback)用上了第三大范式——强化学习(第 1 章):

  1. 让模型对同一问题生成多个回答
  2. 人类标注员对回答排序(排序比打分容易,也更可靠)
  3. 用排序数据训练一个奖励模型(Reward Model),学会给回答打分
  4. 用强化学习(如 PPO)微调语言模型,使其输出向奖励模型的高分方向靠拢

直觉上,SFT 是"临摹字帖",RLHF 是"教练纠偏"。它解决的是"什么是好回答"中难以明说的部分:语气、分寸、诚实度、安全性。

近年的轻量替代是 DPO(直接偏好优化):跳过奖励模型和强化学习的复杂工程,直接从"偏好对"数据优化,效果接近、实现简单。还有基于 AI 反馈的 RLAIF/宪法 AI(用另一个模型代替人类标注员做排序),把对齐成本进一步压低。

2.3 对齐税

对齐是有代价的:过度对齐的模型会变得过于谨慎(拒答边缘问题)、过于啰嗦(讨好性)、风格趋同(多样性下降),这被称为对齐税(alignment tax)。你在开发中遇到的"模型太啰嗦""怎么问都说不知道"等现象,很多时候不是能力问题,而是对齐策略的副作用——这也是为什么要发展系统提示词(第 5 章)这类"运行时调控"手段。

3. 思维链:后训练教会模型"想再答"

思维链(Chain-of-Thought,CoT)是后训练阶段最重要的能力注入之一,值得单独一节。

现象(2022 年发现):在提示词里加一句"让我们一步步思考",复杂推理任务的正确率显著上升。

原理:模型是逐 token 生成的(本章第 6 节详解),每生成一个 token,它都成为后续 token 的上下文。直接输出答案时,模型只有一次"开枪"的机会;而先写推理过程,相当于把中间结论写进上下文,后续步骤可以基于这些"脚手架"继续思考——用生成换计算。

无 CoT:  问题 → 答案          (一步到位,容易错)
有 CoT:  问题 → 推理过程 → 答案  (中间结论成为后续的输入)

这也解释了两个日常现象:

  1. 为什么推理模型(o1/R1 类)喜欢长篇分析——它们在后训练中被大量强化了"先充分思考"的模式
  2. 为什么让模型"别思考直接答"复杂问题质量会下降——你亲手拆掉了它的脚手架

Agent 开发与 CoT 的关系比想象中深:ReAct(第 8 章)就是把思维链中的"思考"替换成"思考 + 行动(调用工具)",让推理过程可以接入真实世界的信息。

4. 一个模型的一生:训练流水线全景

  万亿 token 语料              万人写的示范对           人类偏好排序
        │                          │                      │
        ▼                          ▼                      ▼
   ┌─────────┐    SFT      ┌──────────┐   RLHF/DPO  ┌──────────┐
   │ 随机初始化 │ ───────→   │  基座模型  │ ────────→  │ 对话模型   │
   └─────────┘              └──────────┘            └──────────┘
   会续写乱码                  会接话                  有分寸地帮忙
                                                     │
                                        专项后训练 ──┤── Agent 模型(工具调用强化)
                                                     └── 推理模型(长思维链强化)

你在 Ollama 里 pull 一个模型时看到的命名差异,对应的就是这条流水线的不同位置:qwen3 系列的 base 版(纯基座)和 instruct 版(后训练完成)行为完全不同。日常开发永远选 instruct/chat 版,base 版只用于继续训练或研究。

5. 幻觉:流水线的必然副产品

幻觉(hallucination,一本正经地编造事实)不是 bug,是训练方式的必然副产品:

  • 预训练的目标是"预测下一个词",不是"预测真词"。语料本身就有错误、虚构、过时内容;语法通顺的错误答案和正确答案,在损失函数上可能只差一点
  • 模型的全部倾向是生成统计上合理的文本。"合理"和"真实"在多数时候重合,但模型没有内在机制区分二者
  • 对齐训练教会它"诚实",但没有教它"知道自己不知道"——校准(calibration)至今是开放难题

工程对策(Agent 视角,第 13、15 章还会深化):

手段 原理
RAG / 搜索工具 把"回忆"变成"查阅",事实来源外置(第 9 章实战)
要求引用来源 让输出可验证,倒逼生成时"有据"
结构化输出(第 6 章) 收窄输出空间,减少自由发挥
温度调低(本章第 8 节) 降低采样随机性,倾向高概率答案

6. 自回归:一次生成一个 token

模型训练完毕、参数冻结,就进入推理(inference)阶段——每次你按下回车后发生的事。推理的核心是一个循环,称为自回归(autoregressive)生成:

上下文:  "今天天气真"
  │ ① 整段送入模型,对最后一个位置做预测
  ▼
概率: 好(0.60)  不错(0.20)  差(0.15)  凉(0.03)  ...
  │ ② 选出一个 token(怎么选?见第 8 节)
  ▼
上下文:  "今天天气真好"
  │ ③ 把新 token 拼回上下文,回到 ①
  ▼
上下文:  "今天天气真好," → ...
  (循环,直到选出特殊的结束符 <eos> 或达到长度上限)

两个重要推论:

  • 输出长度不可精确预知:结束与否由模型自己在循环中决定。这就是 max_tokens 参数的本质——给循环设个上限
  • 每一步都有完整上下文参与计算:第 N 个 token 的生成依赖前 N-1 个。这个特性带来了"前缀重复计算"问题,下一节的 K-V 缓存就是它的解药

用伪代码总结整个生成过程(第 5 章会换成真实 API):

def generate(model, prompt_ids, max_tokens=512):
    ids = list(prompt_ids)
    for _ in range(max_tokens):
        logits = model(ids)[-1]          # 只关心最后位置的词表分布
        next_id = sample(logits)          # ← 采样策略(第 8 节)
        if next_id == EOS:
            break
        ids.append(next_id)
    return ids

7. K-V 缓存:重复计算的大消除

7.1 问题:前缀的重复计算

朴素的实现有个严重浪费:生成第 1000 个 token 时,要把前 999 个 token 全部重新跑一遍前向传播(第 3 章的完整流水线)——而其中 998 个位置的计算结果和上一轮一模一样。

7.2 解药:缓存历史位置的 K、V

注意第 3 章的细节:注意力计算需要每个位置的 Q、K、V 三个向量。其中 Q 只属于当前最新位置(查询发自"当下"),而 K、V 是所有历史位置的属性。既然历史位置的 K、V 不会变,就把它们缓存下来:

生成第 N 个 token 时:
  - 计算:只有第 N 个位置的完整前向(产出它的 Q/K/V)
  - 读取:缓存里前 N-1 个位置的 K、V
  - 更新:把第 N 个位置的 K、V 写入缓存

这就是 K-V Cache。效果:每步生成从 O(N²) 的重复计算降到 O(N),代价是显存里持续存放历史 K/V(这也是长上下文吃显存的另一个来源——上下文越长,缓存越大)。

7.3 推论:预填充与解码的两阶段节奏

由此推出两个你在开发中天天遇到的现象的原理:

  1. 首 token 延迟(TTFT):第一个 token 之前必须处理完整输入(这个阶段叫 prefill,预填充),输入越长等得越久。系统提示词一长,"开口"就慢
  2. 生成速度恒定:后续每个 token(decode,解码阶段)只需增量计算,通常稳定在几十 tokens/s

7.4 流式输出:不省总耗时,只改善体感

顺带解释流式输出(streaming):API 所谓的"流式",就是把 decode 循环每步的产物即时推给你,而不是攒齐了再发。流式不影响总耗时,只改善体感。

8. 采样策略:温度到底在调什么

模型每步输出的是整个词表上的概率分布,怎么从中选出下一个 token?这一步就是采样策略,也是 temperature、top_p 这些参数的属地。

8.1 贪心 vs 随机

最简单的两种极端:

  • 贪心(greedy):永远选概率最高的。问题:输出确定但呆板,长文容易陷入重复循环("的的的")
  • 纯随机:按概率抽签。问题:偶尔抽到离谱低概率 token,文章跑偏

生产实践在两者之间:先截断再重调再采样。

8.2 截断:Top-k 与 Top-p

  • Top-k:只在概率最高的 k 个候选里抽(如 k=50)
  • Top-p(核采样):从高到低累加概率,累计到 p(如 0.9)为止,只在这批里抽。比 top-k 聪明的地方:分布尖锐时候选少(谨慎),分布平缓时候选多(开放)
分布尖锐: 好(0.85) 差(0.1) ...      → top-p=0.9 几乎只有"好"可选
分布平缓: 红(0.2) 橙(0.2) 黄(0.2) … → top-p=0.9 会保留一大串候选

8.3 温度:分布的锐度旋钮

温度直接改写概率分布——用 logits 除以 T 再 softmax:

$$ P_i = \frac{e^{z_i / T}}{\sum_j e^{z_j / T}} $$

直觉:T 调低 → 分布更尖 → 更确定、更保守;T 调高 → 分布更平 → 更随机、更有创造性。

用 numpy 直接感受:

import numpy as np

logits = np.array([5.0, 3.0, 1.0, 0.5, 0.1])      # 5 个候选的原始分

def softmax(z, T=1.0):
    z = z / T
    e = np.exp(z - z.max())
    return e / e.sum()

for T in [0.2, 1.0, 3.0]:
    print(f"T={T}: {np.round(softmax(logits, T), 3)}")

输出:

T=0.2: [1.    0.    0.    0.    0.   ]   ← 接近贪心:几乎必选第一名
T=1.0: [0.867 0.118 0.016 0.009 0.006]   ← 原始分布
T=3.0: [0.558 0.205 0.075 0.055 0.045]   ← 抹平:冷门候选也有机会

选型建议(Agent 开发直接可用):

场景 temperature 理由
代码生成、结构化输出 0 ~ 0.2 要确定性和格式正确
通用问答 0.3 ~ 0.7 平衡稳定与流畅
创意写作、头脑风暴 0.8 ~ 1.2 需要多样性

注意:温度为 0 也不等于绝对确定(浮点并行计算等原因,少数 API 仍有微小随机性)——所以别把"temperature=0"当作"单元测试断言"的前提。

8.4 其他参数速览

  • presence_penalty / frequency_penalty:压制已出现过的 token,缓解重复。生成"车轱辘话"时可以先拉高试试
  • seed(部分 API 支持):固定采样随机源,配合低温提高可复现性
  • stop 序列:遇到指定字符串提前终止生成(比如工具调用场景里检测到结束标记)

9. 上下文窗口:推理的资源边界

推理时所有内容共享一个预算——上下文窗口(以 token 计,第 1 章提过换算):

┌─────────────────── 上下文窗口(如 32K)───────────────────┐
│ 系统提示词 │ 对话历史 │ 工具定义 │ few-shot 示例 │ 当前问题 │ 生成空间 │
└──────────────────────────────────────────────────────┘

窗口对 Agent 开发是一等公民的约束:工具定义、历史轮次、检索回来的文档,全部在争抢这块空间;生成也发生在窗口内,超长输出会挤占输入。满了会怎样(截断或报错,各家实现不同)以及管理策略(滑动窗口、摘要压缩),第 6 章展开。

一个容易踩的坑:长上下文 ≠ 均匀注意力。研究发现模型对开头和结尾的内容最敏感,中段信息容易被忽略(lost in the middle 现象,第 3 章位置编码一节埋过伏笔)。实用对策:关键指令放开头或结尾,重要文档拆块后置最相关的在两端。

10. 成本:token 经济学

把推理的账算清楚(2026 年常见量级,具体看厂商):

计费项 说明
输入 token 通常便宜;系统提示词+对话历史每轮重复计费
输出 token 通常数倍于输入单价;decode 无法并行,生成慢是物理限制
缓存命中(prompt caching) 相同前缀(如固定系统提示词)命中缓存可大幅打折,第 6 章详解

由此得出的三条省钱纪律(Agent 工程必修):

  1. 系统提示词能短则短——它每轮都在付费
  2. 历史别无脑全量携带——窗口和费用双杀,需要裁剪/摘要策略(第 13 章)
  3. 控制输出长度——输出单价更高,max_tokens 是成本护栏

11. 和 Agent 开发的接口

把本章内容收敛到三个可操作的认知:

  1. 指令遵循来自 SFT——模型"听话"的程度在出厂时已定型,系统提示词只能在边际上引导。指令越贴 mainstream 训练分布,越有效
  2. 知识截止于预训练——涉及实时信息、私有数据,必须外挂工具(搜索/RAG),别指望模型"知道"
  3. 生成即思考——想让模型答得好,往往不是"问得更狠",而是"给它生成中间过程的台阶"(先分析再结论、先列计划再执行)

本章小结

成长(模型怎么被造出来):

  • 预训练 = 预测下一个词 × 万亿级语料 → 产出"续写机器"(基座)
  • 后训练 = SFT(模仿示范)+ RLHF/DPO(对齐偏好)→ 产出"助手"
  • CoT 利用"生成即上下文"的原理,用中间结论给自己搭脚手架
  • 幻觉是训练目标的必然副产品,工程上靠工具外置与输出约束缓解
  • base 版 vs instruct 版的命名差异对应流水线位置,开发永远用后者

开口(内容怎么被生成出来):

  • 生成 = 自回归循环:预测 → 采样 → 拼接 → 再预测,直到 或上限
  • K-V 缓存消除历史重复计算;prefill(吃输入)与 decode(吐 token)两阶段解释了 TTFT 与恒定生成速度
  • 采样 = 截断(top-k/top-p)+ 重调(temperature)+ 抽签;低温确定保守,高温多样奔放
  • 温度旋钮本质是分布锐度;T=0 也不保证绝对可复现
  • 上下文窗口是共享预算:输入和生成在同一空间里此消彼长;中段信息易被忽略
  • token 是唯一成本单位:短提示词、裁历史、限输出是三大省钱纪律

第一章「它是什么」完。从 token 与嵌入,到注意力架构,再到训练流水线与推理机制,你已经拥有了完整的 LLM 心智模型——足够看懂任何模型的官方文档和架构八卦。从下一章开始,我们进入第二章「怎么用好它」:先在本地把模型跑起来,然后一步步搭出你的第一个 Agent。

下一篇:05 · 本地模型与消息结构 —— 五分钟在本地跑起一个能对话的模型,顺便把 OpenAI SDK 这套"行业通用语法学"到手。