图1

图2

—–laya在本机落成侧记,时间三天,踩坑很多,让我一一道来!

系统的每一次工具调用之前,都要先做一次判断,这一步动作是直接执行,还是转给人确认。

只读的命令转人判,是多余的打扰;写文件、删数据、推远端、改系统设置的命令直接执行,判错了就没有退路。本机57天的日志里,这样的调用有119,809条。

这在决策智能里是最简单的一类问题,二选一,标准明确,可以用代码复算。把它交给一个本地小模型,试了三轮都没成,换过的是题目和它的标签,模型没换。第四次补上的是标签的来源,损失才第一次低于“只按比例猜”。

图3

PART 01

图4

标签不在输入里,这件事不用训就能证伪

图5

一个二分类问题能不能学,答案先写在训练损失里,损失就是衡量它错得有多离谱的那个数。如果答案不由题面决定,模型唯一能学到的就是训练数据里两类的比例,于是损失会停在“只按比例猜”那个水平,怎么训都下不去。

这个水平可以算出来,两类各占p和1减p时,一个永远只按p去猜的模型,损失是一个只跟这个比例有关的固定值。两类是6.8%和93.2%时,它是0.2484;是20.5%和79.5%时,它是0.5073。

那条“这一步动作会不会翻车”的任务,该转人的那一类占6.8%,训练到最后,损失停在0.34,另一次尝试停在0.40。两个数字都高于0.2484,也就是说,让模型学,还不如让它什么都不学。

为什么学不到,顺着标签的因果链看就清楚了。一件事从头到尾的链条是上下文、决策、执行、结果,标签却取自末端,看的是退出码非零、报错、用户当场打断。

输入只包含链条的起点,抽二十条该转人的样本一条条摊开,翻车的原因几乎全是文件不存在、依赖没装、脚本自己带着bug,这些事实在决策那一刻还没有发生。

这条答案不由题面决定,它取决于输入之后发生了什么,而模型学不会还没发生的事。

判这件事不需要显卡,开训前跑三道检查就够,同一输入有没有两种标签、表面特征能不能单独把标签判出来、以及跟“只按比例猜”的那份对照。

换掉的题目是“这一步动作该不该自动执行”。判断标准能由人写成文字,看动作文本就能定,标签就写在输入里。

同一套训练方法,同一个模型,损失降到0.1867,而只按比例猜是0.5073,第一次真正低于它。

随便取一条该转人的和一条该自动的,它把该转人的排在前面的可能是0.9563,这就是AUC;它报出的把握和实际命中频率差多少,用校准误差衡量是0.0777。

图6

PART 02

图7

选项一多,模型就分不清,训多久都是噪声

图8

更早一次尝试是让模型从30个工具里挑一个。零样本准确率19%,微调之后48%,而“永远选最常用的那个工具”这条最笨的做法能到68.7%。

问题不出在训练,问题在它的架构,这个模型每次只算一遍,只输出一个选项,而且选项是当作文本编码进同一段序列里的,所有候选项要挤在同一段输出位置里。选项一多,位置就不够分,候选之间的区别就模糊了,架构本来就只装得下很少的选项。

laya官方文档里给过实测,选项涨到77个的时候,准确率掉到0.425。

官方自己划的强区是选项很少的闭集判断,微调之后三类题目分别是0.857、0.733、0.723,弱区写得也很直白,选项一多就崩,状态一长就崩,非拉丁文字就崩。

选模型这件事,选的是它的架构能装下哪一种题目形态。落到工程上有三条界限,选项不超过6个,上下文不超过1024token,判断标准是能由人写成文字。

PART 03

图9

能写成代码的先判掉,模型只管剩下的那一小块

图10

单靠模型能挡住的活很少,真正管用的是把能写成代码的判定摆在模型前面,让模型只管剩下的那一小块。

这段代码在119,809条真实工具调用上判掉了80.4%,成本是零,延迟也是零。只读的命令直接放行,删文件、推远端、动进程、改系统设置的转人。

