Sigildream Tech Blog

平衡医生

一台机器每晚上千次地与自己对战 Sigilwake,为游戏听诊,测出它何处不适,并开出药方。这是一个关于我们如何不再手动做平衡的故事——也是同一个大脑的故事:它今天学着战斗,终有一天会独自让整个阵容保持平衡。

什么是 Sigilwake。一款回合制角色扮演格斗游戏,采用黑白漫画画风,移动优先,多平台(Web、Android、iOS、macOS、Windows),目前处于验证阶段。一对一的对决:两名斗士,每人四个技能,电影级动画,对局可玩、可实时观战,也可作为录像回放。阵容共有 24 个角色,没有任何一个是另一个的翻版。
#GameAI   #GameBalance   #DevLog

第一幕我们不再手动做平衡的那一天

一款格斗游戏,会在某个确切的瞬间,从一个想法变成一道数学题。

对我们来说,那是一个星期二。一个角色赢得太多了。修正看似轻而易举:把他最强招式的伤害稍微调低一点,就搞定了。然后你停下了。因为那个角色并不是一个人在打:他要对战其他所有人。调低那个数值,会让他在面对本就能击败他的对手时更弱,而在面对本就打不过他的对手时依然强势。你挪动一块拼图,另外二十三块都会跟着晃动。你重新算了一遍。然后你发现,靠手动已经再也走不出来了。

从那个星期二起,我们开始构建一个东西,内部戏称它为平衡医生:一个为游戏听诊、测出它何处不适、并开出药方的系统。这是它故事的第一章。

催生技术难题的艺术内核

24 个角色每一个都有自己的套件:招式、被动、属性数值,以及一种独特的战斗身份。有的吸收寒冰,再将它回敬给攻击自己的人。有的随时间缓慢地灼烧对手。有的操控心智。它们是一个个鲜明的个性,而非皮肤。而正是这种多样性——游戏的艺术内核——催生了那道技术难题。

问题:一场组合爆炸的噩梦

一款竞技游戏之所以"平衡",是因为没有哪个角色是必选项,也没有哪个角色是废物。用数字说:长期来看,每个角色都应该大约赢下一半的对局。五五开。这正是那个平衡点——胜负由玩家的水平决定,而不是由抽到错误角色的霉运决定。

麻烦在于,需要同时盯住多少组配对。24 个角色,可能的配对多达 552 组(每个角色对阵其余 23 个)。任何一处改动——一点伤害、一份消耗、一段持续时间——影响的都不止一场对决:它会连锁地重塑几十场。这就像给一支乐团调音,每调准一件乐器,就有另外二十件跑调。面对这张网格,人类设计师只能凭直觉和试错前进:改一改,打几局,然后祈祷。可几局对战根本不足以把真正的失衡和偶然区分开。每一组配对都需要上千场对决,那个数字才变得可靠——而没有人有时间用手把它们一场场打完。

所有角色之间正面交锋胜率的 24×24 网格,单元格从红色(失败)到绿色(胜利)着色。
"谁能打赢谁"的 24×24 网格。每一行是一个处于进攻方的角色,每一列是它的对手,每一格是正面交锋的胜率。绿色 = 赢,红色 = 输;黑色的对角线是角色对阵自己。glacius 那一行是一条鲜亮的绿色长条——对上半个阵容都高达 100;而 umbral 那一行恰恰相反,星星点点布满了零。那 552 个格子,全部放在一起,就是被具象化了的问题。

这张网格是那场噩梦的写照。五百五十二个格子,每一个都是一次判决。人的眼睛在里面会迷失。过分浓烈的绿色是一个碾压别人的角色;饱满的红色则是一个被碾压的角色。目标是把整张表引向一种均匀的色调——既无霸主,也无受害者——同时心里清楚,每一笔涂抹都会牵动其他许多格子。靠手动,这无法驾驭。

论点:如果让机器来玩呢?

到这一步,问题自己就翻转了。如果症结在于需要太多对局、太多计算,那为什么要让人来做呢?

如果由一台机器来玩这个游戏,每晚上千次地与自己对战,自己测出天平朝哪边倾斜,并提出修正方案呢?

这个想法国际象棋界早已熟知:一个与自己对弈数百万局的程序,能比任何人类大师更懂得什么才管用。我们把它转向了另一个目的。我们要的不是一个只顾赢的 AI:我们要的是一个 AI,它把全部 24 个角色都打得很好、彼此捉对厮杀,从而让真正的失衡浮现出来——那些只有在双方都全力以赴时才显现的失衡——然后开出修正它们的药方。

