这半年我用AI写代码的时间可能比手敲的还多。Copilot、Cursor、通义灵码来回换,确实爽——函数名还没写完它就把整个逻辑补全了,注释写“// 根据用户id查询订单”它直接生成一套带事务的service方法。但爽归爽,栽过的坑也一点没少,有些甚至比我自己写bug还隐蔽。
今天聊聊我踩过最典型的三个坑,每个都重复犯了好几次,浪费的时间加起来够我手写一个完整模块了。
第一次踩坑:看起来完美的代码,一跑就崩
去年底接了个电商项目的订单导出功能,需求是“批量导出指定时间范围内的订单,生成Excel并提供下载”。我心想这不就是CRUD吗,让AI帮你一把。于是就在Service层写了段注释,Copilot直接给我补全了六十多行代码,从参数校验、数据库查询到Excel生成一气呵成。我一眼扫过去,字段映射正确,异常处理也有,单元测试跑得通,直接就合进dev分支了。
结果第二天测试丢给我一张截图:导出1000条订单时服务器内存直接飙到9个G,CPU打到100%,最后超时。我回看代码才发现AI生成的Excel写入逻辑用了内存流一次性加载所有数据再写入,而官方推荐的分批写入、释放内存的方式它根本没考虑。我这种“扫一眼没问题”的习惯害了自己——AI给的是“语法正确、逻辑上看起来合理”的答案,但它不会主动考虑性能边界,除非你在提示里明确要求。
第二次踩坑:提示词太随意,AI帮我写BUG
第二次是在搞一个定时任务同步第三方物流轨迹数据。我在注释里写“每隔5分钟拉取一次XX物流接口,将状态更新到订单表”,然后Accept Tab一路到底。AI给我生成了一个很漂亮的批处理逻辑,用了多线程并发拉取,考虑到了接口超时和重试,我看了下觉得考虑挺周全。
上线后却发现一个诡异问题:线上的订单表开始频繁出现相同物流单号的多条记录,状态还不一致。查了好久才发现,AI生成的代码在并发拉取时,没有对相同订单加互斥锁,导致两个线程可能同时拉取到同一个订单的物流信息,然后同时去更新数据库,因为没有幂等性设计,最终产生了重复记录。我回头看提示词,我只写了“拉取物流信息更新订单”,根本没提并发、幂等这些关键约束。AI不会假设你的生产环境有多复杂,它只会按最直白的理解把功能实现出来。
第三次踩坑:没Review直接合,差点背锅
第三次最冤。我需要写一个很简单的工具:从ElasticSearch里按条件查日志,聚合出TOP10的错误类型。AI很快给我补全了一段基于Java High Level REST Client的聚合查询,我看了下DSL构建感觉没问题,本地ES数据量小跑得也挺快,直接就提交了。这次我甚至连单元测试都没加,心想这种脚本级的工具能出什么问题。
结果运维部署到测试环境后,发现这个接口每次调用都会触发ES的分页不准确警告,而且返回的聚合结果有时候会少几条。我仔细debug才发现AI用的聚合查询默认size只取了前10个桶,没有设置size为全部,导致如果错误种类超过10种就会丢失数据。而我的ES数据量较小恰好没暴露这个问题。这完全是AI给的“默认行为”,我如果能Review一下代码并对照ES文档看一眼,就不会犯这种低级错误。
最后的解法:把AI当副驾驶,别让它握方向盘
踩了三次坑之后,我开始给自己定了几条硬规矩:
1. 先搭骨架,再让AI补肉。 自己把函数签名、核心流程、异常处理边界写好,只让AI补全重复性代码,绝不把整个函数逻辑交给它自由发挥。
2. 提示词里把约束写清楚。 比如“方法需要考虑并发安全、幂等性、内存使用不超过xx MB”,甚至把关键的性能指标写上。AI很听话,但需要明确的指令。
3. 每次生成必须逐行Review。 哪怕只是复制粘贴一小段,也要逐行看逻辑、查API文档、补单元测试。AI帮你提速,但质量的最后一道关必须自己守。
4. 测试用例不能全靠AI生成。 AI会倾向于写“能跑通”的case,而不是“能揭露问题”的case。边界条件、异常场景都得自己写。
现在用AI最大的感受就是:它像是一个博学但没经验的新人,知道所有语法和常用库,但缺乏对系统全局的理解、对生产环境的敬畏。只要你把把关,它能帮你省下不少打字时间;一旦你放手让它自己开,翻车的概率远比自己写高。
说到底,AI编程工具提升的是“编码速度”,而不是“工程能力”。代码的质量、系统的鲁棒性,这些还是要靠人脑去设计、去验证。别让一个帮你写提示符的工具,最后替你做了架构决策。