跳到主要內容
wen aidev

Kiro SDD 入門(四):為什麼 AI 幫你重構總是越搞越糟?(AST vs LSP 實戰)

8 分鐘po-wen

叫 AI 改個變數名,結果全專案的 import 壞光光?這篇將從底層邏輯聊起,探討為什麼重構必須依賴 AST 與 LSP,並教你如何在實戰中正確使喚 Claude Code 等 Agent 進行安全重構。

目錄

系列文章地圖

點節點可以直接跳到那一篇。

在 Cursor 或 Claude Code 叫 AI 把專案裡的 User 改名成 Client,它回報改完了,跑 yarn dev 卻一片紅字。常見的是這三種:

  • 有個檔案的 import { User } 沒改到。
  • 註解 // notify the User 也被改成 Client,但那裡的 User 只是一般英文。
  • 名字裡剛好有 User 的 UserCard 元件被一起改名,引用它的檔案全部壞掉。

三個錯的原因一樣:AI 用字串搜尋取代來改名。改名要改的是程式裡的 symbol,哪些地方引用了它,要靠語法分析才找得準,光比對文字做不到。

上一篇講 Bug Fix Paradox,這篇講重構:為什麼改名、搬檔要交給 LSP 或 AST 工具,以及在 Claude Code 裡怎麼下指令。


理論篇:重構的底層邏輯(AST 與 LSP)

在探討怎麼叫 AI 做事前,我們要先理解為什麼傳統的 Find & Replace(也就是預設 AI 幫你改程式碼的方式)一定會出包。

重構是一件要找出 AST(抽象語法樹)關聯 的精確工程。你「只改一個名字」或「搬移一個檔案」,背後就牽扯到 imports 和 exports、linter 規則,還有 module resolution。

文字替換只認得字串,LSP rename 認得 symbol,所以同一個專案裡的 User,兩種改法會改到不同的地方。

User → Client
2
改對
3
誤改
1
漏改
文字替換在做什麼
AI 用 grep 找出字串 User,一個檔案一個檔案改。它只認得字,不知道哪個 User 是型別、哪個只是剛好同名的文字。
點任一列,看它為什麼被改或沒被改。

1. 傳統 AI:只看字串 (Text-based)

你叫 AI 改名,它(如果沒有配備好工具)就是拿著你給的字串,用正規表示式去整個專案裡撈。這種「純文字替換」沒有上下文觀念,它不知道哪個 User 是一個 interface,哪個 User 只是一個恰巧同名的變數。所以誤改(改錯註解)跟漏改(沒改到動態 import)幾乎是必然的。

2. 現代作法:照語法結構改 (Semantic-based)

如果你平時用 VSCode,在一個變數上按下 F2 (重新命名),IDE 是不會猜測的。它透過 LSP (Language Server Protocol) 去問 language server。language server 早就把你的檔案解析成語法樹並建好索引,它知道這個 User 的定義在哪,被哪 15 個檔案引用。

重構要照這份索引找位置,不該交給只會文字接龍的 LLM 去猜。


實務篇:如何在 2026 讓 AI 幫你正確重構?

既然知道了問題出在哪,我們該怎麼解決?身為開發者,你需要幫 AI 準備對的工具。

目前有兩種工具:LSP 與 AST CLI 工具。很多開發者會把它們搞混,認為只要是操作 AST 就好。

該用哪種工具,看改動的性質:IDE 內建的重構動作交給 LSP,同一種轉換要套到大量檔案時用 AST codemod,跟 symbol 無關的內容才直接改文字。

這個重構交給誰
3
首選
0
可行
4
不適合
LSP在做什麼
language server 已經把整個專案解析成語法樹。rename、搬檔、extract 這類 IDE 內建的重構動作,它會回一份 WorkspaceEdit,列出每個檔案要改的位置。
點任一列,看該怎麼跟 agent 交代。

