先说结论
GameASG-Bench 直接验证 Coding Agent 能否交付一个可玩的、能被稳定复现和验证的完整浏览器游戏,而不把“网页像不像游戏”当作完成标准。每道题要求模型在干净工作区里写出一个自包含的 index.html。评测端再用预先固定的静态检查和浏览器行为检查验证它。
这套 benchmark 最值得研究的是测试边界。人类开发者先写玩法规格、测试接口规格和隐藏检查。Agent 能读到规格,但拿不到 checks.json、checks.js 或以前的测试报告。这样既给了模型足够明确的工程契约,也避免模型直接针对断言字符串做题。
论文包含 47 个任务、336 个 L1 静态检查和 885 个 L2 浏览器行为检查。表现最好的 GPT-6-Astra + Codex CLI 通过了 26/47 个任务,严格成功率 55.3%。它的平均 L2 通过率却有 93.2%。这两个数字之间的差距正是论文的主要发现:一个游戏可以让绝大多数检查通过,仍然在某条必需机制上失败。
Motivation:完整应用没有一个天然的判题器
函数题有输入和返回值,仓库修复题通常有现成测试。一个游戏把控制、状态机、渲染、动画、资源、反馈和终局绑在一起。以下几种“看起来完成了”的证据都不够:
- 页面能打开,只能说明 HTML 没有在启动阶段崩掉。
- 截图里有角色、HUD 和按钮,只能说明某一帧像游戏。
- 源码里出现
win、ammo、restart,不能证明这些变量真的接上了玩法。 - Agent 自己写的测试可能只走测试接口,漏掉鼠标、触摸和自然时间推进。
- 平均通过率会掩盖必需机制失败。一个任务如果只漏掉 1 个 P1 检查,平均分可能仍然很高,严格成功则必须记为失败。
评测还面临一个工程矛盾。纯 GUI 操作很难稳定到达“敌军运输车已经接近基地”这类罕见状态;直接修改实现内部变量又会把测试绑在某个对象名和数据结构上。GameASG-Bench 采用一个公开的语义接口来准备合法状态、执行玩家级动作并读取稳定快照。测试知道“要发生什么”,无需知道游戏内部怎样组织对象。
Related work:差别不只在任务更长
论文把自己放在完整应用与游戏生成评测这一支。下面的比较按论文第 5 节整理;名称链接到各工作的原始页面。
| 工作 | 主要产物 | 状态与证据 | GameASG-Bench 的差别 |
|---|---|---|---|
| APPS / EvalPlus | 边界明确的函数程序 | 输入、返回值、扩展测试 | GameASG-Bench 处理持续运行、可交互、可渲染的完整产物。 |
| SWE-bench | 已有仓库中的修复 | Issue、仓库上下文、项目测试 | 这里从空工作区生成完整单页游戏,并额外定义可测试的运行时接口。 |
| WebGameBench | 浏览器游戏 | 真实浏览器交互与规格引导 | GameASG-Bench 强调生成前固定的人写接口规格与隐藏检查。 |
| GameCraft-Bench | Godot 项目 | 回放、多模态证据、隐藏 rubric | GameASG-Bench 的交付协议更窄,统一为自包含的浏览器 `index.html`。 |
| GameGen-Verifier | 生成游戏 | 从规格抽取 keypoint,运行时状态注入 | 本文限制场景必须是正常游玩可达的合法状态,且不能预先制造待测结果。 |
| GameXpert-Bench | 生成、修复与迭代 | 代码检查、现场交互、人工审核 | GameASG-Bench 给出固定、可复跑的 L1/L2 检查和严格成功定义。 |
任务范围窄也带来好处。所有产物都能在同一种浏览器沙箱里运行,同一套 runner 可以记录输入监听、动画帧、Canvas/WebGL 活动、异常与语义快照。它牺牲了后端、多文件工程和长期服务行为,换来可复现的端到端检查。
checks.json 和 checks.js 到底从哪来
论文第 3.2 节写得很明确:每个游戏概念选定后,人类开发者写 game-spec.md,再定义 tdd.md 里的场景、动作、快照字段、期望结果、拒绝行为和不变量。L1 检查写入 checks.json,L2 检查实现于 checks.js,P0/P1/P2 的优先级也由人类在测试编写阶段分配。
每道题还有一个独立验证过的参考实现。人类会实际操作它,检查核心状态转移、终局与重启,并确认测试接口和屏幕上的游戏同步。随后,同一套 L1 与 L2 检查会跑在参考实现上。47 个参考实现全部通过了所有 L1 和适用的 L2 P0/P1 检查。
因此这些文件不是模型生成后再让另一个模型临时编出来的,也不是从提交代码中自动猜出来的。它们在生成开始之前就已经固定。
| 文件或产物 | 作者 | Agent 是否可见 | 作用 |
|---|---|---|---|
target.md | 人类 benchmark 作者 | 可见,直接作为生成任务 | 工作区规则、交付协议、简短玩法说明。 |
game-spec.md | 人类 benchmark 作者 | 可见 | 玩家看到的机制、反馈、资源变化、终局和最低可玩循环。 |
tdd.md | 人类 benchmark 作者 | 可见 | 公开测试接口、合法场景、动作、快照字段、拒绝语义与不变量。 |
checks.json | 人类 benchmark 作者 | 不可见 | L1 静态检查,包括结构、正则、工具检查和反模式。 |
checks.js | 人类 benchmark 作者 | 不可见 | L2 浏览器检查,组合场景准备、真实输入、语义快照与浏览器证据。 |
| 参考实现 | benchmark 团队 | 不可见 | 人工验证后的正控制,用于确认测试不会把合格游戏误判为失败。 |
index.html | Coding Agent | Agent 自己生成 | 最终交付物,HTML、CSS 与 JavaScript 自包含。 |
一道题从编写到计分的完整路径
下面是根据论文第 2、3 节和附录 B 重绘的流程,不是论文原图。
生成和评测放在两个容器。生成容器有可写工作区,但测试与 runner 不挂载进去。Agent 结束后,系统先做交付预检:进程成功退出,index.html 必须是常规文件、非符号链接、非空,并包含 </html>。通过后,评测容器以只读方式挂载提交和测试。
每个 task 与 configuration 组合只跑一次。论文使用固定的 1280×800 无头 Chromium。这个细节很重要:表里的差异包含模型、harness、工具权限和单次运行随机性的共同影响,不能直接读成模型能力的精确总体排名。
tdd.md 不是测试代码,它是一份公开的行为协议
所有游戏暴露同一个入口:
1 | window.__gameTest = { |
四个方法的名字统一,具体场景、动作和快照字段由任务决定。
reset回到初始状态,并清除上一局的弹窗、结果锁和临时对象。loadScenario把游戏放到正常游玩可达的状态。它可以调整位置和资源来缩短准备时间,但不能直接制造胜利、伤害或订单完成。input执行玩家级语义动作,例如下单、选择目标或暂停。部分 L2 检查会绕过该方法,直接发送鼠标、键盘或触摸输入。getSnapshot返回 JSON 可序列化的语义摘要。字段需要稳定,但 Agent 可以自由决定内部对象图和代码结构。
接口的状态必须和画面共用同一份底层状态。测试端不接受一套只给 __gameTest 看的影子状态。L2 会把快照变化与真实输入、Canvas 哈希、渲染 revision、动画帧和异常记录相互对照。
Armor Alley:从玩法要求到隐藏断言
Armor Alley 是一款横向卷轴直升机战术游戏。玩家既驾驶直升机,又花钱生产地面单位。友方运输车到达敌方基地后获胜,敌方运输车突破己方基地则失败。公开 game-spec.md 还要求持续飞行、持续射击、炸弹、制导武器、士兵投放、落地补给、生产队列、雷达、暂停、胜负锁和重启。
这里选“按住空格持续开火,松开后停止”这一条,因为它能把规格如何落到测试里完整串起来。
1. game-spec.md 写玩家能观察到的因果链
公开需求要求:按住开火键会持续消耗弹药,并生成向目标或朝向移动的可见弹丸;松开后持续射击停止。只有数字下降不够,只有屏幕特效也不够。
2. tdd.md 给出合法起点和可观察字段
测试场景 air_attack_with_targets 必须处于 phase === "playing"、result === "none"、直升机在空中,并且存在可攻击目标。快照公开弹药、弹丸数量、战斗 revision 和通知等语义字段。场景只能准备条件,不能提前开火或造成伤害。
3. checks.json 先检查契约外壳
下面是官方仓库中 Armor Alley 的真实 L1 条目,正则被缩短为便于阅读的形式。原文件会同时检查四个方法的多种合法 JavaScript 写法。
1 | { |
另一个 P1 条目会搜索 startBattle、setFlightIntent、holdFire、dropBomb、orderUnit 等动作分支。L1 的目标是快速发现缺失接口和明显空壳。论文也承认它的上限:正则可能匹配到注释或字符串,所以 L1 通过并不代表玩法成立。
4. checks.js 用真实键盘输入验证持续射击
下面保留了官方检查的核心代码。测试没有调用 input({type: 'holdFire'}) 来“帮”游戏开火,而是向浏览器发送真实 Space 键按下与松开。
1 | const setup = await legalScenario( |
这条检查的完整判定链是:
legalScenario先验证起点没有提前满足结果。- 浏览器按下 Space,等待 650 ms。
- 弹丸数量、弹丸 revision、战斗 revision 或弹药至少一个发生正确变化。
- 浏览器松开 Space,再分两次取样。
- 弹丸增长进入平台期,证明 release 真的终止了持续射击。
它能排除几类常见空壳:只实现 holdFire 语义 API 却没有键盘监听;快照里写 firing: true 但没有弹丸、战斗或弹药变化;松开按键后计时器仍在生成弹丸。
5. 同一个游戏还会检查方向、伤害、经济和终局
Armor Alley 的方向检查会分别从 flight_control_sample 场景开始,向右、左、上、下移动真实鼠标。它要求左右位移符号相反、上下位移符号相反,并确认世界仍在推进。危险检查则从安全且非终局的 air_hazard_nearby 开始,让直升机朝可见危险移动,随后寻找生命、战斗 revision、爆炸效果或警告变化。
这解释了为什么 checks.js 很长。它不只问“有没有按钮”,还要验证准备状态、动作渠道、结果证据、拒绝路径和无关状态不变。
两层检查分别能证明什么
L1 runner 检查 HTML 及其内联或本地脚本,支持工具检查、正则和反模式。每一条都会留下结果与修复提示。L1 即使失败,L2 仍然继续运行,这样报告能区分“契约没声明”和“玩法运行失败”。
L2 在无头 Chromium 中执行 checks.js。每一条检查创建一个新页面,结束或超时后关闭,再开始下一条。共享浏览器 hook 记录 animation frame、输入监听器、Canvas/WebGL 活动和运行时异常。单个检查按需要组合这些证据,不要求每条都使用全部信号。
P0 覆盖启动、测试接口和最低运行条件。P1 对应核心机制、交互、不变量与相关接口。P2 记录高级玩法和完整度,不进入严格成功条件。L2 返回 PASS、FAIL 或 NOT_APPLICABLE。论文特别指出,当前 runner 没有限制 P1 返回 NOT_APPLICABLE,这是一个真实的计分边界。
严格成功为什么比平均通过率低得多
对任务 g,严格成功需要同时满足:交付有效、评测完成、全部 L1 通过、所有适用的 L2 P0/P1 通过。任何一个必需检查失败,整个任务记 0。P2 不影响严格成功。
这是一种产品交付式指标。一个射击游戏的 99 条要求都工作,唯独玩家按键不能开火,它仍然没有完成。平均检查通过率适合观察“差多少”,严格成功率回答“能不能交付”。论文同时报告两者,避免只看一个数字。
最直观的一组对比来自 GPT-6-Astra:平均 L2 已到 93.2%,严格成功仍只有 55.3%。Claude-Opus-5 的 L1 最高,为 99.6%,严格成功是 51.1%。源码级合规在所有模型上都接近满分,但可交付率没有同步接近满分。
工具、轮数、推理强度和 harness 分别改变了什么


完整工具让 DeepSeek-V4-Flash 从 6 至 9 个严格成功上升到 18 个。只增加语法检查并没有稳定改善 P1,说明能解析不等于能玩。轮数结果还暴露了 benchmark 的工程属性:30 轮只有 10/47 个任务完成评测,其中 7 个严格成功;把未完成任务从分母拿掉会得到 70.0% 的条件成功率,但全体任务成功率仍是 14.9%。


同一个 DeepSeek-V4-Flash 在 Claude Code 与 Codex CLI 上得到相同总数,却解决了不同任务。harness 包含系统指令、上下文管理、工具 schema、命令执行和 endpoint 协议,因此它本身就是被测 agent stack 的一部分。只报总分会把这种差异抹掉。
两个失败案例为什么比总榜更有用
Diner Dasher:API 能服务,真实拖拽不工作
测试先加载 tray_with_correct_item,从快照读取托盘物品和顾客的屏幕边界,再从两个矩形中心发送真实鼠标拖拽。拖完后,它要求服务计数、当日收入或顾客完成数至少有一个增加;若顾客已被服务,托盘数量还必须下降。最后再比较 Canvas 哈希或 render revision,确认画面真的变化。
GPT-6-Astra 的失败产物通过 L1,也通过 L2 的 P0/P2,但鼠标和触摸拖拽都没有推动服务流程。这类问题不会出现在接口存在性检查或静态截图里。
1 | const setup = await game.loadScenario('tray_with_correct_item'); |
Turbo Smash Beast:场景加载和自然时间单独都能跑,组合后停住
失败实现里,reset 或 loadScenario 会开启 test mode,并关闭自然时间模拟。Agent 自测了两条独立路径:通过测试接口显式推进时间,以及从新页面直接做真实驾驶。两条都通过。benchmark 的 L2 先加载合法场景,再发送真实鼠标按住并等待浏览器自然时间。这个组合让车辆完全不前进,随后加速、滑行和相关检查一起失败。
真实加速检查会在 readyUnlockedLevel 中按下鼠标,分别等待 350 ms 和 450 ms,要求 speedRatio 连续增长,forwardProgress 和 motionRevision 增长,HUD 速度也同步上升。松开检查再要求车辆短暂滑行,然后减速。场景、输入、时间和 HUD 缺一不可。
这套 benchmark 仍然有哪些边界
- 47 个任务都限制为自包含浏览器单页。结果不能直接外推到后端服务、多人同步、大型资产管线或长期运行系统。
- 每个 task-configuration 组合只跑一次。模型与 harness 排名包含随机性,论文没有给多次运行的方差或置信区间。
- 语义接口提高了可控性,也增加了实现负担。Agent 需要同时写游戏和测试适配层,能力测量包含了“能否正确实现公开测试契约”。
- L1 主要给出源码证据,正则可能命中注释。论文没有把它解释成玩法正确性。
- P1 的
NOT_APPLICABLE当前缺少硬性限制,可能让某些必需检查退出分母。 - 参考实现通过说明测试能接受一组人工确认合格的实现,不能证明测试覆盖了规格里的每一种错误。
这篇论文最有价值的部分在于它把完整应用评测拆成了可检查的职责边界:人类先固定行为契约和隐藏检查,Agent 自由实现内部结构,评测器用合法场景、真实输入、稳定快照和渲染证据复核因果链。55.3% 的榜单数字会随模型更新,测试设计更值得迁移到编辑器、数据产品或交互式科研工具。
原论文表格索引
为了不丢失原文信息,下面保留其余实验表的原图入口:
- Table 1:任务文档
- Table 2:检查数量
- Table 3:主结果
- Table 4:资源消耗
- Table 5:工具消融
- Table 6:轮数预算
- Table 7:推理强度
- Table 8:harness 比较
- Table 9:失败诊断
可交互图解
论文:GameASG-Bench: Benchmarking Autonomous Software Generation for Game Development。代码与任务:areal-project/GameASG-Bench。文中的 Figure 与 Table 图片均裁自原论文;流程图与中文解读根据论文第 2、3 节和官方仓库整理。
留言