2026 年 7 月,Robert C. Martin 寫道,他已不再閱讀他的智能體所產生的程式碼。
這句話引起了不少關注。要理解他的工作方式,文章後半段更為重要。Martin 以單元測試、Gherkin 驗收測試、QA 程序、變異測試、覆蓋率檢查及品質指標包圍智能體。程式碼必須通過這套系統才能獲得他的信任。
幾個月前他也提出過類似觀點。他不檢查實作細節,而是關注測試覆蓋率、依賴結構、圈複雜度、模組大小及變異測試結果。當有人將這解讀為完全放棄審查時,他澄清:「我審查很多——只是不是程式碼本身。」
他的評論描述了 AI 密集型軟體開發中的一個實際問題。智能體產生變更的速度遠超過人類閱讀的速度。一旦 AI 生成程式碼的量超過團隊的審查能力,逐行檢查就無法再成為唯一的信心來源。
過去八個月,我們在 vm0 也面臨同樣的問題。我們的程式庫大部分實作由智能體撰寫——流行語稱為 vibe coding——而六位工程師則對這些程式碼在生產環境中的行為負責。
簡要說明
vm0 是一個 vibe-coded 程式庫:智能體撰寫大部分實作,六位工程師負責其生產行為。八個月後,程式庫已有 1,329,170 行程式碼,單週合併 630 個 pull request。五項機制承擔了逐行審查無法再獨力承擔的品質重擔。
- 環境收斂。 工程師與智能體在同一開發容器中工作,每個 pull request 都可擁有自己的資料庫分支。智能體能執行的指令,人也能執行。
- 可執行約束。 嚴格 TypeScript、約 135 個型別 API 契約模組、Oxlint、ESLint 及架構規則,CI 不接受任何警告。能機械檢查的規則不留給審查。
- 邊界導向測試。 採用測試獎盃而非測試金字塔:透過公開模組邊界進行整合測試,使用真實 PostgreSQL 及遷移,僅在外部系統使用 mock。測試程式碼約佔程式庫 36%。
- 完整回饋迴路。 智能體啟動應用程式與資料庫、執行遷移、操作真實瀏覽器,並回報執行過的指令、測試路徑及截圖。pull request 中位合併時間約 53 分鐘。
- 持續清理。 Knip 決定性移除無用程式碼,每日工作流程清理 AI 殘渣,常見模式則提升為 lint 規則或型別系統。
什麼是 vibe coding 與 agentic coding
Vibe coding 是向 LLM 提示產生程式碼、執行產出、要求修改,且完全不關注生成的程式碼本身。Martin Fowler 的定義刻意狹窄,強調「甚至忘記程式碼存在」。這適用於原型、一次性軟體及後果有限的小工具。
Agentic coding,Fowler 稱為agentic programming,則是團隊預期要維護成果時的做法。智能體閱讀程式庫、編輯檔案、執行測試,長時間獨立作業,而人類則持續擁有架構與行為的主導權,並審查執行產生的證據:測試結果、品質訊號、預覽及生產行為。
差異不在於模型寫了多少程式碼,而在於人類注意力的分配。
| Vibe coding | Agentic coding | |
|---|---|---|
| 智能體自主性 | 提示、執行、再提示 | 閱讀程式庫、編輯、測試、反覆迭代 |
| 誰閱讀程式碼 | 無人 | 有風險部分由人閱讀 |
| 驗證內容 | 輸出看起來對即可 | 型別、契約、測試、預覽、生產訊號 |
| 最適用情境 | 原型、一次性工具 | 需維護的軟體 |
| 典型失敗 | 無人理解的程式碼 | 驗證強度不足以應付規模 |
會編輯程式庫的智能體只是更廣泛變革的一支;我們也單獨討論過非開發者面向。
我們常稱 vm0 為 vibe-coded 專案,因為這詞已成 AI 撰寫軟體的通用簡稱。以 Fowler 的術語來說,其實更接近 agentic coding。我們工程師實作的程式碼比過去少,但仍負責架構、維護成本與生產行為。
隨著程式碼生成速度提升,更多責任轉移到開發環境、型別系統、測試套件與自動化維護工作流程。
八個月的 vibe-coded 程式庫成長
vm0 程式庫建立於 2025 年 11 月。根據我們最新的每週工程規模報告,程式庫約八個半月大。
程式庫內容如下:
| 指標 | 數量 |
|---|---|
| 非空邏輯行數 | 1,329,170 |
| 生產程式碼行數 | 850,913 |
| 測試程式碼行數 | 478,257 |
| 原始檔案數 | 5,549 |
| 測試檔案數 | 1,327 |
| 套件數 | 44 |
| main 分支提交數 | 14,005 |
這些數據來自 2026 年 7 月 20–26 日那週的每週工程規模報告,直接從 monorepo 量測。測試程式碼約佔程式庫 36%。這是程式碼量的比例,不是測試覆蓋率,但可反映驗證相關實作的累積程度。
最近三週內,六位工程師分別提交了 541、640、631 次。20–26 那週,GitHub 記錄了 630 個合併的 pull request。六位工程師貢獻了其中 556 個,其餘 74 個由發佈自動化產生。
pull request 從開啟到合併的中位時間約 53 分鐘。第 90 百分位約 7.4 小時。
在這種變更速度下,人為審查仍有價值,但無法獨力承擔品質體系。我們需要在變更生命週期的多個階段有獨立訊號。
我們目前的方法有五大主題:環境收斂、可執行約束、邊界導向測試、完整回饋迴路及持續清理。
以 dev container 收斂開發環境
許多難以重現的失敗來自 pull request 中未出現的狀態。
開發者可能有未記錄的環境變數、全域安裝的工具、舊設定檔,或已運行數月的資料庫。人會習慣這些細節,智能體通常無法察覺。
我們逐步不再將主機視為標準開發環境。工程師與智能體都在 dev container 內工作。開發映像包含專案工具鏈、PostgreSQL、pgvector、Chromium 及瀏覽器自動化工具。
CI 執行從同一組多階段 Dockerfile 建構的版本化工具鏈映像。開發與 CI 映像用途不同,生產環境有自己的部署型態。關鍵特性是收斂:工具版本、依賴與執行假設皆明確且有版本控管。
這帶來明確預期。智能體執行的指令,工程師在同一開發容器內也能重現。開發階段通過的檢查,應在 CI 近似工具鏈下執行。
資料也採用類似概念。每個 pull request 預覽都可有自己的資料庫分支,執行真實遷移與種子步驟。智能體可建立、變更資料,重複破壞性測試,而不會借用開發者現有資料庫或繼承其他 pull request 的狀態。
環境變更透過程式庫傳遞。工具升級、瀏覽器版本、資料庫擴充皆與應用程式程式碼一樣審查與推送。
以型別與 lint 規則將工程標準可執行化
書面標準有助於理解設計決策,但對於確保每次變更都遵循這些決策,尤其在長時間智能體作業期間,效果有限。
只要規則能可靠表達,我們就將其納入型別系統、linter 與 CI。
vm0 採用嚴格 TypeScript 設定,包括 strict 與 noUncheckedIndexedAccess。部分套件啟用額外未使用值與隱式回傳檢查。
API 採用 schema-first 型別化 REST 契約層,結合 tRPC 型別機制與 Zod schema。Drizzle 將資料庫存取與 TypeScript 型別連結。此文撰寫時,程式庫約有 135 個契約模組。
這些選擇無法攔截錯誤的產品決策,但能及早發現介面漂移。當欄位或回應變更時,相關呼叫者通常會在靜態分析時失敗,錯誤訊息也足夠明確,智能體可用於下次迭代。
Lint 覆蓋第二類規則。平台執行 Oxlint、型別感知檢查、ESLint 及專案特定架構規則。CI 不接受任何警告。可長期存在的警告容易成為背景噪音,無論對人還是智能體都容易忽略。
當問題反覆出現時,我們會思考檢查應歸屬何處:
- 型別系統能否表達?
- linter 或結構工具能否準確偵測?
- 是否需跨程式庫語意判斷?
前兩者能對每次變更給予快速、決定性回饋。第三類則以後文介紹的定期工作流程處理。
收斂 AI 生成程式碼中的易錯模式
某些語言特性有正當用途,也常見於脆弱的智能體生成程式碼中。
try/catch 會模糊錯誤邊界。智能體遇到失敗時,加個 catch 區塊與備援是讓路徑繼續執行的簡單方法,但會遺失原始錯誤。Promise 的 .then() 與 .catch() 混用 async/await 會讓控制流程分散於多種風格。
React 的 useEffect 在狀態管理上也有類似問題。常用於複製狀態、同步兩個真實來源,或編碼難以從資料模型看出的順序依賴。
核心 web 平台預設限制這些模式。合理例外可保留,需在旁明確說明。
目前核心 web 平台生產程式碼完全不含 useEffect。我們用 ccstate 及其他無副作用模式更明確建模依賴與副作用。monorepo 其他地方仍有少量生產 useEffect 呼叫,主要在共用 UI 與桌面程式碼,因此聲明範圍需明確。
這些規則源自本程式庫反覆出現的失敗。當某模式反覆造成同樣維護問題時,我們會將其從審查指引提升為可執行約束。
模組邊界測試:測試獎盃而非金字塔
vm0 不採傳統測試金字塔。我們的測試指南描述的是測試獎盃:底層為靜態分析,中層以整合測試為主,頂層僅少量端對端測試涵蓋關鍵用戶流程。
單元測試相對少見,僅針對安全敏感邏輯、演算法與狀態機選擇性使用。大多數業務行為透過模組公開邊界測試。
API 測試透過契約呼叫真實應用程式。測試資料盡量透過生產端點準備,斷言也以公開行為為主。測試避免直接操作內部服務或資料表,以免與當前實作耦合。
內部基礎設施只要成本合理就保持真實:
- PostgreSQL 與 pgvector
- 資料庫遷移
- 檔案系統
- 內部服務
- 僅在外部系統邊界 mock
這些整合測試比高度隔離的單元測試慢,需要更完整環境。但也縮小「測試通過」與「應用程式能用真實資料庫執行」的落差。
邊界測試讓大型內部重構有空間。智能體可重組模組、拆分服務或更改資料存取層,只要公開行為受保護即可。
Uncle Bob 偏好不同組合,重用單元測試、Gherkin 與變異測試。共同原則是獨立驗證。產生程式碼的過程不該是唯一聲稱程式碼可用的來源。
給智能體完整回饋迴路
我們早期的智能體執行常以熟悉報告結束:程式碼已變更且 TypeScript 通過,請啟動應用程式並檢查頁面。
這讓開發迴路有一半仍需工程師完成。有人還得準備資料庫、啟動服務、開瀏覽器、建立資料、觀察失敗並回報給智能體。
現在智能體已能取得足夠開發環境,執行更多工作。能啟動應用程式與資料庫、執行遷移、建立測試資料、造訪 pull request 預覽並進行真實瀏覽器互動。
瀏覽器驗證能捕捉型別檢查與 API 測試難以涵蓋的問題:壞掉的導覽、永遠未完成的載入狀態、僅在完整流程中出現的權限錯誤、視覺回歸等。
執行結束時,智能體會回報執行過的指令、測試路徑與觀察結果。若為 UI 變更,還可附上截圖。工程師可先檢查這些證據,再決定是否親自開啟預覽。
截圖不是測試,無法證明沒有其他錯誤。但能降低重建智能體上下文的成本。對小型介面變更而言,可重現步驟與最終截圖遠比「應該修好了」這類訊息有用。
智能體工作的品質極度依賴其能獨立獲得的回饋。
以 trunk-based development 縮短分支
快速程式碼生成會產生大量分支。
長壽命功能分支會累積合併衝突、重複工作與過時上下文。pull request 越大,審查越困難、越慢。我們採 trunk-based development,持續整合於 main。
main 分支規則要求:
- 所有變更需 pull request
- 線性歷史與 squash 合併
- 合併佇列
- Turbo、Rust 與安全檢查
- 必要檢查無例外繞過
自動化也遵循同一路徑。智能體可建立 pull request,部分低風險維護任務可自動合併,但仍需通過 CI 與合併佇列。
pull request 的規模與壽命解釋了為何一週能合併 630 個。小變更上下文少、易驗證,也較不易與產品開發或其他自動修復衝突。
Knip 作為程式庫垃圾回收:移除無用程式碼
程式碼生成自然會新增檔案與抽象,刪除則常需額外提示。
重構後,舊檔案可能殘留。移除功能時,可能留下 export、依賴與進入點。這些殘留物很少讓測試失敗,卻會讓程式庫日益難以瀏覽。
我們用 Knip 找出未使用的檔案、export、依賴與進入點。TypeScript 只確認程式碼有效,Knip 則問它是否仍參與系統。
這些殘留對智能體還有額外成本。程式庫是其最重要的上下文來源之一。過時的 helper 或棄用實作,對下個智能體來說可能像是已核准的模式。保持上下文乾淨是上下文工程的樸實一環:智能體從程式庫讀到的內容與提示同等重要。
移除無用程式碼也改善未來執行的輸入。Knip 能快速處理決定性部分,成為常規品質檢查。
定期 AI 殘渣清理工作流程
Knip 與 ESLint 有明確極限。許多劣化型態需專案上下文與語意判斷。
我們將「AI 殘渣」作為這類殘留的實用標籤:不必要的備援、重複抽象、繞過公開邊界的測試、針對不可能狀態的防禦分支。單一實例看似無害,累積起來卻讓程式庫難以理解,也給未來智能體壞榜樣。
多個定期 vm0 工作流程按排程掃描這些模式。
每日 AI 殘渣清理會尋找新殘留,挑選高信心、低風險的小修正。其他流程檢查觸及內部服務的 API 測試、React 與 ccstate 反模式,以及可安全處理的技術債。
每個流程都保持變更範圍狹窄。會開 pull request,並依賴正常型別檢查、lint 規則、測試與合併佇列。自動合併的 pull request 也必須通過同樣檢查。

