◥ AI 互動教室 ‹ 生成式 AI 導論
下載 .py 單獨開啟實驗場 ↗ 留言回報
GENAI 進階補充 · E · AGENT SKILLS

Agent Skills:
把 SOP 打包成 AI 的技能

主線〈AI Agent 與 MCP〉的生態系那一節,Agent Skills 只佔了一段:一份 SKILL.md, 平常只露 name 和 description 兩行。這一課把它拆開來量、拿去實測。 先玩一個真的實驗——同一個 skill、同一份 SOP,只改 description 那一句話,模型還叫不叫得到它?

模型
description
實測紀錄,2026-09-24:每句 prompt 跑 3 次,● 載入了 skill、○ 沒載入。點任一句看那 3 次各自做了什麼。 Claude 那組是 claude-haiku-4-5 在 Claude Code 2.1.281 裡跑;qwen 那組是本課的最小 skill loader(開源小模型)。

實驗場是真的 Python(在你的瀏覽器裡跑,不用安裝任何東西,也不用任何帳號或金鑰)。 首次載入約需 30–60 秒,正好夠你讀完第 1 節。每個實驗都有選單與滑桿可以拉,拉完立刻重算。

01 · 解剖

Skill 就是一個資料夾

一句話重點:Skill = 一個資料夾,裡面一份 SKILL.md——開頭幾行 frontmatter 寫 name 與 description,下面是寫給 AI 看的 SOP; 需要的話再附 scripts/、references/、assets/。

沒有 SDK、沒有伺服器、沒有要註冊的 API——就是檔案。下面是本課實驗用的玩具 skill: 幫一個四人小團隊寫週報,工時要從 timesheet.csv 加總(description 是節錄,全文在實驗場 3️⃣)。

weekly-report/ ├── SKILL.md ← 必要:frontmatter + SOP ├── scripts/hours.py ← 加總工時(會算錯的事交給程式) ├── assets/template.md ← 週報固定格式 └── references/style-guide.md ← 「給主管看」才需要讀的文風規則
--- name: weekly-report description: 產生 ACME 團隊的每週工作週報:用 scripts/hours.py 精確加總 timesheet.csv 的工時,套公司固定的週報格式。當使用者要寫週報、本週工作摘要、 status report、進度彙整…時使用——即使他沒說出「週報」兩個字。 不用於修改或檢查工時資料、一般書信、寫程式。 --- # ACME 週報 SOP 1. 先執行 python3 <本 skill 目錄>/scripts/hours.py timesheet.csv。 工時數字一律照抄腳本輸出,不要自己加總。 2. 讀 timesheet.csv 的 note 欄,每個專案歸納 2–4 條「本週完成」。 3. 套 assets/template.md 的格式輸出。 4. 使用者說要給主管看時,再讀 references/style-guide.md 的「主管版」規則。

frontmatter 的規則是開放標準(agentskills.io 規格,2026-09-24 查):

欄位必填規則
name是1–64 字;小寫英數與連字號;不能以連字號開頭/結尾、不能連續兩個連字號;要跟資料夾同名
description是1–1,024 字;要寫「做什麼」和「什麼時候用」
license否授權名稱或附帶的授權檔
compatibility否≤500 字;需要什麼環境(產品、系統套件、網路)
metadata否任意字串鍵值(作者、版本…)
allowed-tools否預先核准的工具清單(實驗性,各家支援程度不同)

真實世界的 skill 長什麼樣?做出這堂課的就是一個:本站 repo 裡的 make-lesson, SKILL.md 之外還有 2 份 references(工程底線、網站規範)、9 支 scripts、8 個範本。 實驗場 1️⃣ 把它和另外 8 個 skill 一個檔一個檔攤開,量給你看每層多少 token。

02 · 漸進揭露

三層載入:用到才付錢

一句話重點:Agent 啟動時只讀每個 skill 的 name+description(Level 1); 判斷用得上才讀 SKILL.md 全文(Level 2);做到那一步才讀參考檔、跑腳本(Level 3)。 這叫漸進揭露(progressive disclosure)。

為什麼要這麼麻煩?回想主線講過的兩件事:上下文有上限,而且 API 是無狀態的——每一輪都要把整包上下文重送一次。 塞進 system prompt 的每一個字,整場對話每一輪都在付錢。用本 repo 的 skill 實際量一次(token 用 tiktoken o200k_base,2026-09-24 的檔案快照):

