Administrator
发布于 2025-11-15 / 3685 阅读
32

研发流程中的 AI 卡点设计

把 AI 塞进研发流程半年,哪些卡点活下来了

四月份我们开始在研发流程里加 AI 卡点,到这个月正好半年。团队 14 人,一共试过九个卡点,活下来五个。先说总体结论:AI 卡点的价值不在「生成了多少内容」,而在「拦截了多少问题」——纯生成类的(写文档、写注释)普遍活不下来。

我们试过的九个卡点

卡点位置状态核心数据
需求澄清提问需求评审前存活平均提前发现 2.3 个遗漏点
编码实时补全IDE 内存活采纳率 31%
提交前自检pre-commit存活拦截 340 次带问题的提交
AI 代码审查PR 创建时存活有效问题率 34%
测试用例生成PR 创建时存活覆盖率 +8.2pp
接口文档生成合并后砍掉准确率 92%,但没人看
代码注释补全编码时砍掉——
发布说明生成发布前半存活从 40 分钟降到 8 分钟
线上问题分析故障时存活MTTR 降 27%

活下来的:提交前自检

这个是性价比最高的,也是我最推荐的起点。做法是在 pre-commit 里跑一个轻量检查,不是 lint(我们有 Checkstyle 了),而是三类 lint 抓不到的问题:

#!/bin/bash
# .husky/pre-commit  +  服务端 hook 双保险
STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep '\.java$')
[ -z "$STAGED" ] && exit 0

# 只检查本次改动的 diff,不扫全量代码(快)
git diff --cached | ai-check \
    --rules sensitive-data,null-risk,resource-leak,sql-injection \
    --model qwen-plus \
    --timeout 20s \
    --fail-on high

# 超时或 AI 不可用时不阻塞提交(重要!)
[ $? -eq 124 ] && echo "AI check timeout, skipped" && exit 0

四条规则的检出情况(半年累计 2,841 次提交):

规则命中次数真问题率
sensitive-data(硬编码密钥、手机号、身份证)4789%
null-risk(明显未判空的链式调用)16341%
resource-leak(流/连接未关闭)7873%
sql-injection(字符串拼接 SQL)5281%

一共拦截 340 次,其中 208 次是真问题(61%)。最值钱的是 sensitive-data 那 47 次——有一半是我们自己写的测试配置里带了真实的内网账号,如果提交到仓库就是安全事故。

  • 只扫 diff 不扫全量。全量扫要几分钟,没人愿意等。扫 diff 平均 3.2 秒。
  • AI 不可用时不阻塞。这点我们吵过,有人觉得应该失败安全,但模型服务抖动导致的误阻塞会让大家对 hook 失去信任,最后被绕过。现在本地 hook 不阻塞,服务端 push 时的强制检查才阻塞。

活下来的:AI 代码审查

第一版上线时,AI 对每个 PR 平均提 11.4 条评论,开发的反应是「噪音太大,不看」。第二周开始有人在 PR 里回复「bot 闭嘴」。我们做了三轮收敛:

// v1:什么都提 —— 11.4 条/PR,有效问题率 9%
"Review this PR, point out any issues."

// v2:限定类别 —— 6.8 条/PR,有效问题率 17%
"Review for: NPE risks, resource leaks, concurrency issues, SQL problems."

// v3:限定类别 + 要求证据 + 分级 —— 2.9 条/PR,有效问题率 34%
"""
Review the diff. Only report issues that meet ALL criteria:
1. Can cause production failure, data error, or security problem
2. You can point to the exact line and explain the trigger condition
3. NOT a style preference or "could be better" suggestion

For each issue output:
  FILE:LINE | SEVERITY(high/medium/low) | PROBLEM | TRIGGER CONDITION

If no issue meets these criteria, output exactly: NO_ISSUES
Do not praise. Do not suggest refactors. Do not mention naming.
"""

v3 的三个关键改动:

  1. 要求指出触发条件。这一条过滤掉了大部分臆测。AI 说「这里可能 NPE」没用,要说「当 order.getItems() 返回 null 时会 NPE」才保留。
  2. 明确禁止夸奖和改进建议。原来 AI 会花三分之一篇幅说「代码结构清晰,命名规范」,全是废话。
  3. 允许输出 NO_ISSUES。不给它「必须提点什么」的压力。现在约 38% 的 PR 会收到 NO_ISSUES

有效问题率 34% 是什么概念?我们人工 CR 的有效问题率大概在 55%(提的问题里一半是风格偏好)。AI 还差得远,但它的价值在于不疲劳——我们统计过,人工 CR 在周五下午和周一早上的检出率明显偏低,AI 不会。不过要强调一条:AI 审查不能当成「已审查」,人工仍需完整看 diff,AI 只是帮着标重点。

活下来的:测试用例生成

我们的做法是 PR 创建时,如果改动了核心业务逻辑且没带测试,自动生成测试用例草案推给作者。关键是「草案」——不是自动提交,而是作为 PR 评论贴出来,作者自己决定采纳哪些。

@Test
void should_reject_when_stock_insufficient() {
    // AI 生成的草案,作者确认后手动加入
    Order order = order("SKU-001", 5);
    when(stockClient.available("SKU-001")).thenReturn(3);

    assertThatThrownBy(() -> orderService.create(order))
        .isInstanceOf(InsufficientStockException.class)
        .hasMessageContaining("库存不足");
}

