Unity 工具链修复实录:让 AI Agent 直接驱动 Unity 编辑器编译与测试

项目:Unity 2022.3 模拟经营游戏
环境:macOS / Unity 2022.3.51f1c1 / Unity Pipeline(com.unity.pipeline 兼容分支)
一、背景:为什么需要这套工具链
在做 ChaRestaurant 这个 Unity 2D 模拟经营游戏时,我们引入了 Unity Pipeline(Unity 官方的 com.unity.pipeline 包)——它能在 Unity Editor 内部跑一个 HTTP 服务器,让外部程序(CLI、CI、AI Agent)远程驱动编辑器:触发编译、跑测试、改场景、查日志、控制 Play Mode。
理想的工作流是:
AI Agent / CI 脚本
│ HTTP 请求
▼
Unity Editor (内置 Pipeline HTTP 服务器, 端口 7800)
├── 触发 recompile → 返回编译结果
├── 运行单元测试 → 返回测试报告
├── 读写场景/资源/组件
└── 控制 Play Mode / 截图 / 查日志
这套工具链能让 AI Agent(如 Claude / Codex / 自研 Agent)直接驱动 Unity 编辑器,实现"改代码 → 自动编译 → 跑测试 → 拿结果"的闭环自动化。
但问题是:这套工具链一开始根本没有配置成功。
二、问题诊断:为什么"没配置成功"
拿到任务后,我按顺序排查了 6 个环节,发现了整整 6 个问题:
问题 1:unity CLI 根本没安装
检查 which unity → command not found。官方文档说通过 Unity CDN 安装:
curl -fsSL https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.sh | UNITY_CLI_CHANNEL=beta bash
安装后得到 unity CLI v0.1.0-beta.3。
问题 2:com.pipeline.unity2022 包严重不完整
仓库里 Packages/com.pipeline.unity2022/ 只有 3 个文件(完整包应有 582 个):
com.pipeline.unity2022/
├── Runtime/Common/BasePipelineServer.cs ← 唯一的核心文件
├── Runtime/Unity.Pipeline.asmdef
└── Tests/Editor/ServerLifecycle/PipelineServerTests.cs
BasePipelineServer.cs 里引用了 Unity.Pipeline.Models、Unity.Pipeline.Commands、Unity.Pipeline.Security、Unity.Pipeline.Threading 等命名空间——全部不存在,代码根本编译不过。
问题 3:manifest.json 从未引用 pipeline 包
Packages/manifest.json 里根本没有 com.pipeline.unity2022 / com.unity.pipeline 的依赖项,Unity 压根不会加载它们。
问题 4:fork 依赖的 Roslyn 在项目里不存在
fork 的 asmdef 声明了 precompiledReferences 指向 Microsoft.CodeAnalysis*.dll 等 Roslyn DLL,但项目 Assets 里一个都没有。
问题 5:asmdef 引用了未安装的 InputSystem
fork 的 asmdef 引用 Unity.InputSystem,但项目 manifest 里没有这个包。
问题 6:官方源码有 Unity 6 专属 API
从官方 0.3.1-exp.1 拉下来的源码里,用到了 PhysicsMaterial(Unity 6 才有的类型,2022.3 叫 PhysicMaterial)和 Material.rawRenderQueue(Unity 6 属性,2022.3 只有 renderQueue)。
三、修复过程:六步走
第一步:找到完整源码
仓库里的 fork 是基于 Unity 官方内部包 com.unity.pipeline(版本 0.3.1-exp.1)做的 2022.3 兼容适配。我从 Unity 官方包注册表下载了原始 tarball:
https://download.packages.unity.com/com.unity.pipeline/-/com.unity.pipeline-0.3.1-exp.1.tgz
对比后发现:fork 的 BasePipelineServer.cs 和官方源码几乎一致(只差 watchdog 心跳的几行改动),确认 fork 就是官方源码的轻量适配。
第二步:补全包结构
把官方源码的 Runtime/、Editor/、CodeGen/ 全部复制进 com.pipeline.unity2022/(共 309 个文件),并:
-
创建
package.json(fork 之前根本没有!):{ "name": "com.pipeline.unity2022", "version": "0.3.1-exp.1.compat.2", "unity": "2022.3", "dependencies": { "com.unity.test-framework": "1.1.33", "com.unity.nuget.newtonsoft-json": "3.0.2", "com.unity.nuget.mono-cecil": "1.11.6", "...": "..." } } -
移除 asmdef 的
Unity.InputSystem引用——检查发现RuntimeInputCommand.cs的所有 InputSystem 调用都在#if ENABLE_INPUT_SYSTEM保护内,没有 InputSystem 包也能编译(运行时返回 Unavailable)。 -
修改
manifest.json,添加三个包:"com.pipeline.unity2022": "file:com.pipeline.unity2022", "com.unity.pipeline": "file:com.unity.pipeline", "com.unity.nuget.mono-cecil": "1.11.6"
第三步:硬碰硬解决 Roslyn 问题(最深的坑)
编译后报了一堆 error CS0246: The type or namespace name 'SyntaxNode' could not be found。
排查发现编译命令里 Microsoft.CodeAnalysis*.dll 被 Unity 的 Bee 编译器静默过滤掉了——只保留了 Newtonsoft.Json.dll 和 Unsafe.dll。查证后确认:Unity 2022.3 的 Bee 构建系统硬编码排除用户提供的 Microsoft.CodeAnalysis 程序集(为了和它自带的 Roslyn 4.3.1 编译器不冲突)。
试了 isExplicitlyReferenced: 1 标记也不行,彻底确认这是引擎级限制,无法绕过。
解决方案:裁剪 Roslyn 依赖。 由于 Roslyn 只服务于 eval(动态执行 C#)和热重载(hot reload)这两个功能,而它们与我们的核心需求(触发编译 + 跑测试)无关,所以:
- 删除 7 个 Roslyn 依赖文件(
RoslynCompilationService.cs、EvalCodeCompiler.cs、HotReloadCompiler.cs、4 个 HotReload 处理文件) - 把
eval/eval_file/reload_file/reload_file_override/cleanup_hotreload命令改为返回明确的"Not Supported"结果(而不是神秘报错) - 从 asmdef 的
precompiledReferences移除所有 Roslyn DLL 引用
经验:兼容旧版本引擎时,与其硬啃 API 差异,不如评估"被砍的功能是否核心"。砍掉边缘功能、保留核心,是更务实的策略。
第四步:修复 Unity 6 API 兼容问题
PhysicsMaterial→ 用反射辅助方法解析PhysicMaterial(2022.3 的正确类型):private static Type PhysicsMaterialType() => typeof(PhysicMaterial);Material.rawRenderQueue→ 改用Material.renderQueue(2022.3 的 getter 行为一致,-1 表示继承 shader 队列)。
第五步:清 Bee 编译缓存
删掉 Roslyn DLL 后,报 error CS0006: Metadata file '.../System.Runtime.CompilerServices.Unsafe.dll' could not be found——这是 Bee 构建系统的增量缓存还引用着已删除的文件。删除 Library/Bee/artifacts 下所有 Unity.Pipeline* 缓存文件后解决。
第六步:修复 CmdFailure 参数错误
重写命令时,HotReloadResponse.CmdFailure() 需要 3 个参数(error, errorDetails, executionTimeMs),我漏传了第 3 个。补上后编译通过。
四、过程中遇到的"环境坑"
坑 1:运行 18 小时的编辑器不响应文件变更
Unity Editor 已经连续运行了 18 小时(PID 21996),修改 manifest.json 后它完全没有反应——文件系统监听失效。Asset 文件触碰、AppleScript 激活、Hub CLI 都不行。
最后发现:用户手动点击编辑器窗口就能触发重新编译。所以整个调试过程变成了"我改文件 → 请用户点一下编辑器 → 看日志 → 继续改"的循环。
经验:长时间运行的 Unity Editor 会进入"深度空闲"状态,外部文件变更不触发刷新。改包、改 manifest 这类操作,最好先让编辑器"醒"过来(点击窗口或重启)。
坑 2:unity open . 会截断 Editor 日志
调试过程中尝试 unity open . 想触发刷新,结果它启动了一个短暂的新实例,把 ~/Library/Logs/Unity/Editor.log 截断重写了。原编辑器的日志被转移到 Editor-prev.log。
经验:运行中编辑器,别用
unity open去"唤醒"它,会弄丢主日志。
坑 3:域重载期间服务器短暂不可用
触发 recompile 后,Unity 会做 Domain Reload,Pipeline 服务器会短暂断开(连接被重置)。这是正常现象——[InitializeOnLoad] 会在重载后自动重启服务器。轮询 recompile_status 时遇到连接失败,重试即可。
五、最终效果(实测数据)
修复完成后,工具链完全可用:
| 验证项 | 结果 |
|---|---|
| Pipeline 服务器 | 监听 127.0.0.1:7800 ✅ |
| 实例描述文件 | Library/Pipeline/.unity-pipeline-port(含认证 token)✅ |
| 注册命令数 | 140 个 ✅ |
recompile 触发编译 |
{"status":"compiling"} ✅ |
recompile_status 轮询结果 |
{"status":"completed","failed":false,"errors":[]} ✅ |
list_tests / run_tests |
正常列出/运行测试 ✅ |
get_scene_hierarchy |
返回完整场景层级树 ✅ |
get_performance_stats |
返回 draw calls / 内存 / 帧时间 ✅ |
get_console_logs / console |
返回控制台日志(含编译警告)✅ |
set_autotick |
已启用(16ms 间隔),失焦也能持续运行 ✅ |
| 认证 | Bearer token(存于描述文件,权限 600)✅ |
实际调用方式(因为 unity CLI 的 command 子命令官方还没发布,直接用 HTTP):
TOKEN=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1]))['evalToken'])" "Library/Pipeline/.unity-pipeline-port")
BASE="http://127.0.0.1:7800"
# 触发编译
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"command":"recompile","parameters":{}}' "$BASE/api/exec"
# 查询编译结果
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"command":"recompile_status","parameters":{}}' "$BASE/api/exec"
# → {"status":"completed","failed":false,"errors":[]}
六、这套工具链能做什么(使用场景)
场景 1:AI Agent 自动开发闭环 ⭐ 核心场景
AI 修改 C# 代码 → 触发 recompile → 拿到编译错误 → 继续修改 → 编译通过 → 跑测试 → 修复失败用例
完全自主,无需人工介入编辑器。这也是我们引入它的初衷。
场景 2:CI/CD 自动化
- 提交代码后自动触发
recompile+run_tests - 失败时自动抓取
get_console_logs的错误详情 - 自动截图(
capture_game_view)作为构建产物 - 自动构建(
build/switch_build_target)
场景 3:测试与验证
list_tests/run_tests(EditMode + PlayMode,支持 filter 精确跑单个用例)test_status异步轮询,cancel_tests中止- 测试失败后自动获取堆栈和日志
场景 4:场景与资源批量操作
get_scene_hierarchy查看完整场景结构create_gameobjects批量创建对象(支持 positions/rotations 数组)find_assets/create_asset/move_asset/rename_asset资产管线set_component_properties/set_serialized_field改组件属性- Prefab 全套:
create_prefab/instantiate_prefab/apply_prefab_overrides/unpack_prefab
场景 5:远程诊断
get_performance_stats:draw calls、内存、帧时间console/get_console_logs:实时控制台editor_play/editor_stop/editor_pause:远程控制 Play Modescreenshot/capture_game_view/capture_scene_view:远程截图
场景 6:构建与烘焙(异步任务)
bake_lighting/bake_navmesh/bake_occlusion_culling+ 对应*_status轮询build/build_status/switch_build_target
场景 7:项目设置管理
- 8 大设置域读写:Audio / Graphics / Physics / Player / Quality / Time / Tags & Layers / Input
- 全部支持
dry_run+confirm安全门
七、安全机制
这套工具默认带安全防护(对 AI Agent 自动化尤其重要):
- Bearer token 认证:所有请求必须带令牌,令牌存于
Library/Pipeline/.unity-pipeline-port(权限 600) - 仅限本机回环:只监听
127.0.0.1,外部网络无法访问 - 双保险写操作:所有写/删命令支持
dry_run(先验证不执行)+confirm(显式确认)
# 先 dry_run 验证(不实际执行)
-d '{"command":"delete_asset","parameters":{"asset":"Assets/Foo.mat","dry_run":true}}'
# 确认后再真删
-d '{"command":"delete_asset","parameters":{"asset":"Assets/Foo.mat","confirm":true}}'
八、已知限制(2022.3 专属)
由于 Unity 2022.3 的 Bee 编译器硬性排除 Microsoft.CodeAnalysis,以下功能不可用(返回明确的 "Not Supported",非报错):
| 命令 | 功能 | 原因 |
|---|---|---|
eval / eval_file |
动态执行 C# | 需要 Roslyn 编译 |
reload_file / reload_file_override |
热重载 | 需要 Roslyn |
cleanup_hotreload |
清理热重载 DLL | 需要 Roslyn |
这些功能在 Unity 6(6000.0)上是完整可用的。如果团队需要 eval / 热重载,升级到 Unity 6 是唯一路径。
九、配套的 Skill 规范
为了让 AI Agent 能规范地使用这套工具链,我们还更新了仓库的 unity-pipeline Skill(.agents/skills/ 和 .claude/skills/ 双份同步),内容包括:
- 连接方式(token 读取、端口、HTTP 调用格式)
- 140 个命令的分类索引
- 核心工作流(编译循环、测试循环)
- 安全规范(dry_run → confirm 门控、执行后读回验证)
- 明确标注不可用功能,避免 Agent 误用
这样任何新会话的 AI Agent 加载 skill 后,就能立即按规范驱动 Unity,无需重新摸索。
十、总结
这次修复的核心收获:
- 工具链的价值:把 Unity Editor 变成"可编程的自动化节点",AI Agent / CI 可以直接驱动它,实现编译-测试-改资源-打包的全自动闭环。
- 版本兼容的务实策略:旧引擎适配时,评估"被砍功能是否核心",砍边缘保核心,比硬啃 API 差异更高效。
- 工程排坑经验:Bee 缓存要清、域重载期间服务器会断、长时间运行的编辑器需要"唤醒"、
unity open会截断日志——这些坑都能省下大量排查时间。 - 安全设计值得借鉴:token 认证 + 回环绑定 + dry_run/confirm 门控,是给外部 Agent 开放编辑器控制权的正确姿势。
如果你们的项目也在做"AI 辅助开发"或"Unity 自动化测试/构建",这套工具链值得一试。
(本文记录了 ChaRestaurant 项目的真实修复过程。技术栈:Unity 2022.3.51f1c1 / com.unity.pipeline 0.3.1-exp.1.compat.2 / macOS)

浙公网安备 33010602011771号