聊天讨论 我用 AI 一周写完了整个项目,上线第一天就崩了——这是我踩过最贵的 5 个坑

193577746(kyriewen) · June 18, 2026 · 16 hits

这不是标题党。上个月,我用 Claude Code + Cursor 花了 7 天从零写完了一个内部工具平台,提前两周交付,老板在周会上点名表扬。然后上线第一天,报警群炸了 47 条消息。

先说背景

我们团队接了一个内部需求:给运营团队做一个数据看板 + 工单系统。

需求不复杂,技术栈是 React + Node.js + PostgreSQL,正常排期两个人三周。但当时另一个同事被抽去救火了,变成我一个人,排期不变。

我想,这不正好?上个月刚充了 Claude Code Max,Cursor 也续了费,这种 CRUD 项目,AI 写代码不是手到擒来?

于是我做了一个大胆的决定:全程用 AI 辅助开发,目标一周交付。

结果是——我确实一周写完了。代码量大概 1.2 万行,前后端 + 数据库 + 部署脚本,全套。

但上线后第一天,就出了三个线上事故。

这篇文章,我会把这 7 天的真实经历和踩的 5 个坑完整地写出来。不是为了黑 AI,AI 确实让我效率提升了 3 倍以上。但那些"AI 写代码真香"的文章不会告诉你的暗面,我来说。

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

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

AI 给的代码很漂亮:

async function getTicketStats(startDate, endDate, department) {
  const result = await db.query(`
    SELECT 
      department,
      status,
      DATE_TRUNC('day', created_at) as date,
      COUNT(*) as count
    FROM tickets
    WHERE created_at BETWEEN $1 AND $2
      AND ($3 IS NULL OR department = $3)
    GROUP BY department, status, DATE_TRUNC('day', created_at)
    ORDER BY date DESC
  `, [startDate, endDate, department]);

  return result.rows;
}

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

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

问题出在哪?

  1. 时区问题DATE_TRUNC 默认用的是 UTC,但运营看的是北京时间。跨天的工单被归到了前一天。
  2. 空值处理:当 departmentundefined 时,$3 IS NULL 这个条件在 PostgreSQL 中的行为不是"忽略过滤",而是匹配 department IS NULL 的记录。
  3. 大分页缺失:没有 LIMIT,当时间范围选了一整年,直接返回了 12 万行数据,前端图表库 echarts 卡死了。

这三个问题,每一个在代码层面都是"AI 写得没错",但在业务层面全是 bug。

修复后的代码:

async function getTicketStats(startDate, endDate, department) {
  const conditions = [
    'created_at >= $1',
    'created_at < $2'
  ];
  const params = [startDate, endDate];

  if (department) {
    conditions.push(`department = $${params.length + 1}`);
    params.push(department);
  }

  const 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 ${conditions.join(' AND ')}
    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 写代码之前,先问它一个问题——"这个需求有没有成熟的开源方案?列出前 3 个最流行的,对比优缺点。"

这一个 prompt 能帮你省掉 80% 的轮子代码。

坑 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 追踪了。

教训:

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

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

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

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

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

// AI 生成的测试
describe('createTicket', () => {
  it('should create a ticket successfully', async () => {
    const mockTicket = {
      title: 'Test Ticket',
      description: 'Test Description',
      department: 'Engineering',
      priority: 'high'
    };

    db.query.mockResolvedValue({ rows: [{ id: 1, ...mockTicket }] });

    const result = await createTicket(mockTicket);

    expect(result).toEqual({ id: 1, ...mockTicket });
    expect(db.query).toHaveBeenCalledTimes(1);
  });
});

看出问题了吗?

它在测试自己 Mock 的返回值。 db.query 被 mock 成返回 { id: 1, ...mockTicket },然后断言结果等于 { id: 1, ...mockTicket }

这个测试永远不会失败,因为它测的不是业务逻辑,而是"mock 框架能不能正常返回我设定的值"。

真正应该测的是什么?

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

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

教训:AI 生成的测试覆盖率是虚假繁荣。让 AI 写测试时,要明确要求:"不要测试正常流程,只测试边界条件和异常场景。列出你认为最可能出 bug 的 5 个场景,然后为每个场景写测试。"

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

这是最隐蔽的坑。

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

AI 说啥我就用啥。前端组件的 props 定义,后端的 API 路由结构,数据库的表设计——全部是"边写边定"。

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

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

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

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

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

教训:AI 加速的是"写代码"这个环节,但软件开发中最贵的从来不是写代码——是设计。在动手之前,先让 AI 帮你做设计评审:

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

复盘:一周后的反思

上线后那个周末,我花了两天修 bug + 重构。回头看这 7 天,我的结论是:

AI 确实帮了我

  • 1.2 万行代码,如果纯手写至少要三周,AI 帮我压缩到了一周
  • 很多样板代码(CRUD 接口、表单校验、SQL 建表语句)AI 写得又快又标准
  • 遇到不熟的库(比如 echarts 的配置项),AI 比翻文档快 10 倍

但 AI 不能替代的

能力 AI 能做 AI 不能做
写代码 快速生成 理解业务上下文
测试 生成模板 识别真正的边界场景
架构设计 给出方案 判断哪个方案适合你的团队
安全 生成示例配置 保证你不犯低级错误
Debug 分析错误日志 理解线上环境的复杂性

我现在的 AI 编程工作流(踩完坑后的版本)

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

关键原则:AI 是副驾驶,不是自动驾驶。你可以让它帮你打方向盘,但你不能闭着眼睛。

写在最后

我不是要劝你别用 AI 写代码。恰恰相反,经过这次踩坑,我现在更离不开 AI 了。

但我想说的是:AI 让写代码变快了,但没有让写"好代码"变容易。 恰恰相反,因为生成速度太快,很多本该深思熟虑的环节被跳过了。

下次当你用 AI 一天写完了别人一周的量,先别急着发朋友圈炫耀。

问自己一句:这些代码,你敢不看直接上线吗?

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

如果你也在用 AI 写代码,欢迎评论区说说你踩过的坑。点赞收藏不迷路,我会持续分享 AI 编程的实战经验。

No Reply at the moment.
You need to Sign in before reply, if you don't have an account, please Sign up first.