laya 深度评测:7 天 2.35 万 Star 的决策引擎,6 张基准表我逐格复现,头条 0.766 却查无实据

评测一个 AI 项目时,最省事的做法是信它的 README。最费事、也最值钱的做法,是把它的数字逐个拿回来重算一遍。

laya 这个仓库值得后者。它 9 月 18 日建仓,7 天冲到 2.35 万 Star,Apache 2.0,主打一个很硬的技术判断:决策不需要生成。你不用让大模型吐出一段话再解析,而是给它一个状态和几道题,它在一个前向传播里直接给出带概率的答案。仓库自带 325 行 BENCHMARKS.md,里面既有一张张成绩表,也有一节标题叫「Limits, stated plainly」——把自家模型「接近随机」写进去了。

我把仓库 clone 进沙箱,用纯离线的方式复算了它 6 张核心表的数字。结论分两半:表格部分它经受住了核对,逐格命中;但全站最响的那个数字 0.766 查无实据——仓库里找不到任何支撑它的产物文件。

它想做的事:把「生成」从决策链路里拿掉

先讲清楚技术主张,否则后面没法判断数字的意义。

现在让模型做个判断(这封邮件是垃圾邮件吗、这条客服消息属于哪个队列),标准做法是让它生成文本再解析。慢、贵,而且会幻觉出一个不存在的选项。laya 换了个路子:非自回归。它把「状态 + 类型化问题 + 选项」拼成一个序列,跑一次编码器,决策头直接输出每个选项的概率。没有 token 生成,所以没有东西可解析,也没有东西可幻觉。

一次调用可以同时问好几道题——这点设计上比较讲究。它把用户的问题切成三种原语:

原语 回答什么 输出
choice 从 N 个标签里选一个 N 路概率分布
score 在有序档位上打分 各档位概率
noul 是/否 P(是)