规则本身也会错,这一点比规则有用更值得记。第一版按竖线切命令段,把引号里的正则切碎了,像grep -iE ‘a|b’这种只读命令被当成命令拼接,拿不准的部分虚高到57.8%。

改成先认引号再切之后降到31.1%。这不是调参,是把解析改对,而解析错了比参数错了更难看见。

第二版补的是工具级规则,把代码执行、子代理派发、技能文件修改、定时任务、浏览器交互这几类工具按意思归到自动或转人,拿不准的部分从31.2%压到19.6%,其中“还没写规则”的那一部分从12.7%降到1.1%。

剩下拿不准的部分里94.5%是终端命令,也就是真正需要语义判断的那一部分。规则的边界不在能力,在枚举成本,而后者是个会一直变大的数。

这些命令归成同类写法,能看出成本有多高。22,151条终端命令归成7596种写法,剩下的一千多种各出现不了几次,散得很开,靠一条条写规则写不完,这一块就该交给模型。

官方的做法是同一个思路,它在前面放了一个纯Python的路由器,在半毫秒内识别文字脚本再决定进哪个检查点,比模型自己算一遍快六十倍。

先用能写成代码的办法划出范围,模型只在这个范围内出力,这是让两类手段各干自己擅长的那一段,不是谁替代谁。

PART 04

图11

误拦的代价更大,所以判错了要能退回来

图12

这条链路里两种错误的代价不一样,漏拦是白花一次云端调用,账面上只是浪费;误拦是让一个干不了这活的去干,结果只会更差。

两边代价不一样,看哪个数就得跟着变,只能看拦下来的人里有多少真该拦,不能看总共对了几成。

早期一版四类路由给出的数字很直白,拦截精准率64.4%,拦三个错一个。想靠置信度把精准率提到95%,阈值要卡到0.98以上,覆盖率只剩0.4%,精准率和覆盖率互相矛盾,这条路走到头也没有收益。

更值得记的是误拦拦错了什么,误拦的442条里有409条实际是终端命令,这409条里逐条看过,83%真的需要shell,rm、pytest、跑脚本这类活,窄工具干不了。

这说明同一件事本来就有两种干法,可以用窄工具,也可以用万能终端,日志记下的是当时那个选择,不是唯一正确的答案。

为了把这件事钉死,做过一次决定性实验,可以让本地那个9B模型真去写这些命令,看能不能写出等价的。60条里等效4条,6.7%,而且这4条还是“解释器写成裸python、勉强算对”的从宽口径,按严口径是零。

这个负面结果同时证明了两件事,能不能本地做和必须上云端之间,是真的能力差异,本地兜底这条路走不通。

结论落在架构上,既然误拦躲不掉,就让它变便宜,把拦截限定在能退回来的范围里。判错了退回云端,代价从结果变差降成一次失败重试。自动和转人的分界线划在“判错了能不能退回来”上,不划在“难不难”上,原因就在这里。

图13

PART 05

图14

蒸馏换来的不是能力,是位置

图15

题目换对之后,日志里人点过的记录,只有28条确认、0条拒绝,57天攒不出一个数据集,人工标注这条路走不通,于是改用最强的那一档生成。

这条路的正式名字是硬标签蒸馏,把拿不准的命令送给远端大模型,让它判自动还是转人,顺手留下理由。三千多条标完,零显存占用,成本几毛钱。

蒸馏的上限是清楚的,学生的上限就是教师,学不会超过它,教师判错的地方会一起学走。所以它换来的不是能力,是位置,把一次云端调用换成一次本地计算。

这个定位决定了收益该记在哪一栏,真实账单摊开是221次一问一答,输入3000万token,其中99.01%命中缓存,缓存价是输入价的五十分之一,总花费0.1630美元。

就算路由器完美无错,把该拦的全部拦下来,上限也只省0.0635美元。省钱这一栏几乎是零,这是数字,不是看法。

收益记在别处,拦下来的那些回合吃掉980万token,占全部上下文的32.6%,而窗口是有硬上限的,这是拿不回来的余量。