微调系统的控制台:配置区、循环命令,以及显示 NashGap 0.0066 的状态卡片。
系统控制台。左侧是配置:模拟对手的强度等级(tier5,最强的一档),以及每组配对打多少场(10,也就是每一轮 5,500 多场对决)。中间是命令区——红色的"Stop auto-tuning"、琥珀色的"Regenerate sandbox"、熄灭的"Promote to data/live",并由"Force apply"这把锁保护着。右侧是状态:第 4 次迭代、循环存活中(pid 92233),以及 NashGap 为 0.0066——一个单一的数字,概括了整个阵容距离五五开的平衡还有多远。它越低,游戏就越公正。

上面这张控制台就是指挥台。每一轮,系统都会在一个不触碰真实游戏的独立环境里,让超过五千场对决开打——全部 552 组配对,反复进行。然后它把这数千场对局的结果浓缩成一个数字,我们称之为 NashGap,你可以把它读作"我们在整个阵容上距离五五开还有多远"。在这一张快照里它是 0.0066,离我们视为"平衡"的门槛只差一线。它是一支体温计。有东西恶化时它上升,药方奏效时它下降。医生不再用肉眼去看 552 个格子:他看的是体温。

一段更宏大弧线的第一步

我们投入做这件事、而非走捷径,是有原因的。与此同时,Sigilwake 正在构建一套新一代的游戏人工智能——一个 AlphaZero 形态的神经网络,正是那一类从零开始、通过与自己对弈学会国际象棋和围棋的系统。这是本项目最前沿的技术,终有一天它将把对手驱动到人类玩家难以企及的水平。

而两条路在这里交汇。今天我们正教它战斗的这同一个网络,一旦达到职业水准,就能独自平衡整个阵容。但有一个必须遵守、且没有商量余地的次序:要在真正贴近实战的游戏物理上训练那个网络,先得有一个干净的阵容,没有霸主,也没有受害者。一个平衡的游戏,就是网络学习所依托的试验台。如果你给它看一个扭曲的世界,它就会学会扭曲地玩。这正是平衡医生要先行的原因:它不是配件,而是其余一切将要立足的地基。我们会在最后一幕再回到这层关系上——它比看上去更紧密。

你今天看到的系统还没有用上神经网络——它用的是一个更简单、更透明的统计引擎,而这是一个刻意的选择:先造出可靠的工具,再去增强它。但方向已经定下。第一块砖就是它:一台与自己对战、并测量游戏体温的机器。让我们打开引擎盖。

第二幕与自己对战的机器

一个与真实游戏隔离的实验病区

要判断一个阵容是否公平,经典的做法是让成百上千的人玩上好几个月,再去读那些抱怨。我们造了不一样的东西:一台与自己对战的机器,为每一组配对打上千次,全在一个从不触碰已发布游戏的密封实验病区里进行。

我们把它叫作 sandbox——这个词在这里恰恰就是"沙盒"的意思:一个可以随便砸烂一切、却不会有任何后果的受保护区域。真实游戏,也就是玩家会跑的那个,活在它自己的文件里。实验病区只在一份副本上工作。这两者从设计上就永不相碰。这与制药实验室是同一套纪律:实验药物在有人签字确认它准备就绪之前,绝不进入病房。而这里的签字,永远出自一个人之手。我们会再回到这一点——正是它让整个系统安全,而非危险。

你在第一幕里看到的那张控制台,就是这个病区的指挥台。它一眼就能看懂,就像汽车的仪表盘。左侧是配置——对手的强度(tier5,那个下手毫不留情的),以及每组配对的十场对局,乘以 552 组配对,就是 每转一圈超过一万一千场对决。中间是命令区,只有一个红色按钮:停止调校,那个巨大的紧急停止键,会干净利落地收尾当前迭代,不留任何半途而废的东西。而在最下面,是唯一会触碰已发布产品的按钮:提升到真实游戏,故意做得很不顺手,由一把锁(Force apply)保护着,必须手动解开。没有任何东西会被误提升。

NashGap: 0.0066 —— 我们衡量阵容距离完美五五开平衡有多远的尺度。取每个角色,看它偏离"赢下一半对局"有多少,把每一处偏差平方(这样大的失衡权重就大得多),再取平均。这个数字越接近零,游戏就越公正。在 0.0066,我们已经很近,但还没进入我们给自己定下的靶心(0.005)——而且我们要求连续三次迭代全部亮绿灯,才肯宣布胜利,就像一位不会在第一次检查合格就让病人出院的医生。

