要让一个模型稳定输出客服需要的 JSON,可以修改全部参数,也可以只训练 LoRA;训练信号则可以来自示范,也可以来自偏好比较。“改哪些参数”和“按什么目标训练”是两件事,LoRA 与 SFT 完全可以同时使用。把这两个问题分开,后面的选择就容易多了。

这页负责比较方法。想看具体计算,可以接着读:

  • Prompt / Prefix / Adapter:同一小模型里,更新位置、参数量和部署成本怎样不同。
  • LoRA / QLoRA:低秩更新的梯度、初始化、显存与量化。
  • 蒸馏:软标签、top-k 尾部概率与 on-policy 前缀。

四种参数适配方式

Full Fine-Tuning:整个模型都能动

Full-parameter fine-tuning 对所有参数求梯度:

$$ \theta\leftarrow\theta-\eta\nabla_\theta\mathcal L. $$

它给优化器最大的自由度,通常也需要最多的训练显存、optimizer state 和 checkpoint 存储。数据少或学习率控制不好时,还更容易过拟合(overfitting)或破坏原有能力。它适合数据充分、任务变化大,而且确实需要改变模型内部表示的场景。

LoRA:学习权重更新,而不是重训整块权重

对冻结的线性层 $W_0\in\mathbb R^{d_{out}\times d_{in}}$,LoRA 学习低秩增量:

$$ W=W_0+\Delta W,\qquad \Delta W=\frac{\alpha}{r}BA, $$

其中 $A\in\mathbb R^{r\times d_{in}}$、$B\in\mathbb R^{d_{out}\times r}$,且 $r\ll\min(d_{in},d_{out})$;$\alpha/r$ 控制增量尺度。基础权重冻结,只更新 $A,B$。它改的是模型内部线性变换,比只改输入的 Prompt Tuning 表达自由度更高;部署时也可以动态挂载或合并 adapter。

Prompt Tuning:只学习输入前的 virtual tokens

Prompt Tuning 冻结整个模型,只在正常 token embedding 前拼接 $m$ 个可学习向量 $P$,直接参数量是 $m\,d_{model}$。 $P$ 叫 soft prompt。它不是一句隐藏的自然语言,也不对应词表(vocabulary)里的 lexical token ID (框架可以给它分配占位索引),通常不能翻译成人能读懂的词。公式、参数账,以及“模型冻结了,梯度为什么还要穿过它”,见 Prompt / Prefix / Adapter。

每个任务可以保存一份很小的 $P_k$,共享同一个大模型:

P_refund  + 用户消息 → 冻结模型 → 退款任务输出
P_routing + 用户消息 → 冻结模型 → 路由任务输出
P_summary + 对话记录 → 冻结模型 → 摘要

推理时 soft prompt 也必须放在输入前;它不是训练完就被吸收到基础模型里。代价是多占 $m$ 个上下文位置,并让每层多处理这些位置。

完整例子:用 Prompt Tuning 做电商客服分类

假设固定类别为 退款 / 物流 / 商品咨询。为这个任务训练五个 virtual-token embeddings:

$$P_{route}=[p_1,p_2,p_3,p_4,p_5].$$

一条训练数据是:

输入:我的包裹什么时候到?
标签:物流

模型实际接收:

[p1][p2][p3][p4][p5] 我的包裹什么时候到?

如果第一次给“物流”的概率很低,classification loss 或 label-token CE 产生梯度。模型权重不动,五个 $p_i$ 被更新。许多样本之后,这组向量学会把冻结模型带入“客服路由”的内部工作状态。上线后,任何新消息都先拼同一组 $P_{route}$。

这组向量主要是在调用与重组模型已有能力。如果基础模型根本不懂新的企业政策或商品事实,soft prompt 很难凭少量参数把知识装进去;此时更应考虑 retrieval、continued pretraining、LoRA 或 full fine-tuning。

Prefix Tuning:不只在输入层加向量

Prompt Tuning 通常只在 embedding 层加 virtual tokens;Prefix Tuning 为每一层 attention 直接提供可学习的 prefix key/value,普通 token 的 Query 可以在每一层关注它们。直接存储的规模约为 $2Lmd_{KV}$,其中 $d_{KV}$ 是每层实际的 KV 宽度,GQA / MQA 下小于 $d_{model}$;若用小 MLP 生成各层 prefix,可训练参数还要把 MLP 算进去。逐项的参数账见 Prompt / Prefix / Adapter。它比 Prompt Tuning 更直接影响各层注意力,参数更多、表达力也通常更强:

Prompt Tuning:input embedding 前加 P
Prefix Tuning:每一层 attention 都加入 learned K/V prefix

两者都属于 parameter-efficient fine-tuning(PEFT),但不是同一个机制。

一句话分清:为什么 Prompt Tuning 也会产生每层 K/V,却仍不等于 Prefix Tuning?

Prompt tokens 像普通 token 一样从输入层逐层传播,因此当然会在每层产生 K/V;但这些状态都由同一组输入 embeddings 间接演化而来。Prefix Tuning 则为各层直接提供 layer-specific prefix K/V,每层拥有独立控制信号。

分类输出怎么保证只落在合法标签里

Soft prompt 只能让正确标签更可能,不能单独保证输出 schema。可靠系统要把“模型学得准不准”和“输出是否合法”分开处理。

方法一:直接给固定标签打分

不让模型自由生成,而是比较候选(candidate)标签的 sequence log-probability(条件里的 $P$ 是前面学到的 soft prompt,$c_j$ 是标签 $c$ 的第 $j$ 个 token):

$$ \hat c=\arg\max_{c\in\mathcal C}\log P(c\mid P,x), \qquad \log P(c\mid P,x)=\sum_j\log P(c_j\mid P,x,c_{<j}). $$

工程上常用单 token、等长的 A/B/C 再映射到业务标签,避免不同 tokenization 与标签长度带来的偏差。

方法二:Constrained Decoding

约束的是完整标签序列,不是把标签里出现过的 token 合成一张固定白名单。例如合法标签是两个 token 组成的 a b 和 a c,仅允许 a/b/c 仍会生成非法的 b a。即使标签都是单 token 的 A/B/C,连续生成两步也可能得到非法的 AA。

多 token 标签可以组织成前缀树:每一步根据已经生成的标签前缀,只保留仍能到达某个合法标签的下一 token;只有当前前缀已经是完整标签,才允许结束。若一个标签也是另一个标签的前缀,可以结束,也可以沿合法分支继续。对其余 logits 置 $-\infty$。

下面用字母代指已经确定的 token ID,用保留符号 <EOS> 表示结束;它不属于任何标签。 prefix 只包含新生成的标签部分,不包含输入问题。这只是下一步允许集合的示例,不是完整解码器:

def legal_next_tokens(prefix, labels):
    allowed = set()
    for label in labels:
        if label[:len(prefix)] != prefix:
            continue
        allowed.add("<EOS>" if len(prefix) == len(label) else label[len(prefix)])
    return allowed


labels = (("a", "b"), ("a", "c"))
print(sorted(legal_next_tokens((), labels)))
print(sorted(legal_next_tokens(("a",), labels)))
print(sorted(legal_next_tokens(("a", "b"), labels)))
print(sorted(legal_next_tokens(("b",), labels)))

四行输出依次是 ['a']、['b', 'c']、['<EOS>']、[]。最后一个空集合表示路径已非法,应报告失败,不能退回“不加约束”。实际服务还要处理 tokenization、logits mask 和停止条件;被长度或时间上限截断的未完成标签不能作为合法结果返回。

若已验证业务标签在当前 tokenizer 和生成上下文中分别对应一个 token,则可以只允许这些 token,恰好生成一步就停止,再映射回业务枚举。前缀约束或这个单步特例保证的是成功完成时的格式,不是分类准确率;它们也不保证每次请求都能成功完成。

实现接口可参考 Transformers v5.20.0 的前缀约束文档 (2026-10 核对);这里没有调用该库,也没有假设其他版本的行为。用推理服务部署时,引擎通常自带这类约束:例如 vLLM 的 structured outputs 可以用 choice 让输出恰好是几个候选之一,也支持正则、JSON schema 和语法约束(2026-10 核对 stable 文档)。

方法三:Classification Head

取一个 hidden state $h$,训练固定输出维度的分类头:

$$ p(c\mid x)=\operatorname{softmax}(W_ch+b). $$

类别固定、只需要分类时,这通常比让 decoder 自由生成更直接。可以冻结 backbone,同时训练 soft prompt 与小分类头。

模型或 soft prompt 提高 accuracy;serving constraint 保证 schema。 不要把格式保证寄托在一句“请只输出标签”的自然语言指令上。

Distillation:监督来自 Teacher

Knowledge Distillation(知识蒸馏)通常有一个能力更强或成本更高的 Teacher,以及要部署的 Student。它不是一种固定的参数更新方式,而是一类监督来源。

