跳转至

6. 效果评估:微调到底有没有比提示词强

本章回答一个工程上很实际的问题:花 GPU 时间微调,比只写好提示词强多少?草稿数据可以直接做这组探索性对照,用来练习实验方法;要对外报告结论,先完成数据审核。

本章速览

  • 本章做什么:让三组模型(原模型 + 简单提示、原模型 + 好提示词和示例、LoRA)回答同一批验证题;比较两个 rank;用盲评打分;选定候选后才用测试集
  • 需要准备:第 3 章的 .venv-train 和基座;能连续使用 GPU 数小时;至少一位评分人(最好不是训练者本人)
  • 做完得到:一份有原始输出、评分和不确定性区间的实验记录,能回答“微调值不值”
  • 什么时候做:第 4~5 章主线跑通之后。本章 GPU 时间约 10~20 小时(含多次推理和两次训练),人工评分另计

为什么不能只看 loss?loss 只衡量“像不像参考回答”。参考回答本身也可能啰嗦、错漏;原模型配一份好提示词,也许已经说得够好。要判断微调有没有价值,必须在没训练过的主题上,让“好提示词”和“好提示词 + LoRA”回答完全相同的输入,再由人在不知道哪个是哪个的情况下打分。这和后端做 A/B 实验是一回事:控制变量、盲测、看置信区间。

本章分两半:6.1~6.4 准备数据并生成三组回答,6.5~6.8 评分、冻结和下结论。命令都在 GPU 主机的项目根目录执行。

6.1 现有数据规模与审核要求

当前已经有 500/50/50 段,无需再次扩到旧版的规模。每类 100/10/10 段,共 60 张事实卡。formal 是本教学实验的固定配额,不是 LoRA 通用最低要求。

所有同主题变体用同一个 group_id;事实引用也不能跨集合。每个验证、测试集合各只有 5 个独立主题,因此即使有 50 段,也不能当作 50 个互不相关的知识测试。

什么算审核。 正式审核逐段检查:来源是否支持事实、有没有过度拟人、孩子是否听得懂、比喻边界是否清楚、观察是否安全可行、是否尊重孩子不想被提问或想结束。审核直接在 dataset.json 里进行,用版本控制保留历史。只有真正审核过的条目才把 review.status 改成 approved,并填写实际的 reviewer、reviewer_kind、notes;不要批量改状态冒充审核。程序能查结构,查不了近重复、模板味和科学错误:10 类路径有意重复教学行为,同主题也复用部分回答,50 个 train 主题不等于 500 个独立主题;val/test 与训练主题隔离,但仍共享光、力、生命等基础概念。

草稿数据加 --allow-draft 即可完成本章第 6.1~6.6 节的验证集对照,产物 manifest 会记录 draft: true。冻结候选和测试集(第 6.7 节)仍要求审核后的数据,避免把草稿结果当成正式结论。

6.2 怎样继续改善数据

先按主题读完 10 条路径,检查孩子每次反馈是否引起对应改变。低年级若仍出现未解释术语,应重写;同一比喻不能反复替代具体解释;一个观察也不能证明与它无关的全部结论。

用验证集找到失败类型后补充训练示范,避免根据 test 的答案改数据。新增主题先分组再划分集合。当前十类路径是结构化合成,并非来自真实儿童互动;有条件时在监护人知情同意下收集匿名反馈,另评估理解与自愿探索,不以多聊几轮作唯一目标。

6.3 校验与准备

在 GPU 主机的项目根目录打开终端,先激活第 3 章安装的训练环境;以下命令需要 PyTorch 与 TRL:

source .venv-train/bin/activate

python -m lab.data \
  --input data/dataset.json --allow-draft --formal

python -m lab.prepare \
  --input data/dataset.json \
  --tokenizer models/qwen3-4b --allow-draft --formal --output data/processed/experiment-v1

python -m lab.audit --data data/processed/experiment-v1 \
  --output runs/formal-token-audit.json

