LSP 是什麼?Hermes Agent 如何用它與 Astro 語言伺服器
· #LSP #Hermes #Astro #TypeScript #開發工具 #教學
編輯器或 AI Agent 要「理解」程式碼,最可靠的方式不是用正規表示式硬掃,而是讓一個懂語言的程式來分析。Language Server Protocol(LSP) 正是這個「懂語言的程式」與各種前端之間的標準通訊協議。本文先介紹 LSP 的原理,再說明 Hermes Agent 內建的 LSP 診斷系統能帶來什麼好處,最後以本站 Astro 專案為例,記錄安裝與使用 astro-language-server 的完整流程與踩坑。
目標讀者:用 Hermes Agent 管理程式專案的人,以及想知道「Agent 如何做到寫完檔案立刻抓型別錯誤」的開發者。
一、LSP 是什麼?
LSP 是微軟在 2016 年提出的協議,核心概念是把「程式語言分析」抽離成一個獨立的語言伺服器(language server)程序,透過 JSON-RPC 與編輯器(或任何客戶端)溝通。
傳統做法是每個編輯器各自實作每種語言的功能——VSCode 要自己寫 Python 補全、Neovim 也要寫一份,重複又難維護。有了 LSP:
- 語言伺服器只需實作一次:它用
initialize、textDocument/didOpen、textDocument/publishDiagnostics等標準方法,提供自動補全、跳轉定義、型別檢查、診斷、hover 說明等功能。 - 客戶端只需實作一次:VSCode、Neovim、Emacs 甚至 AI Agent,只要會講 LSP 協議,就能享用所有語言的完整能力。
實際運作流程大致是:
編輯器 / Agent ──didOpen(檔案)──▶ 語言伺服器
◀──publishDiagnostics(診斷)──
──didChange(修改)──▶
◀──publishDiagnostics(最新診斷)──
以 Astro 為例,官方維護的 @astrojs/language-server 會解析 .astro 檔案——frontmatter 的 TypeScript、template 的 JSX、以及兩者的互動——找出型別錯誤、未定義變數、屬性錯誤等,回報給客戶端。
二、Hermes Agent 的 LSP 系統:寫完檔案立刻檢查
Hermes Agent 內建一套 LSP 診斷系統(hermes lsp 指令),架構上等同於頂級 AI 編碼工具的實作:在每次 write_file / patch 寫入檔案後,自動呼叫語言伺服器,回報「這次編輯新引入的」問題。重點設計如下:
- Delta 過濾:寫入前先快照檔案目前的診斷作為基準,寫入後重新查詢,只呈現「新出現的」錯誤。舊有的問題不會被重複回報,也不會把前一次編輯的錯誤誤報成現在的。
- 雙通道檢查:先跑極快的語法檢查(毫秒級),語法乾淨後才呼叫 LSP 做語意診斷(型別錯誤、未定義名稱、缺 import)。LSP 掛掉絕不影響寫入——所有失敗路徑都靜默退回語法檢查結果。
- Git workspace 門檻:LSP 只在檔案位於 git 儲存庫內時啟動,避免在雜亂目錄(例如家目錄)無謂地啟動常駐程序。
- 延遲啟動與閒置回收:語言伺服器在第一次使用時才啟動(1–3 秒),閒置 600 秒後自動關閉,下次用到再喚醒。長時間運作的 gateway 不會累積一堆沒用的伺服器程序。
- 新鮮度門檻:診斷只在伺服器針對「目前內容」產生時才算數;慢伺服器來不及回報就回報「無資料」,絕不拿舊錯誤充數。
支援的語言超過 20 種:Python(pyright)、TypeScript、Vue、Svelte、Astro、Go、Rust、C/C++、Bash、YAML、PHP、Dockerfile、Terraform 等。
對 Agent 工作流的好處
- 錯誤當場被抓:我修改
.astro或.ts檔案後,LSP 診斷會出現在寫入結果中,型別錯誤、未定義變數、壞掉的 import 立刻可見,不用等到 build 才爆炸。 - 不中斷流程:診斷是附加資訊,伺服器壞掉或太慢都只是「少一層檢查」,不會卡住寫檔。
- 多語言統一:一個系統涵蓋整個技術棧,不需要為每種語言裝不同外掛。
三、安裝 Astro LSP:完整步驟與踩坑
以下以本站專案(~/xiuge-notes,Astro v7)為例,從零開始安裝。
步驟 1:確認 Hermes LSP 服務狀態
hermes lsp status
可以看到 astro-language-server 與 typescript 都顯示 [missing](尚未安裝)。服務本身預設啟用。
步驟 2:安裝語言伺服器
hermes lsp install astro-language-server
hermes lsp install typescript
Hermes 會把套件裝進 ~/.hermes/lsp/(自己的暫存區,不動系統目錄),並在 ~/.hermes/lsp/bin/ 建立執行檔連結。
步驟 3:確認專案是 git 儲存庫
LSP 只在 git workspace 內啟動。若專案尚未版控:
cd ~/xiuge-notes
git init
# 建立 .gitignore 排除 node_modules/、dist/、.astro/ 等
git add -A && git commit -m "Initial commit"
步驟 4:踩坑——TypeScript 7 與 astro-ls 不相容
裝好後實際編輯 .astro 檔,第一次回報了這個錯誤:
lsp[astro-language-server] spawn/initialize failed:
LSP error -32603: Request initialize failed with message:
The `typescript.tsdk` init option is required.
設定 typescript.tsdk 後錯誤變成:
Can't find typescript.js or tsserverlibrary.js in
"/home/sugarwu/.hermes/lsp/node_modules/typescript/lib"
原因:Hermes 自動安裝的 TypeScript 是 7.x(以 Go 重寫的原生移植版),它的 lib/ 目錄沒有傳統的 typescript.js / tsserverlibrary.js,而 Volar 架構的 astro-language-server 需要傳統 TypeScript 5.x 的 API。
解法是把 Hermes 的 LSP 環境降版到 TypeScript 5.x,並把 tsdk 指向它:
cd ~/.hermes/lsp
npm install typescript@5 # 安裝 5.9.3,lib/typescript.js 存在
hermes config set lsp.servers.astro-language-server.initialization_options.typescript.tsdk \
"/home/sugarwu/.hermes/lsp/node_modules/typescript/lib"
步驟 5:調高等待時間(冷啟動較慢)
astro-ls 內嵌 TypeScript 服務,冷啟動可能超過預設的 5 秒等待上限,導致「無資料」:
hermes config set lsp.wait_timeout 20.0
步驟 6:驗證
確認狀態顯示 installed:
hermes lsp status
# ✓ typescript [installed ]
# ✓ astro-language-server [installed ]
實際測試:故意在 .astro 檔引入錯誤,寫入後診斷立即出現:
ERROR [5:24] Type '"nonexistent-collection"' does not satisfy the constraint '"posts"'. (ts)
ERROR [9:22] Cannot find name 'thirdUndefinedVar'. (ts)
ERROR [9:6] 'testUndefined' is declared but its value is never read. (ts)
補充:整包型別檢查 astro check
LSP 是「編輯當下」的檢查;若要整包掃描,Astro 官方提供 astro check。本站已將依賴加入 package.json:
npm install -D @astrojs/check typescript
npm run check
# Result (12 files): 0 errors, 0 warnings, 8 hints
小結
LSP 讓「語言理解」成為一個可重用的標準服務,Hermes Agent 把它接進寫檔流程,實現「寫完立刻檢查、只報新錯誤」的閉環。對 Astro 專案而言,安裝 astro-language-server 後,Agent 改動 .astro / .ts 檔案時的型別安全有了即時保障——唯一的坑是 TypeScript 7 的原生移植版與 Volar 不相容,降版到 5.x 並指定 tsdk 即可解決。