與 AI 共事:巫師學徒問題的一個具體案例

與 AI 共事:巫師學徒問題的一個具體案例

AI 是開發強大的工具,但它可能導致「巫師學徒問題」(Sorcerer's Apprentice problem),即開發者變得依賴 AI,並失去理解與解決自身系統中問題的能力。在修復 hyperscript 解析器中回歸問題(regression)的詳細記錄中,Carson Gross 展示了 AI 如何在調查與測試生成方面表現出色,但在高層次架構設計與防止技術債方面卻顯得吃力。

AI 在根本原因分析與測試方面的優勢

AI 代理(特別是 Claude)被證明在快速識別錯誤(bug)的根本原因方面非常有效。在 hyperscript 0.9.91 的回歸問題案例中,一個特定的表達式——fetch {% url 'trade:get_symbol_data' %}?symbol=${symbol} as JSON——無法正確解析,因為 as JSON 修飾符被視為轉換表達式,而非 fetch 命令的修飾符。

Claude 識別出,將 gofetch 命令重構為共享一個共同方法 parseURLOrExpression(),不經意地擴展了語法,使其包含了通用表達式,導致解析器過早地消耗了 as 關鍵字。

除了分析之外,AI 在生成針對性、小規模的測試以驗證錯誤及其隨後的修復方案方面也具有高度能力。這使得開發者能夠創建比他們手動編寫更有廣度的測試套件,這對於維護舊專案特別有利。

AI 在架構設計方面的失敗

雖然 AI 在分析方面很快,但在提供乾淨、通用的解決方案方面卻很吃力。AI 提出了三種不同的修復方案,其中兩種是有缺陷的:

  1. 特定的補丁(Hack):第一個提案建議先解析「類字串」葉節點,這雖然能修復眼前的錯誤,但在通用情況下會失敗,例如當變數被用作 fetch 目標時。
  2. 不必要的複雜度:第二個提案建議在解析器中添加一個 noConversions 標記,這會使解析器變成上下文相關(context-sensitive)。雖然 hyperscript 解析器本身已經是上下文相關的,但這會引入不必要的狀態與技術債。
  3. 過度廣泛的應用:第三個提案在人類開發者的引導下,利用現有的「follows」基礎設施來防止 as 關鍵字被解析為表達式。然而,它將此修復應用到了共享的 parseURLOrExpression() 方法中,這破壞了 go 命令中的 as 轉換表達式。

最終,正確的解決方案是由人類開發者實施的,他將特殊情況具體縮小到 FetchCommand#parse() 方法中,確保了 go 命令不受影響。

人類在環(Human in the Loop)的角色

為了避免呈指數級增長的技術債,知識淵博的人類必須留在環中,扮演「巫師」而非學徒的角色。這能確保解決方案符合現有的架構,並維持系統的整體的連貫性。

Hacker News 討論串中的社群討論突顯了幾個關鍵見解:

"AI 是擅長分析與樣板代碼(boilerplate),但並不擅長進行良好設計所需的批判性思考... LLM 並不具備世界模型。它們不像人類那樣去研究並思考設計。"

"如果 AI 真能擅長為自己設計智能測試,那麼所有那些較弱的被拒絕的解決方案本就可以避免。"

AI 作為資深開發者的無障礙工具

對於資深開發者而言,AI 可以減輕與年齡相關的記憶力下降以及長時間工作的能力下降。AI 可以作為記憶輔助工具,並作為樣板代碼與測試的「研磨機」,讓資深開發者能更有效率地地在不同專案之間切換,並減少處理瑣碎任務的負擔(capacity)。然而,人們也擔心過度依賴 AI 可能會加速「智力的鈍化」與批判性思考能力的普遍退化。

結論

有效的 AI 輔助編碼需要一種平衡:利用 AI 進行調查、測試生成與快速原型設計,同時依靠人類判斷來進行架構決策與防止技術債技術債。

Sources