如果 AI coding agent 知道最新 Go 寫法,卻不知道你的專案仍鎖在 Go 1.24,它的「現代化」就可能直接變成編譯錯誤。Version-Aware Skill 要解的正是這個落差:先讀專案真正宣告的版本,再只載入該版本可用的規則。
截至 2026 年 9 月 4 日,JetBrains 的 go-modern-guidelines 在 GitHub 顯示 3,104 stars,當週新增 1,403 stars。這只能當成採用熱度訊號,不能證明 Agent 產生的程式一定更好;所以本文不比星星數,而是把它改造成可重跑、可失敗、可留下收據的版本相容流程。
先記住這個公式:Version-Aware Skill = 版本來源(go.mod)× 規則路由(list → explain)× 工具鏈收據(gofmt/go vet/go test)。少任何一項,都只是一段看起來很懂版本的提示詞。
先說結論:這個 Skill 值得裝嗎?
- 值得:同一個團隊同時維護多個 Go 版本、又常讓 Claude Code 或 Codex 新增/重構 Go 時,它能把「最新知識」裁到專案允許的邊界。
- 不等於正確性保證:Skill 只縮小版本與慣用法的搜尋空間;行為、並行生命週期、效能與安全仍由 code review 和測試負責。
- 不要把整份規則貼進 CLAUDE.md:長期規則只要要求「改 Go 前查版本」;會隨 Go 發行而變的內容交給可更新、可查詢的 Skill。
- 成功標準不是安裝完成:同一修改要在模組最低版本通過編譯、
vet與測試,並保存 Agent diff 和命令輸出。
本文提供完整 A/B 驗收法,但不刊一個虛構勝率:本輪文章查核環境沒有可用的 Go runtime,因此沒有把未執行的四格結果稱為「實測」。下文的版本邊界取自 Go 官方文件與目前的 repository code;請在自己的 disposable repo 依步驟重跑,得到屬於你所用模型與工具版本的結果。
Version-Aware Skill 是什麼?
一般規則檔像一本固定講義:不論專案是 Go 1.20 或 1.26,Agent 都看到同一批內容。Version-Aware Skill 則像圖書館員,先讀門牌上的版本,再把不可能使用的章節拿掉。JetBrains 這套 Skill 的官方方法分兩段:
list --file-path path/to/file.go:由目標檔案往上找go.mod,回傳該版本以前可用的短規則,順序由新到舊。Skill 明確要求完整讀完,不能用head、grep截斷。explain <rule-id>:只有某條規則真的可能套用時,才展開原因與 before/after 範例。例如 Go 1.25 的sync_waitgroup_go。