全景视图:看着迭代呼吸

控制台告诉你它状况如何。全景视图告诉你它此刻正在做什么

第四次迭代的实时视图:六张状态卡片、进度行,以及 24 个角色的胜率排行榜。
第四次迭代,实时进行中。顶部六张卡片:距离平衡 0.0066、最糟角色的偏差 0.272(病房里最重的病号)、已过去 42 分钟、累计 5 条修改提案。下方是那条跳动的行:3.165 / 11.040 场对局、平均回合 19.9、瞬杀 0。还有实时更新的 24 人排行榜:glacius 以令人尴尬的 83.3% 高居榜首,cenere 以 37.8% 垫底,阵容的大部分则紧挤在 44% 到 56% 之间。

顶部,六张卡片概括了这次会话。然后是那条在你眼皮底下移动的行:

LIVE ITER 4 — 3.165 / 11.040 场对局 · 28.7% · 已过去 23m · 平均回合 19.9 · 瞬杀 0

一万一千场对决在排队,三分之一已经打完。还有几个对设计师而言宛如天籁的质量数字:平均一局持续将近二十回合——既不太闪电,也不没完没了——而第一回合就能杀死对手的招式,是 。没有人在还没来得及出招之前就被秒杀。这正是我们想要的:由招式、而非抽签的运气来决定的对决。

对局时长的直方图:将近四千场对决分布在 7 到 51 回合之间,峰值出现在 19 回合。
一场对决持续多久。基于 3.925 场采样对决的对局时长分布:短则 7 回合,长则 51 回合,隆起的峰聚集在 19 回合 附近(429 场对局,最常见的时长)。既非闪电,也非马拉松——曲线的形状印证了那个 平均回合 19.9:对局是被玩出来的,而不是被硬扛下来的。

下方是全部二十四人的实时排行榜。系统的诚实在这里立刻显现。榜首,鲜绿色的 glacius 高达 83.3%。垫底,cenere 停在 37.8%。阵容中绝大多数都聚集在 44% 到 56% 之间——队伍的大部分已经平衡——但两端在嘶吼。系统不会把它们藏起来:它把它们放上头版。一张只显示好看数字的控制台,毫无用处。

四次迭代上的二十四条胜率曲线:几乎全都贴着 50%,只有一条洋红色曲线孤立在高处、约 77–78%,并在缓慢下降。
正在收敛的阵容——以及唯一掉队的那个。24 个角色在四次迭代(run 1run 4)上的胜率,健康区间为 0,5 ± 0,07。大部分曲线如今已收成一束、紧贴 50%:队伍已经稳定下来。孤立在高处的那条洋红色曲线是 glacius,仍在区间之外、约 77%——是系统正一次次迭代地往下带的最后一个病号。
精细诊断:AI 延迟、开局即注定的配对、下降中的 NashGap 曲线,以及修改提案的柱状图。
精细诊断。AI 的思考速度:在一万三千多次决策中,平均耗时 3 ms,几乎从不超过 9。开局即注定的配对——aurora 0% · 100% solarisaeryn 0% · 100% glacius——其中一个角色对阵另一个会输掉所有对局。距离平衡的曲线正朝靶心下降(0,0097 → 0,0066)。还有修改提案的绿色柱:在这个阶段几乎全是增强,而非削弱。

再往下滚,就到了诊断部分。模拟对手在一眨眼之间就能思考完毕——它是个既强即时的玩家,这让"一小时内与它对战一万一千次"变得可信。然后是那份令人心痛的清单:开局即注定的配对,也就是一个角色对阵另一个会输掉所有对局的对抗。十二场,零胜。用国际象棋的行话说,这是一种 hard counter:开局即败的局面,无论你走哪一步。这些是最严重的病例,因为——正如我们将在专讲 Doctor 的那一幕看到的——它们没法靠微调一个数字来解决。它们必须被重新设计。

模拟 AI 的延迟行:在一万五千多个回合中,最小 1 ms、平均 3 ms、95 百分位 10 ms、最大 279 ms。
思考速度,实测。模拟对手决定一步棋所花的时间,基于 15.338 个回合:最小 1 ms、平均 3 ms、95 百分位 10 ms,仅有一个孤立的尖峰达到 279 ms。正是这种即时性,让一小时内打完一万一千场对决成为可能——一个既强即时的对手。

