上个月我干了件挺疯狂的事:用Cursor加Claude Code花了7天从零搭了一个项目,本来给两周排期的活硬是压缩到一周交付。

上线第一天,报警群炸了47条消息。

这篇文章把踩过的坑写出来。不是劝退AI编程——效率确实提升了3倍不止——而是那些"AI写代码真香"的文章不会说的事,我来补充。

踩坑1:AI生成的代码"看起来对",但数据边界全是雷

第三天让Claude Code帮我写了一个数据聚合接口,把工单按部门、状态、时间维度做分组统计。

AI给的代码很简洁:

async def get_ticket_stats(start_date, end_date, department):
    result = await db.query("""
        SELECT department, status, 
               DATE_TRUNC('day', created_at) as date,
               COUNT(*) as count
        FROM tickets
        WHERE created_at BETWEEN %s AND %s
          AND (%s IS NULL OR department = %s)
        GROUP BY department, status, DATE_TRUNC('day', created_at)
        ORDER BY date DESC
    """, [start_date, end_date, department, department])
    return result.rows

一眼看去没问题。测试环境跑了一下,数据出来了。

上线后运营总监说"这个数据不对"。

问题出在哪?三个地方:

第一个是时区。DATE_TRUNC默认用UTC,但运营团队看的是北京时间。跨天的工单就被归到了前一天。

第二个是空值处理。当department传None时,%s IS NULL这个条件在PostgreSQL里的行为不是"忽略过滤",而是去匹配department为NULL的记录——这根本不是我想要的逻辑。

第三个是大分页。查询没加LIMIT,时间范围选一整年的话直接返回12万行数据,前端图表库直接卡死。

修复后的版本:

async def get_ticket_stats(start_date, end_date, department=None):
    conditions = ['created_at >= %s', 'created_at < %s']
    params = [start_date, end_date]
    
    if department:
        conditions.append(f'department = %{len(params) + 1}s')
        params.append(department)
    
    result = await db.query("""
        SELECT department, status,
               DATE_TRUNC('day', created_at AT TIME ZONE 'Asia/Shanghai') as date,
               COUNT(*) as count
        FROM tickets
        WHERE ' AND '.join(conditions)
        GROUP BY department, status, date
        ORDER BY date DESC
        LIMIT 10000
    """, params)
    return result.rows

教训就一条:AI不懂你的业务场景。时区、用户是谁、数据量多大——这些上下文它不会主动问你,你不说它就不管。

踩坑2:AI特别擅长"造轮子",但从不告诉你有现成的

第二天让AI帮我写一个文件上传模块,支持分片上传、断点续传、进度显示。

AI非常兴奋地给我写了将近400行代码,包括前端的分片逻辑、MD5校验、后端的分片合并、进度回调。写得非常完整,我当时还觉得"好厉害"。

直到上线后,有个同事看了我的代码来了一句:“你为什么不用TUS协议?tus-js-client加tus-node-server两个包加起来不到20行配置就搞定了。”

我当时脸就绿了。

AI的默认行为是从零实现,而不是先搜索有没有成熟方案。它不会说"这个需求其实用XXX库三行代码就能搞定",因为它的训练目标就是生成代码,而不是帮你少写代码。

解决办法其实很简单:在让AI写代码之前先问一句"这个需求有没有成熟的开源方案?"让它列出前三个最流行的库,对比一下优缺点。

光这一个prompt就能省掉八成以上的重复造轮子工作。

踩坑3:复制粘贴了AI生成的环境变量,差点把数据库密码提交到Git

这个坑差点让我被开除。

第五天配置部署脚本的时候,让AI帮我写Docker Compose文件。AI很"贴心"地帮我生成了一个完整的.env.example:

DATABASE_URL=postgresql://admin:your_password_here@localhost:5432/dashboard
JWT_SECRET=your-super-secret-key-change-this
REDIS_URL=redis://localhost:6379

我当时赶进度,直接把your_password_here改成了真实密码,然后继续写代码。

那天晚上提交代码的时候,我习惯性git add .,幸好提交前我多看了一眼diff——.env文件赫然在列。

如果这个文件被推到了远端,里面有生产数据库的真实密码。

后来检查发现,AI生成的项目里.gitignore确实有.env,但它同时生成了.env文件本身。问题在于,某些情况下我手动删过.gitignore的缓存(因为之前另一个文件不生效排查过),导致.env被Git追踪了。

