返回全部文章

让 AI 智能体写游戏代码,就把性能回归门禁放到机器这一侧

过去一年里,让 Claude Code 或 Codex 写游戏代码,已经从新鲜尝试变成了日常习惯。重构、整套系统的实现、着色器和玩法的调整,智能体产出 diff 的速度不是人能比的。现在的问题不再是这个 diff 能不能跑,而是它是不是还一样快。

AI 写代码时代的瓶颈

写代码的工夫一降下来,瓶颈就从「写」挪到了「确认」。功能能不能跑,测试会自己给出答案。可这段代码有没有把真机帧时间悄悄抬高几毫秒,一片绿的测试是不会告诉你的。

一旦智能体一天提交几十个 diff,逐个用手去剖析就不现实了。渲染线程上不知不觉多了一次分配,更新循环的计算量悄悄变差,GC 触发得更频繁。这些都能通过单元测试,也躲得过肉眼的代码评审,直到放上真机才作为体感上的劣化显现出来。

用智能体在写这一头提上来的速度,把确认这道工序变成了新的瓶颈。

所以不能再把性能确认留成一道靠评审者的警觉、靠老手直觉的工序。它得变成一个和智能体同速运转、由机器给出的判定。

把回归门禁放到机器这一侧

要做的事很简单。给每个构建收集性能遥测,和上一个已知良好的构建相比,一旦超过阈值变差,就让 CI 挂掉。不是由人盯着数字来判断,而是由机器判定是否发生回归,并作为流水线的通过/失败返回。

Framedash 的 framedash perf-diff 会给出两个构建在帧时间、内存、GPU 时间上的 P50 和 P95。加上 --fail-on-regression,当候选构建的 P50 超过阈值变差时,它会以退出码 1 挂掉(门禁按 P50 的比较来判定,P95 作为参考一并列出,不参与判定)。

framedash perf-diff --baseline "$BASE_SHA" --candidate "$GITHUB_SHA" \
  --threshold 5 --fail-on-regression

比较的对象除了帧时间、内存、GPU 时间,还包括地图加载时间(load_time_ms)和磁盘 IO(io.*),都按越小越好的指标处理。你可以用 --metric 把门禁收窄到某个指标,或者用 --map--platform 限定比较范围。

这里的关键是作为比较单位的 build_id。如果一个数字属于哪个构建都定不下来,构建之间的比较本身就无从谈起。

工作流全貌

我们来跟一遍智能体写的代码走到这道回归门禁前的流程。

智能体编辑 剖析测试 CI 回归门禁

门禁一挂,智能体就自己读取遥测数据来缩小原因范围。

在 CI 里把这条流程一把跑完的是 framedash run-profile-test。这条命令会写出自动会话用的 FRAMEDASH_* 环境变量,启动你指定的剖析构建,等它的遥测被收集进来,再对着基线跑 perf-diff 门禁。

framedash run-profile-test \
  --command "./Build/Game.exe -nullrhi -ExecCmds='Automation RunTest Perf'" \
  --scenario nightly --api-key-file ci-read.key \
  --baseline "$BASE_SHA" --threshold 5 --fail-on-regression

被启动的游戏这一侧,在自动测试入口处调用一次自动会话 API。当 SDK 调用 BeginAutomatedSessionFromEnvironment(),它会读取 run-profile-test 写出的 FRAMEDASH_BUILD_ID / FRAMEDASH_GIT_BRANCH / FRAMEDASH_GIT_COMMIT / FRAMEDASH_TEST_SCENARIO,此后每个事件都自动带上 CI 构建以及它的分支、提交、场景。不需要逐个事件打标签的代码。

TelemetrySDK.Instance.BeginAutomatedSessionFromEnvironment();
// ... 运行剖析场景 ...
TelemetrySDK.Instance.EndAutomatedSession();

这里有一个运维上的注意点:短构建或无头运行可能在 SDK 的定期刷新之前就退出。请让运行一直存活到遥测真正发出为止(各 SDK 的 CI 与无头运行指南里有做法);随后 run-profile-test 会等遥测被收集进来,再执行门禁。

build_id 记为顶层字段,分支、提交、场景则挂在 ci.branch / ci.commit / ci.scenario 属性上。这样,智能体提交的 build_id 就直接成了回归比较的候选。

只有密钥的区分要留意。门禁用 analytics:read 密钥读取遥测,被启动的游戏则用另一把 events:write 采集密钥发送遥测。为避免名字冲突,门禁那把密钥用 --api-key-file 传,而不是 FRAMEDASH_API_KEY 环境变量,让 FRAMEDASH_API_KEY 留给游戏当采集密钥。

门禁挂了,该看哪里

perf-diff 挂掉时,你能知道的只到哪个指标变差了、差了多少。在哪里变差,光凭这个数字看不出来。

这时候用的是性能热力图。它把 FPS、帧时间、GPU 时间、内存占用按格子叠加在你的游戏地图上。你可以按设备或构建配置筛选,于是能把回归构建里哪张地图哪一带变重了,定位成地图上的一个位置。

地图上的分布,是由带位置的事件画出来的。当你的剖析场景把玩家位置连同一个已注册的地图 ID 一起上报,SDK 就会给这些事件自动附上相机朝向(偏航和俯仰)。有了这些,「build 1042 的 desert_ruins,朝北看的一个角落里 P95 会跳」这种粒度你就能追下去。回归就此成了可复现的调查对象。

让智能体自己读取遥测

上面这条流程里还剩一处有人:打开热力图、缩小原因、写下修复代码。

这道工序也能交给智能体。Framedash 的 MCP 服务器把针对遥测的只读工具和资源开放给 LLM。热力图网格数据、仪表盘 KPI,乃至原始 SQL 查询,智能体都能从一句自然语言指令直接拉出来。

claude mcp add framedash \
  -e FRAMEDASH_API_KEY=fd_xxx \
  -e FRAMEDASH_PROJECT_ID=your-project-uuid \
  -- npx -y @framedash/mcp-server

这样就能搭出一个闭环:让制造了回归的智能体自己去读它弄坏的那处,再把它修好。用 get_heatmap 俯瞰地图上变重的地方,用按 build_id 过滤的 query 把候选构建的热点单独摘出来,形成对原因的判断,然后改代码。工具是只读的,所以智能体不会改写或删除你的遥测。改好的代码有没有真正消除回归,会在下一个构建里由同一道 CI 门禁再客观判定一次。

CI 回归门禁通过/失败由机器判定构建间是否变差
热力图与 MCP原因由智能体读出在哪里变差

判定交给机器,读原因交给智能体。留给人的,是阈值划在哪里,以及最后看一眼修法是否稳妥。

如何开始

你需要做的,只是给游戏接入 SDK、从 CI 传入 build_id,再往流水线里加一道门禁。SDK 接入几行就够,支持的引擎是 Unity、UE5、Godot (C#)。

  • SDK 和 CI 的具体配置整理在 CI 集成剖析里。
  • 命令清单请看 CLI 参考
  • 要交给智能体使用的话,Claude Code 插件会一次性装好 MCP 服务器和技能。
claude plugin marketplace add crane-valley/framedash-claude-plugin
claude plugin install framedash@framedash
让性能确认跟上智能体的速度 支持的引擎是 Unity、UE5、Godot (C#)。无需信用卡即可开始。
免费开始 UnityUE5Godot (C#)