最后是那条给人希望的曲线:距离平衡一次次迭代地下降,指向那条虚线靶心。这是病人正在退去的体温。下方,绿色的柱统计着每一轮提出的修改——在这个阶段几乎全是增强:系统在设法先把弱者拉起来,再去压低强者。

NashGap 的迷你趋势线,从约 0,008 起,跌破 0,005 的虚线靶心,一路降到 0,0038——约减少 51%。
烧退了。NashGap 的历史被精简到极致:先是向上一跳,随后锁定为稳定的下行——从约 0,008,直直穿过 0,005 的虚线靶心,一路降到 0,0038:降幅过半。仅仅一段下行的线条就说明了一切——药方奏效,而距离平衡的差距,甚至越过我们设定的目标之后,仍在继续收窄。
按严重程度排序的最严重失衡排行榜,以及带事件时刻的活动控制台。
重症病人与航行日志。在视图末尾,是按严重程度——而非胜率——排序的排行榜,glacius 高居榜首(0.272),其后是 umbralsolariscenerelyra。还有一个滚动显示事件、并带精确时刻的控制台:loop_startiter_end nash=0.0066。系统做的每一件事都留下一条可读的痕迹。没有魔法,没有黑盒。

那张网格:谁能打赢谁

排行榜说明每个人赢多少。但它藏起了一个更深的问题:它赢的是?一个 50% 的角色可能确实很平衡——也可能碾压半个阵容、又被另外半个碾压,平均值掩盖了这场灾难。要看清它,需要完整的地图:就是你在开篇遇到的那张全身 X 光片,涵盖所有配对的 24×24 网格。

一双有经验的眼睛会把它当作一张 X 光片来读。glacius 那一行是一条鲜绿色的长条——他就是最强的那个病号,是让游戏变得不公平的那个。umbral 那一行恰恰相反,星星点点布满红色和零:它到处都输。再看那些极端的格子,散落各处的干脆利落的 1000:开局即注定的配对,开局即败的判决。网格把它们全部放在一张图里、一齐呈现。这正是人类设计师要花上几周才能手工汇编出来的东西——而在这里,它每次迭代都自行重新生成。

每个人的性格:不只是是否赢,还有怎么

还有最后一个问题,最微妙的一个,而对一款游戏而言它或许是最重要的。一个角色可以在 50% 上完美平衡,却依然无聊:如果它总是靠无脑重复同一个招式取胜,数字是没问题,但乐趣已经死了。统计上的平衡还不够。还需要深度。

每个角色的卡片,包含胜率、选择多样性、致命一击的集中度,以及失效技能。
每个角色一份病历,从最失衡到最公平排序。在胜率旁边,有三个质量指标:选择多样性(H)、致命一击的集中度(kb:超过 0,7 就会触发红色的 1-trick 标签),以及从未用过的技能。在最下方、带着绿色对勾的,是 raiden50.0%,偏差 0.000——完美居中的角色。那正是我们想把其余所有角色带到的位置。

这正是为什么我们在胜率旁边放了三个指标,它们讲述的是游戏的质量,而不只是结果:

选择多样性H)衡量一个角色是否真正用上了它的全部武器库。高值(趋近 1,0)意味着它像一个变换出拳的拳手那样交替使用四个技能;低值则暴露出一个单调的玩家。Seraphtessara 在这里闪光(0,950,94):它们打得很丰富。Umbral 除了输,还只依赖少数几招,多样性仅为 0,71

致命一击的集中度kb):有多少胜利是由同一个、一模一样的收尾招式终结的。超过 70% 就会触发红色的 1-trick 标签——那种只学会了一套制胜连招、然后不断重复的角色。系统把它明明白白地标在 theronzephyrseraph 身上。它们在数字上是平衡的,但需要变得更多样。

失效技能dead ab):角色在可以选择时、却从不选择的招式。一个失效技能既是被浪费的代码,也是对玩家未能兑现的承诺。几乎每一份卡片都会标出一两个。名单顶端又是那些老面孔——glacius 带着它的 77,2% 和那个警示的小三角,然后是 umbralsolaris;而在最下方、精准居中的,是 raiden

为什么那个沙盒就是一切

让我们在那个让这套系统站得住脚、而非危险的要点上停一下。你所看到的一切——数千场对局、逐渐填满的网格、不断累积的修改提案——都发生在那个密封病区里、在一份副本上。当机器碾过一万一千场对决时,已发布的游戏一个标点都不会变。团队可以去做美术、菜单、一个新模式,而没有人会看到数字在自己脚下移动。