--formal 核对 500/50/50 段、60 张事实卡及每类 100/10/10 的配额;--allow-draft 允许未审核的条目。两者是独立的检查:完成真实审核后去掉 --allow-draft,得到的就是正式数据版本(换一个输出目录,例如 experiment-v2)。

自动检查:配额、审核状态、来源 ID、完整对话组交叉、相同用户对话、控制符、非空目标、提问数量。近重复、语义错误、来源不支持等还需要审核,程序无法仅凭一个 URL 判断事实真伪。

6.4 三组基线与两个 rank

组别 权重 提示词与示例
A 原模型 基本提示词,不附示例
B 原模型 完整角色提示词 + 训练集选出的 3 个 few-shot
C 原模型 + 本次 LoRA 与 B 完全相同的提示词和 3 个 few-shot

B、C 的 3 个 few-shot 由 lab.prepare 从 train 的开头、中间、结尾附近各选一段(尽量覆盖三个学段),只取第一轮问答,写进快照的 fewshots.json。few-shot 只在推理时使用;SFT 训练样本不插入示例,避免把样本自己的答案提前贴进输入。

三组都使用当前题目的同一事实卡、NF4 精度与贪心解码。默认读取 val,参考答案只用于后续评审;固定历史模式会把前轮参考回复作为上下文。本节 B/C 与 Notebook 的三个无 few-shot 观察题属于不同协议,不混合评分。

先运行验证集 A、B:

python -m lab.infer --data data/processed/experiment-v1 --variant A \
  --output runs/val-A.jsonl
python -m lab.infer --data data/processed/experiment-v1 --variant B \
  --output runs/val-B.jsonl

训练 r=16,1 Epoch:

python -m lab.train --data data/processed/experiment-v1 \
  --output runs/formal-r16 --allow-draft --epochs 1 --rank 16
python -m lab.infer --data data/processed/experiment-v1 --variant C \
  --adapter runs/formal-r16/adapter --output runs/val-C-r16.jsonl

只改变 rank 和对应的 alpha,重新从基座开始:

python -m lab.train --data data/processed/experiment-v1 \
  --output runs/formal-r8 --allow-draft --epochs 1 --rank 8
python -m lab.infer --data data/processed/experiment-v1 --variant C \
  --adapter runs/formal-r8/adapter --output runs/val-C-r8.jsonl

代码始终设置 alpha=2×rank,所以两轮缩放比都是 2。不要从 r16 的 adapter 接着训练 r8,并将其称为独立对照。

1150 条训练样本、有效 Batch≈16 时,1 Epoch 约 72 次优化器更新,和 Notebook 默认训练量相同。B 组已经有好提示词和 few-shot,C 组没有明显优势也很正常,这本身就是有价值的结论:说明这个任务用提示词就够了。

验收: 两轮的数据、提示词、生成参数和基座一致;能比较验证效果、训练时间、显存、adapter 大小;不以训练 Loss 单独选出“更好的探索伙伴”。

新开终端时先运行 source .venv-train/bin/activate,并确认第 6.3~6.4 节的数据快照与候选模型已经生成。

6.5 先固定历史,再连续对话

固定历史(默认 --mode fixed)使用数据里的参考历史。B/C 每条输入的哈希必须相同,适合定位某一轮表达差异。

连续对话使用模型自己的回答作为后续历史:

python -m lab.infer --data data/processed/experiment-v1 --variant B \
  --mode rollout --output runs/val-B-rollout.jsonl
python -m lab.infer --data data/processed/experiment-v1 --variant C \
  --adapter runs/formal-r16/adapter --mode rollout --output runs/val-C-rollout.jsonl

两组使用相同用户脚本,模型各自生成后续历史,因此后续 prompt 哈希可能不同。有的预设追问可能接不上生成回答,评分时要记录这种情况。真人根据回答追问属于另一种评测。

6.6 人工盲评

完整程序:evaluate.py。

python -m lab.evaluate blind --base runs/val-B.jsonl \
  --tuned runs/val-C-r16.jsonl --output runs/blind-val-r16