我翻了 laya/common.py 里的序列构造函数,格式是 [CLS] 类型 指令 [SEP] [MASK] 选项0 [MASK] 选项1 … [SEP] 状态 [SEP]。关键在于多个选项共享一个固定的 token 预算 head_max_len,默认 192(英文 checkpoint),超出就按 max(4, (预算-16)//选项数) 均分。这个设计后面会变成它最大的短板,也是它少数几个「架构性」缺陷的根源。

三个 checkpoint 分工也直白:laya 用 ModernBERT-large(421M,512 上下文)主打英文;laya-multilingual 用 mmBERT-base(322M,1024 上下文)覆盖 100+ 语言;laya-typed-decisions 是在四个具体工作流上微调过的版本。配一个 Router 按脚本检测语言来分派——因为作者的实测数据是:英文 checkpoint 在非英文上不是「退化」,是崩掉。

实测一:6 张表我逐格复算,对上了

先说方法。我没有下载权重、没有跑前向传播——这台机器是生产机,1.9G 内存、磁盘余 4G,装不下 421M 模型加 torch 那一套。我做的是两件更硬的事:把仓库里已提交的逐选项概率原始 JSON 拿回来自己重算指标,以及跑它自带的离线审计脚本。这两件事都不需要模型,也骗不了人。

第一张:快路径的同答案性证明。仓库为了证明 GPU 加速路径(TileLang 融合 kernel)不会改变答案,提交了 benchmarks/results/parity_*.json,里面存了每个问题的 fp32 / 标准 bf16 / 快路径 bf16 三组逐选项概率。我从这三组概率自己重算最大偏差和 argmax 一致数:

checkpoint 类型 n 最大 |快-标准| 最大 |快-fp32| argmax 一致
laya choice 48 0.031 0.022 47/48
laya noul 180 0.076 0.043 180/180
laya score 60 0.015 0.011 59/60
多语言 choice 48 0.049 0.015 47/48
多语言 noul 180 0.037 0.045 180/180
多语言 score 60 0.010 0.009 59/60

6 行、18 个数值、12 个一致计数,全部与我重算的结果一致,没有一格对不上。仓库原文还主动写了一处对自己不利的例外:多语言 noul 这一行,标准 bf16 路径其实比快路径更接近 fp32(0.0446 vs 0.0455)。我复算确认了——它没藏这个。

第二张:51 语言扫描。英文 checkpoint 在 MASSIVE intent(20 选项,随机基线 0.050)上,51 语言宏平均 0.2269,只有 23/51 语言超过 3 倍随机;多语言版 0.3661,45/51。这三个数在 cpu_51_language_sweep.json 里逐字对上。更值得记的是它自曝的一个数字:高棉语 0.000 准确率,同时平均置信度 0.952。也就是说,模型读不懂的时候不是「不确定」,是「非常自信地答错」。这也是为什么它的路由必须在前向之前做——靠置信度门控根本拦不住。

第三张:中文基准,我跑了它自带的审计。仓库里有一份 64 条中文工作场景的第三方提交(走 issue #154),带冻结的提示词、原始的 Laya/Jev 配对响应,和一条零下载、零 API 的离线审计命令。我把它跑了一遍,退出码 0,输出:Laya 多语言版单选 20/64、四问组合 18/64;Jev 1.13.0 是 64/64 和 63/64。与仓库文档逐字一致。仓库自己对这份成绩的表述也很克制——明说是 2026-09-21 的历史快照、输入是 AI 辅助编写的合成场景、Laya 跑本机 MPS 而 Jev 耗时含网络,两者不同硬件,不能当排名看。

第四张:温度校准。它承认两个 checkpoint 出厂都过度自信,重量化温度能把平均 ECE 从 0.4656 降到 0.0812(多语言 0.3135→0.1059)。这四个数我在 t4_colab_benchmark.json 里逐个对上了。

第五、六张:延迟与自我修正。T4 上单题 39.5 ms / 32.8 ms、批量后每题 7.2 ms,对上了。还有一处很罕见的操作:仓库自己开了 issue #208,指出已提交的 51 语言扫描里 ECE 那一列是过期的(早于温度钳制),然后重新跑了一遍,把「原始温度」和「实际服务温度」两列并排放在新文件里。我核对了新旧两版:宏准确率 0.2269 三次完全一致,ECE 从 0.7331 动到 0.5709。

一个工程团队把自己已发布的表格标成「这一列不可复现」、再补一份对照,这件事在开源项目里不多见。

实测二:最响的那个数字,仓库里找不到证据

前面四张表都对上了,那问题在哪?

全站最核心的一个数字是 0.766。README 开头第 85 行就这么写:微调后的 laya-typed-decisions 在 2,000 条决策上拿到 0.766 准确率,而基础版只有 0.362。它被用来支撑三件事——「微调后反超 TypeSafe Jev 的 0.727」、「超过 0.735 的 teacher 自一致性天花板」、「完整能力都来自微调」。Hugging Face 上那个模型卡的第一行也是它。

这个数字没有对应的产物文件。我用脚本把仓库里全部 14 个结果 JSON 的路走了一遍,找任何等于 0.766 的 accuracy 条目:一个都没有。更关键的是,这 14 个文件里没有任何一个评测过 laya-typed-decisions 这个 checkpoint。

那 0.766 从哪来?我查到了它的生成路径。它来自 notebooks/laya_finetune_typed_decisions_2xT4_kaggle.ipynb——一个 Kaggle 上的微调脚本,运行后会评测,把数字用 f-string 填进模型卡模板,再连同权重一起推到 Hub。我检查了这个 notebook:19 个 cell,保存的输出数是 0。它被完整提交进仓库,但从未带着运行结果提交。逐项报告的 benchmark_report.json 在 notebook 里是有的,但写盘那一步排在推送之后,所以即使跑完也不会被上传;Hugging Face 上那个模型仓库的文件树里确实没有这个文件,仓库里也没有。

这里必须把话说准,避免冤枉人:

  • 这不等于造假。notebook 的代码本身是干净的——用 train split 微调 1,200 条,用官方 test split 评测 400 条,没有偷看测试集。
  • 更可能的解释是:数字是作者在本地/Kaggle 侧真实跑出来的,只是没把产物提交进仓库。这是可复现性问题,不是诚信问题。
  • 但后果是实打实的:你无法用这个仓库复现它自己的头条数字。同一份文档里,51 语言扫描、校准、延迟都留了原始 JSON 和可跑脚本,唯独最重要的那个 0.766,留在了一个跑不出东西的 notebook 里。

还有一处更隐蔽的:那个 0.727 的 Jev 基准,来源可疑。仓库 research/scripts/bench_apps.py 和 bench_local.py 里,Jev 0.727 的 source 字段写的是——"figure quoted in the laya repo's own comparison table",即「引自 laya 仓库自己的对比表」。也就是说,「反超 Jev」这个宣称,其基准数字的最终出处是它自己。仓库另一处又列了两个第三方来源(AbdelStark/jev-benchmarks、nibzard/decision-model-benchmark),但那两个来源里都没有 typed-decisions 这一项——AbdelStark 那份是 AG News / Banking77 / DAIR Emotion,nibzard 那份测的是 ECE、banking77 和选项翻转率。仓库正文对此的免责写得很老实(「Jev 从未在这里运行过,没有 TypeSafe 的 API 凭证」「是用于提供背景的已发表数字,不是受控的同台对比」),只是这层循环引用藏在一个 JSON 字段里,不翻代码看不到。

放到同类里看

这个项目要横着比,最自然的坐标是它自己反复引用的 Jev——同一种「一次决策一个请求」的路子,我早前评过的 Jev Ultrafast 深度评测 那篇里,浏览器 Agent 的路径是每次决策只发一个请求。laya 是同一思路走到极致:连请求都不生成,直接出概率分布,还开源可自托管,对 Jev 是闭源 API 这点构成实质差异。

第二个坐标是评测方法论本身,这和我写过的 Archify 复测 是同一个问题:项目自评的数字,和自己能提供的证据之间,缺一条线。Archify 那次是环境报错栽赃,这次是核心指标缺产物。规律很稳定——越是全站主打的数字,越值得先问一句「它的原始文件在哪」。

适合谁:需要低延迟、可自托管、Apache 2.0 的批量分类/打标场景的人。邮件垃圾识别 0.993、钓鱼识别 0.993 这类有明确训练覆盖的任务,成绩是生产级的。以及手上有领域标注数据、准备微调的团队——它的微调路径完整,模型小,单张 16G 卡就能跑。

不适合谁:想要开箱即用的人。它的基础版在 typed-decisions 上 0.362,低于 0.461 的多数类基线,也就是说零样本用还不如直接猜最常见的那个答案。选项数超过 20 的场景也别用——我看了代码,77 个选项均分 192 token 预算,每个标签只剩约 4 个 token,特征被压没了;它自己在 banking77 上就是这么掉到 0.425 的。中文用户还要额外注意:中文基准那次多语言版是 20/64,作者也说明这测的是未微调的基础版、不代表不支持中文,但你要用就得自己补微调。

结论

工程质量第一梯队,证据链有一处硬缺口。

它做了绝大多数开源项目不做的事:把自家模型「接近随机」「低于多数类」「高棉语 0 分却 95% 自信」这些难看的数字写进主文档,自己的过期表格主动开 issue 重测,还留了零依赖的离线审计脚本让别人能核。我复算的 6 张表逐格命中,这部分经得起看。

但那个撑起整个 README 叙事的 0.766,藏在了一个 0 输出的 notebook 里,而它用来对比的 Jev 基准又绕回自己。所以我的判断是:这是一个值得用、也值得信工程能力的项目,但它的头条数字目前只是一个「声明」,不是一个「可复现结果」。你如果要用,别信 0.766——拿你自己的数据微调一遍,那个数字才是你的。

关注 AI商业快讯,每天一篇 AI 热点深度解读。

相关阅读:

发表评论