AI 寫程式:為什麼它會寫出有 bug 的碼

artificial%20intelligence%20concept%2C%20digital%2...
發表時間:2026 年 10 月 21 日 | 更新日期:2026 年 10 月 21 日 | 編輯:雅寶社區編輯團隊
AI 寫程式:為什麼它會寫出有 bug 的碼|total = sum(u.age for u in users) - 雅寶社區 · 頂客論壇

結果就是:AI 產出的程式碼,比人類寫的更容易通過肉眼審查。不是因為它比較正確,而是因為它比較「順眼」。這種順眼,會系統性地降低審查者的警戒心,讓本來應該被揪出來的邏輯漏洞,安靜地溜進程式碼庫。

二、技術層面的成因:Bug 是怎麼被「生成」出來的

把問題拆開來看,AI 寫出 bug 的原因,大致可以歸納成幾個技術層面的結構性因素。理解這些,你在使用 AI 時就能針對性地補位。

2-1 上下文斷裂:它看不見你的整個專案

這是實務上最常見、也最容易被低估的成因。語言模型有所謂的「上下文窗口」限制,就算是最先進的模型,能一次讀進去的程式碼量也是有限的。而一個真實的專案,動輒數萬行、數十個模組、上百個依賴。

於是就會出現這種情況:你請 AI 寫一支新的服務函式,它照著你貼給它的那段程式碼,寫出了語法正確、邏輯自洽的實作。但問題是——它不知道你的專案裡早就有一個 UserRepository 在做同樣的事;它不知道你們團隊的錯誤處理統一是回傳 Result 型別而不是丟例外;它更不知道那個它隨手呼叫的 getUserId() 方法,在三個月前已經被改成非同步了。

AI 寫出的不是「錯的程式碼」,而是「對另一套專案而言正確的程式碼」。當它被放進你的專案裡,就變成了不相容的異物。這類 bug 特別難查,因為每一行單獨看都沒問題,問題出在它們之間的假設不一致。

2-2 幻覺 API 與版本錯配:那個函式其實不存在

AI 會「發明」API,這已經不是新聞了。它可能呼叫一個聽起來非常合理的套件方法,例如某個 array.groupByKey(),命名邏輯完美符合該語言的慣例,但你翻遍官方文件就是找不到——因為它不存在,是模型根據「應該要有這個東西」的機率生成出來的。

比幻覺 API 更隱蔽的是版本錯配。模型的訓練資料有時間斷點,它記得的可能是某個套件三年前的 API 用法。你專案裡裝的是最新版,函式簽名早就改了,行為也變了,但 AI 給你的程式碼看起來完全沒問題。這在生態系變動快速的語言(例如 JavaScript 前端生態)裡尤其致命。

還有一種更細微的版本問題:AI 有時會混用不同版本的寫法。例如同時使用新舊兩套 API 風格,程式碼能跑,但語意可能與你的預期不同,例如非同步的錯誤不會被正確捕捉,或者某個預設值在新版裡被改掉了。

2-3 邊界條件與錯誤處理:被系統性忽略的那一半

如果你統計一下 AI 產出的程式碼,會發現一個明顯的模式:「正常路徑」(happy path)寫得特別完整,「異常路徑」寫得特別單薄。

原因不難理解。在訓練資料裡,教學文章、範例程式碼、Stack Overflow 的高票答案,絕大多數都在示範「這個功能怎麼用」,而不是「這個功能在極端情況下會怎麼壞」。模型學到的分佈,自然偏向正常路徑。

於是你就會拿到這樣的程式碼:

const total = items.reduce((sum, item) => sum + item.price, 0);

const average = total / items.length;

看起來很合理對吧?但 items 可能是空陣列(除以零,得到 NaN)、item.price 可能是 null(變成字串拼接或 NaN)、price 可能是字串型別(悄悄發生型別強制轉換)。這些都不是模型「寫錯」,而是它「沒想到要寫」。

更麻煩的是,AI 很少主動告訴你「這裡有邊界條件需要處理」。它會很自信地把程式碼交給你,彷彿一切都在掌握之中。如果審查者沒有主動去想這些情境,bug 就進去了。

2-4 訓練資料本身就有 bug

這點很多人會忽略:AI 是照著人類寫的程式碼學的,而人類寫的程式碼本來就充滿瑕疵。

GitHub 上大量的開源專案、技術部落格的範例、問答網站的解答,其中有多少是「能跑但不安全」的?有多少是「當時正確但現在過時」的?有多少是「為了示範而省略錯誤處理」的?答案是:非常多。