而实验室与病房之间的那扇门,只有凭一个人的签字才会打开。那个提升到真实游戏的按钮,熄灭着、由锁保护着,是唯一的通道。机器想提多少方案都可以;把它应用到真实产品上却是一个决定,而非自动化。这就是一个帮你做出诊断的助手,和一个独自给你动手术的机器人之间的区别。我们刻意造的是前者。

这就是那台与自己对战的机器:测量起来不知疲倦,暴露缺陷时毫不留情,并且从设计上就无法在没有人拍板的情况下破坏真实游戏。它用四种不同的工具测量平衡在哪里坏掉了。但有一种情况——那些开局即被判死刑的角色,那些任何数值微调都救不回来的 0%——即便是最好的测量也会止步。那里需要的不是一支更精确的体温计。需要的是一位重新设计病人的医生。

第三幕Balance Doctor:从药剂师到外科医生

我们为平衡问题造了一位医生。它叫 Balance Doctor,活在一张控制台里。像一位真正的医生一样,它在两个层面上工作。第一层调整剂量。第二层——全新的那层,本章的新意所在——在诊断结果是病人的解剖结构本身就错了、任何剂量都无法把它扳正时才出手。

诊断控制台

Doctor 卡片:诊断标题栏,含 17 个目标、5 次削弱、12 次增强,以及带有建议疗法的首批角色卡片。
诊断报告。顶端,三个数字:17 个角色在区间之外,其中 12 个需要强化(绿色徽章 BUFF),5 个需要打磨(红色徽章 NERF)。旁边是 NashGap 0.00662 和"medium"级别的异常。然后是每个病号一张卡片:最严重的是 umbral,胜率 38.8%(在及格线之下 11.2 点);另一个极端是 eclisse,58.2%,高出八点。每张卡片都已经给出疗法,并估算它的效果。

Doctor 以一份诊断报告开场。然后是报告的主体:每个病号一张卡片,带着已选定的疗法("chosen patch")和预期效果。这不是一份意见清单。它是一份干预措施清单,每一条旁边都有一个数字,就像一份治疗方案:

  • umbral暗影之爪的消耗从 80 降到 68(让它更省):预估影响 +5.3 点
  • eclisse虚空之箭的威力从 4.2 降到 3.78:约 3.5 点从高处回落至区间内。
  • theron分叉之刃状态效果的持续时间从 3 回合增至 4 回合:+5.8 点
  • aurora强效治疗的消耗从 100 降到 85+5.3 点
Doctor 中 glacius 的角色卡片:胜率 78.8%,高出区间 28.8 点,NERF 徽章,所选补丁是把寒霜之咬的消耗从 50 提到 62,预估影响 8.4 点。
诊断单元,近观。报告中的单张卡片:glacius,胜率 78.8%+28,8 点,高于基准线),红色标签 NERF。所选的疗法既精准又一目了然:寒霜之咬的消耗从 50 提到 62,预估影响 +8,4 点、朝区间靠拢。底部还有 2 alternative(2 个备选方案)待命,以防这一个不够。

第一层:转动旋钮

17 项修改以按层级分组的表格呈现:全部落在 Cards 一列,Passives、Stats 和 Global rules 上均为零。
1.0/2.0 版的药方:校准数字。17 项修改被重新整理为一张表格,按层级分组:全部落在"Cards"一列,"Passives"为零,"Stats"为零,"Global rules"为零。每一行都是一个被小幅挪动的单一参数:消耗 80→68、威力 4.2→3.78、持续时间 3→4。底部,NashGap 正在下降:三个周期前是 0.00969,现在是 0.00662——阵容在三轮里朝平衡靠近了 31.6%

Doctor 手上有一整块旋钮面板——一个技能的消耗、它的伤害随角色属性增长多少、一次冰冻的持续时间、一击造成眩晕的概率——它每次只拧动一格。没有任何技能被彻底推翻:调一调剂量,再重新测量。而在它的限度之内,这管用:靠转动旋钮,医生把大多数角色带进了健康区间。