這叫 progressive disclosure(漸進揭露):先送一份小索引,只有命中的規則才載入細節。它同時降低上下文噪音與知識過期風險。若想先補 Skill、MCP、rules 的分工,可看〈Agent Skill 與 SKILL.md 完整教學〉;本文只往前推一步,處理「同一套知識如何依專案版本動態裁切」。
為什麼一定要讀 go.mod,而不是問模型「最新版 Go」?
Go 官方模組文件把 go directive 定義為模組所需的最低 Go 版本;自 Go 1.21 起,這條要求會被嚴格執行。專案寫 go 1.24,代表程式不能因為 Agent 知道 Go 1.25 就偷用 1.25 才加入的標準庫 API。
還要分清 go 與 toolchain:前者描述模組語言/函式庫的最低邊界,後者可建議實際執行哪個工具鏈。預設 GOTOOLCHAIN=auto 時,Go 可能自動下載較新的工具鏈。因此「我的電腦裝 Go 1.27」與「這個模組允許 Go 1.27 API」不是同一句話。
兩個容易漏掉的邊界:截至本文查核的 commit 91a30b3,CLI 只有收到 --file-path 才會往上找 go.mod/go.work;裸跑 list 會讀本機工具鏈。若找到的模組檔沒有 go directive,它也會回退到本機工具鏈;但 Go command 對缺少 directive 的模組採 Go 1.16 語意。實務上應明寫 go directive,並永遠傳入正在編輯的檔案路徑。
步驟 1:在 disposable repo 備份、安裝並固定版本
官方快速安裝會追 marketplace 當前版本;要做能重跑的 A/B,請先固定同一個 checkout。以下 SHA 是 2026 年 9 月 4 日本文查核的 upstream main,plugin manifest 為 1.1.1。日後重做新研究時應重新審查新版,不要永遠鎖死。
mkdir -p .lab/plugin-backup .tools
printf '.lab/\n.tools/\n' >> .gitignore
# 只備份會被這次流程碰到的設定,不複製 auth 檔
cp ~/.claude/plugins/known_marketplaces.json .lab/plugin-backup/ 2>/dev/null || true
cp ~/.claude/plugins/installed_plugins.json .lab/plugin-backup/ 2>/dev/null || true
cp ~/.codex/config.toml .lab/plugin-backup/codex-config.before.toml 2>/dev/null || true
git clone https://github.com/JetBrains/go-modern-guidelines.git .tools/go-modern-guidelines
git -C .tools/go-modern-guidelines checkout 91a30b36f05bb6424bd77e9817811c0e9c003aa2
git -C .tools/go-modern-guidelines rev-parse HEAD
Claude Code 用 local scope,把 marketplace 宣告留在這個專案;Codex 目前的 plugin 指令沒有 scope 參數,所以先保留 config.toml,並在實驗完移除。兩者都指向同一個本機 checkout:
# Claude Code 2.1.252 查核語法
claude plugin marketplace add "$PWD/.tools/go-modern-guidelines" --scope local
claude plugin install modern-go-guidelines@goland-claude-marketplace --scope local
claude plugin list --json > .lab/claude-plugins.with-skill.json
# Codex CLI 0.152.0 查核語法
codex plugin marketplace add "$PWD/.tools/go-modern-guidelines"
codex plugin add modern-go-guidelines@goland-codex-marketplace
codex plugin list --json > .lab/codex-plugins.with-skill.json
第一次真正呼叫 Skill 時,wrapper 會透過 go install 把 CLI 放進 $XDG_CACHE_HOME/go-modern-guidelines 或 ~/.cache/go-modern-guidelines,所以 PATH 上仍要有 Go。CLI 目標為 Go 1.25+;較舊本機 Go 可在預設 GOTOOLCHAIN=auto 下切換,但首次可能需要網路與下載時間。
實驗結束後的卸載路徑如下;先移除 plugin,再移除 marketplace。若輸出與預期不同,先停下來比對備份,不要直接覆蓋整個設定目錄。
claude plugin uninstall modern-go-guidelines@goland-claude-marketplace --scope local
claude plugin marketplace remove goland-claude-marketplace --scope local
codex plugin remove modern-go-guidelines@goland-codex-marketplace
codex plugin marketplace remove goland-codex-marketplace
步驟 2:建立 Go 1.24 與 Go 1.25 兩個 fixture
兩個 fixture 的程式與測試完全相同,只讓 go.mod 不同。Go 1.24 版本寫 go 1.24,Go 1.25 版本寫 go 1.25;模組名稱分別用 example.com/go124 與 example.com/go125。在兩邊放入同一個 worker.go:
package worker
import "sync"
// Run executes non-panicking jobs and waits for all of them.
func Run(jobs []func()) {
var wg sync.WaitGroup
for _, job := range jobs {
job := job
wg.Add(1)
go func() {
defer wg.Done()
job()
}()
}
wg.Wait()
}
兩邊再放入同一個 worker_test.go。它建立多個 job、用 mutex 記錄次數,最後斷言每個 job 恰好執行一次,而且 Run 回傳時全部完成:
package worker
import (
"sync"
"testing"
)
func TestRunExecutesEveryJobOnce(t *testing.T) {
const n = 8
seen := make([]int, n)
jobs := make([]func(), n)
var mu sync.Mutex
for i := 0; i < n; i++ {
index := i
jobs[i] = func() {
mu.Lock()
seen[index]++
mu.Unlock()
}
}
Run(jobs)
for i, count := range seen {
if count != 1 {
t.Fatalf("job %d ran %d times", i, count)
}
}
}
這裡故意留下兩個現代化候選:Go 1.22 起,for loop 每輪會建立新的變數,job := job 可移除;而 WaitGroup.Go 是 Go 1.25 才加入,只應出現在第二個 fixture。
步驟 3:同一 prompt 跑 without/with Skill A/B
對 Claude Code 與 Codex 各跑一次下面的四格矩陣,總共八組;每組從同一個乾淨 commit 開始。without 組先卸載 plugin,with 組安裝已固定的 checkout。模型、推理設定、prompt、可用工具與測試都保持相同:
在不修改 go.mod、公開 API 與 Run 行為的前提下,現代化 worker.go。只改必要檔案;完成後列出採用的版本規則、實際執行的驗證命令與 exit status。

