The Strict CI/CD Agent
行业:软件开发 | 规模:研发团队
背景
CI/CD 与自动化测试已是现代研发的标配;将「修 bug」也交给 AI 的尝试并不少见,但常见失败模式是:AI 自信地声称「已修复」并尝试提交,而实际代码无法通过编译或测试,甚至引入回归。业界与社区对此有大量讨论:若没有以测试结果为唯一准绳的闸门,AI 的修改无法被信任。
本案例中的团队在智能体工具链中加入了停止钩子(Stop Hook):仅在测试全部通过时才允许执行「提交 PR」类动作,否则将失败日志回灌给智能体,驱动其反思并再次尝试,形成「修—测—再修」的闭环,直至通过。
问题
表象问题(开发者能直接感知)
让 AI 自动修 bug 时,AI 常回复「已修复」,但本地或 CI 一跑测试仍失败;有时 AI 修改了无关文件或引入了新问题;开发者不得不自己再看日志、再改一遍,对 AI 的信任度下降。
根本原因(技术与流程层面)
智能体缺少「成功」的客观定义:它依赖自身输出或模型推理判断「修好了」,而不是以测试运行结果为准。没有闸门阻止「测试未通过就提交」的行为,错误信息也未系统性地反馈给智能体做下一轮修正。
核心痛点
- 误报「已修复」:模型可能幻觉式地认为修改正确,而实际编译/测试失败
- 无闭环:失败日志未自动回到智能体上下文,无法驱动针对性重试
- 信任缺失:人工不得不二次验证,自动化修 bug 的价值大打折扣
解决方案:测试闸门 + 日志回灌 + 反思重试
阶段一:提交前拦截(The Stop Hook)
当智能体尝试调用「提交 PR」或「标记完成」类工具时,系统不直接执行,而是先触发一次确定的测试运行(如同一套本地/CI 测试)。若任一项失败,Stop Hook 阻止提交,并将测试失败时的 STDERR/日志作为新上下文回传给智能体,不给予「完成」信号。
阶段二:读码、改码、跑测(Tool Use)
智能体使用 Tool Use 读文件、编辑代码、在隔离环境中执行测试。它只能通过「测试通过/不通过」来判断是否修好,而非自我声称。每次失败后,新日志被追加到上下文中,供下一轮推理使用。
阶段三:反思与再试(Reflection)
收到失败日志后,智能体先进行 Reflection:归纳失败原因(编译错误、断言失败、超时等),再制定更针对性的修改策略(如只改某文件、只调某条件),然后再次编辑与跑测。此循环持续直到测试全部通过,此时 Stop Hook 放行,允许提交。
实施难点
难点 1:测试稳定性(Flaky Tests)
若测试本身存在不稳定(如依赖时间、网络),可能造成「其实修对了但测试偶发失败」而被误判。需要在 Stop Hook 侧区分确定性与 flaky,或对关键路径做重试/去 flaky 处理。
难点 2:修复策略的完备性
复杂 bug 可能需要多文件、多轮修改;智能体有时会陷入局部策略。通过限制最大迭代轮次、或人工在关键轮次介入,可避免无限循环。
难点 3:与现有 CI 的对接
Stop Hook 触发的测试需与团队现有 CI 用例一致,否则「通过」仍可能在上游 CI 失败。通常做法是复用同一套测试脚本或调用同一 CI 接口。
效果(估算,非精确数字)
| 指标 | 变化 |
|---|---|
| 提交质量 | 仅当测试通过才放行,避免「声称修好却未过测」的 PR 进入主分支 |
| 人工介入 | 预计减少部分「看日志再自己改」的重复劳动;复杂 bug 仍可能需人工收尾 |
| 迭代轮次 | 单次修 bug 可能经历多轮试错,实际轮次因问题复杂度而异 |
以上为基于案例设计的预期效果。实际效果取决于测试覆盖度、测试稳定性(flaky 比例)与 bug 类型;复杂架构或跨模块问题仍可能需人工参与。
用到的模式及其在本案例的具体作用
| 模式 | 在本案例解决的具体问题 |
|---|---|
| The Stop Hook | 在「提交/完成」前强制跑测,仅当通过才放行,在本案例中直接解决「AI 声称修好但未过测」的信任问题 |
| Tool Use | 读文件、改代码、执行测试均通过工具完成,保证行为可复现且结果可验证 |
| Reflection | 根据失败日志归纳原因并调整修复策略,避免盲目重试,提高后续轮次命中率 |
参考依据
| 来源 | 具体内容 | 年份 |
|---|---|---|
| CI/CD 最佳实践 | 测试作为发布闸门、Green build 文化 | — |
| 业界讨论 | AI 辅助修 bug 时「以测试为准」的实践与工具设计 | — |