按迭代统计的调校活动表格:每一行都有补丁总数、增强数、削弱数,以及起始 NashGap。
每一轮改变了什么。迭代记录,逐行呈现:系统提出了多少项总修改、多少个 buff、多少个 nerf,以及起始 NashGap。头几轮每次只改一项,且总是一次增强1 buff · 0 nerf):策略是先把弱者拉起来,再去打磨强者,一次一个参数,每改一个都重新测量。
五个最反常角色在三个周期上的胜率轨迹,带 50% 的虚线。
旋钮在哪里咬得住,在哪里咬不住。五个最顽固病例的轨迹,带 50% 的虚线。cenere 缓缓回升(39% → 40% → 41%),lyra 随之而动:病人有反应。而 solaris 却钉死在原地(61% → 61% → 61%),三个周期纹丝不动。glacius 则以一种不愿痊愈的迟缓往下走(83% → 78% → 77%)。在某些角色身上,旋钮你想拧多少就拧多少:指针却不肯按它应有的样子移动。

但极限就在这里浮现。五个最顽固病例的轨迹讲述了两个不同的故事:有的有反应,有的则原地不动。在某些角色身上,校准已经不够用了。

当旋钮不够用时

有一类病人,校准在他们身上不仅不够用——还让情况变得更糟。让我们看清这一点的病例叫 boreus,一个冰之守护者,设计初衷是吸收攻击、再将它回敬。纸面上是个优雅的概念。实际上,它长期低于基准线,而且——这是最反常的部分——我们每次强化它,它反而赢得更少。降低它技能的消耗?更糟。提高威力?还是更糟。

极端配对的实时清单:aurora 对 prisma、solaris 和 raiden 的胜率为 0%,aeryn 对 glacius 为 0%,aurora 对 boreus 为 100%。
开局即败的判决,一目了然。那些在全部十五场对局里都以 0%100% 收场的配对:auroraprismasolarisraiden 输掉每一场对决;aeryn 从不曾战胜 glacius;而 boreusaurora 横扫(0%)。这些不是几点之差的失衡:它们是 hard counter,开局即输的对抗。把旋钮拧一格根本扳不正它们——这是概念错了的症状,而非剂量错了的症状。

当每一种疗法都让病情加重时,诊断的性质就变了。boreus 的问题不在剂量。而在概念:它的技能、被动和战斗身份彼此咬合的方式,内在就是自相矛盾的。没有哪个旋钮能扳正一副扭曲的解剖结构。需要的是一位外科医生,而不是一位药剂师。

可验证的部分:diff

在谈外科医生之前,先来一次诚实的证明。系统提出的一切最终都汇入同一个地方,而那个地方会在任何东西进入生产环境之前,展示真实的代码,逐行呈现

Diff 卡片:live 数据与工作副本之间的 git 风格对比,abilities.json 上新增六行。
提交前的 diff。线上、生产环境的数据,与应用了全部修改的工作副本之间的并排对比。顶部是承诺:这正是"Apply + Commit"将要写入数据的那份 diff。在 abilities.json 上:新增六行,删除零行——boreus 被动的那些"尖刺"。characters.jsongame_config.json:"无修改",副本与线上完全一致。没有黑盒。

而在这里,boreus 的重新设计变得具体可见。它的被动被加上了一个新区块:

data/abilities.json  vs  overlay/abilities.json      +6 · −0      "flatValue": 15,      "multiplier": 1,      "type": "counter"+    },+    {+      "affectsSelf": true,+      "flatValue": 8,+      "trigger": "cantAct",+      "type": "auraDamage"     }   ],   "element": "gel",

翻译过来就是:一圈始终生效的"尖刺"。谁攻击 boreus,谁就承受一份恒定的反伤,而它自己什么都不用做——这与它作为一个惩罚攻击者的防御者身份相吻合。这次干预既精准又局限,一个人在碰生产环境之前十秒内就能读懂。这就是证明:系统的产出不是一张幻灯片,而是真实、可验证的代码。

3.0 的跃迁:重新设计,而非微调

boreus 的那些"尖刺"并不是把旋钮拧动一格:它们是一块被重新设计的套件。这就是这位医生的 3.0 层级——不再校准数字,而是开始重新思考角色的结构

外科医生的推理建立在我们交到它手里的两套知识库上。第一套是每个角色的背景设定(lore):它是谁、由什么元素构成、性格如何、怎么战斗。第二套是引擎的机制百科全书:一个技能可以用来搭建的全部积木——光环伤害、生命偷取、反击、控制、护盾。翻开这两本书,Doctor 3.0 就能提出此前力所不及的干预:增加或移除一个效果、替换一个技能、改变触发它的条件、从头重新设计被动、更换原型,或是锻造一个独一无二的签名(signature)。