常见的有三种。Response distillation:Teacher 先生成答案,Student 把它当示范做 SFT;实现简单,但只保留一条采样结果,看不到 Teacher 对其他 token 的相对偏好。Logit / distribution distillation:Student 拟合 Teacher 的 token 分布,经典做法是用温度 $T$ 软化两边分布后算 KL,再乘 $T^2$;只存 Teacher top-$k$ logits 时,要明确处理剩余概率质量、tokenizer 映射以及 mask 和归一化。On-policy distillation:Student 先从当前策略采样,Teacher 再给这些前缀上的 token 分布打分;监督更贴近 Student 真正会访问的状态,代价是持续 rollout、Teacher 推理和权重版本管理。三种做法的算例、温度和 top-k 的细节见蒸馏。

Distillation 可以和任何 parameterization 组合:Student 可以 full fine-tune,也可以只训 LoRA。Teacher 通常冻结;Student 才是被优化和最终部署的模型。

怎么选

目标 更自然的起点 原因
多个简单任务共享同一超大模型 Prompt / Prefix Tuning 每个任务只保存少量参数
需要明显改变内部行为,但资源有限 LoRA-SFT 比 soft prompt 自由度高;可训练参数、optimizer state 和 checkpoint 远小于 full FT
数据充分、任务差异大、追求最高适配上限 Full Fine-Tuning 参数约束最少,但成本和回归风险最高
把大模型能力迁到小模型 Distillation Teacher 可以大量生成示范;logit 蒸馏还能提供比 hard label 更密的监督
固定枚举分类 Label scoring 或 classification head 不需要承担自由生成的不确定性
缺少会变化的外部事实 Retrieval / tool use 不应指望微调(fine-tuning)参数充当实时数据库

面试时最值得说清楚的三句话

  1. Prompt Tuning 学的是连续 virtual-token embeddings,不是自然语言 prompt;模型冻结,推理时仍要把它们拼到输入前。
  2. LoRA、Prompt Tuning 和 full fine-tuning 描述参数怎样更新;SFT、DPO 和 distillation 描述监督与 objective,两组概念可以交叉组合。
  3. 对分类任务,训练方法负责 accuracy,固定标签打分、constrained decoding 或 classification head 负责输出合法性。

自检

如果真的理解了,你应该能解释:
  1. 为什么 soft prompt 不对应词表里的 lexical token,也不一定能翻译成人话?
  2. Prompt Tuning 与 Prefix Tuning 分别在哪一层加入参数?
  3. 为什么“LoRA 和 SFT 哪个更好”不是一个完整的问题?
  4. 如何让生成式分类器保证只返回合法枚举值?
  5. Response distillation 与 token-distribution distillation 丢失的信息有什么不同?

继续阅读

快速学习:先把两条轴分开

两分钟讲清这些方法到底差在哪里

第一条轴是 learning objective(学什么):可以用 demonstration 做 SFT,用 teacher distribution 做 distillation,用 chosen/rejected pair 做 DPO,也可以用 reward 做 RL。

第二条轴是 parameterization(改哪里):可以更新全部权重,训练 LoRA / Adapter,或者只训练输入侧的 soft prompt。两条轴可以组合,例如 LoRA-SFT、LoRA-DPO,或者用 LoRA 参数化的 student 做 distillation。

Distillation 决定监督从 teacher 来;LoRA 与 Prompt Tuning 决定梯度允许改哪些参数。

深挖:为什么这个区分很重要?

如果实验说“LoRA 比 SFT 好”,比较本身就不完整:LoRA 是更新参数的方式,SFT 是数据与损失。正确对照应当是 full-parameter SFT 与 LoRA-SFT,或者在相同 parameterization 下比较 SFT 与 distillation。否则改变了两件事,却不知道提升来自哪里。

flowchart LR
    B["Pretrained / SFT model"] --> O{"训练信号<br/>Learning objective"}
    O --> S["Demonstrations · SFT"]
    O --> D["Teacher outputs · Distillation"]
    O --> P["Preferences · DPO"]
    O --> R["Reward · RL"]
    S --> U{"更新哪些参数<br/>Parameterization"}
    D --> U
    P --> U
    R --> U
    U --> F["Full fine-tuning"]
    U --> L["LoRA / Adapter"]
    U --> T["Prompt / Prefix tuning"]

参考论文

本页术语 5
过拟合 overfitting
训练集越来越好,没见过的数据反而变差
词表 vocabulary
模型能输出的所有 token 的集合
候选 candidate
召回阶段捞出来、等待精排挑选的内容
蒸馏 distillation
用一个模型的输出训练另一个通常更小的模型
微调 fine-tuning
在预训练权重上继续训练以适配具体任务