延迟上,本地15.6毫秒对云端几百毫秒,第三方测过同类模型是7.6毫秒对588毫秒,差着两个数量级。最要紧的一项是数据不出厂,断网、隔离、甲方院内这些场景里,云端的钱不是省,是根本花不出去。

这里还有一条官方口径值得抄在墙上,置信度只能给决策排序,不能证明决策正确,而且模型错的时候也照样自信。所以阈值不是模型的属性,是在测得的质量与覆盖曲线上选出来的策略,选的是哪些错误可以接受。

外部给的数字比这更激进,伯克利的RouteLLM报过在MT-Bench上省85%成本、保住95%的GPT-4水平,FrugalGPT报过省到98%,用的都是标准考题,真实流量要脏得多。

方向是同一个,便宜模型先接,接不住才升级。

PART 06

图16

越用越准,靠的是新的信息来源

图17

一套会记录、会反馈、会重训的机制能不能越用越准,取决于新的信息从哪里来。任务判别、判定记录、样本汇总、重训替换四环搭起来不难,难的是每一环都别把同一份信息重复吃一遍。

教师标签是同一个来源的复制,标得再多,涨的是数据量,不是信息量,指标在1000到2000条之间就不动了,再往上堆样本,AUC的动静全落在噪声里。

这一条已经测出来,所以力气不该往样本量上使。

人的真实决定是独立来源,同一个动作被判定之后,人点过确认、点过拒绝,这些记录带着教师没有的信息,因为教师是从文本往前推断,人是从结果回头核对。这是唯一能让指标重新往上走的一类新信息。

有一条线不能碰,不许拿模型自己的输出当新标签。自己给自己打分,误差会一层层放大,越转越偏,而且偏得看不出来,因为一致率会很好看。

能这样越用越准的地方,按成本排有三处,规则层最便宜,把漏放和误拦的案例写进配置,今天就能生效;阈值层要攒一批反馈重算操作点,不能单条即时调,那样会左右横跳;模型层最贵,要等真实反馈攒够,而且换版要通过检查,同一个验证集上的指标不能低于现行,还得留一条回滚。

PART 07

图18

测量能力本身会骗人

图19

最容易被忽略的教训来自测量,不是模型,当时用551条、其中105条该转人的验证集,去测再补数据还有没有用,得到“每加1000条涨3个点”,据此又标了三千条教师样本。等验证集扩到826条重跑,同一区间是平的。

该转人的只有105条时,这个验证集能分辨的最小差别是4.2个点,按0.95的排序能力和Hanley-McNeil的标准误算,该转人的涨到170条,能分辨的最小差别才收到3.3个点,涨到600条才收到1.7个点。3个点的“趋势”本来就在分辨能力之下,读出来的是噪声。

这件事的教训落在顺序上,测一个效应之前,得先算这次测量能不能分辨它。于是它被做成了一道检查,输入数据集和切分比例,算出能分辨的最小差别,想说的差别比它还小就报错退出。这道检查在当初那个条件下必须报错,那是它的验收口径。

同一条纪律还有一半,标准要先写死再跑,免得事后往好里解释;但标准本身也要被数据检验,一条标准当时成立、换一个更大的验证集就不成立,那说明按这条标准做的测量本来就分不出这么小的差别,得如实说,不能把它当成结论。

图20

PART 08

图21

五条标准

图22

三次失败,没有一次败在模型上,都败在题目、边界和流程的设计上。从这可以看出大模型应用的落地最终都会回到工程化。

这件事能立住的标准有五条,标签必须在输入里,题目不能超出它给定的上限,能写成代码的判定先划出来,误拦必须能退回来,新标签必须来自独立来源。

这五条都不在模型的参数里,它们落在题目、边界和流程上。

同一台机器,同一个322M的小模型,同一套训练方法,前三次一件都交不出来,第四次交出来的是规则档在所有调用里判掉80.4%,本地模型在剩下拿不准的部分里再处理掉87.2%,折算到全体只剩2.5%需要上大模型,大模型调用比逐条送云端省掉97.5%。

真正稀缺的东西从头到尾都不在模型那一侧。