同一个模型,同一套代码,同一组 60 个随机种子,什么都没改,跑了两遍。平均打到的回合数,一遍 6.58,一遍 6.32。
差 0.26 回合,看着不多。可其中一个种子,第一遍打到第 15 回合,第二遍第 3 回合就死了。两遍从第 7 步开始走岔,岔在商店里买没买一张小丑。
后来我改了一句提示词,平均回合涨到 9.12,60 局配对 36 局更远、7 局更近,这个是真的。但把同样这 60 局按顺序切成三段,第一段 20 局只涨了 0.65,p=0.30。我之前的实验全是 20 局一批,所以这一句话要是早一周写出来,大概率会被我当成「没效果」扔掉。
想直接拿公式的看第 3 章和第 5 章;想知道「什么都不改跑两遍」为什么还不够,看第 5 章。
1. 让 35B 玩小丑牌
小丑牌(Balatro)是一个扑克牌型的肉鸽游戏。每回合有个分数线,你打出牌型拿分,过线进下一回合,不过就死。中间逛商店,买「小丑」,它们会给分数加倍率,后期全靠小丑撑着。每三个回合算一个「底注」,越往后分数线涨得越凶。
我让一个 35B 的本地模型在掌机上玩。玩法很省:游戏 mod 把当前所有合法动作列成 A、B、C…… 候选,模型只读一个 token,看哪个字母的概率最高就选哪个。一步大约 150 毫秒。
指标就一个:一局打到第几回合。基线也放了两个,「永远出估分最高的牌」的贪心,和纯随机。
第一批 20 个种子,模型平均 5.90 回合,贪心 3.25,随机 1.95。同种子配对,模型比贪心打得远的 16 局,比贪心近的 0 局。这个差距大到不用算,肉眼就能看出来。
问题出在下一步:之后每个改动都只值一两回合,肉眼看不出来了。
2. 第一次「改进」,和第一次反效果
第一个改动看着很该做。我手写的估分没算小丑:手里 5 张小丑时,一手 A 对,我估 64 分,真打出来 704 分。模型只读一个 token,没法自己心算小丑乘起来是多少,只会照着我给的估分选,等于一直拿着错的数做决定。
于是装了一个开源的计分模拟 mod,让游戏自己算每种出法的真实得分。验了两手,模拟 704、真打 704;模拟 850、真打 850。
同一批 20 个种子重跑:平均 5.90 → 7.00,涨了 1.1 回合。到达第 4 底注的局从 4 涨到 6。
看着挺好。配对一数:9 局更远,4 局更近,7 局一样,p=0.27。不显著。
第二个改动是商店提示:告诉它利息怎么算,每个购买选项标出买完剩多少钱。结果平均 7.00 → 6.60,8 涨 9 跌。拆开看行为,它确实听进去了:带着不到 5 块钱离店的比例从 40% 降到 27%。可为了攒利息,每局买的小丑从 2.5 张降到 1.4 张。小丑才是得分来源,它把火力省掉了。
这两次我都对着一个 20 局的平均数在猜。到这一步我才意识到,我根本不知道 20 局能看出多大的差。
3. 先跑一遍什么都不改的
这个做法叫 A/A 测试:两组配置完全一样,跑出来的差就是纯噪声。
先给游戏开了快进和无画面模式,一局从 109 秒压到 35 秒左右,其中模型思考只占 6 秒,剩下全是动画。然后同一套配置,60 个种子,跑两遍。
结果:
| 第一遍 | 第二遍 | |
|---|---|---|
| 平均回合 | 6.58 | 6.32 |
| 到达第 4 底注 | 13 局 | 11 局 |
| 配对 | 12 局第一遍更远 | 15 局第二遍更远 |
33 局两遍打到同一回合,p=0.70。整体上没差,这是对的。
但关键数字在每个种子两遍之差的标准差上:2.51 回合。同样的配置,同样的种子,单局差两三个回合是常态。原因是这个 35B 自己有跑间抖动,同一个局面两次给出的置信度最多能差 0.11,碰上两个选项本来就接近的时候,一次选 A 一次选 B,后面抽到的牌就全不一样了。60 个种子里只有 11 个两遍一步都没走岔,岔开的那 49 个里,中位数在第 9 步。
有了这个数,能算一笔账。配对比较能看出来的最小改进大约是:
最小可检出差 ≈ 2.8 × 配对差的标准差 ÷ √种子数
2.8 是「95% 置信、80% 把握」这一对常用门槛折出来的系数,算的是近似值,不用纠结小数点。反过来解出种子数:
需要的种子数 ≈ (2.8 × 配对差的标准差 ÷ 想看出的差)²
代进 A/A 的 2.51:
- 20 个种子,最小可检出差 ≈ 2.8 × 2.51 ÷ 4.47 ≈ 1.57 回合
- 60 个种子 ≈ 0.91 回合
- 想看出 +1 回合,要约 49 个种子;+2 回合,约 12 个
回头看第 2 章:精确估分那次,20 局配对差的标准差是 4.17,算出来 20 局最多能看出 2.6 回合的改进。它涨了 1.1,连门槛的一半都不到。那个 p=0.27 的意思是这批数据回答不了这个问题,它没说改动无效。
4. 一句话 +2.5 回合
有了尺子,下一步先找病根再改,不再拍脑袋。
翻了 A/A 那 120 局的记录:死的时候手里平均只有 2.0 张小丑。全部逛店记录里,离开商店 654 次,买小丑 247 次。小丑栏一共 5 个位置,它常年空着一大半,后期火力不够,分数线一涨就死。
于是在商店的提示里加了一句:「小丑栏还有 N 个空位,空着是浪费,优先买小丑。」
60 个种子:
| A/A 第一遍 | A/A 第二遍 | 加了这句 | |
|---|---|---|---|
| 平均回合 | 6.58 | 6.32 | 9.12 |
| 到达第 4 底注 | 13 | 11 | 34 |
| 对它配对(更远:更近) | 36:7 | 35:8 | |
| p | 9e-6 | 4e-5 |
死时手里的小丑从 2.0 张涨到 3.7 张。机制和成绩对得上,这次可以放心收下。
然后我做了开头那个切分:把这 60 局按种子顺序切成三段,每段 20 局,分别跟 A/A 第一遍比。
| 段 | 平均涨幅 | 更远:更近 | p |
|---|---|---|---|
| 前 20 | +0.65 | 10:5 | 0.30 |
| 中 20 | +3.25 | 13:1 | 0.002 |
| 后 20 | +3.70 | 13:1 | 0.002 |
同一个真实的 +2.5 回合效果,第一段只露出来四分之一。我前面每批都是 20 局,碰上那种运气就会写下「无显著效果」。说白了,20 局一批的实验,连这周最好的那次改动都可能漏掉。
5. A/A 量出来的噪声只是下限
第 3 章那个 2.51 我以为够用了,下一次实验就露了馅。
再下一个改动,是把给人看的游戏攻略提炼成四条规则塞进系统提示:没方向就打同花和对子、按总分翻几倍评估小丑、前三个底注先攒钱、星球牌早用。
对照上一版,60 局:平均 9.12 → 9.22,配对 25:25,p=1。
行为是真变了。打同花的比例 11% → 34%,打两对 30% → 16%,离店时手里的钱中位数从 6 块涨到 10 块。成绩一动没动。说明牌型和经济都不是现在的瓶颈。
麻烦在配对差的标准差:4.82。比 A/A 的 2.51 大了快一倍。加小丑那次也是 4.22。
原因看「第几步开始走岔」就清楚了:
| 比较 | 一步都没岔的种子 | 第一次走岔的中位步数 | 配对差标准差 |
|---|---|---|---|
| A/A(什么都不改) | 11/60 | 第 9 步 | 2.51 |
| 加「先买小丑」 | 0/60 | 第 6 步 | 4.22 |
| 加攻略 | 0/60 | 第 2 步 | 4.82 |
A/A 两边只有模型抖动这一个分叉来源,很多局要走好几步才岔开,岔开后也常常殊途同归,49 个岔开的种子里 22 个最后还是死在同一回合。真改了提示词,两边从开局第一个决定就开始不一样,后面整盘牌全换了,配对的那点「同种子」优势基本没了。
所以拿 A/A 的标准差去规划样本量会偏乐观。用真实对照里的 4.2 到 4.8 重算:
- 60 个种子,最小可检出差 ≈ 1.5 到 1.7 回合
- 想看出 +1 回合,要 140 到 180 个种子
按一局一分钟、两组各跑一遍算,大约 4.7 到 6 小时。攻略那次「+0.10,p=1」,准确的读法是:真实效果如果小于 1.7 回合,这 60 局看不出来。
那批里还出了第一次通关:一个种子拿到一张「每 5 块钱加 2 倍率」的小丑,正好配上攻略的攒钱打法,通关时手里 206 块。60 局通关 1 局。它很好看,统计上什么也说明不了。
6. 读「AI 打通了某某游戏」「改一句提示词涨了 X%」该问什么
这类说法我现在先问四句:
- 跑了几局? 一局通关、一段录屏,样本量是 1。我那次通关是 60 局里的 1 局,换个人截个图就能发「本地模型通关小丑牌」。
- 是配对的吗? 同种子、同起始条件比,噪声会小很多。两组各跑各的随机局,再比平均数,要的局数还得往上翻。
- 有没有跑过「什么都不改」的对照? 没跑过的话,他自己也不知道噪声多大。我的 A/A 里,什么都没改,单局能差 12 回合。
- 报了行为还是成绩? 攻略那次行为指标全动了,同花比例翻了三倍,成绩零变化。只报「模型打法变了」的,等于没报结果。
拿第 3 章的公式反推一下也很快:别人说「20 局平均涨了 1 回合」,你拿 2.5 当噪声下限一算,20 局最小可检出差就有 1.6,他报的数在门槛以下,几乎可以直接当没看见。
7. 这批实验的毛病
- 评估器自己有个洞。 后来挖死因才发现,我写的商店候选里有一句「小丑栏满了就不列商店里的小丑」。满栏逛店 241 次,其中 122 次手里有 25 块以上,换小丑 0 次,整局都在用前期凑的那 5 张。上面所有数字都是在这个洞里测的。修好的版本只跑了 17 个种子就停了,效果还不知道。
- 只有一个模型、一种玩法。 全部是同一个 35B、红牌组、最低难度。换模型、换难度,噪声大小会变,标准差要重新量。
- 「打到第几回合」是个粗指标。 它是整数,还有上限,死在分数线 95% 和 5% 记的是同一个数。按「死时分数占目标的比例」细化一下,标准差可能会小,我没做。
- 公式是正态近似。 实际判显著用的是符号检验,只数输赢不管赢多少,两者之间差多少我没逐一核对。公式算出的种子数当量级看,别当精确值。
- 20 局切三段只是一次切分。 前 20 局恰好偏弱,换个切法结果会不同。它说明「20 局能漏掉真效果」,不能拿来估漏掉的概率。
8. 下次给 AI 智能体调提示词,按这个顺序做
- 先把当前配置原样跑两遍,算每个种子两遍之差的标准差。这是噪声的下限。
- 改动之前用 (2.8 × 标准差 ÷ 想看出的差)² 估种子数,再乘上每局时长,看跑不跑得起。真改动的标准差按 A/A 的 1.5 到 2 倍预留。
- 每次都同种子配对,只数谁打得更远。
- 先用已有记录找瓶颈(我这次是「死时只有 2 张小丑」),再写针对它的那一句提示。
- 行为指标和成绩分开报。行为变了、成绩没变,说明你改的不是瓶颈。
- 实验跑完回头复查一遍候选生成器,看有没有哪类动作模型根本选不到。我那 241 次满栏逛店,模型就算想换小丑也没这个选项。