生成 ratings.jsonl、key.json 和协议。评分时只看 ratings 与事实卡,不看 key;完成后再揭晓哪一侧是 LoRA。可以请未参与训练的人评分,减少作者对候选的偏好。

每条填写:winner 为 X/Y/tie、reason 写具体原因;分别填写 fact_claims_X/Y 和 supported_X/Y。无可核查事实时填 0,不把它当作“100% 正确”。issues 字段记录事实错误、中文超出学段或术语堆积、过度提问、忽略偏好、错误归因、假装看见孩子的观察等问题。

维度 0 分 1 分 2 分
事实 关键断言无依据/错误 部分不清楚或范围过宽 可核查断言均有依据,未知明确
学段适配 超出理解水平、术语堆积 能懂但解释未随反馈调整 具体简明,没懂时换解释
探索价值 套话、编造或强迫提问 有兴趣点但下一步模糊 具体、安全、可选择的观察或追问
互动 忽略明确选择 基本响应但重复 尊重选择、节奏合适
证据意识 把猜测或比喻当事实 有限定但不充分 区分观察、解释和比喻,承认信息不足

量表用于帮助判断 winner,分项可以写在 reason 中;不是自动关键词打分。一个有严重事实错误但更“好玩”的回答不应仅凭趣味取胜。

python -m lab.evaluate score --ratings runs/blind-val-r16/ratings.jsonl \
  --key runs/blind-val-r16/key.json --output runs/val-r16-score.json

胜计 1、平计 0.5、负计 0。脚本按 group_id 科学主题进行 bootstrap,避免把同主题十条路径和多轮当成独立样本;报告轮数、对话数及主题数。少于 2 个主题不输出区间。各 5 个验证/测试主题仍很少,区间不能支撑广泛结论。小样本区间只是探索性结果,不能消除评分偏差。

事实支持率=获得资料支持的断言数/可核查断言数;脚本不会自动核实这些断言。未填写全部事实审查项时标记 factual_review_complete=false,不能把局部比率当成完整质量结论。

6.7 冻结后才使用测试集

本节需要审核后的正式数据(第 6.3 节去掉 --allow-draft 重新 prepare);草稿数据会被 freeze 和测试集推理拒绝。基于验证集选定模型。以下以 r16 为例;若 r8 更合适,将后续 adapter 参数统一改为该候选。选择是这次学习实验的结果,不是教程预先假定。

python -m lab.evaluate freeze --data data/processed/experiment-v1 \
  --adapter runs/formal-r16/adapter --output runs/frozen-candidate.json

python -m lab.infer --data data/processed/experiment-v1 --split test --variant B \
  --freeze runs/frozen-candidate.json --output runs/test-B.jsonl
python -m lab.infer --data data/processed/experiment-v1 --split test --variant C \
  --adapter runs/formal-r16/adapter --freeze runs/frozen-candidate.json \
  --output runs/test-C.jsonl

python -m lab.evaluate blind --base runs/test-B.jsonl \
  --tuned runs/test-C.jsonl --output runs/blind-test

同样用 --mode rollout 与新的输出文件执行测试集连续对话。test 禁止使用 --limit 挑选容易的题。冻结文件记录数据哈希、基座、adapter 权重与配置的联合指纹、推理代码和解码参数。

测试文件仍在本地,实验者需要在冻结模型前保留测试题,避免据此补写训练答案。若看过测试结果又继续调整,下一轮要换新的独立测试集。

6.8 怎样作出结论

按以下顺序写一页实验记录:训练配置与成本 → B/C 的事实与盲评比较 → 代表性成功和失败 → 不确定性 → 下一步。

根据验证结果选择下一步:差异不确定时补充独立评测;某类行为出错时补充对应训练样例;LoRA 收益不足时保留提示词基线。结论需要同时考虑事实错误与表达偏好。

成人偏好和模型自评不能直接证明孩子更愿意探索。真实目标还需观察孩子是否理解核心原因、能否自发提出相关新问题、愿不愿意选择一次安全观察,并尊重拒绝参与。

验收: 保存完整评分、原始输出和失败分类,让他人能复查每个比较用了什么输入。