AI 把代码产量拉爆之后,为什么团队反而更累了?
AI 编程最容易让人上头的一点,就是它真的快。
一个下午写完原本要做三天的需求,一个人顶过去一个小组的产出,PR 一开就是上千行,屏幕上全是绿色。那种感觉很容易让人误以为,软件开发终于进入了一个只要"多生成一点"就能持续提效的阶段。说真的,第一次用 Claude Code 把一整个模块的 CRUD 跑通的时候,我自己也觉得——这也太爽了。
但很多团队最近开始慢慢回过味来:代码确实变多了,人却没有更轻松。
Review 队列更长了,线上风险更多了,安全审计更吃力了,真正理解系统的人反而更焦虑了。代码产出像开了闸,审查、验证和兜底能力却没跟着一起扩容。表面上看是效率提升,往里看更像是工程压力整体后移。
《纽约时报》最近发布的一篇报道《The Big Bang: A.I. Has Created a Code Overload》[1],就抓住了这个越来越明显的矛盾:AI 把代码产出推高了,治理能力却没有同步跟上。
另一组数据也能说明这种拧巴。Stack Overflow 2025 Developer Survey 显示,84% 的受访者表示正在使用或计划使用 AI 工具参与开发流程;在职业开发者中,51% 表示每天使用。与此同时,开发者对 AI 输出准确性的信任并不高:46% 表示不信任,33% 表示信任,只有 3% 表示"高度信任" [2]。
说白了,大家已经离不开它了,但真要把这些代码推上线,心里又都没那么踏实。
所以这篇文章不想再讲“AI 编程有多快”。这件事已经不是新闻了。
更值得讲的是另一面:当代码产出快到超过团队的阅读、审查和兜底能力,工程代价会怎么一点点冒出来。

