FeedLens反馈透镜

评测报告

本文所有数字都来自 eval/results/ 下实际运行产生的文件。完整的自动生成表格见 评测原始表格;每个系统在每份数据上的逐条预测、失败案例都保存在 eval/results/<系统>/。

训练数据和测试数据全部是合成数据。 这些结果回答的是“模型学会这个任务的合成版本了吗、换一种说法还行不行”,不能回答“在真实用户反馈上效果如何”。

1. 评测设计

1.1 四份数据,各有分工

数据 条数 怎么来的 用来做什么 能不能用来做决定
val 969 合成语法,核心表达与训练集不重叠 训练中选检查点;在候选模型之间做选择 能
test 977 合成语法,核心表达与训练集不重叠,含一个训练未见的领域 报告“同分布”效果 不能,只在最后看
ood_dev 63 逐条手写,不经过语法 看失败案例,指导数据改进 能(看过之后就不再独立)
ood_test 117 逐条手写,不经过语法 报告“分布外”效果 不能,只在最后看

数据的生成方式、防泄漏措施和已知问题见 数据说明。

1.2 参评系统

系统 是什么 回答什么问题
rules 约 90 行关键词规则,不用模型 这个任务不用模型能做到什么程度
base-zeroshot MiniMind 官方 full_sft 权重,用与微调时相同的简短指令 训练前是什么水平
base-detailed 同一份官方权重,提示词里写明标签集合并给一个示例 给足提示,训练前的模型能不能做
scratch-v1 同结构随机初始化,只用任务数据训练 预训练权重贡献了多少
ft-lora-v1 在官方 full_sft 上训练 LoRA,取验证损失最低的检查点(第 350 步) 主线候选
ft-lora-v1-last 同一次 LoRA 训练结束时(第 966 步)的权重 按验证损失选检查点合不合适
ft-full-v1 在官方 full_sft 上全参数微调 主线候选
ft-full-v2 与 ft-full-v1 训练设置完全相同,训练数据换成 v2 依据失败案例改数据有没有用

eval/systems.yaml 里还定义了 ft-full-from-pretrain-v1 和 ft-lora-v2,对应的训练没有执行,因此没有结果。

定义文件:eval/systems.yaml。

1.3 指标与计分口径

指标 定义
格式合规率 输出能被解析为四个字段、且三个标签都在取值集合内的比例
类别 / 情感 / 紧急度准确率 该字段被解析出来且与标注一致的比例。没解析出来算错
macro-F1 各标签 F1 的算术平均,不受类别不均衡影响
三标签全对率 格式合规,且类别、情感、紧急度同时正确
摘要 ROUGE-L 预测摘要与标注摘要按字符计算最长公共子序列的 F1;没有摘要记 0
摘要完全一致率 预测摘要与标注摘要逐字相同
95% 置信区间 对逐样本得分做 1000 次自助法重采样

三条口径对所有系统一视同仁:

  1. 格式不合规按错误计,不剔除、不修正。
  2. 同一个解析器。规则基线的输出也要先渲染成四行文本,再走同一个解析函数。
  3. 贪心解码,同一输入每次结果相同。

指标实现在 feedlens/metrics.py,用手算的例子做了单元测试(tests/test_metrics.py)。

摘要指标的局限:ROUGE-L 只衡量字面重合。标注摘要只有一种写法,模型写出意思相同但用词不同的摘要会被低估;反过来,套用了相近模板但意思不对的摘要也可能拿到不低的分。所以摘要质量还要结合失败案例来看(第 6 节)。

1.4 速度的测法

2. 先说结论

  1. 微调是有效的,但没有达到预期。 未微调的 MiniMind 完全不会这个任务(格式合规率 0%,把标签和示例都写进提示词也只有 18.8%)。微调后格式合规率 100%,三标签全对率到了 67%–71%。预先写下的五条验收标准,达成两条,三条没有达成。
  2. 在标签准确率上,微调后的模型和一份约 90 行的关键词规则分不出高下。 同分布测试集上模型 66.8%,规则 71.9%;手写的分布外测试集上两者都是 58.1%。差值的置信区间都跨过 0。
  3. 模型明确强于规则的只有两处:情感判断(两份测试集上分别高 11.5 和 16.2 个百分点),以及同分布数据上的摘要。到了分布外数据,摘要的优势也消失了。
  4. 预训练权重有明确的贡献。 同样的结构随机初始化、只用任务数据训练,验证集上低 20 个百分点。
  5. 针对失败案例补数据,只对补到的那部分有效。 第二轮按分布外开发集的失败类型扩充了语法:开发集从 54.0% 升到 90.5%,但独立的分布外测试集没有进步(58.1% → 53.0%,差值区间跨过 0)。
  6. 模型与规则判断一致的那一半样本,准确率很高(同分布 94.3%,分布外 86.5%)。这是事后分析中最有实际用途的一个发现。