半年数据:生成测试用例 1,240 个,作者采纳 713 个(57%);采纳的用例里 46% 被人工修改过(主要是调边界值和 mock 数据);模块单元测试覆盖率从 61.3% 提到 69.5%。

57% 的采纳率是我认为这个卡点能活下来的原因。如果是自动提交,46% 需要修改的用例会污染代码库。而作为草案推给作者,修改的成本由作者承担,质量可控。

还有一个意外收益:AI 生成的用例里,有 23 个直接发现了真实 bug(跑不通,因为代码逻辑有问题)。这些 bug 在 Code Review 时都没被发现。

被砍掉的:接口文档自动生成

这个卡点技术上最成功——生成准确率 92%,覆盖了我们 340 个接口,文档质量比人写的还规范。但我们三个月后砍掉了。

原因是没人看。生成的文档页面月均访问 47 次,其中 31 次是我们自己人。前端同学的原话是:「我都是直接看 Swagger 或者问后端,没想起来去看这个。」

问题出在选错了卡点位置。文档没人看不是因为写得不好,是因为大家获取接口信息的路径已经固化了。我们生成了更好的文档,却没有改变任何人的工作流。教训是:AI 卡点要嵌进现有工作流,别指望它创造新工作流。后来把接口说明挪进 Swagger 注解,CI 时自动补全缺失的 @Operation 描述,效果就好了。

被砍掉的:代码注释补全

这个砍得最快,两周就下了。原因很简单:AI 生成的注释基本都是「重复代码在说什么」。

// AI 生成(毫无价值)
/** 根据用户 ID 查询用户名 */
public String getUserName(Long userId) { ... }

// AI 生成(甚至有害,把实现细节写死在注释里)
/**
 * 先查缓存,缓存没有再查数据库,查到后写入缓存并设置 30 分钟过期
 * @param userId 用户 ID
 * @return 用户名
 */

第二种注释比没有注释更糟——代码改了注释不改,变成误导。我们统计了两周生成的 890 条注释,有实际信息量的(解释「为什么」而非「是什么」)不到 5%。后来改成只在方法体超过 50 行时才生成,且只解释「为什么这么做」,生成量降到 1/12,有用率提到 40%。

半存活的:发布说明生成

这个卡点省时间很明显——从 40 分钟手工整理降到 8 分钟(AI 生成 + 人工校对)。但「半存活」是因为我们对生成内容做了强约束。

第一版让它「根据这些 commit 生成发布说明」,结果是流水账,还经常把内部重构(「调整 XxxUtil 的包路径」)也写进去给业务方看。现在改成分类 + 模板:

"""
根据以下 commit 生成发布说明,只输出三类内容:

【新功能】面向用户可感知的变化,用业务语言描述,不要出现类名方法名
【问题修复】格式:修复了「{用户可感知的现象}」的问题
【重要变更】可能影响下游的变化(接口签名、配置项、行为变更),必须列出

忽略:纯重构、测试改动、依赖升级、格式化、注释修改

如果某一类为空,写"(无)"
"""

「忽略纯重构」这条是我们被业务方投诉后加的——他们不关心我们重构了什么,只关心会不会影响使用。现在还剩人工校对,平均 6 分钟,总归省了 26 分钟。

成本核算

半年下来的总投入:

项目金额/时间
模型调用费用¥3,840(月均 640)
卡点开发与维护1 人 × 约 60 小时
团队适应成本约 2 周低效期

收益方面两个实在的数字:线上缺陷密度从每千行 0.42 降到 0.31,Code Review 平均时长从 4.2 小时降到 3.1 小时(都是 -26%)。缺陷密度下降不完全是 AI 的功劳,同期还做了其他改进;但 CR 时长下降基本可以归因于 AI 预处理了那些低级问题。

几条经验

  • 从「拦截型」卡点做起,别从「生成型」做起。生成的东西没人看,拦截的东西有即时反馈。我们活下来的五个里有四个是拦截型。
  • AI 不可用时要降级而不是阻塞。这一点决定了卡点能不能长期存活。
  • 给 AI 的输出设上限。提 11 条评论等于提 0 条,因为没人看。宁可只要 2 条高价值的。
  • 要求输出证据。「这里可能有问题」没用,「当 X 为 null 时会 NPE」才有用。这一条适用于所有 AI 卡点。
  • 别指望 AI 改变工作流。把它嵌进大家已经在用的工具里(Swagger、PR 评论、IDE),而不是新建一个页面。

小结

半年下来我的判断是:AI 在研发流程里的价值,目前主要集中在降低低级错误的逃逸率。NPE、资源泄漏、硬编码密钥、SQL 注入、边界条件遗漏——这些人类容易疲劳而 AI 不会疲劳的领域,效果最扎实。

而在「创造性工作」上(设计文档、架构决策、复杂业务逻辑实现),AI 目前只能当副驾。我们试过让它生成技术方案,输出看起来很完整,但缺少对现有系统的理解和权衡,没法用。

接下来打算试两个方向:一是把线上故障的日志分析做成卡点(现在每次故障都要翻半小时日志);二是用 AI 做接口兼容性检查(微服务间接口变更经常漏通知下游)。两个都是「拦截型」。

参考