这些都是强有力的操作——也正因如此而危险。一个错的数字毁掉一个角色;一个错的概念毁掉这个角色的整个构想。因此,重新设计始终伴随着两条不容商量的保证

  1. 逐字引用背景设定。每一条提案都必须挂靠到角色叙事卡片中的一句原文——不是转述,而是精确的引用。这是我们对抗凭空捏造的抗体:如果系统在背景设定里找不到一处字面上的依据,提案就会在到达我们面前之前,先被校验器驳回
  2. 最后拍板的永远是人。没有任何结构性的重新设计会自行应用,从来不会。提案会带着两个按钮出现在控制台里——批准 / 驳回——并停在那里、暂停着,直到有一个人去点击。没有捷径,没有自动模式。它的作用范围太大了,大到不能交给一台机器。

这一切都不是纸上谈兵。下面就是那道人类否决权在真刀真枪地起作用——而机器也因此变得更敏锐——发生在一个名叫 neve 的角色身上:

病例档案:医生起初为过强的角色 neve 开出了增加治疗的处方——一个披着削弱外衣的增强——人类审阅者驳回了它,随后我们教会了设计器方向,它转而提出移除 neve 的被动自我治疗,也就是她强势的根源。
会自我纠错的医生。Neve 过强,且对数值微调毫无反应,于是被升级交给了外科医生。它的第一刀开反了——它提议给一个本已过强的角色增加续航,一个披着削弱外衣的增强,人类审阅者当场驳回。随后我们教会设计器方向——高于平衡带的角色必须被削弱,绝不能被喂养——它于是提出了相反的一手:移除那个不知疲倦、正是她强势根源的被动自我治疗,同时完整保留她的稳定控制与 −40% 减伤身份。人类抓住了错误;机器学会了规则——就在那个暴露问题的案例上。

诚实的教训:"设计"对上"选择"

有一个错误值得一讲,因为它很有教益。外科医生的第一个版本是最雄心勃勃的:给人工智能一张白纸,对它说"你从零开始设计这个角色吧"。理论上很优雅。实践中,却是慢得一塌糊涂:一次生成要花四分半钟以上,而且多数时候什么提案都产不出来——直接卡死。一个在敞开的病人面前沉思这么久的外科医生,不是一个有用的外科医生。

诊断很精确:问题既不在问题的规模,也不在环境。是任务本身太重了——"从零设计"是一种开放式的推理行为,无处着力。修正颠覆了整个设定,我们称之为 "design → curate":现在改由代码生成一系列本就有效的选项——全部挂靠背景设定,全部兼容引擎——而人工智能只需挑出最好的那个,并用自然语言把它讲清楚。从发明者变成策展人。在 boreus 上实测的结果:从"四分多钟、几乎从不给出答案"变为约 50 秒给出一条有效提案,还有一张安全网,保证提案永远存在。普适的教训:当你让一个 AI 在真空里推理,你会在时间和可靠性上付出代价;当你给它具体的选项去挑,它就会起飞。

五个阶段,一句话说清

在引擎盖之下,3.0 版医生是一连五步:(1) 把所有角色的背景设定收集进一个有序的档案库;(2) 把引擎的每一项机制编入一部可查询的百科全书;(3) 打造外科医生的工具——那些重新设计的招式,加上校验它们的校验器;(4) 接入那个负责选择并说明理由的人工智能;(5) 把这一切缝合进控制台,配上"批准 / 驳回"按钮,以及为人工签字而设的强制暂停。

第四幕与大脑的连接:为什么这位医生在训练冠军

到这一步,一位细心的投资者会问一个问题:那又如何?一个平衡的阵容很好,但它是目的,还是手段?

是手段。平衡医生所做的一切——测量胜率、绘制谁能打赢谁的矩阵、计算阵容距离平衡有多远、开出疗法——本身都不是终点。它是我们在其上构建真正病人的手术台:一个游戏神经网络。

我们真正在构建的东西

在 Sigilwake 的引擎里,今天的对手由一个"暴力"思考的人工智能驱动:它向前推演许多步,然后挑出最好的一步。稳健,却对复合策略视而不见——那些在十个回合里徐徐展开的策略。下一步,是一个与击败过围棋和国际象棋世界冠军的系统同族的网络:一部分负责提出招式,一部分负责估计谁在赢,还有一个规划器向前探索十二到二十五步