with 組還要保存 Skill 的中間證據。它應針對 worker.go 跑完整 list;Go 1.25 若評估改寫,再跑 explain sync_waitgroup_go。Go 1.24 的清單不應包含這條 1.25 規則。若 Agent 沒自動呼叫,可在 session 內明確執行 /modern-go-guidelines:use-modern-go,但要把「自動觸發」與「人工觸發」分開記錄,不能混成同一組。
每次跑完,把 git diff、Agent transcript、list/explain 輸出與驗證 log 放到獨立資料夾。想把評測設計再做得更嚴謹,可搭配〈Agent Skill 路由 A/B 測試〉的控制變因方法。
步驟 4:先寫預期邊界,再看 Agent 答案
- Go 1.24:可以移除多餘的
job := job,但不能呼叫wg.Go;相容寫法仍是Add(1)、go func、defer Done()。 - Go 1.25:可以評估改成
wg.Go(job),但「API 存在」不是唯一條件。官方文件要求傳入的函式不得 panic;當 WaitGroup 為空時,Go必須發生在Wait之前,遞迴或巢狀啟動也要檢查生命週期。 - without Skill:不預設一定失敗。它可能剛好寫對、可能兩版都用舊 pattern,也可能在 1.24 錯用新 API;誠實記錄即可。
- with Skill:不因用了新寫法就加分。若它忽略 panic contract、改變呼叫順序或測試失敗,仍判定不合格。
這個語意閘門不是吹毛求疵。go-modern-guidelines 的 issue #27 在 2026 年 8 月指出,當時 sync_waitgroup_go 的說明沒有完整帶出 panic 與生命週期限制;Go 官方 API 文件才是最後依據。Skill 適合當候選規則索引,不適合取代標準庫 contract。
步驟 5:用四張收據驗收 Version-Aware Skill
先在每個 fixture 跑格式、靜態分析與行為測試,再用模組的最低 toolchain 重跑。Go 1.23 起,go vet 內建 stdversion analyzer,會找出對目前檔案有效 Go 版本而言太新的標準庫符號;Go 1.27 的 go test 也會預設呼叫它,但為了相容較舊 CI,仍明確執行 go vet。
# 在 fixtures/go124
gofmt -w worker.go worker_test.go
go vet ./...
go test ./...
GOTOOLCHAIN=go1.24.0 go test ./...
# 在 fixtures/go125
gofmt -w worker.go worker_test.go
go vet ./...
go test ./...
GOTOOLCHAIN=go1.25.0 go test ./...

