如何撰寫自己的 agent skill:從失敗開始
從一次真實失敗撰寫 agent skill,了解 SKILL.md 結構、決定觸發時機的 description 行,以及如何用相同任務測試是否修正成功。
從一次真實失敗撰寫自己的 agent skill
撰寫自己的 agent skill,最好的方法是從一次真實失敗中提煉。找出 coding agent 曾經兩次做錯的任務,記下你兩次輸入的修正內容,並將該修正儲存為 agent 可自行載入的 SKILL.md 檔案。之後其餘內容都只是機械性的設定:檔案配置,以及決定該 skill 是否會觸發的那一行。
這個順序很重要。憑空撰寫的 skill,記錄的是你從未遇過的問題,而且每次工作階段都會佔用 context。從你親眼觀察到的失敗中提煉 skill,則會自帶測試:再次提出相同要求,確認 agent 這次是否能正確處理。如果你還不熟悉這個格式,請先閱讀agent skill 是什麼,以及 agent 如何載入它,再回來撰寫自己的 skill。
從 agent 兩次做錯的工作開始
做錯一次可能只是偶然。做錯兩次就形成模式,而模式值得寫入檔案。
以下是實際伺服器上會反覆發生的失敗情境。你要求 agent 在 nginx 中加入反向代理區塊。它修改了 /etc/nginx/conf.d/app.conf,接著執行 sudo systemctl restart nginx。修改內容有錯字,因此 nginx 拒絕啟動;你修正前,網站都會維持中斷:
nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12
Job for nginx.service failed because the control process exited with error code.你在對話中修正錯誤。先使用 sudo nginx -t 測試設定,再使用 reload 套用變更,而不是使用 restart。一週後,在另一項工作中又犯了相同錯誤。第二次發生時,就是應該記錄的訊號。
趁失敗仍在眼前時,記下兩件事:你輸入的請求,以及你提供的修正,保留你當時使用的措辭。這兩行內容就會成為 skill。請求會告訴你觸發條件必須比對什麼。修正則是完整內容。
Anthropic 自己的撰寫指南也把這點列在最前面。先在沒有 skill 的情況下,讓 agent 執行具代表性的工作,記錄它失敗的位置,再撰寫能修正這些失敗的最少指示。失敗情境就是規格;如果無法追溯到某個失敗情境,通常就表示沒有人真正需要這個 skill。
若要查看相同提煉過程的完整範例,可以從頭讀完 Ponytail 將 agent 過度改寫內容這項反覆失敗,轉換成一個 skill,再撰寫自己的 skill。
技能的結構
技能是一個目錄,其中包含一個必要檔案。
.claude/skills/nginx-config-changes/
├── SKILL.md
├── reference/
│ └── proxy-headers.md
└── scripts/
└── check-and-reload.shSKILL.md 開頭是 frontmatter 區塊,其中包含以 YAML 撰寫的幾項設定(Docker Compose 檔案也使用相同的設定格式),並以 --- 標記包圍,後面接著 Markdown 指示。以下是上述失敗案例的完整技能。
---
name: nginx-config-changes
description: Tests and reloads nginx safely after a config edit. Use when editing files under /etc/nginx, adding a server block or a reverse proxy, or changing a TLS certificate path.
---
## Rules
Run `sudo nginx -t` after every edit under `/etc/nginx`. Do not touch the service until it prints `test is successful`.
Apply the change with `sudo systemctl reload nginx`. Never use `restart`. A reload keeps the running workers serving traffic until the new config parses, so a broken config leaves the site up. A restart stops nginx first, so a broken config takes the site down.
If `nginx -t` fails, fix the file and test again. Never reload a config that failed the test.
For the proxy header defaults this project expects, see [reference/proxy-headers.md](reference/proxy-headers.md).這個檔案不到 20 行,但已經是完整的技能。各部分如下:
name:最多 64 個字元,只能使用小寫字母、數字與連字號,且不得包含claude或anthropic。在個人技能或專案技能中,這只是顯示標籤。實際輸入的命令來自目錄名稱,因此這個技能的命令名稱是/nginx-config-changes。description:說明技能的功能與使用時機,最多 1,024 個字元。這一行負責實際觸發技能,下一節只會說明這一點。- 主體:僅在技能實際觸發時載入的指示。
reference/:代理程式按需讀取的額外檔案。請從SKILL.md建立連結,並將連結深度限制為一層,因為從另一個參照檔案連結的檔案,通常只會讀取部分內容。scripts/:代理程式會執行而不是讀取的檔案。只有輸出內容會占用上下文,因此 300 行的 script 所需成本很低。
目錄的位置會決定哪些人可以使用這項技能。
- 儲存庫中的
.claude/skills/<name>/SKILL.md:只有這個專案可以使用,並會隨儲存庫提供給所有 clone 該儲存庫的人。 ~/.claude/skills/<name>/SKILL.md:你機器上的所有專案都可以使用,但其他人的機器無法使用。<plugin>/skills/<name>/SKILL.md:隨 plugin 一起提供,只要啟用該 plugin,就能在任何位置使用。
使用 mkdir -p .claude/skills/nginx-config-changes 建立技能,然後寫入檔案。Claude Code 會監看這些目錄,因此編輯現有技能後,變更會在目前執行中的工作階段生效。若工作階段啟動時不存在頂層 skills 目錄,之後才建立該目錄就需要重新啟動,因為工作階段開始時沒有可監看的目錄。
description 欄位是檔案中影響最大的一行
啟動時,agent 會將每個可用 skill 的 name 與 description 載入其 context。它不會載入內文。當你的請求送達時,這一行就是判斷該 skill 是否相關的唯一依據。因此,即使內文寫得再完善,只要 description 含糊不清,就永遠不會被讀取。
description 應使用第三人稱撰寫。「安全地測試並重新載入 nginx」即可。「我可以協助你處理 nginx」則不行,因為這段文字會注入 system prompt,在該情境中使用第一人稱會像是模型在描述自己。
其中應包含兩項資訊:skill 的功能,以及適用的條件。將重要的使用情境放在前面,因為 Claude Code 會在 1,536 個字元處截斷清單項目。另有選用的 when_to_use 欄位,可放入額外的觸發詞組與請求範例;該欄位會附加在 description 後面,並受相同的字元上限限制。
接著使用你實際會輸入的詞語。description: Helps with nginx 不會匹配任何內容,因為沒有人會輸入「helps with」。上述版本列出了 /etc/nginx、server block、reverse proxy 與 TLS (transport layer security) certificate path,這大致涵蓋任何應觸發該 skill 的請求所使用的詞彙。
description 的測試方式如下:將這一行文字與你準備輸入的請求,一起提供給從未看過內文的人,詢問他們該 skill 是否適用。如果他們無法判斷,模型也無法判斷。
保持內文精簡,因為內容會持續保留在上下文中
呼叫 skill 時,其轉譯後的內容會以一則訊息加入對話,並在整個工作階段中持續保留。Claude Code 不會在後續回合重新讀取該檔案。你寫入的每一行都會成為整個工作階段的成本,而不只影響單一回答。
Anthropic 建議將 SKILL.md 控制在 500 行以下,並將詳細內容移至個別檔案。內容壓縮能說明這個數字並非任意設定。對話經摘要以釋放上下文時,Claude Code 會重新附加每個 skill 最近一次的呼叫內容,每個 skill 最多保留前 5,000 個 token,並從最近呼叫的 skill 開始,在合計 25,000 個 token 的額度內填入內容。過長的 skill 會在中途遭截斷。多個過長的 skill 也可能讓其他 skill 完全被排除。
因此,只寫入模型原本不知道的內容。模型知道 nginx 是什麼,也知道 reverse proxy 的用途。模型不知道你對 reload 超過 restart 的內部規範,而這項規範正是此檔案存在的唯一原因。
如果 skill 要求代理程式執行隨附的 script,請使用 ${CLAUDE_SKILL_DIR} 指定路徑,讓它能在 skill 的任何安裝位置解析,並預先核准相同的命令,避免執行時因權限提示而停止。
---
name: nginx-config-changes
description: Tests and reloads nginx safely after a config edit. Use when editing files under /etc/nginx, adding a server block or a reverse proxy, or changing a TLS certificate path.
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/check-and-reload.sh *)
---此授權涵蓋呼叫 skill 的該回合,並會在你傳送下一則訊息時清除,因此不會在未察覺的情況下成為永久權限。
如何證明技能會觸發
觀察技能載入只能確認代理程式找到了它,無法確認答案已經改變。兩者都要檢查,而且要在新的工作階段中檢查,因為撰寫技能的工作階段已經保留了撰寫過程中的所有內容。這些殘留內容會掩蓋檔案中的缺漏。
- 在專案中使用
claude啟動新的工作階段。 - 以一般工作日會使用的方式,用自己的話輸入請求,不要提及技能名稱。
- 觀察技能是否被呼叫。如果技能沒有觸發,請修正描述。此時問題還不在內容。
- 使用
/nginx-config-changes手動呼叫技能作為對照。手動呼叫時行為正確,但透過請求呼叫時行為錯誤,表示問題在觸發條件,而不是指示內容。 - 關閉技能後執行相同請求,並比較兩個答案。在
/skills選單中選取技能,按Space將其狀態切換為off,再按Enter儲存。這會在.claude/settings.local.json中寫入skillOverrides項目;完成後再次按Space,即可將狀態切換回on。 - 撰寫幾個不應觸發技能的請求,確認技能對這些請求保持靜默。
若要自動化這個流程,請從官方 marketplace 安裝 skill-creator plugin。
/plugin marketplace add anthropics/claude-plugins-official
/plugin install skill-creator@claude-plugins-official如果安裝輸出顯示 Run /reload-plugins to activate.,請執行該命令。接著要求 Claude 依技能名稱評估技能。plugin 會在技能目錄中的 evals/evals.json 儲存測試案例,並在各自的 subagent 中執行每個案例,因此每次執行都會從乾淨的 context 開始。接著它會產生啟用技能與未啟用技能的比較;這才是可信的數字:相對於技能所耗用的 tokens 與時間,衡量通過率的提升幅度。
失效模式:技能完全不會觸發
您輸入請求後,代理程式仍執行原本錯誤的操作,而且沒有出現技能列。請依序檢查以下項目。
- 描述只說明技能的用途,卻沒有說明何時使用,因此請求中沒有任何內容能與它相符。
- 描述未使用您輸入的詞彙。如果您說「nginx」,描述中就必須寫出 nginx。
- 前置資料中設定了
disable-model-invocation: true。這會讓描述完全不出現在模型的上下文中,技能只能由您使用/name叫用。 - 前置資料中的
pathsglob 會將啟用範圍限制為相符的檔案,而您目前處理的檔案並不相符。 - 技能位於起始目錄下的巢狀
.claude/skills/目錄中。代理程式必須先讀取或編輯該子目錄中的檔案,才會載入這些技能;在此之前,技能完全無法使用。
失效模式:技能持續觸發
相反的問題是描述過於寬泛,導致技能在不相關的工作中觸發。「處理伺服器時使用」幾乎符合伺服器儲存庫中的任何請求。接著,主體內容會載入到無法提供協助的工作中,並在本次工作階段的剩餘時間持續保留於上下文中。
請將描述縮小至實際重要的條件,並列出涵蓋的檔案或命令。如果技能只適用於特定檔案,請加入 paths glob。對於 deploy 或 commit 等具有副作用的操作,請設定 disable-model-invocation: true,再使用 /name 自行叫用,讓代理程式不會自行判定現在適合執行 deploy。
失效模式:該技能應放在規則檔中
CLAUDE.md 或 AGENTS.md 這類規則檔會在每個工作階段開始時載入,並套用至所有工作。技能內容只有在技能觸發時才會載入。判斷依據是適用頻率。凡是存放庫中每項工作都成立的事項,例如使用的套件管理程式,都應放在規則檔中。只適用於少部分工作的程序,例如上述的 nginx 規則,則應放在技能中。這樣在沒有人編輯 nginx 的期間就不會產生額外成本。
真正的失效原因,是將同一項指示同時放在兩處。兩份內容會逐漸不一致;當代理程式執行錯誤時,您也無法判斷它遵循的是哪一份。每項指示都應選定唯一的存放位置。技能、MCP servers 與規則檔之間的界線 涵蓋更複雜的情況,包括正確答案是 MCP(model context protocol)server 的情況:它會為代理程式提供新工具,而不是新指示。
分享前,先確認它已經發揮價值
經過一週實際工作仍然有效的技能,才值得提交。.claude/skills/ 中的專案技能會像程式碼一樣接受審查,並隨儲存庫一併提供,因此團隊成員複製儲存庫後,不需額外設定即可取得你的修正內容。在不同儲存庫之間移動技能而不使用複製貼上,則是另一個問題,詳見如何在儲存庫之間共用 agent 技能。
另有一項可攜性注意事項。Claude Code 接受一長串 frontmatter 欄位,但 Agent Skills standard 只允許 6 個欄位:name、description、license、compatibility、metadata 和 allowed-tools。如果 frontmatter 含有其他欄位,將技能上傳至 claude.ai 或打包供 Skills API 使用時,會直接失敗,而不是忽略該欄位:
Unexpected key(s) in SKILL.md frontmatter: argument-hint. Allowed properties are: allowed-tools, compatibility, description, license, metadata, name只使用這 6 個欄位,同一個檔案就能在 Claude Code 及其他讀取該標準的工具中載入。讓指令內容本身能適用於不同模型,則是另一項工作;詳見撰寫適用於任何模型的技能。
FAQ
SKILL.md 檔案應該多長?
請控制在 500 行以內,而且大多數實用的 skill 都應遠短於此。本文內容會在 skill 調用時載入對話,並在該工作階段的其餘時間持續存在,因此每一行都是持續成本,而不是一次性成本。請將較長的參考資料移至 skill 目錄中的獨立檔案,並從 SKILL.md 建立一層深度的連結,讓 agent 僅在需要時讀取。隨附的指令碼會直接執行,而不是讀取,因此成本只有其輸出內容。
為什麼我的 skill 從未觸發?
通常原因是描述,因為模型決定是否使用 skill 時,內容中只有描述可供參考。請確保描述說明何時使用 skill,而不只是說明它的功能,並包含你實際在請求中輸入的詞語。如果描述看起來正確,請檢查 frontmatter 中的 disable-model-invocation: true;此設定會讓模型完全看不到 skill。也請檢查 paths glob,確認它沒有將 skill 限制在你未操作的檔案上。若 skill 位於起始目錄下的巢狀 .claude/skills/ 目錄中,也可能導致此問題:只有在 agent 讀取或編輯該子目錄中的檔案後,skill 才會載入。
這應該是 skill,還是我規則檔中的一行?
請先確認它適用於多少工作。規則檔會在每個工作階段載入,因此應放入適用於所有工作的事實,例如套件管理器或分支命名慣例。skill 僅在觸發時載入,因此適合放置只適用於少部分工作的程序。請勿在兩處寫入相同指示,因為兩份內容會逐漸分歧,讓你無法判斷 agent 遵循了哪一份。
如何確認 skill 確實有幫助?
請與基準結果比較。收集幾個實際請求,在 skill 可用的全新工作階段中逐一執行,接著從 /skills 選單關閉 skill,再次執行這些請求,並將兩組回答並列比較。使用全新工作階段很重要,因為撰寫 skill 的對話仍包含你的說明,會讓不完整的檔案看起來像是完整的。skill-creator plugin 會代你執行這項比較,並在 token 成本旁報告通過率。
我可以在不同的 agent 上使用相同的 SKILL.md 嗎?
可以,只要使用 Agent Skills standard 定義的欄位:name、description、license、compatibility、metadata 和 allowed-tools。Claude Code 接受更多欄位,也支援其他工具不會執行的 body 功能,例如 shell command injection。若上傳的 skill 包含 standard 未定義的欄位,系統會失敗並明確列出允許的屬性。因此,請及早決定 skill 是只留在 Claude Code 中,還是需要移植到其他工具。