Agent 交出一份 PR,程式碼能跑,測試全過,摘要還寫得比我自己寫的完整。這時最容易省掉的,是回頭想一下:它到底解了哪個問題?
以前自己寫程式,碰到規格沒寫清楚的地方,手會停下來。你得決定這個狀態怎麼處理,問同事,或去翻舊程式。現在 Agent 可以選一個合理的做法,順手把測試寫完。原本會讓人停下來討論的事,有可能直到上線後才被看見。
這是我讀 Addy Osmani 的〈Critical thinking when agents do the work〉最有感的地方。模型越好用,這種情況反而越難察覺。明顯的錯誤會讓人停下來。合理、順暢、只漏掉一個條件的答案,通常會一路走到下一步。Addy Osmani 原文
Addy Osmani 在 Anthropic 參與 Claude Code。他先前在 Google 工作超過 14 年,帶過 Chrome、DevTools、Lighthouse 等工具的開發者體驗,也寫過《Learning JavaScript Design Patterns》。如果你做過前端,可能早就用過他參與的工具。Addy Osmani 個人網站
我覺得他的背景和這篇文章很有關係。做開發工具的人,一直在想怎麼拿掉工程師工作裡的摩擦。到了 Agent 這一代,連「遇到不確定的地方,必須自己停一下」這種摩擦也可能消失。省下來的時間很有價值,但原本那一下停頓在做什麼,值得拆開來看。
Addy 把這件事看成一段光譜。你可以把工作交給 AI,自己掌握結論怎麼來,這是認知卸載。再往前一步,你開始直接拿它的輸出當下一步的前提。到了他說的「認知投降」,你甚至忘了這個前提原本還有待確認。
假設我們請 Agent 修一個重複扣款的問題。它看到同一筆請求可能重送,就加了一道檢查。如果資料庫已經有付款紀錄,就跳過第二次扣款。讀起來合理,測試也可以寫得很漂亮。
但如果第一次請求已經在金流端成功扣款,服務卻在寫入資料庫之前掛掉呢?第二次請求還是看不到付款紀錄。如果團隊直接接受「有查重,所以可以安全重試」這個結論,下一個 Agent 甚至可能以此為前提,加上自動重試。第一份修改留下的是一個邊界沒處理好,第二份修改卻把那個邊界變成更容易碰到的路徑。
這也解釋了理解債為什麼難發現。每一份 PR 單獨看都很合理,真正缺掉的是跨過幾次修改之後,還有沒有人說得清楚整條流程依賴哪些條件。通常是要改需求或處理事故時,團隊才發現要重新把這段理解補回來。
我之前寫過,Agent 寫程式的速度上來以後,驗收會變成瓶頸。讀完 Addy 這篇,我想再補一層:就算 Agent 連測試都能跑,還是得有人決定什麼證據足以接受這個結果。AI 工程師與他的 Agent 軍隊
拿扣款來說,測兩次依序送出的請求,可以確認正常情況下的查重。要知道中途失敗能不能安全重試,測試得刻意製造另一種情境:讓金流端先成功,再讓本地寫入失敗,然後重送同一筆請求,核對金流端實際扣了幾次。如果兩個請求可能同時進來,那又是另一個需要驗證的情境。
我喜歡 Addy 提到的做法,先在問 Agent 之前寫下自己的假設。以這個例子來說,只要寫一句就有用:「我懷疑第一次付款成功後,如果本地寫入失敗,重試會再扣一次。」接著讓 Agent 去查程式、找反例或設計測試。如果證據推翻我的猜測,我也知道自己改變看法的理由。
看 PR 時,我也會想問「你替我做了哪些決定?」通常更值得看的,是它怎麼認定兩次請求屬於同一筆付款、用哪一邊的紀錄判斷成功,以及它把哪些失敗情境留在這次修改之外。這些決定有時只佔 diff 的一兩行,後面維護的人卻要繼續承擔它們。
大型系統本來就很難靠一個人記住全部細節。遇到問題時,可以請 Agent 找出相關程式、追呼叫路徑,再跟著證據重建局部的理解。對我來說,比較實際的要求是:在同意一個會影響使用者的變更之前,我能說明它在哪些條件下成立,條件失效時會發生什麼,以及我憑什麼相信它。
如果今天有人接手剛才那個付款流程,問我「金流端顯示成功,但我們沒存到紀錄,客服能不能叫使用者再試一次?」我希望我能回答,還能指出哪一項測試支持這個答案。那才是這份 PR 值得我按下合併的理由。
分享這篇文章