泼冷水:90.12% 裸精度不算数,决策模型的天花板在"选项多了就崩"
【免费下载链接】Bespoke-Nimble-9B项目地址: https://ai.gitcode.com/hf_mirrors/bespokelabs/Bespoke-Nimble-9B
9 月下旬,Bespoke Labs 开源的 Bespoke-Nimble-9B 借着"System One 决策模型"的东风火了一轮:不生成文本、只从给定选项里挑答案、一次前向传播出概率,配合 Ollama 0.35 的本地化支持,被社区包装成"客服工单路由、Agent 决策、内容审核"的即插即用组件。CSDN 报道中"判断准确率达 90.12%"的数字更是成了传播锚点。但如果我们把这层热度剥开,回到仓库本身的评估配置与推理代码,会发现一个更值得讨论的事实:90.12% 是在一个低基数为主、选项顺序固定、样本高度受限的环境里测出来的裸精度,它既没有回答"选项多了怎么办",也没有回答"选项顺序换了怎么办"。本文以仓库源码为据,把这三个问题逐一拆开:这个数字是怎么测出来的、Softmax 在高基数下为什么会崩、以及决策模型真正的适用边界在哪里。
一、90.12% 是在什么任务集上测的:样本构成与选项数
先看仓库自带的评估契约。schema_config.json 里的data_audit字段给出了完整的数据账本:
- 训练 12,026 行 / 8,468 分组 / 5,370 family,验证集仅324 行,注册的评估只有两个:
bespoke-eval(324 行,标注reporting_only)和jevbench-eval(534 行); - 验证集按任务类型拆分:
choice(多选一)146 行、noul(布尔判断)114 行、score(评分)64 行——没有一个是真正的高基数分类任务; - 训练集里,布尔与评分任务合计 3,946 行(
noul2,412 +score1,534),占比近三分之一;choice 任务 8,080 行中,绝大多数来自original(2,826)、contrastive-addition(1,000)、retrieval-classification-local(1,200)等自建组件,选项数被限制在可枚举的小范围内; - 唯一的高基数公开数据集
public-banking77(77 类)只有 2,000 行,public-dbpedia(14 类)、public-trec(6 类)、public-ag_news(4 类)各仅 500 行。而test_split_used: false、heldout_family_overlap: false明确表示:公开测试集未被用于训练,但也意味着报告口径里没有公开测试集上的成绩。
还有一处容易被忽略的细节:validation_order: "original inference choice order; no shuffling"——验证时选项保持原始推理顺序,不做打乱。也就是说,这个 324 行的验证集连"选项顺序鲁棒性"都没有纳入考察范围。
结论很直接:社区流传的 90.12%(仓库本身并未记录该数字,它是媒体报道口径)即便准确,也只能代表"低基数任务 + 固定选项顺序 + 训练分布内样本"的受控环境。它测的是模型在熟悉地形里的稳定发挥,而不是它在陌生选项空间里的泛化能力。
二、高基数场景为何集体翻车:Softmax 与选项爆炸的数学直觉
要理解高基数为什么是决策模型的死穴,先看推理核心。inference.py 中的candidate_logits直接从最后一层 logits 里用gather取出候选 token 的分数,然后decision_result里执行一次温度缩放后的 softmax:
scaled_logits = logits / temperature probs = scaled_logits.softmax(-1) index = logits.argmax().item()配合 temperature_config.json:temperature: 1.0、temperature_fitted: false——这个版本没有做任何温度校准,上一版的 2.179 校准值被明确废弃(README 也特别提醒"do not reuse the older model's 2.179 calibration")。
问题就出在这个裸 softmax 上。设选项数为 K,若各候选 logit 相当(模型对它们的区分度有限),softmax 输出趋近均匀分布 1/K。要让某个选项拿到超过 0.5 的概率,所需的 logit 边际随ln K增长:K=2 时约 0.69,K=25 时约 3.18,K=255 时约 5.54。反过来看,当训练数据几乎全是低基数任务时,模型学到的 logit 边际模式是为"几个对手"设计的;一旦选项数翻到几十上百,同样的 logit 尺度摊到更多竞争者头上,最高概率被系统性稀释,argmax 与第二名的差距被压缩到噪声量级——此时温度微调、数值精度、甚至选项顺序都会改变预测结果。
比数学更致命的是编码层的先验失衡。仓库把候选码表从 26 个(A–Z)扩到 255 个(A–JT),但请看 schema_config.json 的candidate_codes:255 个码里 229 个是双字母/三字母,而 Qwen3.5 的 BPE 词表根本不会给每个双字母分配独立 token。extended_schema.py 的extended_codes注释写得很直白:"Qwen3.5 splits multi-digit numbers",代码只能用len(tokenizer.encode(s, add_special_tokens=False)) == 1暴力过滤"能作为答案边界单 token 使用"的大写码。结果就是码表布满缺口:BQ、CJ、CM等双字母被 BPE 拆开,只能跳过;剩下的码对应的 token id 从 32(A)一路分布到 93924 这种预训练语料里几乎不出现的高位 id。前 26 个单字母码是模型熟悉的"常客",后面 229 个码是词表里的"边缘人口",它们的 logit 先验天然就不均匀——模型要在"谁更可能出现在答案位置"的 token 先验之上再叠加"谁代表正确的类",双重不确定性随 K 放大。
社区的两个观察与这个分析互相印证:开源复刻 Laya 的测评明确提到"高基数分类(如 77 类 Banking77)表现受限";另一篇对 8 个开源 Jev 复刻项目的横向核查则把"RLCD 式概率校准、高基数选项泛化、选项顺序鲁棒性"列为当前所有方案的共同差距。这不是 Nimble 一家的问题,而是"读 logits + softmax"这条技术路线的结构性天花板。
三、决策模型适用边界:25 类以内很香,以上请另请高明
仓库代码其实已经用工程结构标出了能力分界。看 serving_schema.py 的调度逻辑:
width = max(len(extended_schema.choices_for(field)) for field in schema.values()) module = parallel_schema if width <= 26 else extended_schema26 类以内走parallel_schema(单字母码 A–Z,训练分布的主力),超过 26 类才切换到extended_schema(255 码宽提示)。255 这个"max_choices"只是接口上限——能编码这么多候选,不代表模型有能力在这些候选之间做出可靠区分。训练数据分布也印证了这一点:12,026 行训练样本中,高基数公开集合计只有 3,500 行,且全部按低基数任务的配方提示构造;README 对评分、布尔、枚举的使用说明也暗示了设计者预期的场景全部是有界小枚举。
结合前述 ln K 的数学约束和 26 类的工程分界,"25 类以内很香,以上请另请高明"是一个有据可依的判断:
- 25 类以内(最好是个位数):路由、护栏、意图分类、布尔判定、3–5 档评分等场景,logit 边际足以撑起稳定 argmax,一次前向传播出概率的延迟优势(配合本地部署可做到几十毫秒级)是实打实的;
- 超出 25 类:先把大枚举压缩成两到三级的小枚举,用"决策树式分层"——第一层先粗分类到十几类,第二层再在子集内精分。直接把 77 类、上百类塞进一个 softmax,等于让模型在 ln K 的数学定律面前裸奔;
- 无论选项多少:生产环境必须自建选项顺序打乱与置信度阈值(ECE/Brier 检查),因为仓库验证协议本身就没有覆盖顺序鲁棒性,而
temperature_fitted: false意味着输出的概率绝对值并不自带校准保证。
90.12% 是一面诚实的镜子,只是要看镜子里照的是哪块地形:在它照到的地方,决策模型确实快、便宜、够用;在它照不到的高基数与乱序选项面前,崩盘不是意外,而是 softmax 数学与 token 先验的必然。理解了这条边界,"System One 决策模型"才算真正落地——把它当作一个有严格适用域的快速分类器,而不是一个万能决策引擎。
【免费下载链接】Bespoke-Nimble-9B项目地址: https://ai.gitcode.com/hf_mirrors/bespokelabs/Bespoke-Nimble-9B
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考