若 GOTOOLCHAIN 首次下載被公司網路擋住,不要刪掉這個檢查;改用預先安裝 Go 1.24/1.25 的 CI matrix。A/B 最終記三個離散指標即可:錯用新 API 次數、可移除卻保留的過時 pattern 次數、四張收據是否全綠。這比主觀打「程式看起來更漂亮」更容易複核。
把方法泛化到 Python 與 Node:四層模板
JetBrains 這個 plugin 只處理 Go;可泛化的是架構,不是它的規則內容。若要自己做 Version-Aware Skill,可沿用四層:
- Resolver:從可信專案檔讀版本。Python 可讀
pyproject.toml的requires-python,Node 可讀package.json的engines.node;缺值時應 fail closed 或要求明確參數,不要偷偷採本機最新版。 - Index:每條規則保存
id、since_version、一句話與風險等級,讓list只回傳可用索引。 - Explain:按 rule ID 載入 contract、反例與最小 diff;避免每次都把整本文件塞進 context。
- Verifier:用對應最低 runtime、linter、type checker 與 tests 產生收據。版本欄位若只是提示而不被工具強制,CI 必須補上 enforcement。
這也解釋了它和 AGENTS.md/規則閘門的分工:rules 放「每次都要遵守的流程」,Version-Aware Skill 放「依版本選擇的知識」,CI 放「不符合就不能合併的機械證據」。
真正可攜的不是某一條 Go 規則,而是把知識路由與驗收責任拆開:前者幫 Agent 縮小版本相容的候選集合,後者阻止一段看似合理、實際未通過最低版本與行為測試的改動直接進入正式分支。
六個最常見的失敗點
- 只跑裸
list:它會看本機 Go,不會自動把目前工作目錄當目標;傳--file-path。 - go.mod 沒有 go directive:plugin 的現行 resolver 會回退本機工具鏈,可能高估專案邊界;先補明確版本再做實驗。
- 把 auto toolchain 當相容性:較新工具鏈能下載、能編譯,不代表最低支援版本也能編譯。
- 只看規則、不看 contract:
WaitGroup.Go的 panic 與 Wait 排序就是典型反例。 - 沒有固定 marketplace checkout:A/B 期間自動更新,等於中途換掉處置組;保存 commit SHA、CLI 版本與 plugin list。
- 只跑一次就宣布提升:生成式模型有抽樣變異。至少每格三次,逐次公開成功/失敗,不要只挑最好看的 diff。
常見問題 FAQ
1. Version-Aware Skill 和 CLAUDE.md 一樣嗎?
不一樣。CLAUDE.md 適合放穩定的專案政策;Skill 可以封裝會更新的規則、腳本與按需說明。最好的組合是 CLAUDE.md 要求先查版本,Skill 負責回傳版本相容內容。
2. 安裝 plugin 後還需要 Go 嗎?
需要。marketplace 本身能加入,但首次執行 wrapper 會用 go install 安裝 CLI;PATH 上沒有 Go 就無法完成版本解析與規則查詢。
3. Claude Code 會自動觸發 Skill 嗎?
官方設計會在修改 Go 時自動觸發,但 A/B 不應只相信文字宣告。保存 transcript 與 list/explain 輸出;必要時另開一組明確 slash command 的人工觸發測試。
4. Codex 也能使用同一套規則嗎?
可以。repository 同時提供 Claude Code 與 Codex marketplace manifest,規則與 wrapper 共用;但兩邊的安裝 scope、更新與移除指令不同,收據要分開保存。
5. go.mod 是 Go 1.24,可以用 WaitGroup.Go 嗎?
不可以。它在 Go 1.25 才加入。即使開發機是新工具鏈,模組最低版本仍是 1.24;要使用就先做正式版本升級,而不是讓 Agent 偷改 API。
6. go vet 通過就代表重構安全嗎?
不代表。vet 能抓部分靜態問題與太新的標準庫符號,但不能證明並行順序、panic、資料競爭或業務行為相同;仍要跑單元測試,必要時加 -race 與整合測試。
7. 為什麼不用最新版 marketplace 直接測?
日常使用可以追新版;受控比較必須固定處置內容。用本機 checkout 的完整 SHA,才能讓 Claude Code、Codex 與下一位驗證者看到同一套 Skill。
8. 這個方法能直接支援 Python/Node 嗎?
這個 plugin 不能;你可以重用 resolver → index → explain → verifier 的設計。各語言的版本檔、相容規則與驗證工具要獨立建立、測試與維護。
新手最後帶走三件事
- 先定版本,再談現代:「最新」不是全域值,而是
go.mod允許的集合。 - 先 list,再 explain:把索引與細節分開,才不會用更多 context 換來更多噪音。
- 讓工具鏈做裁判:Skill 給建議,最低 toolchain、vet 與 tests 給能否合併的答案。
接著閱讀
左右滑動查看更多推薦
最小可行做法很簡單:挑一個有測試的 Go 檔、複製成 1.24/1.25 兩個 fixture、固定同一個 Skill checkout,然後讓每個答案交出四張收據。做完這一次,你得到的不只是 Go plugin,而是一套可搬到任何語言的版本感知 Agent 工程法。更多基礎路線可從 AlphaLab AI 專區與免費課程繼續學。
封面所用 JetBrains 標誌依官方品牌規範呈現且未經修改。Copyright © 2026 JetBrains s.r.o. JetBrains and the JetBrains logo are trademarks of JetBrains s.r.o.