迷思釐清:AST vs LSP 哪個好?

  • LSP 負責大部分日常重構:如果你只是要重新命名檔案/符號、搬移資料夾、把一段 code 提取成共用函式,直接交給 LSP 就好。它已經建好整個專案的索引,跟你手動按 F2 是同一套機制。
  • AST 工具負責大規模客製重構:如果你遇到 LSP 預設按鈕沒有的功能,比如「把整個專案的 React Class Component 全部轉換成 Hooks」,LSP 辦不到。這時候才需要讓 AI 用 ast-grep 或 jscodeshift 寫腳本轉換。

怎麼對 agent 下指令(以 Claude Code 為例)

在終端機用 Claude Code 時,prompt 要換個寫法。

❌ 容易出事的 Prompt:

「幫我把整個專案的 authHelper 改名成 securityCore,還有幫我把 Auth.tsx 移到 shared 資料夾。」 (結果:Claude 會開始生成 bash 腳本,用 sed 指令或是手動幫你改檔,跑完後常常一堆破圖跟路徑錯誤。)

✅ Agentic Workflow 的正確 Prompt:

「我要把 authHelper 重命名為 securityCore。請你不要手動去改文字,先用 LSP 找出 authHelper 所有的 references 列給我,再用當前專案的 refactor CLI 或 codemod 執行改名。改完後請跑 npx tsc --noEmit 和 yarn lint,確保所有的 import 都有被更新。」

Claude Code 內建的 LSP 工具只能查詢(跳到定義、找 references、看型別),沒有 rename,所以這個 prompt 讓它用 LSP 盤點位置,實際改名交給 CLI。如果你使用的環境已經把 IDE 的 rename API 包成 agent 工具,AI 就能自己去「按 F2」。Kiro 就是這樣做:它的 semantic rename 工具呼叫 VS Code 的 vscode.executeDocumentRenameProvider,搬檔工具則用 WorkspaceEdit.renameFile 順便更新 import。

💡 給進階玩家的提示:

如果你的 CLI 環境沒有串接 LSP,你可以直接指使 Claude Code 去跑你設定好的 eslint --fix 或是你寫好的 ast-grep rule。 讓 AI 下指令給驗證過的底層工具,由工具去改 code。


結論:Agentic AI 的正確協作邊界

一個設計優良的代理(Agent)工作流,不應該是什麼都叫 LLM 自己硬刻。

一次安全的 rename 裡,agent 負責傳話和驗收,要改哪幾行由 language server 算出來。

Rename 委派 · authHelper → securityCore
U
你
開發者
A
Agent
有 rename 工具
L
LSP
TS server
F
專案檔案
src/**
「把 authHelper 改名成 securityCore」
textDocument/rename
WorkspaceEdit · 4 files
apply WorkspaceEdit
tsc --noEmit · yarn lint
0 errors
已把 authHelper 改成 securityCore:4 個檔案、9 處。tsc 與 lint 都通過。
01 / 06給意圖
你只說要改什麼。改哪幾個檔案、哪幾行,不用 agent 自己去找。
user: 把 authHelper 改名成 securityCore
1 / 6 · 給意圖

一個重構回合裡,三方各做一件事。

  1. 開發者 (你):給出重構意圖(我要重組架構、改名)。
  2. AI Agent (Claude Code):負責理解意圖與統籌流程。它知道要改名,但不自己動手改字。
  3. AST Tool / LSP:負責實際的修改。AI 將任務委託給它,由它在語法樹上找到節點,一次更新全部檔案裡的引用與路徑。

AI 負責下指令和檢查結果,實際改檔交給工具。把「創意與意圖」交給 AI,把「精確與結構」交給編輯器底層工具,AI 做重構才安全。


參考與延伸閱讀

支持作者 ☕

台灣用戶:

透過 LINE Pay 支持

國際用戶:

透過 Ko-fi 支持

相關文章

留言討論

Facebook 留言