AI 生成代码质量防线实战:5 个 CI/CD 配置,把 8% 的逻辑错拦在线上之前0

AI 写代码 3 个月后,我在 CI/CD 里加了 5 道防线

【掘金摘要】AI 写的代码单测全绿、上线翻车,问题不在 AI,是你的流水线没设防。5 个配置,照着抄。


AI 编程接入三个月,我们组踩了个大坑:AI 重写过的库存模块,单测全绿、接口全过,上线第二天账对不上。

事后复盘,问题不在 AI 代码有多阴,是我们的 CI/CD 压根没设防。从提交到上线,没有任何一步在验证"业务逻辑对不对"。

这 5 个配置就是踩完坑之后补上的防线,全部能直接抄。目标只有一个:让"逻辑正确性"在 CI 阶段就被验证,而不是等线上数据自己说话。

Step 1:断言业务顺序,别只断言"调用成功"

AI 代码最常见的翻车点:方法调用了、返回值对了,但顺序错了。而大部分测试只断言结果,不锁顺序。

我们原来的用例长这样,AI 特别喜欢这种:

python 复制代码
def test_deduct_success():
    result = order_service.deduct(stock_repo, product_id=1001, qty=2)
    assert result.success is True   # 只断言调用成功,顺序错了一无所知

改成锁死调用顺序:

python 复制代码
def test_deduct_checks_stock_before_updating(mocker):
    repo = mocker.Mock()
    repo.get_stock.return_value = 10

    order_service.deduct(repo, product_id=1001, qty=2)

    # method_calls 按时间记录所有调用,顺序错直接红
    assert repo.method_calls[0][0] == "get_stock", \
        f"必须先查库存,实际第一个调用是 {repo.method_calls[0][0]}"
    assert repo.method_calls[1][0] == "update_stock"

关键点:mock 住依赖,用 method_calls 断言先做什么、后做什么。凡是涉及"查→改""校验→提交"这种有顺序语义的逻辑,都这么写。

Step 2:属性测试扫边界,AI 想不到的输入它来想

AI 幻觉 bug 很少藏在你手写的样例里,藏在边界和组合里。用 hypothesis 自动生成几百组输入,专治这种。

bash 复制代码
pip install hypothesis
python 复制代码
from hypothesis import given, settings, strategies as st

@given(
    stock=st.integers(min_value=0, max_value=10_000),
    qty=st.integers(min_value=1, max_value=100),
)
@settings(max_examples=300)
def test_deduct_stock_never_negative(stock, qty):
    repo = FakeStockRepo(stock)
    order_service.deduct(repo, product_id=1001, qty=qty)
    assert repo.current() >= 0, f"库存扣成负数了: stock={stock}, qty={qty}"

写的是不变量:库存永远不为负。300 组随机输入跑下来,AI 代码里"库存不足还硬扣"这类问题直接现形。它还会把失败的输入缩到最小,报错信息能直接当 bug 描述用。

Step 3:变异测试拆穿"假覆盖率"

AI 最阴的一手:测试代码和业务代码一起生成,一起错。覆盖率能拉到 95%,全是虚的。

变异测试专治这个:故意把源码改出 bug(叫变异体),看你的用例能不能杀掉它。杀不死的,就是你的测试盲区。

bash 复制代码
pip install mutmut

# 只变异核心业务模块,别全量跑
mutmut run --paths-to-mutate order_service.py

# 看存活变异体 ------ 活着的都是用例没拦住的问题
mutmut results

跑一次你就知道:原来"95% 覆盖率"的用例,存活变异体能占三成。CI 门槛就定为存活变异体超过 5 个直接失败,逼着把用例补到位。

Step 4:AI 代码自动打标,走强化评审

人不可能逐行审所有代码,但 AI 生成的必须审。先立规矩:AI 生成的关键逻辑,文件头必须写 # GENERATED_BY_AI 标记。然后让 CI 自动认领。