層級什麼時候進上下文規格建議make-lesson 實測本 repo 9 個 skill 合計
Level 1一直都在(啟動就載入)約 100 tokens/個156561
Level 2判斷用得上才讀 SKILL.md< 5,000 tokens、< 500 行4,18920,695
Level 3做到那一步才讀/跑不限(沒讀就不花)42,02851,717

Level 1 的 561 只算 8 個能被模型自己叫的 skill(第 9 個 grill-me 設成只能手動叫,不進清單)。

換成 Claude 自己的 tokenizer 呢?我們在一個玩具專案裡用 Claude Code 2.1.281+claude-haiku-4-5 實測, 只改 .claude/skills/ 裝了什麼,讀 API 回報的 input tokens: 沒裝 skill 時每輪 21,012;裝進 make-lesson +198、publish-videos +212、九個全裝 +468; 而一旦真的叫了 make-lesson,下一輪一口氣 +5,376——那就是 Level 2 進場。

便宜不等於免費。Claude Code 把所有 skill 的描述排成一張清單,這張清單有字元預算(文件寫「context window 的 1%」)。 九個全裝那一次,debug log 當場跳出:

[WARN] Skill listing over budget: 21 skills, 8210 chars > 8000 budget — descriptions will be truncated.

21 個=Claude Code 內建的 13 個+我們 8 個。超過預算,最少用的 skill 描述會被截短、甚至只剩名字—— 而描述正是模型決定要不要叫它的唯一依據(下一節)。skill 不是裝越多越好,用不到的就關掉。

03 · 觸發

description 是 skill 唯一的招牌

一句話重點:模型打開 SKILL.md 之前,對這個 skill 的全部認識就是 description。 寫太模糊,該用的時候叫不到;寫太寬,不該用的時候亂叫——而且換個模型,結果可能完全不同。

開場那個實驗的設計照 agentskills.io 的建議:12 句 prompt,6 句該觸發(有直說「週報」的、沒說的、英文的), 6 句是「差一點」——跟 timesheet 或主管沾邊、但要的不是週報(改一筆工時、寫請假信、寫轉 Excel 的程式)。 每句跑 3 次,看模型有沒有載入 skill。Claude 那組結果(claude-haiku-4-5,2026-09-24,每格 18 次):

description該觸發(18 次)誤觸發(18 次)觀察
模糊版「協助處理報告。」120 英文的 status update 3 次全沒叫到;「主管要本週工作摘要」只叫到 1 次——另外兩次它自己讀 CSV、自己寫
精準版(上一節那段)180每一句該觸發的都是第一步就叫 skill
太寬版「跟 timesheet、工時、主管或撰寫文件有任何關係就用」181 請假信那句被叫了 1 次;Claude 其實很保守

沒叫到 skill 的那幾次,haiku 自己寫的週報裡「總工時」分別寫了 128.5、141、138 小時—— 正確答案是 141。格式也每次都不一樣。skill 沒被叫到的代價不只是「沒用到」,而是SOP 整個沒發生。

把開場 hero 的模型切到 qwen3.5-2b(開源 2B 小模型,接在本課的最小 skill loader 上): 同樣 12 句,模糊版和太寬版是每一句都叫,連「什麼是 OKR」都 3/3;精準版也還有 10/18 次誤觸發。 觸發品質是 description 和模型能力一起決定的——換 agent、換模型,觸發測試要重跑。

寫 description 的四條原則(agentskills.io〈Optimizing skill descriptions〉):

  1. 用祈使句告訴 agent 何時動手:「當使用者…時使用」,而不是「這個技能可以…」。
  2. 寫使用者想達成什麼,不是內部怎麼實作。
  3. 主動一點:把沒說出關鍵字的說法也列進去(「即使他沒說出『週報』兩個字」、status report、進度彙整)。
  4. 畫邊界:加一句「不用於…」,擋掉差一點的請求;總長守在 1,024 字內、重點放最前面(清單超預算時後面會被截掉)。

另一個實測細節:「timesheet.csv 每個欄位代表什麼意思?」三個版本都沒觸發——agent 通常只在任務需要額外知識或流程時才去翻 skill, 自己讀一下檔就能答的事,description 寫得再像也不會叫。

04 · 腳本

確定性的工作交給程式,不靠模型

一句話重點:會算錯、要每次都一樣的步驟(加總、轉檔、檢查格式),寫成 scripts/ 讓 agent 去執行—— 腳本的程式碼不進上下文,只有輸出進來。

週報 SOP 第 1 步寫「工時一律照抄腳本輸出,不要自己加總」。為什麼要這麼兇?我們把 36 筆 timesheet 直接貼給模型、 不准用工具,要它加總四個專案的工時(實測,2026-09-24):