先看根子:顺风顺水路径陷阱
AI 生成代码的常见问题,不是完全不会处理复杂场景,而是在没有明确约束时,往往先给你一版顺风顺水路径。
所谓顺风顺水路径,就是一切条件都刚刚好的执行路径:网络始终可用、数据库始终秒回、用户输入永远合法、第三方 API 永远不超时也不限流。
这不是 AI 笨。模型虽然见过大量开源代码,但训练数据并不会天然标注哪些实现真正经历过高并发、脏数据、缓存雪崩和线上事故的拷打。那些真正能扛事的工程细节,往往不在最容易被学到的那层表面代码里。
它当然能写出看起来很像那么回事的代码,但真到出血的时候,常常不知道先捂哪儿。这个落差,才最麻烦。
例子一:缓存击穿
让 Claude Code 写一个加 Redis 缓存的商品查询接口,它会给你这种代码:
AI 生成(顺风顺水路径):
@RestController
public class ProductController {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private ProductRepository productRepository;
@GetMapping("/api/hot-products")
public List<Product> getHotProducts() {
String cached = redisTemplate.opsForValue().get("hot_products");
if (cached != null) {
return JSON.parseArray(cached, Product.class);
}
List<Product> products = productRepository.findTop20ByOrderBySalesDesc();
redisTemplate.opsForValue().set("hot_products",
JSON.toJSONString(products), 1, TimeUnit.HOURS);
return products;
}
}
逻辑清晰,本地跑也没问题。真上线上压一压,就容易出事。我第一次看到这段代码的时候还想,这不是挺好的嘛;直到在压测环境亲眼看着连接池被打满,才明白问题出在哪。
原因:缓存过期瞬间,高并发场景下(假设 QPS 10000),这 10000 个请求同时发现 cached 为空,同时打到数据库,连接池秒空。
下面的代码只是示意,用来说明为什么生产环境要额外处理并发和回源问题,不是可以直接照抄上线的完整方案。
防御性写法(示意):
@GetMapping("/api/hot-products")
public List<Product> getHotProducts() {
String cached = redisTemplate.opsForValue().get("hot_products");
if (cached != null) {
return JSON.parseArray(cached, Product.class);
}
String lockKey = "lock:hot_products";
boolean locked = false;
try {
// 分布式锁,NX + EX,防止缓存击穿
locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (!locked) {
// 没拿到锁,短暂等待后重试(读旧缓存或等别人回填)
Thread.sleep(50);
cached = redisTemplate.opsForValue().get("hot_products");
if (cached != null) {
return JSON.parseArray(cached, Product.class);
}
return productRepository.findTop20ByOrderBySalesDesc();
}
// 双重检查:拿到锁后再查一次缓存
cached = redisTemplate.opsForValue().get("hot_products");
if (cached != null) {
return JSON.parseArray(cached, Product.class);
}
List<Product> products = productRepository.findTop20ByOrderBySalesDesc();
redisTemplate.opsForValue()
.set("hot_products", JSON.toJSONString(products), 1, TimeUnit.HOURS);
return products;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return productRepository.findTop20ByOrderBySalesDesc();
} finally {
if (locked) {
redisTemplate.delete(lockKey);
}
}
}
复杂度直接提升一个量级:分布式锁、锁过期、try/finally、双重检查、退避策略,全都进来了。更关键的是,这里就算用了锁也还没完,生产上通常还要处理锁值校验、过期后误删、旧缓存兜底或 singleflight 等细节。这就是生产代码和 Demo 代码的区别:前者长这样,不是因为它喜欢复杂,而是被事故逼的。
这正是问题所在。AI 很擅长先把功能拼出来,却不一定会主动替你补上这些让系统真正扛得住流量的约束。
例子二:支付接口为什么会重复扣款
写一个扣减余额的接口:
AI 生成(顺风顺水路径):
@Service
public class PaymentService {
@Autowired
private UserRepository userRepository;
@Transactional
public void deductBalance(Long userId, BigDecimal amount) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new BusinessException("用户不存在"));
if (user.getBalance().compareTo(amount) < 0) {
throw new BusinessException("余额不足");
}
user.setBalance(user.getBalance().subtract(amount));
userRepository.save(user);
}
}
本地测试通常也很好看。可一到生产环境,用户网络一抖,连点 3 次支付按钮,3 个并发请求同时查到余额 100,同时执行扣减,最后就会出现用户 100 块买走 300 块东西这种很难看的场面。这种 bug 我见过不止一次,查到最后几乎都是同一个原因:代码能跑,但没人想过“同时跑”会怎样。
问题出在哪?@Transactional 只保证了方法内事务,没加行锁,3 个事务可以并行读到同一个 balance 值。
下面的代码同样只是示意。真正落地时,幂等键、唯一索引和账户一致性控制都要一起设计,少一个都可能出事。
防御性写法(示意):
@Service
public class PaymentService {
@Autowired
private UserRepository userRepository;
@Autowired
private PaymentLogRepository paymentLogRepository;
@Transactional
public void deductBalance(Long userId, BigDecimal amount, String transactionId) {
// 幂等性校验:同一笔交易不重复扣款
if (paymentLogRepository.existsByTransactionId(transactionId)) {
log.info("重复请求,跳过: {}", transactionId);
return;
}
// 悲观锁:SELECT ... FOR UPDATE,保证串行
User user = userRepository.findByIdForUpdate(userId)
.orElseThrow(() -> new BusinessException("用户不存在"));
if (user.getBalance().compareTo(amount) < 0) {
throw new BusinessException("余额不足");
}
user.setBalance(user.getBalance().subtract(amount));
userRepository.save(user);
// 记录交易流水,支撑幂等
paymentLogRepository.save(PaymentLog.builder()
.transactionId(transactionId)
.userId(userId)
.amount(amount)
.build());
}
}
三个关键改动:幂等键、串行化控制、交易流水记录。再往前走一步,生产里通常还会给 transactionId 加唯一约束,避免 exists + save 这种先查后写留下竞态窗口。
问题不在于 AI 完全想不到这些,而在于如果没人明确约束,它通常不会优先替你把这些坑填平。
更大的代价:Code Review 开始崩
代码产出翻 10 倍,Review 速度没变。真正的矛盾就在这里。
一个初级程序员用 Cursor 随手一划拉,提交一个 3000 行、横跨 15 个文件的 PR。Reviewer 打开 GitHub,看到满屏绿色,第一反应往往不是兴奋,而是头大。人的大脑在短时间里根本建立不了 3000 行代码的全局上下文。
结果就是 LGTM 综合症:扫两眼,没语法错误,CI 测试也过了,于是直接 Approve。可问题是,测试本身也可能主要覆盖顺风顺水路径。看着 3000 行的 PR,很多人心里想的都是:“算了,先过吧,有问题再说。”然后问题就真的来了。
技术债开始滚雪球。
更麻烦的是,很多团队会误把“代码变多了”当成“交付变快了”。
AI 最容易优化的是“开始写”的速度,但软件工程真正昂贵的部分,往往不在把代码敲出来的那几小时里,而在理解上下文、补齐边界、验证行为、定位问题,以及后续长期维护的成本里。
代码产量上去了,不代表系统就更容易演进;很多时候,团队只是把原本分散在设计、Review、联调和线上兜底阶段的压力,统一推迟到了后面。
站在团队管理的角度,这种后移尤其伤。资深工程师本来应该花时间做架构、拆复杂问题、带新人,结果越来越多的精力被大体量 PR 和风险排查吃掉。表面上看,团队每个人都“写得更多了”;实际上,真正稀缺的判断力反而被 Review 和救火不断抽干。
这也是为什么很多团队会出现一种别扭的状态:新人提交速度更快了,仓库里的代码也明显变多了,但真实吞吐并没有同步上涨,核心成员反而更累。
还有一层代价,经常在项目跑了一阵子后才显出来:可观测性没跟上。AI 很会补业务逻辑,却不一定会顺手把日志、指标、链路追踪、报警阈值这些非功能性部分一起补齐。结果不是 bug 单纯变多,而是问题一旦出现,团队更难定位、更难回溯,也更难判断影响范围。
更隐蔽的问题:幻觉依赖与供应链投毒
如果说 Review 崩溃还算显眼,那安全问题往往更隐蔽。AI 会"捏造"不存在的第三方库。
处理冷门视频格式转换,AI 可能给你写 import com.example:video-converter-pro:1.0,看起来很合理。你顺手加到 pom.xml 或执行 pip install video_converter_pro——但 Maven Central 或 PyPI 上根本没有这个包。
攻击者早就盯上这个漏洞:大量收集 AI 幻觉出来的包名,抢先注册,植入挖矿木马或窃密脚本。你的 CI 一拉依赖,构建服务器就可能被顺手接管。更糟的是,你可能连自己是什么时候中招的都不知道。
这不是传统供应链攻击的替代品,而是 AI 把旧问题放大后出现的新风险形态。最近这类问题常被称为 slopsquatting:模型先幻觉出一个不存在的包名,攻击者再抢先注册,等着别人自己把门打开 [3]。
怎么兜底:三种更现实的做法
1. 先让 AI 审 AI
既然代码是 AI 大规模生成出来的,审计层也应该部分自动化。在 CI/CD 流水线里加一个审计 Agent,是值得认真考虑的方向:
# .github/workflows/ai-code-review.yml
name: AI Code Audit
on:
pull_request:
types: [opened, synchronize]
jobs:
ai-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get PR diff
id: diff
run: |
DIFF=$(git diff origin/main...HEAD)
echo "diff<<EOF" >> $GITHUB_OUTPUT
echo "$DIFF" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: AI Security Audit
run: |
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: ${{ secrets.CLAUDE_API_KEY }}" \
-H "content-type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-20250514",
"max_tokens": 4096,
"system": "你是一个极其严苛的资深安全架构师。审查以下 PR diff,从 5 个维度攻击性审查:1) 并发与竞态条件 2) 资源耗尽/内存泄漏 3) 缓存击穿/穿透/雪崩 4) 幂等性 5) 安全漏洞与幻觉依赖。发现问题直接 REJECT 并给出修复建议。没问题才 APPROVE。",
"messages": [{"role": "user", "content": "'"${{ steps.diff.outputs.diff }}"'"}]
}'
这类方案的价值,不是让 AI 代替人拍板,而是先把明显的并发漏洞、资源风险和幻觉依赖筛掉,别让人工 Review 一上来就淹死在噪音里。
当然,真到生产落地,还得补上脱敏、分片、失败门禁和合规边界。自动化审计能挡住一部分低级错误,但挡不住所有侥幸心理。
2. 把爆炸半径收小
单体不是原罪,但如果系统本来就边界模糊、资源混用、发布回滚粗糙,AI 只会把这些问题放大得更快。它在某个角落写个死循环,最后可能拖垮的不是一个接口,而是一整片链路。
更稳的做法,是先把爆炸半径控制到最小:
三个原则:
- 严格 API 契约:不管内部是人写还是 AI 写,模块间通信走 gRPC/OpenAPI,契约不能动
- 资源隔离:AI 模块跑独立容器/K8s Pod,配 ResourceQuota,OOM 只重启自己
- 数据库权限最小化:只能访问专属 schema,不给全局库权限
接口不变,内部实现才有条件反复调整。这样即使 AI 写崩了一个隔离区模块,也不至于把核心交易链路一起带下水。
3. 把测试重新拿回人手里
业务代码可以让 AI 帮你写,但测试约束最好别一起外包。边界条件、异常状态、并发场景,还是得由人先想明白。
流程要翻转:先手写测试用例(覆盖边界条件、异常状态、并发场景),再让 AI 实现业务逻辑直到测试全过。
测试用例就是给 AI 戴上的缰绳。它不保证内部实现优雅,但至少能让外部行为别轻易跑偏。这事听起来不浪漫,真出事故时却往往最实在。说白了,测试代码才是你的底线。
最后要分清:哪些代码适合交给 AI
真正现实的做法,不是“全交给 AI”,也不是“坚决不用 AI”,而是先把代码分层。
有些代码天生更适合让 AI 提效:边界清晰、风险可控、出错后容易替换的部分,比如后台管理页、数据转换脚本、样板接口、测试桩、内部工具。这类代码更接近“局部实现题”,AI 往往能帮你省掉不少重复劳动。
但有些代码,天然就不适合放手让它自由生成:强状态、强一致性、高耦合、跨系统事务、涉及资金、安全、权限、审计、合规的链路。这些地方真正值钱的不是把代码拼出来,而是做对取舍、守住边界、明确失败语义。
换句话说,判断标准不该是“这段代码难不难写”,而该是“这段代码一旦写错,代价由谁承担,能不能快速发现,出了问题能不能安全回滚”。用一句糙话讲:这段代码炸了,你会不会半夜被电话吵醒?如果会,那就别偷懒。
如果这三个问题的答案都不轻松,那就别把它当成普通的生成任务。
如果现在就要做,先落这 4 件事
- 限制 PR 大小和变更范围,避免一次性把上下文压垮
- 核心链路要求人工先写关键测试用例,再让 AI 参与实现
- AI 生成代码默认提高 Review 等级,重点查并发、幂等、资源释放和异常路径
- 新增依赖必须校验来源、仓库可信度和包名真实性,别让幻觉依赖直接进入 CI
参考
- [1] The New York Times: The Big Bang: A.I. Has Created a Code Overload — https://www.nytimes.com/2026/04/18/technology/ai-code-overload.html
- [2] Stack Overflow 2025 Developer Survey, AI section — https://survey.stackoverflow.co/2025/ai/
- [3] arXiv: Library Hallucinations in LLMs: Risk Analysis Grounded in Developer Queries — https://arxiv.org/abs/2509.22202
- [4] SecurityWeek: AI Hallucinations Create a New Software Supply Chain Threat — https://www.securityweek.com/ai-hallucinations-create-a-new-software-supply-chain-threat/
AI 把代码生成的边际成本一把拉低之后,团队真正稀缺的能力就会往别处移动:架构设计、逻辑审查、复杂度控制,以及出问题时能不能稳住局面。
说得再直白一点,未来真正拉开差距的,未必是谁写得更快,而是谁更能判断什么适合交给 AI,什么必须自己扛,什么上线前一定要死磕到底。出了事谁来兜底,才是真本事。
工程师当然还是要写代码,但只会写代码,恐怕越来越不够了。你还得会收边界、定约束、做审查、控风险。AI 让写代码这件事变快了,却也把工程判断的重要性重新抬回了台面上。
本文链接:AI 把代码产量拉爆之后,为什么团队反而更累了? - https://h89.cn/archives/576.html
版权声明:原创文章 遵循 CC 4.0 BY-SA 版权协议,转载请附上原文链接和本声明。