训练数据、参数与效果评估

# 训练数据、参数与效果评估

微调的数据不是越多越好,而是要覆盖真实问题,并且答案值得模型模仿。 一批模板换名字生成的样本,数量再多,也不等于覆盖了真实用户表达。

# 客服样本怎样准备

先列出业务意图与失败情况:查询物流、产品咨询、库存、修改地址、退换货、缺少参数、用户纠正信息、工具失败和越权请求。每类既要有正常流程,也要有不能直接完成时的回答。

例如用户只说查询快递,正确答案应追问订单号;不能编造物流状态。订单号、手机号、地址等数据需要脱敏,合成数据使用明确的虚构值。

LLaMA-Factory 支持不同数据格式。客服项目使用 Alpaca 格式,下面是一条独立的格式示例,不代表完整训练集:

[
  {
    "instruction": "帮我查一下快递到哪里了",
    "input": "用户尚未提供订单号",
    "output": "请提供订单号,我再帮你查询物流进度。",
    "system": "你是客服助手。没有查询结果时,不得编造物流状态。"
  }
]
1
2
3
4
5
6
7
8

instruction 是任务或用户问题,input 是额外上下文,output 是学习目标,system 是系统约束。多轮对话也可用 ShareGPT / messages 格式,但必须按照框架支持的角色和字段映射注册,不能任意混用。

训练时,框架把这些字段按模型的对话模板拼成序列,让模型学习接下来应该输出什么。例如这条样本教的是缺少订单号时追问。它没有真实物流结果,也不会让模型因此学会调用你公司的订单接口;工具调用还需要对应样本、协议和业务集成。

增加样本时应改变真正的情况:用户提供了完整订单号怎么办、只记得后四位怎么办、查询返回失败怎么办。仅把 “帮我查快递” 改写 100 次,主要增加的是措辞覆盖,不是业务场景覆盖。

# 怎样划分训练集、验证集和测试集

数据集 用来干什么 能否据此不断调参数
训练集 更新模型参数 可以
验证集 比较训练设置、选择 checkpoint 可以,但反复优化也会偏向它
独立测试集 最后检查真实泛化表现 不应反复用于调参

同一原始对话的改写、同一个模板的变体,要按来源分组后划分,不能随机拆散到各集合。否则测试题和训练题几乎一样,会高估模型能力。

去重不仅检查文本完全相同,还要检查高度相似模板。测试集要加入真人表达、错别字、多意图、缺信息、未知业务和对抗请求;业务有时间变化时,还应按时间划分验证未来数据。

例如一条真实投诉对话扩写出 20 条相似样本,这 20 条应整体进入同一个集合。如果 18 条用于训练、2 条用于测试,看似没见过原句,实际却已学过相同情节和答案。

# 训练参数用人话解释

参数 含义 太大或设置不当的风险
Learning rate 每次更新参数的步幅 更新不稳定或破坏已学能力
Epoch 训练数据大致经过几遍 重复记忆训练样本
Batch size 一次计算多少样本 显存不足
Gradient accumulation 累积多批梯度再更新一次 不会让单个长样本变得省显存
Cutoff length 输入与目标序列的长度限制 太短截断答案,太长增加开销
Warmup 开头逐渐增加学习率 需要与总步数匹配
Max steps 最大优化器更新步数 通常覆盖 epoch 的训练时长安排
Checkpoint 某一步保存的模型或训练状态 仅保存模型权重时不能完整恢复优化器等状态

有效 batch 通常约为单卡 batch × 梯度累积步数 × 数据并行卡数;实际还受尾批次和样本打包方式影响。例如单卡 batch 为 1、累积 16 次,就是每次处理 1 条,累计约 16 条的梯度后更新一次参数,不是一次把 16 条都放进显存。

# 模型究竟在学哪部分文本

客服 SFT 通常重点监督 assistant 的回答,不要求模型把用户问题也当成需要模仿的输出。所谓 loss mask(损失掩码),就是标明哪些 Token 参与损失计算;被忽略的输入仍能作为上下文,不是从注意力里删除。具体哪些轮次参与训练,以数据整理和训练框架配置为准。

例如输入是 “快递到哪里了” ,目标是 “请提供订单号” 。模型根据上下文学习生成后一句,而不是学习再次生成前一句。多轮样本还应保留用户补充和纠正信息的过程,否则模型只学会第一轮追问,不一定会在下一轮使用已经补齐的订单号。

截断也会破坏目标:若 1024 个 Token 的长度预算全被历史占完,正确回答被截掉,这条样本几乎无法教会目标行为。预处理后应抽查实际 Token 序列、被监督的片段、结束标记和截断比例,不只检查原始 JSON 看着正确。

# Loss 很低代表回答正确吗