避坑清单

  • 永远不要在AI生成的配置文件模板里直接填写真实密钥
  • 提交前必须 git diff --cached 检查暂存区
  • 项目初始化第一件事就是配好.gitignore和git-secrets扫描
# 安装git-secrets,自动阻止密钥提交
git secrets --install
git secrets --register-aws
git secrets --add 'password\s*=\s*.+'

踩坑4:AI写的单元测试,覆盖率90%,但全是"自嗨型"测试

第六天想补测试,让AI帮我生成了全套单元测试。

跑完一看,覆盖率92%。漂亮!

但仔细一看测试内容,人麻了:

# AI生成的测试
def test_create_ticket():
    mock_ticket = {
        'title': 'Test Ticket',
        'description': 'Test Description',
        'department': 'Engineering'
    }
    
    db.query = MagicMock(return_value=[{'id': 1, **mock_ticket}])
    
    result = create_ticket(mock_ticket)
    
    assert result == {'id': 1, **mock_ticket}
    assert db.query.called_once()

看出问题了吗?它在测试自己Mock的返回值。

db.query被mock成返回指定数据,然后断言结果等于那个数据。这个测试永远不会失败,因为它测的不是业务逻辑,而是"mock框架能不能正常返回我设定的值"。

真正应该测的是什么?

  • title为空时,是否抛出参数校验错误?
  • priority传了一个非法值(比如"urgent"),行为是什么?
  • 数据库连接失败时,错误是否被正确包装和上报?
  • 并发创建同标题工单时,是否有幂等处理?

这些边界场景,AI一个都没测。

解决办法是,在让AI写测试的时候说清楚:“不要测正常流程,只测边界条件和异常场景。先列出你觉得最容易出bug的5个场景,再写测试。”

踩坑5:速度太快等于跳过了设计,技术债一周后就爆了

这是最隐蔽的坑。

因为AI写代码太快了,我在第一天就直接开始写代码。没有画架构图,没有定义API契约,没有设计数据库ER图。AI说啥我就用啥。

前端组件的props定义、后端的API路由结构、数据库的表设计——全部是"边写边定"。

结果上线一周后,运营提了三个新需求:

  1. 工单要支持"转交"功能
  2. 数据看板要加"同比/环比"对比
  3. 要加"审批流"

我一看现有的数据库设计,工单表里assignee就是一个VARCHAR字段存的人名字符串。要支持转交,意味着要有转交记录、转交时间、历史负责人链路。整个表结构要重新设计。

审批流更夸张——现有的状态字段就是一个ENUM(‘open’, ‘in_progress’, ‘closed’),要做审批流相当于引入状态机,加审批人、审批意见、驳回重提等逻辑。

如果当初花半天时间做设计,这些扩展性都能提前预留。但AI让我产生了"反正写代码很快"的幻觉,跳过了最重要的设计环节。

解决方式就是在动手之前先让AI帮你做设计评审——当然,前提是你自己愿意花这个时间:

prompt: "我要开发一个工单系统,核心功能是XXX。
请帮我做以下设计:
1. 数据库ER图(考虑未来可能的扩展:转交、审批流、标签系统)
2. API接口契约(RESTful,列出所有端点)
3. 前端页面路由结构
4. 你认为这个系统最容易在哪些地方埋下技术债?"

踩完坑之后,我的AI编程工作流

现在的方式跟之前完全不同:

  1. 需求分析(自己做) → 30分钟
  2. 让AI做架构设计 + 自己评审 → 2小时
  3. 定义API契约和数据模型(和AI对话式完成) → 1小时
  4. AI生成代码 + 自己逐文件Review → 主要开发时间
  5. 自己写核心业务逻辑的测试,AI补充工具函数的测试
  6. 上线前安全检查清单(手动 + git-secrets)

一句话总结:AI当副驾驶,不当自动驾驶。可以让它帮你打方向盘,但眼睛得盯着路。

最后想说两句

用AI写代码这件事,我确实越来越离不开它了。但前提是你知道自己在做什么。

AI让写代码变快了,这没错。但它没有让写"好代码"变容易。

更麻烦的是,因为生成速度太快,你会下意识跳过那些本该花时间思考的环节——设计、边界情况、安全审查。这些都是写代码本身看不见的东西,但恰恰决定了一行代码能不能上线。

下次你用AI一天干完别人一周的活,先问自己一句:这些代码,你敢不看直接上线吗?

如果答案是不敢——那AI帮你省下来的时间,应该花在Review上。


如果你也在用AI写代码,评论区聊聊你踩过的坑。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