1. 为什么我要把编译和测试的手交给 AI Agent动手做这套工具链的起因很简单我需要让一个基于大语言模型的 AI Agent 不只是看代码提建议而是能真正动手把 Unity 工程编译一遍、跑一遍测试、再把结果拿回来自己分析。听起来不复杂但真正落地的时候问题全卡在Unity 编辑器并不是为命令行而设计的这一件事上。先说背景。我之前维护一个中型 Unity 项目日常迭代要经受两件事本地手动编译检查和 CI 流水线跑测试。手动编译的问题是慢一次切场景、等编译、再跑 EditMode 测试怎么也要十几分钟CI 的问题是死板写好的 pipeline 只管按固定顺序执行没法根据上一次的结果调整策略。更要命的是AI 编码助手在代码侧已经能提 PR 了但到了构建验证这一步就断掉——要么靠人手动点编辑器按钮要么靠一套和 AI 完全无关的脚本任务。断点就在这里。我要做的是补齐这条断裂的链让 AI Agent 通过一个稳定的命令行接口直接驱动 Unity 编辑器完成三件事——发起编译、收集编译错误、执行测试并拿到结构化结果。Agent 拿到结果之后再决定是修改代码、重新编译还是把问题抛回给开发人员。这个过程里Agent 不需要多聪明的高维能力它只需要一个可靠的操作手柄。这套方案适合谁适合两类人。第一类是正在做 Unity 工具链/CI 建设的开发者想把 AI 编码助手拉进构建闭环第二类是想把 Unity 编辑器行为暴露给外部自动化系统不只是 AI也包括脚本、定时的流水线任务的工程师。如果你满足其中任何一项这篇实录里的思路和代码几乎可以照搬。后面所有内容都基于 Unity 2022 LTSWindows/macOS 均可执行方式为批处理模式。在继续之前先说清楚我为什么强调让 Agent 直接驱动编辑器而不是走传统 CI。传统 CI 的本质是固定的流程 人工配置的步骤一旦某个环节失败流水线只会重跑同一个流程。而 Agent 驱动的好处是它能根据上一次执行结果动态调整编译没过就去读错误文件改代码测试挂了就去看失败的测试用例相当于把人工介入排查的那部分也自动化了。这是传统 pipeline 给不了的。2. 打通命令行通道批处理模式就是 Agent 的操作手柄Unity 编辑器从很早就提供了批处理模式在编辑器不启动图形界面、不加载场景资源的情况下通过命令行参数直接执行内部方法。AI Agent 要操作编辑器靠的就是这个。没有这一步后面所有东西都是空中楼阁。2.1 最小可用调用长什么样在命令行里跑一个 Unity 方法基本结构是Unity -batchmode -projectPath /path/to/project -executeMethod YourNamespace.YourClass.YourMethod -quit -logFile -参数拆开看-batchmode告诉编辑器不进入 GUI 模式后台运行-projectPath指定工程路径-executeMethod要执行的静态方法必须是公共、静态、无参数-quit执行完方法后退出编辑器-logFile -把日志输出到标准输出方便外部程序捕获。这里有个容易踩的坑如果-executeMethod指定的方法内部抛出了未捕获异常Unity 进程不一定立刻返回非 0 退出码反而经常停留在挂起状态。所以方法内部一定要用 try-catch 包住主流程并且在退出前把错误信息写入日志文件再通过EditorApplication.Exit(1)明确返回失败码。这个设计直接决定了 AI Agent 能不能准确判断这次编译到底成没成。如果你的 Agent 跑在 Linux 服务器上还要注意 Unity 编辑器在 Linux 下的批处理模式需要额外加-nographics参数。我在实践中有一次把 Windows 上的命令原样搬过去结果进程直接起不来日志里也没有任何有用的报错最后查文档才想起来 Linux 下不带-nographics就是不行。2.2 输出给 Agent 的数据格式别让大模型猜含义另一个关键点是输出格式。Agent 是语言模型理解自然语言没有任何问题但它对埋在 5 万行 Editor.log 里的某一条编译错误往往无能为力——不是不够聪明而是上下文窗口装不下、信噪比太低。所以我们在设计工具方法时专职做一件事把编辑器里的关键信息剥出来整理成 Agent 能直接消费的 JSON。比如编译结束除了在控制台日志里打印状态之外我会同步输出一份统一结构的 JSON 到 stdout大致是这个样子{ success: false, errors: [ { file: Assets/Scripts/PlayerController.cs, line: 42, severity: error, message: CS0103: The name Rigidbody2D does not exist in the current context } ], warnings: [], durationMs: 8312 }注意这里的 errors 里保存的不只是错误文本还包括文件路径行号错误代码完整消息。因为 AI Agent 拿到这些结构化字段以后可以直接拿着 file 和 line 去定位源码文件再结合错误代码做修复方案。如果只给一堆控制台字符串Agent 又要多一步解析解析错了后面就全乱。2.3 退出码与日志策略从自动化角度看外部进程能读到的信号只有两个stdout 文本和退出码。两个都要利用好状态退出码stdout 内容设计编译成功0输出 JSON 含 success:true编译失败1输出 JSON 含 errors 数组方法异常2输出 JSON 含 critical 字段超时被杀9部分日志可供分析我习惯在脚本里用一个 Helper 类统一封装结束并输出 JSON的逻辑避免在每个方法里重复写退出码。这个 Helper 后续也被测试方法复用保持接口一致。注意-logFile -的用法不要直接去掉-logFile参数因为批处理模式下 Unity 有时并不把日志刷到 stdout加了-logFile -才能保证逐行输出。但也要提醒一句日志完全走 stdout 之后日志文件就没了出问题需要回溯时不太方便。我一般用-logFile /tmp/unity-agent.log指定一个固定路径程序里再读取这个文件来捕获输出两边兼顾。2.4 环境变量的确定性Agent 驱动的自动化还有一个隐形杀手环境变量。你手动跑测试时终端里的一切环境都是你熟悉的但 Agent 通过 Orchestrator 启动子进程时环境变量可能来自一个服务进程PATH 里混着各种奇怪路径。我遇到过编译报错结果发现是 PATH 里混进了旧版 Python间接影响了构建脚本的解析。所以我在 Orchestrator 里做了一个环境探测前置步骤先把 PATH、JAVA_HOME、ANDROID_HOME 等最关键的环境变量输出到日志Agent 拿到任务时能看到这些上下文再决定怎么执行。3. 编译触发链路从命令行到 BuildPipeline 再到错误收集通道打通之后接下来是编译本体。这里说的编译其实分两层一层是代码装配/资源导入阶段可以类比为 IDE 里的增量编译另一层是打出真正的 Player 构建包。AI Agent 驱动测试之前通常只需要前者——也就是让 Unity 一次性把 C# 脚本编译成程序集同时把所有资源过一遍导入管线。后者是打正式包时才需要的也支持但不在本次的核心范围。3.1 用 AssetDatabase.Refresh 触发完整编译在编辑器有 GUI 的情况下代码文件变动后 Unity 会自动触发编译。但在批处理模式下进程起来后并不会从头编译一次——它只会把已经编译好的程序集载入。要让 Agent 的代码修改真正生效需要显式调用刷新[MenuItem(Tools/Agent/BuildAndTest)] public static void AgentBuildAndTest() { try { // 强制重新导入所有变更的资源并触发脚本编译 AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); // 编译过程本身是同步的Refresh 会阻塞到编译完成 var compileErrors GetCompileErrorsFromLog(); var result new { success compileErrors.Count 0, errors compileErrors, durationMs stopwatch.ElapsedMilliseconds }; OutputJsonAndExit(result); } catch (System.Exception ex) { OutputJsonAndExit(new { success false, critical ex.ToString() }, exitCode: 2); } }我见过不少人在这里吃亏直接用一个启动方法去调用业务逻辑没有先执行 AssetDatabase.Refresh。结果就是Agent 改了代码之后再跑测试构建的时候用的还是旧程序集测试结果百思不得其解。加一行 Refresh并且在日志里打印 Compilation started问题就少一半。3.2 编译错误的准确收集编译错误可以从两个地方拿。第一是访问CompilationPipeline.GetAllAssemblyNames()以及用CompilationPipeline.GetCompilationTask获取进程这些 API 能帮你得知程序的编译结构但拿本次刷新后新增的错误不如直接从控制台日志取。更稳定的做法是使用 UnityEditor 提供的事件CompilationPipeline.compilationFinished以及通过UnityEditor.LogEntries或UnityEngine.Debug.LogError的捕获机制收集错误内容。在批处理模式下我有自己一套做法private static ListCompileError GetCompileErrorsFromLog() { var errors new ListCompileError(); // 通过注册日志回调获取编译阶段产生的错误 Application.logMessageReceived (condition, stackTrace, type) { if (type LogType.Error) errors.Add(ParseError(condition)); }; return errors; }不过这里有个现实问题Application.logMessageReceived 是异步注册的而 Refresh 是同步阻塞方法。要在编译完成后拿到错误列表需要用一个准同步的信号来等待。常见方案是把逻辑包在EditorApplication.delayCall里或者注册 compilationFinished 事件。下面给一个更稳妥的版本[MenuItem(Tools/Agent/BuildAndTest)] public static void AgentBuildAndTest() { var done false; ListCompileError errors null; CompilationPipeline.compilationFinished () { errors CollectErrorsFromLastCompilation(); done true; }; AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); // 如果编译已经完成没有新编译手动标记 if (!done EditorApplication.isCompiling false) { errors CollectErrorsFromLastCompilation(); done true; } }这背后有个原理当代码没有变动、程序集不需要重新编译时compilationFinished 不会触发进程就会卡在等待里。所以外层要加一个 isCompiling 为 false 的判断兜底。这个小细节我现在写进了所有工具方法至少能帮大家省去大量调试时间。3.3 关于 GameAssembly.dll 的一个常见误解标题里提到了 GameAssembly.dll我也在这里顺带说清楚。GameAssembly.dll 是 Unity 在 IL2CPP 构建模式下生成的程序集包含项目的 C# 代码转换成 C 再编译出的原生机器代码。它跟 Agent 驱动的脚本编译不是一回事——Agent 阶段通常跑的是 Mono 模式下的脚本程序集如 Assembly-CSharp.dll。如果项目开启了 IL2CPP那么在打正式包时才会生成 GameAssembly.dll。你在自动化的编译链路里看到它多半是因为 CI 在打完包之后找产物文件。找它没问题但别把它当作验证脚本编译是否通过的信号——脚本编译没过BuildPipeline 很可能在 IL2CPP 阶段就报错退出了。对 Agent 来说判断代码能不能编译通过的标准应该来自编译事件里的错误集合而不是某个 dll 是否存在。同理vs2010 编译报 error MSB6006这类错误也不应该让 Agent 直接去翻 C 编译器日志除非它真的到了 IL2CPP 构建阶段。4. 测试执行与结果转换从 TestRunner 到 Agent 能读的 JSON编译通过只是第一步。工具链的第二个核心是执行测试。Unity 的测试框架分为 EditMode 和 PlayMode 两种EditMode 在编辑器进程内运行不启动游戏场景跑纯逻辑PlayMode 会启动场景和游戏循环跑组件/系统集成逻辑。AI Agent 驱动测试时两种都要能触发并且把结果整理成统一格式。4.1 用命令行参数直接跑测试的局限Unity 的测试框架本来就支持批处理模式运行Unity -batchmode -projectPath /path/to/project -runTests -testPlatform EditMode -testResults /path/to/results.xml -logFile -这样 Unity 会自动执行所有 EditMode 测试并把结果输出到一个 XML 文件。看上去很方便但直接裸用有一个问题结果 XML 里的信息格式对 Agent 不友好。XML 本身不难解析关键是 Unity 的 test-results XML 字段分散包含大量 Engine 内部的 fixture 信息同时里面出现的错误消息和解包后的堆栈对 Agent 有帮助但格式非常啰嗦。所以我的做法是不在命令行里直接用原生的-runTests而是通过-executeMethod调用自己的方法在方法内部用 TestRunnerApi 发起测试然后把结果序列化成一行 JSON 输出。4.2 TestRunnerApi 驱动的可控测试运行TestRunnerApi 是 Unity 2020.1 以后提供的 API可以编程方式注册回调、执行指定测试集。下面是一个完整的执行脚本using UnityEditor.TestTools.TestRunner.Api; [MenuItem(Tools/Agent/RunTests)] public static void RunTestsForAgent() { var api ScriptableObject.CreateInstanceTestRunnerApi(); api.RegisterCallbacks(new TestCallbacks()); var filter new Filter { testMode IsPlayMode() ? TestMode.PlayMode : TestMode.EditMode, testNames GetTestFilter() }; api.Execute(new ExecutionSettings(filter)); }关键在于回调类。TestRunnerApi 提供了RunStarted、TestFinished、RunFinished三个关键回调。我在 RunFinished 里收集所有测试结果并输出 JSON。这个 JSON 包含每一条测试的名称、状态Passed / Failed / Skipped、耗时、失败原因和堆栈最终写到 stdout。4.3 把测试结果压缩成Agent 友好格式对 Agent 来说最友好的测试结果是分层的摘要 详细错误信息。我最终输出的格式是{ suite: EditMode, total: 128, passed: 121, failed: 6, skipped: 1, durationMs: 8424, failures: [ { test: PlayerController_Move_ShouldUpdatePosition, message: Expected position (1,0,0) but got (0,0,0), stack: PlayerControllerTest.cs:34 } ] }这个结构比原始 XML 干净太多。关键点在于total/passed/failed 这组数字让 Agent 秒懂整体情况failures 数组里保留了完整的失败消息和堆栈方便 Agent 下一步去对应源码。这样一来即使 Agent 没有看Unity 编辑器的能力也可以根据这些字符串规划修复步骤。4.4 测试与编译的先后顺序一个常用的执行策略是先编译再跑测试。如果编译失败就不启动测试进程。这一点在工具方法里要明确判断。我们在第 3 节的 BuildAndTest 方法里有一个布尔变量记录编译是否成功如果为 false就直接输出编译错误并退出不再往下跑测试。这样既省时间也避免在代码根本编译不过的情况下浪费大量的测试运行时间。有时候 Agent 拿到编译错误后会尝试修改多个文件再一次性编译。这时候我建议不要让 Agent 改了代码就立刻跑测试而是先跑一次快速编译等到编译确实通过后再执行完整测试。这个两段式流程虽然多了一次命令调用但整体上反而快很多因为你避免了编译失败却还硬跑测试的无效工时。4.5 测试用例的筛选与分组当项目里的测试数量涨上去以后全量跑一次测试的成本会越来越高。我的工具里支持按测试名称前缀、所属程序集、甚至按特性分组来筛选。例如 Agent 修改的是 PlayerController 相关代码就可以先只跑 PlayerController 相关的测试快速验证通过后再跑全量回归。这个筛选参数在工具定义里暴露给 AgentAgent 自己会根据修改范围决定筛选条件实现了更精细的调度。5. 让 AI Agent 学会按流程办事函数调用与多轮修复循环前面把 Unity 侧的接口都准备好了接下来是 Agent 侧。现在的 LLM Agent 大多都支持函数调用/工具调用Function Calling / Tool Use比如 OpenAI 的 tools 机制、Anthropic 的 tool use、以及各种开源 Agent 框架里的 skill/mcp 机制。我们这边要做的是把前面封装的编译和测试方法抽象成三个工具并把工具的描述写清楚。5.1 三个最小必要工具我定义了三个工具分别是compile_project、run_tests和read_file。每个工具的描述里都包含了参数说明和典型的返回值结构Agent 读到这些描述后就能判断在什么时候调用哪一个。我这里用一段伪 JSON Schema 来表达工具定义实际接入时你可以映射到你的 Agent 框架{ name: compile_project, description: 调用 Unity 批处理模式执行代码编译并返回编译错误列表。编译成功时 success 为 true失败时 errors 数组包含文件路径、行号和错误码。, parameters: { type: object, properties: { timeout_seconds: { type: number, description: 编译超时时间默认 300 } }, required: [] } }run_tests 类似不过多一个参数 testModeEditMode 或 PlayMode。read_file 则是让 Agent 拿到 file/line 之后去读取源码便于分析修复方案。5.2 多轮修复循环的工作流整个修复循环可以概括为Agent 发起 compile → 得到 errors → 根据 fileline 读源码 → 修改代码 → 再次 compile → 通过后再 run_tests → 根据测试失败信息再修。这个循环看起来简单实际跑起来有一个核心前提你的 Agent 框架必须允许工具调用之后的再次调用。很多 Agent 框架默认只能做一次工具调用然后就结束对话这是不够的。我实际用的方案是写了一个简单的 Orchestrator循环执行以下步骤把上一次工具的返回值追加到对话上下文将当前对话上下文交给 LLM请求选择下一步行动如果 LLM 返回的是工具调用请求则执行对应工具把结果追加到上下文回到第 1 步如果 LLM 返回的是最终结论比如问题已修复或无法独立解决需要人工介入则结束循环。这里有个值得注意的性能优化点每轮循环都会重新把全部上下文发送给 LLM如果你中途读过十几个源代码文件上下文会越来越大费用和延迟都会上升。我的做法是在上下文里只保留近两轮的代码内容和所有工具的最终返回摘要而不是保留全部历史。5.3 把编译原理相关的判断交给 AgentAgent 要真正有用不能只会调用命令还要能理解编译错误的深层原因。比如一条 CS0103 错误表面上是名称不存在但 Agent 需要有基本的编译原理概念知道可能是缺少 using 指令、引用了不存在的程序集、或者代码顺序问题导致变量未声明。我在 prompt 里给 Agent 注入了一段关于 Unity 编译流程的简介说明 Unity 的编译顺序、程序集依赖关系、以及常见的编译期异常类型。这段话不长但对 Agent 判断修复方向帮助很大。5.4 和 MCP/Skill 机制的衔接现在的 Agent 生态里MCPModel Context Protocol越来越常见。这个协议本质上就是给 Agent 提供外部工具知识库的标准方式。我们把 compile、run_tests 封装成 MCP server 的 toolAgent 只要按协议发请求就能获得我们的 Unity 工具能力完全不需要改 Agent 核心代码。这个思路是工具接口保持稳定接入方式支持函数调用和 MCP 两种。实际部署时我建议优先用函数调用方式调试成本低等业务稳定后再封装成 MCP server 供多个 Agent 共享使用。你在各种 Agent 平台上看到的技能记忆MCP 工具这类名词放到我们这个场景里编译和测试就是 Agent 最需要的两个技能。6. 踩坑实录MSB6006、GameAssembly.dll、还有那些说不出原因的诡异做任何工具链都要有耐心因为问题往往出现在最意想不到的地方。下面这几个坑是我在实际运行中遇到的每一个都直接浪费过我一整个下午等你遇到了就能省下这段时间。6.1 MSB6006cmd.exe 退出代码为 3这个报错很眼熟——很多人在 Windows 上做 VS 工程编译时都遇到过 error MSB6006。它出现在 Unity 工具链里通常有几种可能但并不都是 Unity 本身的问题。我遇到的一次是批处理模式下编译日志里出现 error MSB6006: cmd.exe 已退出代码为 3后面跟着 CSPROJ 路径。排查链路是这样的先用 Agent 里的 read_file 工具去读那个 csproj 的第一行看是否有奇怪的路径再用命令行手动执行一次dotnet build该 csproj最后发现问题出在环境变量 PATH 里混入了一个旧版本的 MSBuild导致命令解析到了错误的位置cmd 返回 3。解决方案是在执行 Unity 批处理命令之前用export PATH/usr/bin:/bin:...把环境变量清干净再跑。这个经验很重要AI Agent 在启动子进程之前必须明确知道目标机器的环境变量是什么。如果 Agent 只是盲目调用Unity ...命令很容易被环境干扰。我们在 Orchestrator 启动前会做一次环境探测输出 PATH、JAVA_HOME如果用到 Android、和 Node 版本Agent 诊断问题时就有据可依。6.2 编译成功但测试永远跑不起来的案例另一个让我记忆犹新的坑是compile_project 返回 successtrue但 run_tests 一直报 No tests found。排查半天发现原来是批处理模式下 Unity 加载的 Assembly-CSharp.dll 是上次构建的产物而这次代码修改根本没触发重编译。原因就是第 3 节提到的 AssetDatabase.Refresh 没被调用。如果已经加了 Refresh 还是不行再看第二个可能测试方法所在的程序集没有被 Test Framework 扫描到。这时候去检查 asmdef 文件如果测试代码在一个独立的程序集比如 Tests 文件夹下的 asmdef要确保它的 Test Assemblies 选项被勾选并且引用了 nunit.framework。Agent 排查这类问题靠的是读 asmdef 的内容所以我们的 read_file 工具对 asmdef 文件也有读取能力。6.3 批处理模式下的假死与超时统一的一个顽疾是批处理模式经常莫名挂起最常见的原因有两个。一是某个编辑器扩展在加载时执行了等待窗口或者网络请求二是 Shader 编译进入后台但没有及时结束。这两种情况都不会报错进程就一直卡着。我的应对办法是在 Orchestrator 里给每个 Unity 子进程都设了超时一般编译给 300 秒测试给 600 秒。超时后强制杀掉进程并把日志尾部 200 行提取出来交给 Agent让它判断是扩展加载卡住还是 Shader 编译卡住再给对应的处理建议。说到 Shader顺带提一句热词里出现的Unity 阴影问题——如果你在跑 PlayMode 测试时发现场景里的阴影表现和编辑器里不一样多半是 Shader 变体没有及时生成。批处理模式跑测试时如果加载的是未编译的 Shader表现会和编辑器预览有差异。这个不算工具链的 bug但 Agent 在复现渲染相关 bug时容易误判我会在 prompt 里提醒 Agent 优先用 PlayMode 测试去验证渲染行为而不是直接对比截图。6.4 日志缓冲与最后一行不是结果的陷阱写这个工具链的前期我一直以为进程退出前的 logFile 最后一行就是最终结果后来发现完全不是这样。Unity 在退出时可能还有缓冲的日志没刷新直接 tail 最后几行经常看到的是无关紧要的退出版本号。所以我们的脚本从来不是读取日志最后一行来判断结果而是让工具方法主动输出一个特定的 JSON 结束标记行外部脚本只认这个标记行。为了稳定我会把 JSON 放在一行并且在最前面加一个固定前缀 AGENT_RESULT:脚本里按前缀过滤。这个设计看着笨但真的稳。6.5 编辑器加载扩展引起的脏状态批处理模式下Unity 一样会加载项目里的所有 Editor 脚本和编辑器扩展。如果某个扩展在初始化时依赖 GUI 环境比如弹出一个窗口在批处理模式下就可能抛异常但不退出。这种情况最隐蔽因为错误消息可能只在日志的某个角落出现。我的排查方式是先跑一个什么也不做的最小批处理命令如果这个都异常退出基本可以确定是项目里的编辑器扩展不兼容批处理模式。解决方案是在工具方法里先禁用非必要扩展或者把扩展的初始化代码加上if (Application.isBatchMode)的判断。7. 稳定性与效率优化让 Agent 驱动的工具链能长期跑下去工具链能跑通和能长期稳定运行是两回事。前面的章节解决的是能不能跑通这一节聊怎么防患于未然。7.1 并发与锁不要让两个 Agent 同时动一个工程如果你有多个 Agent 并行工作切记同一个 Unity 工程目录同一时间只能被一个进程占用。Unity 的项目锁Temp/UnityLockfile很多时候不可靠所以我用的是自己在工程根目录放一个.agent.lock文件的方式Agent 在开始编译前先尝试创建锁拿不到锁就等待或放弃。这个锁机制的实现可以在 Orchestrator 里做也可以用文件锁 API。重点是锁的释放要可靠——Agent 进程被 kill 后锁文件可能残留所以要写一个过期时间比如 10 分钟前的锁文件自动视为过期。7.2 增量与缓存避免每次全量编译Unity 的增量编译在批处理模式下默认是生效的但我们初始化时用的 ForceSynchronousImport 会拖慢速度。我的经验是普通编译用不带 Force 参数的 Refresh只有确认需要全量重导时才用 Force。另外可以缓存 Agent 已经看过的文件内容避免反复读取。其实真正耗时的往往不是编译本身而是触发资源导入的 AssetDatabase 刷新。如果 Agent 只改了 .cs 文件资源导入的损耗比脚本编译还大。后面我在工具里增加了 skipAssetRefresh 参数只要确认改动不涉及资源就跳过 AssetDatabase 刷新速度能快好几倍。这里的关键是 Agent 要能判断改动是否涉及资源文件——我在 read_file 工具的输出里会附带文件的扩展名和目录Agent 看到.cs就倾向于跳过资源刷新看到.prefab或.mat则执行完整刷新。7.3 日志轮转和上下文控制Agent 驱动的工具链很容易产生海量日志。我的解决方式是按天轮转日志文件并且只保留最近 7 天。同时在 Agent 上下文里不保存原始日志内容而是保存统计信息和关键错误片段只有 Agent 明确请求时才会读日志的指定区间。7.4 一套我落地的验收清单最后分享一份验收清单是我每次在另一台机器上重新部署这套工具链时用来确认一切正常的。你可以直接拿来用命令行手动执行编译工具能输出 AGENT_RESULT 前缀的 JSONJSON 里 success 字段对有错误/无错误两种情况都准确测试工具能正确处理 EditMode 和 PlayMode 两种模式并输出总览和失败明细Agent 能通过函数调用方式触发编译、读取错误、修改代码、重新编译、运行测试并发锁正常第二个 Agent 在锁存在时不会进入同一工程异常退出后锁文件和日志状态可恢复不会污染下一次运行批处理模式下不加载无关编辑器扩展不会出现假死在无图形界面的 Linux 环境下也能正常完成全部流程。这八项全部通过说明这套工具链已经具备从手工调试转向Agent 自主驱动的基本条件了。7.5 关于后续扩展的一点想法工具链做成这样之后扩展空间其实很大。比如可以接入本地代码检索服务让 Agent 在修改代码前先搜索相关函数的引用和被引用关系也可以把历史编译失败的错误码聚合起来做统计分析找出项目里最容易出错的模块反馈给团队优化代码质量。这些后续方向都能在这一套稳定接口之上继续叠加不需要推翻重来。我目前在实际使用中最满意的是 Agent 已经能在我睡着的那个时段独立处理一部分低风险的编译错误和测试修复。它把构建验证的反馈循环从人工按按钮变成了AI 自动迭代虽然还不能完全替代开发者但已经把一个常见的日常事务性工作从我的待办列表里彻底划掉了。