下面是支撑这些结论的数字。

3. 主要结果

数值均为百分比。每份数据上三标签全对率最高的模型系统加粗。

3.1 同分布测试集 test(977 条,来自 70 个训练未见的核心表达)

系统 格式合规 类别 情感 紧急度 三标签全对 摘要 ROUGE-L 摘要完全一致
rules(关键词规则) 100.0 75.2 79.6 78.9 71.9 29.3 0.0
base-zeroshot(训练前) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
base-detailed(训练前,详细提示) 18.8 2.9 16.6 5.9 1.3 0.9 0.1
scratch-v1(随机初始化) 100.0 68.3 93.3 81.4 58.8 48.6 33.4
ft-lora-v1(LoRA,验证损失最低) 99.6 78.3 94.7 84.6 70.3 65.4 46.6
ft-lora-v1-last(LoRA,训练结束时) 99.6 78.9 94.9 85.7 71.4 63.8 44.2
ft-full-v1(全参数,已发布) 100.0 75.5 91.1 83.8 66.8 62.2 44.9
ft-full-v2(v2 数据,验证损失最低) 99.7 75.7 93.2 86.4 69.2 54.6 31.1
ft-full-v2-last(v2 数据,训练结束时) 100.0 82.6 93.9 84.9 73.7 63.8 42.2

3.2 分布外测试集 ood_test(117 条,逐条手写)

系统 格式合规 类别 情感 紧急度 三标签全对 摘要 ROUGE-L 摘要完全一致
rules(关键词规则) 100.0 65.0 69.2 72.6 58.1 32.4 0.0
base-zeroshot(训练前) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
base-detailed(训练前,详细提示) 17.1 2.6 12.0 5.1 1.7 1.5 0.0
scratch-v1(随机初始化) 100.0 58.1 82.1 74.4 51.3 22.2 3.4
ft-lora-v1(LoRA,验证损失最低) 99.1 69.2 87.2 80.3 60.7 38.0 10.3
ft-lora-v1-last(LoRA,训练结束时) 99.1 70.9 88.9 82.1 64.1 34.6 6.8
ft-full-v1(全参数,已发布) 99.1 72.6 85.5 72.6 58.1 35.9 11.1
ft-full-v2(v2 数据,验证损失最低) 99.1 65.8 79.5 71.8 54.7 30.7 7.7
ft-full-v2-last(v2 数据,训练结束时) 100.0 63.2 83.8 75.2 53.0 33.5 7.7

验证集、分布外开发集、macro-F1、逐样本置信区间等见 评测原始表格。

3.3 这些差距有多可信

合成测试集里,同一个核心表达会生成十几条样本,它们的对错高度相关。977 条样本只来自 70 个核心表达,真正独立的观测是 70 个,不是 977 个。所以我按核心表达整组做自助法重采样,对同一批样本上的两个系统计算配对差值(scripts/compare_systems.py,完整结果见 成对比较)。

三标签全对率的差值(百分点)及其 95% 区间:

比较 val test ood_test
发布模型 − 关键词规则 +4.6(−5.6 ~ +15.3) −5.0(−18.0 ~ +9.1) 0.0(−11.1 ~ +12.0)
LoRA(结束时)− 关键词规则 −5.3(−16.1 ~ +5.1) −0.4(−12.5 ~ +12.3) +6.0(−6.0 ~ +17.1)
有预训练权重 − 随机初始化 +20.2(+12.6 ~ +28.1) +8.1(+0.4 ~ +15.9) +6.8(−4.3 ~ +17.1)
全参数 − LoRA(结束时) +9.9(+0.3 ~ +19.5) −4.6(−12.7 ~ +3.4) −6.0(−16.2 ~ +3.4)
v2 数据 − v1 数据(都取结束时) −3.9(−13.6 ~ +5.5) +6.9(−2.3 ~ +15.8) −5.1(−15.4 ~ +5.1)