排程執行智能體並非免費,我們也另文討論過如何壓低這些成本。這些流程不試圖一次清除所有技術債。每日小批次更易驗證,也比數月一次大清理干擾小。
當定期流程常發現同一模式時,我們會考慮將檢查移入 ESLint、Knip 或型別系統。語意流程是觀察與精煉規則的場所,之後再轉為更便宜的決定性檢查。
將不穩定測試失敗自動修復
另一組流程從 GitHub Actions 失敗開始。
當 main 分支或合併佇列測試失敗時,流程會讀取日誌、檢查是否有不穩定證據,並查看重試、時序與環境因素。若證據支持特定修復,則更新測試或實作、開 pull request 並重新跑完整 CI。
重試通過不代表原始失敗無害。依賴重試按鈕的團隊會逐漸失去對紅燈的信任。一旦如此,失敗檢查就成了另一種背景噪音。
自動修復流程將間歇性失敗轉為可追蹤的程式碼變更。診斷、修補與驗證都保留在 pull request。工程師可檢查高風險變更,證據明確的狹窄修正則可通過合併佇列。
我們的品質體系目前有三大層次:
| 階段 | 機制 | 典型關注點 |
|---|---|---|
| 撰寫時 | TypeScript、契約、Drizzle、ESLint | 型別錯誤、介面漂移、已知程式碼模式 |
| 合併前 | Knip、整合測試、真實資料庫、預覽、合併佇列 | 無用程式碼、模組行為、完整執行結果 |
| 合併後 | 定期與事件驅動 vm0 工作流程 | AI 殘渣、語意反模式、不穩定測試、架構漂移 |
這些層次彼此餵養。工作流程發現的問題可成為靜態規則。CI 或生產發現的失敗可成為測試與新工程指引。
人類審查 AI 生成程式碼時的注意力分配
vm0 工程師仍會閱讀程式碼,特別是架構變更、安全敏感工作、金流與資料遷移。我們並未將「永不讀程式碼」作為團隊規則。
改變的是程式碼審查時注意力的分配。閱讀程式碼只是合約、測試邊界、預覽行為、截圖、品質指標與工作流程診斷等眾多訊號之一。
有些決策仍需經驗判斷:
- 需求是否完整
- 模組邊界應設在哪裡
- 哪些失敗可恢復
- 錯誤可能造成多大業務影響
- 安全模型是否合適
- 現有規則未涵蓋的新失敗模式
設計端也有類似轉變,design-as-code 將視覺決策納入同一程式庫與審查流程。工程師也維護智能體周邊環境。當問題反覆出現時,我們會決定是否新增型別約束、lint 規則、測試或定期工作流程。開發系統本身已成為重要工程產物。
可讀性仍重要。下個讀者可能是工程師,也可能是智能體。糾結的程式碼消耗更多上下文,擴大未來變更範圍,也降低驗證可靠性。
安全性與那些無法加速的變更
速度並非一體適用。vm0 保持一份需自行決定進度的變更清單:安全敏感工作、金流、資料遷移與架構決策。這些無論由誰產生,都需工程師逐行審查。
我們經驗中,AI 生成程式碼的安全風險不在於罕見漏洞,而在於無人負責的合理程式碼。重要控管是普通措施,但要持續執行:
- 單元測試(平時較少用)專為安全敏感邏輯、演算法與狀態機設計。
- 測試僅在外部系統邊界 mock。內部基礎設施保持真實,內部契約破壞會在 CI 失敗而非生產環境。
- 智能體在 dev container 內,針對每個 pull request 使用獨立資料庫分支,不用開發者機器或共用資料庫。
- 合併佇列與必要檢查無例外繞過,包括智能體開啟並標記自動合併的 pull request。
try/catch預設受限,智能體為讓路徑繼續執行而加的備援較難吞掉失敗。
憑證處理是另一設計問題,有專文說明我們的broker pattern,可將 token 隔離於智能體之外。
這些措施本身無法讓生成程式碼自動安全。它們只是縮小需人類決策的變更範圍,並讓這範圍明確。
這些數據未顯示的內容
每週報告展現了程式庫規模與交付速度,但本身無法證明生產可靠性。
評估執行品質需看可用性、生產錯誤率、事件數、變更失敗率、回滾頻率與平均修復時間。CI 綠燈只描述交付流程的一部分。
我們仍在持續彙整這些結果指標。工程實踐解釋系統如何管理風險,生產數據則顯示管理成效。
FAQ
什麼是 vibe coding? vibe coding 是向 LLM 提示產生程式碼、執行回傳內容、要求修改,且不閱讀生成程式碼。Martin Fowler 的定義刻意狹窄:開發者應「甚至忘記程式碼存在」。適用於原型、一次性軟體及後果有限的工具。
什麼是 agentic coding? agentic coding 是較長期的 AI 協作開發,智能體閱讀程式庫、編輯檔案、執行測試並長時間獨立迭代。人類仍擁有架構與行為主導權,審查的是執行產生的證據,而非每一行程式碼。
vibe coding 與 agentic coding 差別是什麼? 差別在注意力而非作者。vibe coding 完全不檢查程式碼;agentic coding 則由智能體獨立作業,工程師檢查其周邊證據:測試結果、品質訊號、預覽與生產行為。vm0 通常稱為 vibe-coded,Fowler 的定義則屬 agentic coding。
什麼是 AI 殘渣? AI 殘渣是 AI 生成程式碼留下的殘留:不必要的備援、重複抽象、繞過公開邊界的測試、針對不可能狀態的防禦分支。單一看似無害,累積起來讓程式庫難以理解,也給下個智能體壞榜樣。
你們如何審查每週 630 個 AI 生成的 pull request? 不是逐行審查。在 vm0,人為審查只針對需判斷的部分:架構、安全敏感工作、金流、資料遷移。其他都靠機制:嚴格型別與契約、模組邊界整合測試、每個 pull request 預覽用真實資料庫、瀏覽器驗證、Knip 及無例外繞過的合併佇列。
大規模 vibe coding 的最佳實踐是什麼? vm0 八個月來有五項:收斂開發環境讓智能體與人執行同指令;將標準落實於型別、linter 與 CI,而非文件;模組邊界測試對真實基礎設施;給智能體完整回饋迴路(含瀏覽器);持續小批次清理,而非偶爾大掃除。
AI 生成程式碼的安全風險是什麼?
常見風險不是罕見漏洞,而是無人負責的合理程式碼。vm0 將安全敏感工作、金流、資料遷移留給人審查,針對該邏輯刻意用單元測試,測試時內部基礎設施保持真實,限制會吞掉失敗的 try/catch 模式,且必要檢查無例外繞過。
AI 生成程式碼會產生技術債嗎? 會產生特定型態:仍可編譯、通過測試但已不參與系統的程式碼,以及 linter 無法命名的語意殘渣。Knip 移除決定性部分,定期工作流程每日小批次處理其餘,常見模式則成為 lint 規則或型別約束。
vm0 程式庫有多少是 AI 撰寫的? 大多數實作。六位工程師貢獻了 556 個(共 630 個)於 20–26, 2026 合併的 pull request,其餘由發佈自動化產生,智能體撰寫了這些 pull request 內大部分程式碼。工程師負責的是架構、約束與生產行為。
什麼是測試獎盃,為何不用測試金字塔? 測試獎盃以靜態分析為基礎,中層以整合測試為主,頂層僅少量端對端測試。vm0 採用此法,因為透過模組公開邊界撰寫的測試能在智能體重組實作時持續保護行為,而大量單元測試無法。
如何在 AI 撰寫的程式庫找出無用程式碼? 程式碼生成會新增檔案與抽象,刪除通常需額外提示。vm0 定期執行 Knip,找出未使用檔案、export、依賴與進入點。TypeScript 確認程式碼有效,Knip 則問它是否仍參與系統,這才是無用程式碼的關鍵。
vibe-coded 程式碼能安全上線嗎? 關鍵在驗證機制,而非誰撰寫。必要訊號未變:型別與契約、公開邊界測試、真實基礎設施、必須綠燈的流程。本文數據描述程式庫規模與交付速度。可用性、錯誤率與變更失敗率才是生產安全的答案,我們仍在彙整。
八個月後
八個月還言之過早。模型、智能體工具與程式庫都在變,我們的規則與流程也隨之調整。
有一點已明確。隨著程式碼生成加速,環境、約束、測試與回饋系統承擔了更多品質責任。工程師花更少時間打實作,更多時間定義行為、設計邊界、強化驗證。
vm0 程式庫會持續成長。Knip 移除決定性殘渣,靜態規則阻擋已知失敗模式,整合測試保護模組行為,定期工作流程處理尚無法機械表達的劣化。
程式碼仍然重要。本文最佳實踐不是為了少寫程式碼,而是決定變更進入 main 分支前必須成立的條件。我們現在用更多機器可執行證據來決定變更是否該進 main 分支,以及其實作是否該留在程式庫中。