誰來加總次數四個專案全對
qwen3.5-2b 心算(12/24/36 筆各 5 次)150
claude-haiku-4-5 心算(36 筆)53
scripts/hours.py(15 行 Python)每次每次

重點不是「模型不會加法」——大模型多數時候是對的。重點是 SOP 要的是每次都對、而且查得到為什麼對。 寫成腳本還順便省 token:本 repo 的 publish-videos skill 帶了 3 支腳本、共 7,037 tokens 的程式碼, 它的 SKILL.md 開宗明義:「格式由程式與 video/config.json 決定,不由對話決定」——那 7 千 tokens 從來不必進上下文。

實驗場 4️⃣ 有兩段載入了 skill 的完整執行紀錄可以重播。haiku 照 SOP 叫 skill → 跑 hours.py → 讀 timesheet → 讀範本 → 交件, 工時表一字不差是腳本輸出;但第 4 步「要給主管看就讀文風規則」它沒做——Level 3 讀不讀,是模型判斷的。 2B 小模型也照做跑了腳本、工時全對,卻跳過「讀 note 欄」,完成事項寫成空話: 交給腳本的部分穩如泰山,靠模型自律的部分看模型本事。

05 · 選型

Skill、MCP、CLAUDE.md、subagent、slash command:什麼時候用哪個?

一句話重點:永遠要遵守的寫進專案記憶(CLAUDE.md);特定任務的做法包成 Skill; 要連外部系統用 MCP;要乾淨的獨立上下文開 subagent;只准人決定何時跑用 slash command。
機制什麼時候進上下文適合放什麼本站 repo 的真實例子
CLAUDE.md(專案記憶)每次對話開頭整份載入每一件事都要守的規則、專案地圖 「course id 全站唯一」「marimo 全站釘同一版」這類硬性約束
Skilldescription 常駐,全文用到才讀某類任務的 SOP+腳本+範本 make-lesson(建課)、publish-videos(上傳影片)
MCP server工具說明進上下文,呼叫時才執行連外部系統、拿即時資料(程式跑在另一個行程) 本站 MCP 系列課;新版協定見補充 D
Subagent自己一份獨立上下文大量探索、平行工作、不想污染主對話 這個補充系列 6 課,就是 6 個 subagent 平行各寫一課
Slash command人打 /名稱 才跑何時執行要由人決定的固定流程 grill-me:設了 disable-model-invocation: true,模型不會自己叫

它們不是五選一,常常疊著用:本 repo 的 CLAUDE.md 有一節的標題就是「建課一律走 make-lesson skill」—— 記憶負責指路、skill 負責做法。在 Claude Code 裡,自訂 slash command 已經併進 skill(同一個資料夾格式), skill 也能設定在 subagent 裡執行、能叫 MCP 工具。用程式呼叫這一整套(Agent SDK)是補充 C 的主題。

先自己判斷,再展開看答案:

「所有回覆都要用繁體中文、金額一律加千分位」 CLAUDE.md。每一次對話、每一件事都要守的規則,本來就該一直在上下文裡;做成 skill 反而要等模型「判斷用得上」才讀。
「每月初照 12 步流程做月結報表,其中金額加總常出錯」 Skill+scripts/。只在月結時需要(description 寫清楚何時用),加總交給腳本;平常只佔幾十個 tokens。
「查公司 CRM 裡某客戶的最新訂單」 MCP server(或一般的工具呼叫)。資料在外部系統、每次都要即時查,這是「工具」不是「做法」。 若查完還有固定的整理 SOP,可以再包一個 skill 來指揮怎麼用這個工具。
「翻完整個 repo 的 300 個檔案,找出所有用到舊 API 的地方」 Subagent。大量讀檔會把主對話的上下文塞爆;讓分身在自己的上下文裡找,只把結論交回來。
「正式部署到 production」 Slash command(或 skill 加上 disable-model-invocation: true)。流程可以寫好, 但「什麼時候部署」要由人決定,不能讓模型覺得時機到了就自己跑。
06 · 開放標準

一份 SKILL.md,幾十個 agent 讀得懂

一句話重點:Agent Skills 由 Anthropic 發起、以開放標準釋出(agentskills.io)——同一個資料夾, Claude Code、Codex、GitHub Copilot、Cursor、Goose、OpenCode… 都能讀。但各家的擴充欄位不通用。