加粗的是区间不含 0 的。能下结论的只有“预训练权重有用”。全参数与 LoRA 在验证集和测试集上方向相反,谁更好说不清。模型与规则之间,在任何一份数据上都没有可分辨的差别。

这也意味着:第 3.1、3.2 节表格里各微调系统之间几个百分点的高低,不应当被解读为排名。

4. 验收标准达成情况

标准写在 项目背景 里,是在看到任何微调结果之前定的。核对对象是发布的模型 ft-full-v1。

编号 标准 结果 是否达成
A1 test 格式合规率 ≥ 99% 100.0% 达成
A2 test 三标签全对率 ≥ 90% 66.8% 未达成
A3 ood_test 三标签全对率高于关键词规则 58.1%,规则也是 58.1% 未达成
A4 test 摘要 ROUGE-L ≥ 0.80 0.622 未达成
A5 CPU 单条请求 P95 延迟 < 500 ms 175.8 ms 达成

A2 定得太乐观了:当时没有任何依据,只是觉得“比规则高一截”应该在 90% 左右。实际上规则本身就有 72%,而模型在未见过的说法上只到 67%–74%。A3 是这个项目技术方案成立与否的关键一条,没有达成——换一种训练方式(LoRA)数字上高了 6 个百分点,但区间跨过 0,不能算数。

5. 模型和规则,各自强在哪

逐字段比较发布模型与关键词规则(差值为模型减规则,区间按核心表达聚类):

数据 指标 模型 规则 差值 95% 区间 区间不含 0
test 类别 75.5 75.2 +0.3 −11.3 ~ +11.9 否
test 情感 91.1 79.6 +11.5 +2.7 ~ +20.9 是
test 紧急度 83.8 78.9 +4.9 −6.0 ~ +16.8 否
test 三标签全对 66.8 71.9 −5.0 −18.0 ~ +9.1 否
test 摘要 ROUGE-L 62.2 29.3 +32.9 +25.7 ~ +40.5 是
ood_test 类别 72.6 65.0 +7.7 −2.6 ~ +17.9 否
ood_test 情感 85.5 69.2 +16.2 +6.8 ~ +25.6 是
ood_test 紧急度 72.6 72.6 0.0 −10.3 ~ +11.1 否
ood_test 三标签全对 58.1 58.1 0.0 −11.1 ~ +12.0 否
ood_test 摘要 ROUGE-L 35.9 32.4 +3.5 −3.1 ~ +10.2 否

三点观察:

5.1 两者一致时很可靠(事后分析)

把模型和规则的三个标签逐条对比:

数据 两者三项完全一致的比例 一致时的三标签全对率 不一致时:模型对 不一致时:规则对 至少一方对
val 64.2% 98.7% 43.5% 30.5% 89.9%
test 52.3% 94.3% 36.7% 47.2% 89.4%
ood_test 44.4% 86.5% 35.4% 35.4% 77.8%

两种方法犯的错很不一样,所以“两者一致”是一个相当强的可信信号:大约一半的反馈可以直接采信,准确率在 86%–99%;剩下一半交给人看。应用的接口已经同时返回两者的结果。

这是看到结果之后才做的分析,没有预先设定,而且数据仍然是合成的。它是一个值得用真实数据验证的产品假设,不是结论。

6. 发布模型的细分结果与失败案例

6.1 同分布测试集上,哪些类型做得好

类别 样本数 类别准确率 三标签全对 摘要 ROUGE-L
功能建议 94 98.9 98.9 77.1
账号登录 115 87.8 53.0 55.2
功能故障 141 82.3 75.9 61.4
表扬认可 102 80.4 80.4 63.3
支付订单 125 77.6 61.6 74.9
其他 61 77.0 77.0 30.3
广告骚扰 105 62.9 49.5 61.1
性能体验 120 61.7 61.7 64.5
界面交互 114 54.4 52.6 59.1

按语气和修饰语:

样本类型 样本数 三标签全对 紧急度准确率 情感准确率
功能建议(中性 / 正面 / 负面三种语气) 47 / 22 / 25 100.0 / 95.5 / 100.0 100 100
问题反馈 + 升级修饰语(“现在完全没法用了”) 65 58.5 100.0 100.0
问题反馈 + 降级修饰语(“不过只是偶尔出现”) 19 100.0 100.0 100.0
普通问题反馈 614 59.3 78.7 91.0
咨询 22 45.5 45.5 45.5

6.2 分布外开发集上的失败案例

ood_dev 的 63 条里,发布模型三标签全对 34 条,至少错一个标签 29 条。完整清单见 失败案例:分布外开发集。

出错字段 条数
只错类别 11
类别、情感、紧急度全错 9
只错紧急度 5
类别和紧急度 3
情感和紧急度 1

最多的两种类别混淆是 性能体验 → 功能故障(4 条)和 界面交互 → 功能建议(4 条)。

归纳成四种失败类型:

F1 摘要拼贴。 标签全对的 34 条里,有 20 条的摘要 ROUGE-L 低于 0.5;标签出错的样本,摘要通常也不对。模型没有在“概括原文”,而是在“从背过的摘要模板里挑一个,再把输入里的词塞进去”。下表后三条的标签是全对的,摘要仍然不可用:

原文 模型摘要 标注摘要
首月1元,第二个月直接扣了30,页面上那行小字谁看得见 首月界面发烫 自动续费被扣款
用了五年了,从学生用到上班,一直没换过 学生用上口无法上口 认可长期使用体验
定时提醒根本不响,害我错过了吃药时间 定时提醒关闭成电话骚扰 定时提醒不响
闹钟设的七点,结果八点才响,迟到了 消息通知收不到 闹钟延迟响铃
同样的商品,我的账号比我老公的贵20块,杀熟是吧 我的账号被盗 不同账号价格不一致

最后一条尤其需要警惕:三个标签都对,摘要读起来也通顺,意思却是错的,而且指向了一个更严重的问题(账号被盗)。分布外的摘要目前不能直接使用。

F2 关键词捷径。 某些词在训练数据里只出现在投诉中,表扬里一出现就被带偏:

原文 标注 模型
没有开屏广告这一点就值得五星 表扬认可 / 正面 / 低 广告骚扰 / 负面 / 中
用了五年了,从学生用到上班,一直没换过 表扬认可 / 正面 / 低 功能故障 / 负面 / 高
上传一个几兆的文件要十分钟 性能体验 功能故障
每次返回都回到列表最顶上,又得重新往下翻 界面交互 功能建议

F3 咨询识别不稳。 “你好,企业账号和个人账号有什么区别”被归为“其他”;“怎么解绑微信啊,找遍了设置都没有”被判成界面交互 / 负面。

F4 没见过的紧急度说法不起作用。 “导航完全不能用”“没法玩”都没有把紧急度升到高——训练里的升级说法是“现在完全没法用了”这几种固定搭配。

ood_test 的逐条失败案例已经保存(eval/results/ft-full-v1/ood_test.failures.jsonl),这一轮我只看了它的汇总指标,没有逐条阅读,以保持它对第二轮实验的独立性。

7. 第二轮:针对失败案例改数据,有没有用

假设:第 6.2 节的四种失败都源于训练数据覆盖不够,把对应的说法补进语法就能改善。

做法:只依据 ood_dev 的失败类型扩充语法(新增 44 个问题类型、190 个核心表达,训练集从 5146 条增加到 8408 条),训练设置与 ft-full-v1 完全相同,只换数据。数据怎么改的见 数据说明。

结果(三标签全对率,%;v2 取训练结束时的权重,原因见 训练记录 第 7 节):

数据 性质 v1 数据 ft-full-v1 v2 数据 ft-full-v2-last 变化 差值 95% 区间
ood_dev(63) 第二轮就是照着它改的,不独立 54.0 90.5 +36.5 —
test_v2new(381) 新增问题类型里训练未见的说法 58.3 89.0 +30.7 —
val_v2(1444) v1 验证集 + 新增部分 73.8 77.0 +3.2 —
val(969) v1 验证集,对两者都独立 78.9 75.0 −3.9 −13.6 ~ +5.5
test(977) v1 测试集,对两者都独立 66.8 73.7 +6.9 −2.3 ~ +15.8
ood_test(117) 手写,对两者都独立 58.1 53.0 −5.1 −15.4 ~ +5.1

