5B 小模型后训练冲榜实录:BFCL 涨了 2 分,AA 指数五次试点全部失败
先说结论:在一个 5B 级别的开源模型上做小规模后训练,行为类的评测能涨,能力类的评测基本涨不动。我们在 BFCL(伯克利函数调用榜)上把总分从 55.60 提到 57.57,模型已经发布为 Sylumen-5B;但转头去冲 Artificial Analysis(AA)的 Intelligence Index,四个方向(其中一个只做诊断)、五次训练试点,没有一次在本地代理评测上显著超过原版。这篇把过程、数字和坑都摊开讲,适用范围是 3B~9B 的稠密模型、LoRA、单次训练半小时以内的预算。
底座和预算是什么样的?
底座是 IFM/K2-Horizon-3.7B,实际约 5.1B 参数,36 层,GQA 8 个 KV 头,Apache-2.0。同家族还有 7B 和 32B,词表一样,这一点后面做蒸馏时用上了。AA 官方给这个 3.7B 的指数是 15.6,同家族 7B 是 20.6。
预算上我们给自己定了规矩:每个方向先写一页方向说明,讲清要修哪类失败、预期增益和止损条件;先做约 300 条数据、训练不超过 30 分钟的试点,有信号才放大;同一方向连续两次试点没提升就停。所有评测都和原版逐题配对,用 bootstrap 算置信区间,不看单次跑分。
BFCL 是怎么涨上去的?
路线是三步:先 SFT,再 GRPO,最后缩放 LoRA。
SFT 用了约 6,100 条工具调用对话,一半左右由老师模型生成,其余是我们自己合成的样本。之后用 GRPO 接着训,奖励是严格的规则打分:调用格式必须能被解析、函数和参数要对。这一版 v1 拒绝无关请求的能力明显变好,Irrelevance 从 73% 涨到 83%,但单轮、多轮和记忆类都掉了,总分和原版打平。
真正有用的一步反而最便宜:把 v1 的 LoRA 改动乘一个系数 0.3 再合并回原版,也就是 W' = W + 0.3·ΔW。0 等于原版,1 等于 v1,0.3 落在中间,副作用基本消失,好处留了一点。最终 v2 在 64K 上下文下的成绩:
| 模型 | Non-Live | Live | Irrelevance | Multi-Turn | Memory | 总分(不含 web_search) |
|---|---|---|---|---|---|---|
| 原版 | 76.92 | 71.35 | 73.10 | 39.00 | 54.41 | 55.60 |
| v2 | 76.60 | 70.39 | 74.28 | 39.25 | 59.17 | 57.57 |
总分的提升几乎全部来自 Memory 类(权重 40%)。老实说,Memory 单项的置信区间是 [−0.3, +9.8],原版自己跑四次就能差 12 分,所以这个提升方向是真的,统计上还不够硬。模型卡里我们也是这么写的。
这里有个大坑必须单独说:评测上下文开 16K 会冤枉模型。我们一开始用 16K,原版有 114 道、v1 有 82 道多轮题直接以 context_length_exceeded 判错。改成 64K 以后,排名都变了:16K 时 v1 看起来更强,64K 时反而是原版领先。如果你在复现 BFCL 多轮成绩,先检查上下文。
AA 指数为什么这么难涨?
AA 的指数由十项评测组成:Briefcase、GDPval 这类 agent 交付任务占大头,再加上 SciCode、Omniscience、LCR、HLE、CritPt、Terminal-Bench 等。题目只能用来本地评估,不能拿来训练,这是我们的硬规矩。我们在本地搭了代理评测,然后试了四个方向。
弃答 DPO(两次试点)。 Omniscience 惩罚瞎答,鼓励不确定时说”不知道”。我们用模型自己的错误答案做负样本、弃答做正样本,训完后训练对上的偏好移动了 +31 nats,可留出集上的弃答率只从 0.19% 变到 0.86%,幻觉率纹丝不动。教会了”更喜欢这些句子”,没教会”什么时候该停”。
同家族蒸馏(两次试点)。 词表相同,可以让 3.7B 逐 token 去拟合 7B 的 top-20 分布。KL 确实降了,但第一次蒸馏后幻觉率涨了 4.4 个百分点;第二次去掉事实问答,SciCode 两边都是 220/864,LCR 从 55% 到 59%,区间 [−7.2, +14.4],不显著。分布更像老师,能力没过来。
SciCode 拒绝采样微调(S1)。 让老师出科学计算题和单元测试,原版每题采 8 次,只留 8 次里过 1~6 次的题的自己的正确解,再拿去训它。这是最接近成功的一次:在 100 道自己出的留出题上,通过率从 45.5% 涨到 50.25%,+4.75pp,区间 [+1.0, +8.6],统计显著。可换到真正的 SciCode 上,215/864 对原版 220/864,−0.58pp。在自己的分布上学会了,没迁移过去。
Agent 诊断(不训练)。 原本最寄希望的是 agent 类任务,想着小模型是不是输在格式和流程上,比如不调用 finish、文件名不对。诊断结果是工具调用解析失败 0 次,失败都是语义层面的,比如违反任务约束、选错实体,而且 7B 在这些题上也一样做不好。不是 7B 会、3.7B 不会的那种差距,就没有开试点。
归根到底,3.7B 和 7B 之间 5 个指数点的差距主要是知识和推理容量,这是预训练决定的。半小时的 LoRA 改得了习惯,加不了容量。另外 DeepSeek V4.1 Flash 这种 1M 上下文的模型,KV 缓存每 token 只有约 890 字节,我们的模型是约 147K 字节,这也是架构和预训练层面的差距,后训练碰不到。
有哪些踩坑值得别人避开?
最贵的几个坑都不是算法问题,是流程问题:
- 训练集被悄悄砍小。 训练器拿最长的一条序列测速,测出 300 tok/s,就自作主张只训 104 条里的 25 条。实际稳态是 1,690 tok/s。之后规定每次训练后必须核对”实际训练条数 = 保留样本数”。
- n-gram 去污染误伤。 用 8-gram 精确匹配去和 SciCode 比,175 个命中里 167 个只是
np.array([1.0, 0.0, ...])、import numpy as np这种样板。命中的 n-gram 要排除样板,排除率异常高时要人工看片段。 - 代理评测被环境污染。 AutomationBench 基线里 35% 的题其实是 HTTP 中断,我们差点拿它当有效基线。环境错误超过 5% 就该判无效重跑。
- 评测的噪声比你以为的大。 原版换个随机种子,Omniscience 幻觉率能差 6 个百分点。没有配对和置信区间的对比,基本是在看随机数。
这个项目用的是”Claude 做规划和核验、便宜的执行器跑任务”的循环,每 15 分钟一拍,每拍检查偏差并把根因写进修正清单,最后攒了 53 条。比如”执行器不准往运行中的进程挂调试器”这条,就是吃过两次亏才写进去的。
结论和适用边界
如果你手上是一个 3B~9B 的模型、预算是 LoRA 加半小时训练,想涨的是格式、工具调用、拒答这类行为指标,SFT 加规则奖励的 GRPO 再配合 LoRA 缩放,是性价比很高的路线,BFCL 这类榜能看到实打实的提升。如果想涨的是 AA 这种综合能力指数,小规模后训练大概率是在噪声里打转,要么换更大的底座,要么准备预训练级别的投入。
五次失败不丢人,丢人的是把噪声当成果发出去。数字都在这里了,欢迎拿去复现,也欢迎来拍砖!