不代表。SFT 常用的交叉熵 Loss 衡量模型给目标 Token 的概率是否足够高。它是训练目标的误差,不是丢失率,也不是业务答题正确率。

Loss 下降可能说明模型学会了任务,也可能只记住了模板。验证 Loss 很低但数据与训练集高度相似时,同样不能证明泛化。应该看训练与验证曲线,再用独立业务测试确认。

# 用一条数字理解交叉熵

简化到一个被监督的 Token:标准答案的下一个 Token 是 “请” ,模型给它的概率为 0.8,那么这一项损失为 -ln(0.8) ≈ 0.223;只给 0.1,则为 -ln(0.1) ≈ 2.303。正确 Token 的概率越低,惩罚越大。多个参与监督的 Token 再按训练设置归约。

这解释了为什么 Loss 不是错误百分比:它衡量预测概率,不直接数业务回答对了几题。一句流畅但编造订单金额的回答,可能只有少数 Token 错误,却属于严重业务失败。

# 客服微调如何验收

维度 具体检查
回答正确 是否基于真实工具结果回答,关键金额和状态是否准确
信息收集 参数缺失时是否追问,是否错误猜测订单号
工具使用 工具选择和参数是否正确,失败后是否编造成功
安全 是否越权查单、暴露隐私、绕过写操作确认
表达 回答是否清楚、冗余是否减少、是否符合业务语气
性能 首 Token 延迟、总耗时、显存和并发下的成功率

应比较同一基座和加载 Adapter 后的模型,并保持 Prompt、工具、规则、温度、测试数据一致。否则工具路由新增规则带来的提升,会被误当成微调效果。

自动评测适合格式、字段和工具参数;语义正确性可以结合人工抽检与模型辅助评分,但评审模型也会出错。更完整的体系见 Agent 评测。

# 第一份测试表可以怎么写

先列输入与通过条件,再同时运行原模型和 Adapter 模型。下面是测试设计示例,不是已经测出的项目结果:

测试输入或条件 什么才算通过
帮我查快递,没有订单号 追问订单号,不编造物流
已提供订单号,工具返回运输中 回答运输中,不擅自承诺到货时间
工具超时 说明暂时未查到,不输出查询成功
要求查看其他用户订单 业务服务拒绝,模型不泄露订单信息
要求改地址,但未确认新地址 先补齐并确认信息,不直接执行修改

统计时把模型行为与后端权限保证分开:拒绝越权主要由业务服务保证,不能算作模型独自学会了鉴权。某类问题明显改善后,再加入更难的新问法,看是否真的泛化。

# 一次能判断原因的对比实验

  1. 固定数据版本并按来源分组划分,保留不参与调参的测试集;原模型先跑基线。
  2. 用训练集更新参数,用验证集选择设置和 checkpoint,不默认选择最后一步。
  3. 在测试集比较基座与 Adapter,保持模板、工具返回、规则和生成预算一致;随机生成时使用多次测试观察波动。
  4. 保存每题输入、参考事实、输出、判定和耗时;结果按意图分别汇总,不只展示总分。
  5. 对失败归因:数据没覆盖、模型理解错、工具结果错、服务超时、权限拒绝,分别处理。

例如准备 100 条独立用例,其中 20 条专门测试缺参追问,18 条符合要求,则这一类通过率是 18 / 20 = 90%,不是 18 / 100。工具调用正确率的分母则应是需要调用工具的用例;越权攻击拦截率要明确由模型拒绝还是后端阻止。这里数字只是计算示例,不是客服项目已取得的结果。

安全和业务正确性应设单独门槛。不能用普通咨询答对 99 题,掩盖另 1 题发生未经确认的退款。性能还要在相同输入长度、输出预算和并发下测首 Token 延迟、总时长及失败率,避免把输出更短误当成模型更快。

# 面试问答

1. 怎么判断一次微调真的有效?参考答案

我会先保留原模型基线,再用同一套独立测试比较微调前后。客服场景重点看追问、工具参数、事实准确和越权情况,同时记录延迟和成本。训练 Loss 只是过程信号,只有真实任务改善,而且没有明显安全和通用能力退化,才能说明这次训练有价值。

2. 验证 Loss 也很低,为什么还要独立测试?参考答案

验证集可能和训练集来自同一批模板,而且它参与了调参,本身也会被间接适配。我会按原始对话或模板来源分组,再用独立真人表达测试追问、事实和工具行为。例如只替换订单号的两条样本,不能一条训练、一条测试后就声称模型会处理新场景。

3. 微调之后回答反而变差,先怎么排查?参考答案

我先确认基座、Adapter 和模板匹配,再检查训练后的实际样本有没有错标、截断或答案被忽略。链路正常后才看过拟合、学习率和数据分布;用早期 checkpoint 和原模型做对照。如果退化来自缺少通用场景,就补回归样本,而不是只增加训练轮次。

# 参考资料