摘要 ROUGE-L 的变化方向相同:test_v2new 从 31.3 升到 68.9,ood_test 从 35.9 到 33.5。

结论:假设只成立了一半。

这说明手写集暴露的不是“缺了某几种说法”,而是“合成语法能覆盖的只是真实表达空间里很窄的一条”。照着开发集补 44 个问题类型,开发集上涨到 90%,对另一份同样来源的测试集却没有帮助——这是典型的打地鼠。继续手工扩充语法不是出路。

决定:v0.2 不发布。v0.1 继续作为当前版本。

这一轮实验的两个局限:

8. 对照实验说明了什么

训练前后。 官方权重用相同的简短指令,格式合规率 0%;把标签集合和一个示例都写进提示词,格式合规率 18.8%,三标签全对 1.3%。这个 64M 的模型靠提示词做不了这个任务,必须微调。

预训练权重的贡献。 随机初始化、只用 5146 条任务数据训练的 scratch-v1,格式合规率也是 100%,验证损失也降到了 0.20,但三标签全对率在验证集上比 ft-full-v1 低 20.2 个百分点(区间 +12.6 ~ +28.1),测试集上低 8.1 个(+0.4 ~ +15.9)。分布外摘要 ROUGE-L 只有 22.2。预训练权重提供的语言知识,对“认出没见过的说法”有实际帮助。

全参数与 LoRA。 验证集上全参数高 9.9 个百分点,测试集和分布外测试集上 LoRA 分别高 4.6 和 6.0 个百分点。方向不一致,只有一个种子,不能下结论。LoRA 只训练 0.6% 的参数就达到了相近的水平,这一点是确定的。

从“仅预训练”权重出发的对照没有运行,所以“上游的对话微调阶段有没有帮助”这个问题没有答案。

9. 速度与资源

发布模型 ft-full-v1,Apple M5:

项目 数值 说明
CPU 单条请求延迟 平均 134 ms,中位数 127 ms,P95 176 ms 逐条调用 60 条测试样本
CPU 生成速度 约 178 token/秒 平均每条生成 24 个 token
MPS 批量吞吐 约 44 条/秒 按提示词长度分组成批
参数量 / 权重文件 63.91M / 131.3 MB half 精度存储
训练时 MPS 内存 约 9.2 GB 批大小 32,float32
关键词规则 每秒约 9 万条 作为参照

10. 这份评测本身的局限

11. 下一轮计划

按优先级排列,每一项都对应上面的一个具体发现。

优先级 做什么 依据 怎么判断有没有用
1 拿到 100–300 条真实反馈,建一份真实测试集 第 7 节:合成语法覆盖不了真实表达;现有结论都无法外推 所有系统在真实测试集上重跑一遍
2 把选检查点的指标从验证损失改成验证集生成准确率;每个配置跑 3 个种子 训练记录第 7 节:验证损失两次选错;第 3.3 节:单种子下排名不可信 同一配置多个种子之间的波动小于配置之间的差距
3 用大模型改写来扩充训练数据的说法,而不是继续手写语法;测试集由别人或别的模型来写 第 7 节:手工补语法是打地鼠;数据说明:自己出题自己答会泄漏 在新的独立测试集上,三标签全对率的提升区间不含 0
4 摘要改为“从原文抽取片段”,或者在分布外输入上不输出摘要 第 5、6.2 节:分布外摘要不比抄一句原文好,还会编造 人工评“摘要是否忠实于原文”的比例
5 验证“模型与规则一致则采信”这个组合策略 第 5.1 节 真实数据上,一致样本的准确率是否仍明显高于整体
6 加一个 BERT 类分类器作为对照 模型在标签上没有超过规则,需要知道是任务难还是方法不合适 同一份测试集上的类别、情感、紧急度准确率
7 跑完“从仅预训练权重微调”的对照 第 8 节:这个问题没有答案 —

不打算做的:继续按失败案例手工扩充语法;在没有新测试集的情况下调参。

本页由 docs/09-evaluation.md 生成。