本篇不讲技术栈,讲讲我的个人经历。
一、一个偶然的发现
在做一个 3GPP 规范问答的 Agent 开发时,有天测了一道题:
「IAB-donor 是什么?」
同一个问题,我跑了三次。
第一次 ,它答:IAB-donor 是宿主基站,是 NR 回传在网络侧的终结点,本质上是一个支持 IAB 的 gNB。还对。
第二次 ,它答:IAB-donor 是 Internet Architecture Board(互联网架构委员会) 的成员,常见于 IETF 会议差旅资助语境。
第三次 ,它答:IAB-donor 是 IASB(国际会计准则理事会)的捐赠方,是给 IFRS 基金会提供资金的机构,还给我讲了资金来源改革的历史。
三次。三个完全不同的领域。而且每一次都很自信、都长篇展开、都没有查我那份 38.300 的文档。
IAB 这个缩写在训练数据里至少有三个含义。它每次随机挑一个,然后一本正经地讲下去。
那天我才意识到一件事:用户看到的「正确答案」,取决于模型这次想起了哪段训练数据。
二、构建评测集
为验证模型回答的准确率, 我构建了 20 道题的评测集,分 7 类:
| 类别 | 题数 | 考什么 |
|---|---|---|
| 单工具 | 3 | 基本调用 |
| 多工具 | 2 | 一次两个工单 |
| 长文档 | 3 | 截断后的完整性 |
| 异常边界 | 3 | 库外城市、除零、非法参数 |
| 跨节推理 | 3 | 需要查两次 |
| 计算 | 3 | 参数构造 |
| 拒答 | 3 | 库里没有的东西 |
判分方式很关键:不能用「答案字符串 == 标准答案」。
事实上,同一个问题连跑 10 次,答案长度在 22--31 字之间波动,每次措辞不同,但意思相近。
所以判分只能判「关键信息有没有说到」------每题预设几个必须出现的字符串,全部命中才算通过。
三、误判
第一轮测试,准确率:17/20。
三道错题,我一道一道去看原始答案。最终结果------两道是误判。
第一题:题目是「算子里的 abc 乘以 3」。
我的关键词是 "不支持"。而模型答的是:
计算器只支持数字和 + − * / ( ) . 这些符号,没法直接算 带字母的
abc * 3。 如果你是想做代数化简,结果就是 3abc。
它答对了。 而且比我要求的更完整------它不仅说了不能算,还主动给了代数结果。
只是它没说「不支持」这三个字,它说的是「没法直接算」。
第二题:题目是「IAB-node 的两部分功能」。
我的关键词是 "IAB-MT"。而模型答的是:
移动终端部分(MT ,Mobile Termination) 分布式单元部分(DU,Distributed Unit)
内容正确------MT 向上连、DU 向下服务、F1 接口。但它写的是 MT,不是 IAB-MT。
我的判分要求完整术语,它用了简写,最终导致误判。
那一刻我想到:
判分比被测系统更容易出错。
而且这类错误很隐蔽------它不会报错,只会让数字变难看。如果不查看原始答案,就会得出「模型有问题」的结论,然后去改一个根本没坏的东西。
四、通过率 100%,但是真的 100% 正确吗?
把关键词从 "不支持" 改成 "数字"、从 "IAB-MT" 改成 "MT",重跑,准确率:20/20。
但这并不能说明「我的 Agent 准确率 100%」。
因为我是看着这 20 道题的答案去改的判分标准,对着答案改评分标准。
arduino
看到模型答"没法直接算" → 把关键词改成"数字" → 立刻通过
实际上这是 overfitting to the test set(对测试集过拟合)。同一批 20 题,既是调参集,又是测试集。分数不再衡量能力,只衡量「调得多准」。
所以 20/20 只能读作:
「在这 20 道题上,答案内容全部通过。」
不能读作:
「准确率 100%。」
要严谨得有留出集:用一批题调判分,用另一批没见过的题测。 但题库只有 20 题,拆两半每半才 10 题,错一题就掉 10 个百分点,误差太大。 所以这只能算开发集,不是泛化准确率。
五、通过率 100% 后,如何衡量改动效果
接下来我遇到一个问题:天花板效应。
20/20 之后,我想改点东西,然而无论怎么修改都还是 20/20。看不出任何差异。
满分意味着没有测量能力。
所以我得先换一把尺子------找一个「现在确实做得差」的指标。
我选的是条款引用率 :答案里有没有给出可核验的条款号,形如 §4.7.1。
我目前 Agent 的核心功能是「答案带条款引用」,用户问「RRC 重配条件」,模型答得再顺,仍无法判断它是查的还是编的------除非它说「见 §5.3.5」。
测基线(原有代码):
ini
准确率:20/20
文档题带 §:0/6 = 0%
裸数字引用("4.7.1 节"):7/20
一道都没有 §。 有 7 道写了「4.7.1 节」,格式虽然不规范,但至少提到了。
六、prompt 改动
只改一处:在 messages 前面加一条 system 消息。
回答涉及 3GPP 规范内容(例如 TS 38.300 的章节)时,必须在答案中标注条款号,格式为 §4.7.1。不要只写「第 4.7.1 节」或「4.7.1 节」,要写成 §4.7.1。
重跑:
ini
准确率:20/20
文档题带 §:6/6 = 100%
裸数字引用:0/20(原来 7 处,全部规范化)
准确率零损耗,格式全部规范化。
但此时有处错误 :开始算的是 6/20 = 30%,关键是分母是错的。
20 道题里只有 6 道涉及 3GPP 章节(长文档 3 + 跨节推理 3)。剩下 14 道是天气、计算、时间、拒答------它们引用条款号反而是错的。
如果把 30% 报出去,看到的人第一反应会是:
「还有 14 题该引用却没引用,得提升。」
然后就会去优化一个根本不该存在的指标。
指标选错,优化的方向就错了。
七、结论
第一,判分比被测系统更容易出错。
三轮跑下来,模型内容全对,判分给了 2 个假阴性。而且这种错不会报错,只会让数字变难看。
第二,满分意味着没有测量能力。
20/20 的时候,怎么修改看不出效果。想证明改动有效,得先找一个「现在做得差」的指标。
第三,指标选错,方向就错了。
分母里塞了不该计的题,30% 会导致优化一个错误的目标。
最后,现在只能说:涉及 3GPP 的 6 道题,引用格式全对了。
至于引用得对不对------它引的 §4.7.1 是不是真的支持那个结论------还没测试。
下一步我将验证它引用的条款,是否真的支持结论。
本文的 20 题评测集、判分脚本、跑批脚本都在 github.com/hish-hish/a... 的 evals/ 目录下,可以复现。