【AI全职下属】不要只让 Agent 追求 CI 变绿,要把验收标准变成它不能绕过、不能单方面修改的工程边界
AI Agent 防作弊 CI 实战:自动拦截 assertTrue(true)、跳过测试和空 catch
系列导读:本系列用一个可运行的 Spring Boot 秒杀 Demo,拆解“当 AI 成为我的全职下属”之后,研发工作流应该如何重建。五期内容从一次超卖事故开始,依次讨论并发正确性、上下文裁剪、防作弊 CI、Agent 友好架构和 Human-in-the-loop 上线门禁。主线不是证明 AI 能不能写代码,而是回答一个更实际的问题:当 Agent 已经能高吞吐地产出代码时,工程师如何用边界、验证和审批机制,把它变成可靠的执行者。
文章目录
1. 问题现场:CI 绿了,但问题没有修好
你给 Agent 的任务是“让测试通过”。它确实做到了:流水线变绿,PR 看起来也能合并。
但代码里可能出现了 @Disabled、assertTrue(true)、空 catch,甚至把并发度从 100 改成 1。业务问题没有修好,失败信号被消音了。
本文实现一个轻量级完整性审计器,在进入 Maven 测试前检测 @Disabled、assertTrue(true)、空 catch、捕获 Throwable 和把并发度降为 1 等模式。重点不是依赖几个正则表达式,而是建立不可由执行者自行修改的验收边界。
2. 验证目标
验证目标包括两部分:恶意样例必须被检出,当前合规工程必须以退出码 0 通过。只满足其中一项,都不能证明审计器可用。
3. 原因:绿色流水线为什么可能是假成功
下面几种改动都能让失败的并发测试“恢复绿色”:
@Disabled("偶发失败,先关闭")
void shouldHandleConcurrency() {}
assertTrue(true);
int concurrentCount = 1;
try {
executeSeckill();
} catch (Throwable ignored) {
}
它们没有修复任何业务问题,只是移除了失败信号。
配套动画:
- 假绿色流水线对比动画
- GIF 版本:

4. 原理:把禁止项变成机器可执行规则
Demo 中的规则定义如下:
RULES = (
Rule("DISABLED_TEST", re.compile(r"@Disabled\b"), "禁止跳过核心测试"),
Rule("ALWAYS_TRUE", re.compile(r"assertTrue\s*\(\s*true\s*\)"), "禁止万能真断言"),
Rule("EMPTY_CATCH", re.compile(r"catch\s*\([^)]*\)\s*\{\s*\}"), "禁止空 catch 块"),
Rule("SWALLOW_THROWABLE", re.compile(r"catch\s*\(\s*Throwable\b"), "禁止捕获 Throwable 掩盖失败"),
Rule("LOW_CONCURRENCY", re.compile(r"concurrent(?:Count|cy)\s*=\s*1\b"), "禁止把并发度降为 1"),
)
执行审计:
python pipeline\verify_integrity.py
通过时输出:
Integrity audit passed.
如果测试中出现万能断言,脚本以非零状态退出,流水线立即失败。例如在临时目录中放入一个只包含 assertTrue(true); 的 BrokenTest.java 后,实际输出格式如下:
%TEMP%\cheat-demo\BrokenTest.java:1 [ALWAYS_TRUE] 禁止万能真断言
EXIT_CODE=1
这段输出有三个关键信息:命中的文件、行号和规则码。CI 不需要理解业务语义,只要看到非零退出码,就能阻断这次提交。
配套动画:
- CI 流水线拦截动画
- GIF 版本:

5. 在 Demo 中验证审计器
不能因为工具名叫“审计器”就默认它可靠。项目使用临时目录构造恶意样例:
def test_detector_finds_weakened_assertion(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / "BrokenTest.java").write_text(
"assertTrue(true);",
encoding="utf-8",
)
self.assertTrue(any("ALWAYS_TRUE" in item for item in scan(root)))
运行:
python -m unittest discover -s ai_firm\tests -v
当前 Demo 的两项 Python 测试均已通过:一项验证作弊模式检测,一项验证上下文裁剪依赖遍历。
再对当前仓库执行正向验证:
python pipeline\verify_integrity.py
if ($LASTEXITCODE -ne 0) { throw '完整性审计失败' }
6. 解决办法:不能让 Agent 修改守门脚本
如果 Agent 能同时修改业务代码、测试和审计脚本,它仍可以删除规则后提交。生产环境应至少采用以下一种隔离方式:
- 审计脚本放在独立仓库,由平台团队维护。
- CI 从固定版本的制品或容器中加载规则。
- 使用 CODEOWNERS,修改
pipeline/必须由人类审批。 - 核心测试在远端私有测试集执行,不暴露全部断言。
这就是“只读门禁”的真正含义:不是文件系统只读,而是任务执行者没有单方面改变验收标准的权限。
最小团队落地可以从两段配置开始。先在 CI 中把完整性审计放在 Maven 测试之前:
name: integrity-gate
on:
pull_request:
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Run integrity audit
run: python pipeline/verify_integrity.py
- name: Run Maven tests
run: mvn test
再用 CODEOWNERS 约束守门脚本的修改权限:
/pipeline/ @platform-reviewers
/ai_firm/cheat_detector.py @platform-reviewers
这样 Agent 可以提交业务修复,但凡它试图改掉审计脚本或流水线规则,都必须经过独立维护者审批。
配套动画:
- 只读门禁权限边界动画
- GIF 版本:

7. 正则扫描的边界
本例故意保持简单,适合教学和本地前置检查。生产环境还应组合:
- Checkstyle、PMD 或 Error Prone:Java 语义和代码风格。
- SpotBugs:字节码级缺陷分析。
- SonarQube:质量门、覆盖率和重复代码。
- Maven Enforcer:依赖版本与禁止依赖。
- Git diff 策略:限制 Agent 可修改路径。
静态扫描无法证明代码正确,但能快速淘汰一批确定错误的提交。
8. 把奖励函数改写成验收函数
不要给 Agent 下达“让 CI 通过”,而要给出分层验收:
第一层:编译通过;
第二层:禁止模式扫描通过;
第三层:核心并发测试通过;
第四层:订单数、库存、成功响应三者一致;
第五层:人类 Review SQL、事务边界和锁释放。
Agent 的目标越接近业务不变量,钻空子的空间越小。
实验环境
| 项目 | 版本或参数 |
|---|---|
| Python | 3.12.5 实测,只依赖标准库 |
| 被审计 Demo | JDK 17、Spring Boot 3.5.15、Maven 3.6.3+ |
| 核心验证 | 恶意样例能检出,合规工程以退出码 0 通过 |
小结
测试不是装饰,它是人类把意图固化为机器约束的方式。让 Agent 自动写代码之前,先确保它不能随意改写裁判规则。
下一期将从代码结构本身入手:为什么职责单一、依赖倒置和小接口,会直接提高 Agent 修改代码的成功率。
发布到团队 CI 前的边界
正则扫描可能误报注释、字符串和规则文件自身,也可能漏掉换行、别名封装后的作弊方式。本文工具适合作为快速前置门禁,不能替代 AST、覆盖率差异检查、私有测试集和人工 Review。
测试 Demo 仓库
配套 Demo 仓库地址:https://github.com/quan020406/xiaozhan-blog-column-demos
上一篇:用 AST 依赖裁剪治理 AI 编程上下文
下一篇:小z疯狂码字ing…
感谢阅读,记得点赞、关注、收藏,欢迎各位评论区交流!!!
参考资料
更多推荐


所有评论(0)