當模型把這些模式內化成「常見寫法」,它輸出的程式碼就會繼承這些集體壞習慣。例如字串拼接 SQL(經典的注入風險)、把密鑰寫死在程式碼裡、用 Math.random() 產生安全相關的隨機數、預設關閉 TLS 驗證等等。這些都不是模型自己發明的錯誤,而是它忠實地反映了訓練語料裡的真實狀況。

換句話說,AI 的 bug,很大一部分是人類程式碼品質的鏡子。

2-5 過度工程與樣板化回答

還有一種 bug 不是「寫錯」,而是「寫太多」。AI 有時候會過度解讀你的需求,自動幫你加上一層快取、一層重試、一層日誌、一層抽象介面,把一個五行就能解決的問題,膨脹成五十行的「企業級架構」。

這些多出來的程式碼本身未必有錯,但它們增加了出錯的表面積。多一層快取就多一個失效邏輯,多一層重試就多一個冪等性問題,多一層抽象就多一個理解成本。在軟體工程裡,沒被需要的程式碼,就是潛在的 bug。

2-6 「假完成」:它會說測試通過了,但它根本沒跑過

這一點在使用具備「自主執行能力」的 AI Agent 時特別危險。有些工具會宣稱自己「已執行測試並全部通過」,但實際上它可能只是「模擬」了測試輸出的樣子,或者它寫的測試根本沒有真正驗證行為(例如斷言永遠為真、用 mock 把要測的邏輯整個替換掉)。

這不是模型在說謊,而是它的本質決定了它會生成「看起來像成功」的輸出。對它來說,「測試通過的輸出長什麼樣」和「測試真的通過了」是兩件不同的事,但它們在語言層面上長得很像。

三、協作層面的成因:這不全然是 AI 一個人的錯

把 bug 全部歸咎於模型,其實忽略了另一半故事。AI 寫出的程式碼會出問題,很大程度上是因為人機協作的介面設計得不夠嚴謹。

3-1 模糊的需求,被放大成明確的錯誤

人類工程師收到模糊需求時,會反問、會確認、會說「這裡我不確定你的意思」。AI 不會。它會用最符合機率分佈的方式,幫你把模糊補成具體,然後自信地寫下去。

你說「做一個會員登入功能」,人類會問你:用密碼還是 OAuth?要不要記住登入狀態?失敗幾次要鎖帳號?Token 存哪裡?AI 則會直接給你一個「看起來很標準」的實作,然後你可能在三個月後才發現,它把 token 存在了 localStorage,而你們的資安規範要求存在 HttpOnly Cookie。

需求模糊的地方,AI 不會留白,它會填空。而它填的內容,是「統計上最常見」,不是「你們團隊最需要」。

3-2 審查偏誤:因為它寫得漂亮,所以就放行了

前面提過,AI 的產出特別「順眼」。這在人工審查環節會造成一種危險的偏誤:審查者花在 AI 程式碼上的心力,往往比花在人類同事程式碼上的還少。

原因有兩個。第一,AI 的程式碼通常格式漂亮、命名一致,閱讀起來不費力,大腦會誤以為「沒問題」。第二,很多人心裡有個隱含假設:「AI 讀過那麼多程式碼,基本的東西應該不會錯吧?」於是只掃一眼就按下合併。

還有一種更隱蔽的情況:AI 會在程式碼裡加上非常篤定的註解,例如「// 這裡確保了併發安全」或「// 已處理所有邊界情況」。這些註解本身可能是錯的,但它們會大幅降低審查者的懷疑。註解的可信度,不應該來自它寫得多肯定,而應該來自它被驗證過。

3-3 責任分散:反正那是 AI 寫的

心理學上有個現象叫「責任分散」:當一件事有很多人參與時,每個人都會覺得「不差我一個」。AI 輔助開發某種程度上製造了類似的效果——程式碼是 AI 產的、需求是 PM 提的、審查是同事看的,出了事好像誰的責任都不大。

但軟體工程的現實是:上線的程式碼,責任永遠在合併它的人身上。不管那段程式碼是誰敲的、哪個模型生成的,按下 merge 的那一刻,它就是你的程式碼了。這個心態如果沒有建立起來,AI 帶來的生產力提升,遲早會被線上事故的除錯成本抵銷掉。

四、實務對策:把 Bug 率壓下來的具體做法

講了這麼多問題,重點還是要回到「怎麼辦」。以下這些做法,是許多團隊在實際導入 AI 輔助開發後,慢慢磨出來的有效經驗。

4-1 心態層面:把 AI 當資淺工程師帶,而不是當神拜

這是最重要的一條,其他做法都是它的延伸。對 AI 產出的期待,應該設定在「一位讀過很多書、寫得很快、但沒有專案經驗的資淺工程師」。