agentskills.io 的支援名單在 2026-09-24 列了 46 個產品,包括 Claude(網頁版與 API)、Claude Code、OpenAI Codex/ChatGPT、 GitHub Copilot、VS Code、Cursor、JetBrains Junie、Gemini CLI、Kiro、Roo Code,以及開源的 Goose、OpenCode、OpenHands 等。 各家放 skill 的位置不同:Claude Code 讀 .claude/skills/,Gemini CLI 讀 .gemini/skills/ 或別名 .agents/skills/。本站 repo 的做法是 grill-me 本體放在 .agents/skills/、從 .claude/skills/ 建一個符號連結過去——一份檔案,兩邊都讀得到;旁邊的 agents/openai.yaml 是 Codex 自己的擴充設定。

可攜性有兩個真實的坑,都是這一課實測撞到的:

  1. 擴充欄位:用官方參考驗證器(skills-ref 0.1.1)掃本 repo 的 9 個 skill,8 個通過, grill-me 被擋下——它用了 Claude Code 專屬的 disable-model-invocation。
  2. 寬容的解析器會藏錯:description 裡寫了半形冒號(用途: 產生週報),官方驗證器判 YAML 壞掉; 同一份檔案放進 Claude Code,它照樣把整串字當 description 讀進清單。在這家能跑,不代表換一家也能。

分享 skill 之前,跑一次官方驗證器(免費):

uvx --from skills-ref agentskills validate ./weekly-report # 文件寫的指令是 skills-ref validate,但 PyPI 上的 skills-ref 0.1.1 # 裝好的執行檔叫 agentskills(2026-09-24 實測)