Sigilwake 神经网络的控制台:六个组件、约 45.4 万参数、亚毫秒级推理,以及八阶段的进度条。
神经网络的路线图。AlphaZero 形态的架构,约 45.4 万参数分布在六个组件上——压缩后不到一兆字节,亚毫秒级推理。八阶段的进度条:一个进行中,七个已设计完成。设计阶段已经收尾:两个独立 AI 模型之间的交叉审计,在写下一行训练代码之前就产出了三十多处修正;与真实引擎的结构性偏差如今为 11,64%,公开设定的目标是在说"出发"之前把它降到 5% 以下

围绕这个内核,是极少有工作室敢做的三项扩展。一个习得的世界模型:网络学会想象对局如何一步步演进,而无需重新计算这场交锋的每一个细节——它梦见 rollout,而不是去模拟它们。为 boss 准备的不同人格:同一个大脑,配上一小段"风格码",就能像一个咄咄逼人的莽夫、或像一个耐心编织控制的织工那样去打。八种人格来自同一个模型,而不是八个各自独立的模型。还有对局中的自适应:一个精巧的薄层,会在单场对局的进程中自我微调,于是终局 boss 在两三个回合里就摸清你的风格,随即改变步调。

最冒险的那块集成——让网络跑在游戏服务器内部,而不是一个单独的服务里——已经验证并交付:每次决策二十微秒,即便在 99 百分位,延迟也在一毫秒以下。

确切的关联:两个方向,同一个大脑

这正是为什么平衡不是一项并行的工作,而是同一段阶梯的第一级。这层关联是双向的。

方向一——平衡的阵容是训练网络的前提。神经网络从数据中学习。如果你把在一个坏掉的阵容上打出的对局喂给它——某个角色因为设计缺陷、而非玩家的选择,只在 5% 的情况下取胜——它学不会好好打:它学会的是利用那个缺陷。而且即便在修正之后,也需要海量的重新训练才能消化掉学到的坏习惯。在我们内部的进度表上,这就是字面意义上的头号前提。战斗物理也一样:网络基于一个内部模拟器做预测,而那个模拟器必须与真实引擎相符。今天我们持续测量它——偏差已经降到 11,64%,目标是把它压到 5% 以下。外科医生不会对着一张模糊的 X 光片动刀。而平衡医生,正是让那张片子对上焦的东西。

方向二——到成熟阶段,这同一个网络会自己平衡自己。一旦网络打到职业水准,就不再需要一位外部医生用手校准数字:网络与自己对战,为每一组配对测量胜率,并提出修正。设计师签字,或者拒绝。你在前几幕里看到的全部机器——控制台、正面交锋矩阵、每个角色的轨迹、做诊断的 Doctor——都是一个流程的手工版本,而这个流程终有一天将由网络自己完成。同一个大脑里的两种能力:以职业水准去玩,以及让它所玩的游戏保持平衡。

而这里就是那个站得住脚的竞争壁垒,不加夸张地说:极少有独立工作室拥有一个能打到冠军水准的人工智能。拥有一个还会自己平衡自己游戏的,则更是凤毛麟角。这两件事凑在一起,出现在一个由小工作室打造的产品里,实属罕见。

这不是一张幻灯片:它跑在真实的基础设施上

值得用一段务实的话收尾,因为在这个行业里,人们很容易把一张路线图误当成一段渲染动画。这一切——平衡闭环、战斗服务器、将要到来的大脑——都活在支撑着游戏的同一套生产基础设施之上。

实时机房:进行中的对局、打开的连接、零错误、服务清单,以及按容器的基础设施快照。
实时机房。进行中的对局、打开的连接、每分钟零错误,以及存活服务的清单(匹配、认证、回放推流)。底部是基础设施的快照:战斗服务器占用 13.9 MiB 内存、空闲时 0% CPU,网络核心 81.7 MiB,数据库 55.6 MiB——两个数据中心都标着"OK"。

这些数字描绘出一台节俭的机器。数十个容器,每个都只消耗自身容量的一小部分,在最近的采样窗口里全都零错误

单个容器的详情:内存、CPU 以及最近十分钟的错误,每个服务都标着 CORE。
逐个容器的详情。内存、CPU 以及最近十分钟的错误。每个标着"CORE"的服务,都是生产基础设施的一块砖,而不是实验室里的模拟器。这正是神经网络将要落脚的同一块地板:没有额外的容器,boss 的每一次决策也无需穿越一张物理网络——网络将跑在服务器内部,融进一个更坚实的单一产品里。