yaml 复制代码
# .github/workflows/ai-code-gate.yml
name: ai-code-gate
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  tag-ai-code:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: 扫描 AI 生成标记
        id: scan
        run: |
          if git diff --name-only origin/main...HEAD | xargs grep -l "GENERATED_BY_AI" 2>/dev/null; then
            echo "has_ai=true" >> "$GITHUB_OUTPUT"
          fi
      - name: 打 AI 标签
        if: steps.scan.outputs.has_ai == 'true'
        run: gh pr edit "${{ github.event.pull_request.number }}" --add-label "ai-generated"

再配分支保护规则:带 ai-generated 标签的 PR,必须 2 人 approve,关键逻辑要开发逐行讲清楚为什么对,讲不明白就打回重写。这条人工闸门看着慢,拦下来的事故比省的这点时间值钱得多。

Step 5:线上对账兜底,别让 bug 在账上躺两周

前四道防线挡住大部分问题,但总有漏网的。最后一道:用数据一致性兜底。

sql 复制代码
-- 每日对账:订单扣减量必须等于库存流水变动
SELECT o.order_id,
       o.qty AS order_qty,
       COALESCE(SUM(s.qty_change), 0) AS stock_changed
FROM orders o
LEFT JOIN stock_log s ON s.order_id = o.order_id
WHERE o.created_at >= NOW() - INTERVAL 1 DAY
GROUP BY o.order_id, o.qty
HAVING ABS(stock_changed) <> o.qty;
bash 复制代码
# crontab -e  每天凌晨 2 点跑,有异常就告警
0 2 * * * /usr/bin/python3 /opt/scripts/stock_reconcile.py >> /var/log/reconcile.log 2>&1

有结果就钉钉告警。逻辑错藏得再深,账对不上是藏不住的。

效果对比(我们团队 3 个月数据)

指标 引入前 引入后
逻辑正确性问题暴露时间 平均 3 周(等线上账错) 上线前拦截约 80%
对账发现脏数据 无(靠人工发现) 上线当天逮住 1 笔
单测质量 95% 覆盖率,变异存活率 30% 变异存活率 <5%

最直观的变化:bug 从"线上用户发现"变成"CI 拦住"。测试还是那个测试,工作量一点没少,但活法完全不一样了。

注意事项

  • 别指望单个工具全搞定,5 道防线各管一段:顺序、边界、用例质量、评审、兜底
  • 变异测试慢,放 nightly 跑,别塞进每次提交
  • 打标靠约定,团队没统一规范前,自动化等于空转
  • 别一次全上,先拿订单、支付这种核心模块试点,跑顺了再推广

说句实在话:AI 写代码这事儿挡不住,也犯不着挡。把防线修好,比天天防着 AI、抱怨 AI 有用得多。

你们团队给 AI 生成的代码设了什么门槛?覆盖率?评审?还是直接不设防?评论区聊聊,我想看看是不是只有我们组吃过亏。

关注「晴天」,不讲教科书,只聊真实项目里撞过墙才想明白的东西。

相关推荐
树码小子2 小时前
Pycharm解释器配置问题解决
ide·python·pycharm
国雪2 小时前
python-协程
python
一木 之林2 小时前
Python.六.(一)--1.标准库、常用工具与基础操作(进阶)
python·rpc·dubbo
月光船幽幽3 小时前
铁牌协议卡:节流与重构
python·重构
骇客野人3 小时前
Linux 服务器 Python 版 MCP 服务部署整体方案(适配 Claude/Cursor/自研Agent)
linux·服务器·python
AI视觉网奇3 小时前
动作识别 视频理解大模型
开发语言·python·音视频
Java尧哥学AI4 小时前
35岁Java程序员学AI Day2:从装环境到写第一行Python,踩了3个坑
python
zhiSiBuYu05174 小时前
Flask Session 与 Cookie 新手实战指南
后端·python·flask
码云骑士4 小时前
104-实战论文搜索引擎-ArXiv爬取-Milvus存储-RAG问答-Gradio前端
前端·python·搜索引擎·milvus