不花錢、不用任何服務,自己動手的路徑:

  • 寫與驗:skill 只是文字檔,任何編輯器都能寫;實驗場 5️⃣ 的驗證器逐條照官方規則, 上面那行 uvx 是官方工具本身(本課實測過)。
  • 自己當 agent:本課的實測腳本 裡有一支約 60 行的最小 skill loader——清單放 system prompt、模型要求才塞 SKILL.md、要求才跑腳本, 接任何 OpenAI 相容端點(預設是本機 Ollama 的 http://localhost:11434/v1)。 我們用 qwen3.5-2b 跑通過(就是 hero 裡 qwen 那組);Ollama 本身沒有實測,走的是同一個介面。
  • 用現成的開源 agent:Goose、OpenCode 等都在 agentskills.io 的支援名單上、也能接本機模型——本課沒有逐一實測。
  • 注意:網路上「用免費的 Gemini CLI 玩 skill」的舊教學已不適用——Google 公告 Gemini CLI 的免費使用在 2026-06-18 停止服務、改由 Antigravity CLI 接手。
07 · 速查

本課名詞速查卡

Agent Skill 一個資料夾+一份 SKILL.md(frontmatter+SOP),可附 scripts/references/assets——把做法打包給 agent。
漸進揭露 三層載入:name+description 常駐 → 用得上才讀 SKILL.md → 做到才讀檔/跑腳本。用到才付 token。
description 模型決定叫不叫 skill 的唯一依據:寫「何時用」、列沒講關鍵字的說法、畫「不用於」的邊界;換模型要重測。
scripts/ 確定性步驟交給程式:程式碼不進上下文,只有輸出進;每次都對、查得到為什麼對。
CLAUDE.md vs Skill 永遠要守的進記憶(每次都載入);特定任務的做法進 skill(用到才載入)。
agentskills.io 開放標準:name ≤64 小寫英數連字號且同資料夾名、description ≤1,024;各家擴充欄位不通用,分享前先跑官方驗證器。
08 · 實戰

換你動手

LEVEL 1

在實驗場 2️⃣ 把 skill 數拉到 60、用到 1 個、20 輪、SKILL.md 選 make-lesson:全塞 system prompt 的方案每輪要多少 tokens? 塞得進 200K context 的模型嗎?下面那行 listing 字元數又超過 8,000 預算多少?

LEVEL 2

在實驗場 3️⃣ 選 Claude,重播「s4(英文的 status update)」的模糊版與精準版:兩者的第一步各是什麼? 精準版 description 裡是哪幾個字讓它對上這句英文?

LEVEL 3

挑一個你工作上每週都做的 SOP,在實驗場 5️⃣ 寫出它的 SKILL.md:通過驗證、description 講清楚做什麼/何時用/不用於什麼, 再替它想 3 句該觸發、3 句「差一點」不該觸發的 prompt。

卡住了?三題在實驗場 6️⃣ 都有折疊解答——先自己做,再打開對照。

09 · 驗收

情境測驗

離開前試試看:下面的情境都真的會遇到。每題選一個你認為的最佳做法,選了馬上看得到解釋。

Q1 情境題

團隊整理出 30 份作業 SOP(發版檢查、月結、客訴回覆…),每份 2–4 千 tokens。有人提議:「全部貼進 CLAUDE.md,AI 就什麼都會了。」你會怎麼做?

30 份 × 3 千 tokens ≈ 9 萬 tokens,放進 CLAUDE.md 等於每一輪都重送 9 萬——對話越長越貴,還會擠壓真正的工作空間(實驗場 2️⃣ 可以拉給自己看)。拆成 30 個 skill,平常只有 30 段描述常駐(本 repo 實測一個約 30–170 tokens),真的要做月結才把月結那份讀進來。B 只是換個地方塞:一個大 skill 一觸發就是 9 萬 tokens,而且「公司所有作業流程」這種描述什麼都像、什麼都不準。D 搞錯層次:SOP 是「做法」,MCP 是連外部系統的「工具」;需要查外部資料時,skill 可以指揮模型去用 MCP 工具,兩者是搭配關係。

Q2 錯誤診斷

你的 weekly-report skill 在 Claude Code 裡用得好好的。同事要拿去別的 agent 用,先跑了官方驗證器,卻得到下面的錯誤。最可能的原因與修法是?

$ cat weekly-report/SKILL.md --- name: weekly-report description: 用途: 產生週報: 每週五用 --- $ uvx --from skills-ref agentskills validate ./weekly-report Validation failed for weekly-report: - Invalid YAML in frontmatter: mapping values are not allowed here in "<unicode string>", line 3, column 16: description: 用途: 產生週報: 每週五用 ^ (line: 3)

錯誤訊息的箭頭指在第 3 行第 16 欄——「用途:」後面那個冒號。YAML 看到沒加引號的值裡又出現「冒號+空格」,會以為你要開始另一組鍵值,於是判定格式錯誤。修法:description: "用途: 產生週報: 每週五用",或用全形「:」、或改成 description: > 的區塊寫法。為什麼 Claude Code 沒事?我們實測(2.1.281)它的解析很寬容,照樣把整串字當 description——寬容的 agent 會把錯藏起來,換到嚴格的解析器才爆,所以 C 正好說反。A 不對:官方驗證器對中文 description 完全沒意見(同一份檔換成全形冒號就通過);D 是無中生有,規格只要求 1–1,024 字。英文使用者最常撞的版本是 description: Use when: ...,原因一模一樣。

Q3 錯誤診斷

專案裝了下面這個 skill。使用者說「write up this week's status update for the team lead from timesheet.csv」,實測 3 次 Claude 都是先讀 CSV 就自己寫,從沒叫 skill,交出來的總工時還一次 141、一次 138。最該先改哪裡?

--- name: weekly-report description: 協助處理報告。 --- # ACME 週報 SOP 1. 先執行 scripts/hours.py 加總工時,不要自己加總 ... (實測紀錄,claude-haiku-4-5,2026-09-24:3 次的動作都是 Read(timesheet.csv) → 自己寫報告;沒有任何一次呼叫 Skill)

模型決定要不要叫 skill 時,只看得到 name 和 description——本文寫得再好,沒被叫到就等於不存在(所以 C 不對)。「協助處理報告。」沒說何時用、沒有任何跟 status update 對得上的字,英文請求自然對不上。我們實測把同一個 skill 的 description 換成精準版(寫明週報、本週工作摘要、status report、進度彙整,「即使沒說出『週報』兩個字」,以及不用於什麼),同一句英文 3 次都是第一步就叫 skill。B 可以排除:同一個模糊版,「幫我寫這週的週報」3 次都有叫到——skill 在清單上,只是描述沒涵蓋這種說法。D 解的是「叫了之後能不能跑腳本」,但這裡根本沒叫。

Q4 情境題

你想讓 agent 在「使用者說要發新版」時照 12 步流程做:跑測試、比對三個檔案裡的版本號一致、產 changelog。其中版本號比對很容易看走眼。最合適的包法是?

「只在發版時需要」=skill 的主場(平常只佔描述那幾十個 tokens);「很容易看走眼」=交給腳本(每次都對、程式碼不進上下文)。B 是部分正確:包成 skill 對了,但把確定性的比對交給模型「仔細核對」——實驗場 4️⃣ 的心算實測就是答案:大模型多數時候對,但不是每次。A 讓 12 步在每一輪都佔上下文,跟發版無關的對話也在付錢。C 解的是「上下文要隔離」,發版流程的問題不在這裡;而且 subagent 裡要照什麼 SOP 做,最後還是得寫成 skill 或指令。

Python 環境載入中(首次約 30–60 秒)…讀完第 1 節它就好了