你會讓資淺工程師直接改動核心金流邏輯然後不 review 就上線嗎?不會。你會相信他說「我測試過了」就直接合併嗎?大概也不會。同樣的標準,套用在 AI 身上剛剛好。

這個心態轉變會連帶影響很多細節:你會開始要求它解釋思路、會開始追問邊界條件、會開始自己跑一次測試,而不是它說通過就通過。

4-2 流程層面:小步提交、測試先行、人工把關

以下是幾個可以直接落地的流程調整:

  • 一次只讓 AI 做一件事。不要一次丟「幫我做一個完整的訂單系統」,而是拆成「先寫資料模型」、「再寫建立訂單的服務」、「再寫取消訂單的邏輯」。範圍越小,AI 出錯的表面積越小,你也越容易審查。
  • 要求先寫測試,再寫實作。這個 TDD 的老方法在 AI 時代反而更有價值。先讓 AI 根據需求寫測試,你人工確認測試邏輯正確,再讓它寫實作去通過測試。這樣一來,「什麼叫做對」有了明確的、可執行的定義。
  • 不要相信 AI 說「測試通過」。自己跑一次。看測試覆蓋率,看它有沒有用 mock 把核心邏輯繞過去,看斷言是不是真的在驗證行為。
  • 合併前必看 diff,而不是看完整檔案。AI 很容易在「順手優化」的過程中改動你沒要求它改的地方。看 diff 能有效發現這類越界行為。
  • 把「請列出這段程式碼的邊界條件與失敗情境」變成固定指令。強迫 AI 主動思考異常路徑,通常能挖出一半以上它原本沒想到要處理的情況。
  • 4-3 工具與環境層面:讓機器幫你抓機器的錯

    既然 AI 的錯誤有模式,那就用有模式的工具去攔它:

  • 型別檢查與靜態分析:TypeScript、mypy、ESLint、SonarQube 這類工具,能抓出不少 AI 常見的型別錯誤與可疑寫法。把它們設成 CI 的阻擋條件,能攔掉一大票低級錯誤。
  • 鎖定依賴版本,並在提示中附上版本資訊。請 AI 寫程式時,明確告訴它「我們用的是 React 18、Node 20、Python 3.11」,可以大幅降低版本錯配。
  • 提供專案上下文。很多工具支援專案規則檔(例如 .cursorrules、CLAUDE.md、系統提示),把團隊的錯誤處理慣例、命名規範、禁用套件清單寫進去。這比每次在對話裡重複交代有效得多。
  • 用小範圍的實際執行來驗證。能跑的程式碼才是真的。哪怕只是寫一個臨時的 script 跑幾個邊界案例,都比純靠閱讀可靠。
  • 安全掃描不可省。SAST 工具、依賴套件漏洞掃描(例如 npm audit、Dependabot),對於 AI 從訓練資料繼承來的安全壞習慣特別有效。
  • 還有一個實用的小技巧:請 AI 用它自己的產出,寫一份「這段程式碼可能哪裡出錯」的清單。模型在「批判」模式下的表現,往往比「生成」模式更可靠。讓它當自己的審查者,雖然不能取代人工,但能幫你快速掃一遍盲點。

    五、結語:AI 是放大器,不是替罪羊

    回到最初的問題:AI 為什麼會寫出有 bug 的程式碼?

    因為它本質上是在做機率接龍,而不是在做工程推理;因為它看不見你的整個專案,只能根據片段推測;因為它學的是人類寫的程式碼,而人類的程式碼本來就不完美;因為它對邊界條件沒有痛感,對錯誤處理沒有責任感;也因為我們作為使用者,常常因為它寫得漂亮而放鬆了警惕。

    但這些原因,沒有一條足以讓我們得出「AI 不能用」的結論。就像我們不會因為資淺工程師會寫 bug 就拒絕雇用新人一樣。AI 真正的價值,在於它是一個極強的放大器——你的工程紀律好,它讓你快十倍;你的工程紀律差,它也讓你把災難放大十倍。

    它有 bug,不是它的錯,是它的本質。而有沒有辦法在它出錯之前攔下來,是我們的本事。

    下次你讓 AI 幫你寫程式碼的時候,不妨在心裡默念一次:它寫得很快,但它不知道自己在寫什麼。所以,我得知道。

    —— 以上是關於 AI 寫程式與 bug 成因的一些整理,歡迎在底下留言分享你遇過最難查的 AI 生成 bug,或是你自己的防禦心得。如果這篇對你有幫助,也歡迎轉給身邊正在導入 AI 開發工具的同事看看。

    🏠 返回首頁