description 改再強也沒用:skill 正文在 context 裡的一生
檔案在那裡。YAML 沒問題。/ 選單裡就是沒有它。
monorepo,你在 repo root 跑 claude,前一天替前端寫了一份 apps/web/.claude/skills/deploy-web/SKILL.md,存了檔,路徑確認過三次。打 / 找不到它,直接打 /deploy-web 也叫不動。接下來你會做的事幾乎是固定的:回頭檢查 frontmatter 的縮排、懷疑資料夾名稱要不要跟 skill 名一致、最後乾脆重開一個 session。三件事全部白做。
「我的 skill 好像不靈了」這句話底下藏著兩種完全不同的故障,而它們的解法互斥。一種是它根本沒進場,另一種是它進場過、後來被丟掉了。拿治第一種的方法去治第二種,你改幾次都不會好,而且你不會收到任何錯誤訊息告訴你方向錯了。
它只往上掃,不往下掃
文件對第一種故障講得很白:
Skills in a
.claude/skills/directory below where you started don’t load at startup. They load the first time Claude reads or edits a file in that subdirectory and stay available for the rest of the session.
方向是不對稱的,這點特別容易記反。你的起始目錄、加上一路往上到 repo root 的每一層 .claude/skills/,開場就全部載入;起始目錄底下的那些,開場一個都不載。
公寓的規約也是這樣發的。你搬進去那天,管理室把你這一層跟樓上每一層的都一次塞給你;樓下那幾戶的,要等你哪天真的走下去一趟,才會有人拿給你。在那之前你手上沒有那張紙,不代表那張紙寫錯了。
1 | your-monorepo/ |
在它載入之前,/ 選單看不到、打名字也叫不動。對那個時間點的 session 來說,它還不存在。直覺會以為 Claude Code 掃的是整個 repo。它只往上掃。
解法有兩個,都不用重開 session。隨便叫 Claude 去讀一個 apps/web/ 底下的檔案,它就進場了,而且該 session 剩下的時間都在。或者直接 /add-dir apps/web 把那個目錄拉進來,這個做法需要 v2.1.257 以上。另外如果你習慣用 /cd 搬動 session,v2.1.246 之後它會順手補上新目錄的 project skills。
進場之後,那個檔案就不會再被讀第二次
skill 被叫起來的時候,算繪完的正文以一則訊息的形式進到對話裡,之後每一輪都還在。但那則訊息是載入當下的快照。文件對這件事的說法只有一句:
Claude Code does not re-read the skill file on later turns
你在 session 中途去改 SKILL.md,這個 session 用的還是舊的那份。改完覺得沒效果,跑去把描述寫得更用力,再改一次,還是沒效果,因為你改的檔案根本沒有被重新讀取。
同一節文件裡還藏著一組壽命差很多的東西:正文會留著,權限不會。allowed-tools 給的授權在你送出下一則訊息時就清掉了,正文卻會一路待到壓縮。同一個檔案、同一次呼叫,一個撐一則訊息,另一個撐到壓縮為止。
文件順著這點給了一條寫作建議:SKILL.md 要寫成通篇適用的常設指令,不要寫成「第一步做 A、第二步做 B」的一次性流程。理由很務實,那份正文會在對話裡待很久,而不會有人在第四十輪的時候提醒模型「你現在該回到第 3 步了」。
同一個 skill 叫第二次,有時候免費,有時候不是
這裡有個我一開始猜錯的地方。重複叫同一個 skill,Claude Code 的判斷基準不是名字相同,是算繪後的內容逐字相同。
內容一模一樣,它只補一行「已經載入過了」的註記,不會有第二份正文。內容不一樣,整份正文再 append 一次。會讓內容不一樣的原因文件明列了兩個:參數變了,或者正文裡的動態 context 指令產出了新的輸出。
第二個原因才是麻煩的那個。SKILL.md 裡可以塞在送給模型之前先跑一次的 shell 指令,輸出會取代掉佔位符。如果你塞的是印時間、印 git 狀態這類每次結果都會變的東西,那這個 skill 每被叫一次,context 裡就多一份完整正文。「我的 context 怎麼一直莫名其妙變滿」有時候答案就在這裡,而且它長得完全不像一個 bug。
這筆帳還會往下滾。一份很長、又帶著動態指令的 skill,你在一場對話裡叫了四次,就是四份完整正文躺在那邊佔位子,加速你撞上壓縮的門檻。撞上之後,前面說的那套接回規則才開始跑,而它只會保留你最後那一次。等於你花了四份的 context,換回一份、而且是被切到剩前 5,000 tokens 的版本。這個設計沒有錯,它要的就是不重複塞相同內容;只是「相同」的判準嚴格到逐字,比你以為的嚴格。
壓縮那一刀,砍的方向跟你以為的相反
換一個場景。長 session,你開頭先叫了 /code-style,那是你們團隊的程式碼規範,很長。接下來兩小時陸續叫了一串:
1 | /code-style <- 團隊規範,很長,開場就叫 |
壓縮跑完之後,Claude 開始寫出完全不符合你們規範的程式碼。你把 /code-style 的 description 改得更強,在 CLAUDE.md 加了一行「務必遵守 code-style」,都沒用。
原因在這段:
Auto-compaction carries invoked skills forward within a token budget. When the conversation is summarized to free context, Claude Code re-attaches the most recent invocation of each skill after the summary, keeping the first 5,000 tokens of each. Re-attached skills share a combined budget of 25,000 tokens. Claude Code fills this budget starting from the most recently invoked skill, so older skills can be dropped entirely after compaction if you have invoked many in one session.
四件事同時在發生。壓縮的時候,每個 skill 只有最近一次的呼叫會被重新接到摘要後面,同一個 skill 你叫過三次,只有最後那次回得來。接回來的也不是完整的,每個 skill 只保留正文的前 5,000 tokens,那是「每個 skill 在一次壓縮裡的保留量」,不是整場對話的額度。然後所有被接回來的 skill 共用一個 25,000 tokens 的總額,這個數字是大家一起分,不是每人一份。填的順序則是從最近叫的那個往回填。
填到沒額度為止。填不到的那幾個,不會留下一截開頭。它們整個不在了。
公司要你把桌上的東西全部收進一個固定大小的箱子,來收的人從你最近碰過的那幾樣開始放,放滿就停手。三個月前擱在桌角那本厚厚的規範手冊,不會被撕掉幾頁再硬塞進去,它會整本留在箱子外面。你回到位子上看見桌面清爽,第一個念頭通常是「東西都收好了」,不會是「有東西沒進去」。
/code-style 是你最早叫的,在這個排序裡穩穩排最後一名。
順手算一下:25,000 除以 5,000 是 5。如果每個 skill 都吃滿 5,000 的上限,一次壓縮最多接得回五個。這個「五」是我從那兩個數字推出來的,文件沒有這樣寫,而且實際上多數 skill 根本用不到 5,000 tokens,所以通常接得回更多。它的用處只是給你一個最壞情況的量感:一場對話裡叫過的 skill 只要多過一隻手,最早那幾個就該開始擔心了。
最花冤枉力氣的是接下來這一步。規範失效,直覺會說那個 skill 的 description 寫得不夠有說服力,於是回去把它形容得更重要。這個動作完全動不到問題。description 管的是「模型會不會想去叫它」,那是另一套清單、另一套預算,站上 2026-08-26 那篇 把那一套拆過,這裡不重講。至於「它的正文現在還在不在 context 裡」,是完全另一件事。你在 A 系統上使勁,壞掉的是 B 系統。
兩套預算還差在一個地方。「常用」在第一套是護身符,在第二套完全不管用,因為第二套只看最近有沒有叫。一個你每天都在用、但這場對話只在開頭叫過一次的 skill,壓縮的時候照樣第一個被丟。
什麼時候它反而不是這個原因
逆著問一次,不然這篇會變成一把什麼都往上敲的鎚子。skill 看起來不聽話,有很大一部分根本不是正文被砍了。文件給的分界很乾脆:
If a skill seems to stop influencing behavior after the first response, the content is usually still present and the model is choosing other tools or approaches.
所以要先確認一件事:這場對話壓縮過沒有?compacting conversation 那句話有沒有出現過?
沒有的話,正文八成還在,問題出在模型自己挑了別條路走。這時候加強 description 跟指令是對的方向,不是白工。而如果你要的是「它一定得照做」,那就不該靠說服,改用 hooks 去強制,hooks 是決定性的,模型繞不過去。
有壓縮過、那個 skill 又很大、或者它後面你還叫了好幾個別的,那就是正文真的被砍了。重新叫一次就好。
常設規則不該住在 skill 正文裡
講到這裡我的立場很明確:要跨整場對話都成立的東西,寫進 CLAUDE.md;skill 正文只放這次任務要做的事。這不是品味問題,是兩者的存活機制不一樣。CLAUDE.md 每個 session 開場重新載入,skill 正文則要跟其他 skill 去搶那 25,000 tokens。
壓縮本身的處理順序也指向同一個做法:
Claude Code manages context automatically as you approach the limit. It clears older tool outputs first, then summarizes the conversation if needed. Your requests and key code snippets are preserved; detailed instructions from early in the conversation may be lost. Put persistent rules in CLAUDE.md rather than relying on conversation history.
想更精準控制留下什麼,文件給了兩個手把:在 CLAUDE.md 加一個 Compact Instructions 段落,或者跑 /compact 的時候帶一個焦點進去。
什麼會讓我改變立場?如果哪天 5,000 跟 25,000 變成可調的設定,或者壓縮丟掉某個 skill 的時候會給你一條看得到的訊息,那 skill 正文就可以放心承載長期規範了。目前這兩件事文件都沒有給。
沒有訊息這件事,是這個設計現在最實在的代價。文件有寫清單那套預算爆掉時會往 debug log 寫一條 warning,但壓縮把 skill 正文丟掉的時候會不會也留下什麼,文件沒寫。所以「我怎麼知道自己被砍了」目前沒有官方答案,你只能從模型行為變了這件事反推。麻煩在於,行為變了看起來跟「它只是不想用」一模一樣,而後者會把你推回去改 description。
這篇全部來自 2026-09-21 當天的官方文件,我只讀了文件,沒有實際跑過。上面的版本號、5,000 與 25,000 這兩個數字、以及所有行為描述,都是那天那份文件寫的內容,而那個頁面本身沒有標注自己的最後更新日期。另外有三件文件沒寫、我也答不出來的事:5,000 tokens 的截斷點會不會對齊段落邊界、同一則訊息裡一次叫好幾個 skill 的時候誰算「比較近」、以及正文被丟掉之後模型那邊還看不看得到這個 skill 的描述。
檔案是最後才該打開的東西
那個 skill 看起來不聽話的時候,不要先開檔案。
先確認它有沒有進場過。如果它住在起始目錄底下的子資料夾,/add-dir 那個路徑,或者隨便叫 Claude 讀一個那底下的檔案。再確認這場對話壓縮過沒有,壓縮過就重新打一次那個 skill 的名字,一秒的事,比你改任何一行 frontmatter 都快。兩件都確認完,正文確定在場,它還是我行我素,那才輪到 description,而且這時候真正該做的是寫一個 hook 把行為釘死,不是把描述再形容得動人一點。
改 description 之所以那麼受歡迎,是因為它是唯一一個你可以一直做下去的動作。它不會報錯,也不會拒絕你。
原文來源:Extend Claude with skills - Claude Docs、How Claude Code works - Claude Docs










































































































































































































