我用 AI 一週寫完了整個專案,上線第一天就崩了——這是我踩過最貴的 5 個坑

這不是標題黨。上個月,我用 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 程式設計的實戰經驗。


原文出處:https://juejin.cn/post/7652581847890133018


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝16   💬1   ❤️1
482
🥈
我愛JS
📝1   ❤️1
25
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登