進階:避坑與安全
Skill 寫了不會出大事,但會出小事。本課把 5 個常見坑列清楚。
課程目標
- 認識新手最常踩的 5 大坑
- 學會 PII Scrubbing:公司敏感字串為什麼絕對不能進 SKILL.md
- 知道怎麼用部門
audit-skill工具做安全審查 - 看懂
allowed-tools怎麼設才不會太鬆也不會太緊
一、為什麼要學避坑?
寫 skill 是低風險動作——寫壞了刪掉就好。但有兩種坑會留長期後遺症:
- 公司敏感資訊外洩 → 同步到部門共享 skill 後,回不去
- 目錄膨脹 → 半年後沒人記得有這個 skill,但每個 session 都載入它的 frontmatter,浪費 context
這課專門教你避這兩類。
二、坑 1:PII / 公司敏感資訊外洩
什麼是 PII?
PII = Personally Identifiable Information,廣義包含:
- 客戶實名(任何具體可識別的客戶 / 品牌名稱)
- 金額(合約價、薪資、客戶 GMV)
- 內部 token(API key / OAuth secret / Cloud SQL 連線字串)
- 內部路徑(公司內網域名、內部專案代稱、內部 service 名稱)
- 內部 IP(
192.168.x.x內網 /100.x.x.xTailscale) - 客戶機密(合約細節、競品比較表)
💡 本課用
${COMPANY_DOMAIN}/${CUSTOMER_NAME}等 placeholder 講 PII。 你公司具體該防的字串清單,由你部門 maintain(不寫進公開教材)。
為什麼這是坑?
skill 跟你寫 prompt 不一樣——
- prompt 寫一次就過了,不會留下
- skill 留在檔案裡,未來會 sync 到 git,可能上 GitHub PR,可能被同事看到
如果你的 SKILL.md 寫了:
description: "特定客戶的月報生成器。連到 https://internal-api.${COMPANY_DOMAIN}/clients/${CUSTOMER_NAME},撈 GMV 數據..."
但你真的把 ${COMPANY_DOMAIN} 換成你公司的真實內網域名,把 ${CUSTOMER_NAME} 換成真實客戶名稱——這份 SKILL.md push 到部門 repo → 客戶名 + 內部 API URL 都進去了。回不去。
解法:參數化(Parameterization)
把所有敏感字串換成 placeholder:
❌ 壞範例:
description: "客戶 [真實客戶名] 的月報生成器。連到 https://[真實內部 API] ..."
✅ 好範例:
description: "客戶月報生成器。給客戶名稱當參數,連到部門內部 API 撈 GMV..."
具體寫進 SKILL.md body:
## 輸入
- 客戶名稱:${CUSTOMER_NAME}
- API 端點:從 env var `${INTERNAL_API_URL}` 讀取(不要硬寫)
- API token:從 env var `${API_TOKEN}` 讀取
這樣:
- skill 邏輯通用——不綁定特定客戶
- 敏感資訊在 env / 用戶 input,不進 git
- 同事看到也能用——他自己填自己的客戶名
部門有自動工具
部門寫了一個腳本叫 pii_scrub.py(住在 ~/.claude/skills/skill-spotter/scripts/):
python3 ~/.claude/skills/skill-spotter/scripts/pii_scrub.py path/to/your/skill/SKILL.md --dry-run
它會掃幾類 pattern:
- 公司專屬域名 / 內網域名(具體字串清單在
references/pii-checklist.md,由部門 maintain) - API tokens(
Bearer .../sk-.../AKIA...) - 內部 IP(
192.168.x.x/100.x.x.x) - 內部 service 代號(部門自定)
--dry-run 命中 → exit 1,提醒你先處理。不要繞過這個 gate。
具體該防什麼字串 → 看部門的 references/pii-checklist.md,不要硬寫進公開教材。
三、坑 2:一次性垃圾 Skill
症狀
你寫了一個 skill 叫 2026-q2-okr-helper——專門幫你寫 2026 Q2 的 OKR。
問題:Q3 開始它就用不到了。但它還在 ~/.claude/skills/ 目錄,每個 session 都載入它的 frontmatter,浪費 context。
為什麼會踩?
新手寫 skill 興奮——遇到任何重複工作就想包成 skill。但短期重複 ≠ 該寫 skill。
解法:Stability ≥ 0.5 + 預估有效期 ≥ 3 個月
回想第 5 課的 score 公式:
priority = (frequency × token_saved × stability) / cost
如果:
- stability < 0.5(每次步驟細節都變)→ ❌ 不要寫
- 預估 3 個月後就用不到 → ❌ 不要寫
- 只有你會用,部門其他人用不到 → 寫但不要 push 到 team-skill-lab
解法:定期審查目錄
每季跑一次:
# 列出 skills 目錄,找出最近 3 個月沒被觸發的
ls -lat ~/.claude/skills/ | tail -20
3 個月沒用 → 考慮刪。或改 status 為 deprecated 提醒未來不要載入。
四、坑 3:過度抽象 Skill
症狀
你寫了一個 skill 叫 do-business-stuff——「處理所有商業相關的事情」。
description 寫:
「強大的商業助手,可處理客戶、產品、行銷、銷售相關問題」
問題:
- description 太模糊,永遠不會被觸發到(或誤觸發)
- 同事看不懂該什麼時候叫它
- 內部步驟一定混亂——因為「商業所有事情」不可能寫成固定流程
為什麼會踩?
你想「做大一點,更通用」。但 skill 跟程式設計反過來——skill 越窄越好。
對照表
| 過度抽象 ❌ | 適當聚焦 ✅ |
|---|---|
do-business-stuff | customer-onboarding |
data-analysis | omo-monthly-review |
report-helper | weekly-report |
client-tools | proposal-init-from-template |
解法:一個 skill = 一個動詞 + 一個受詞
generate weekly report ✅
analyze customer churn ✅
onboard new client ✅
如果你的 skill 名稱寫不出「動詞 + 受詞」,範圍太大,先拆。
五、坑 4:Context Bloat(SKILL.md 過長)
症狀
你寫了一個 skill,body 1000 行——把所有可能的 edge case、所有歷史脈絡、所有範例都塞進去。
問題:第 3 課提過——SKILL.md body 觸發後永久留在 context。1000 行的 body 每個對話都壓在你的 context window 上。對話越長,這 1000 行被反覆計費。
為什麼會踩?
你想「寫詳細一點,Claude 才不會出錯」。但 LLM 的注意力是有限資源——body 越長,反而越分心。
解法:Progressive Disclosure(第 3 課教過)
- body 只放決策骨架:步驟 + 失敗處理 + Quality Gates
- 詳細內容丟
references/:決策樹細節、範例輸入輸出、跟其他 skill 對照 - 範圍指引:body < 150 行(中型 skill 甜蜜點)
範本
❌ 壞:
## 步驟
### Step 1: 撈資料
首先你要思考客戶屬於哪個 segment...(接下來 200 行解釋 segment)...
✅ 好:
## 步驟
### Step 1: 撈資料
依客戶 segment 撈對應資料源(segment 定義見 references/segments.md)。
六、坑 5:allowed-tools 太鬆 / 太緊
太鬆的問題
allowed-tools:
- Bash # 完全沒限制 → 任何 bash 命令都自動跑
這等同說「我授權 Claude 跑任何 shell command 不用問我」。如果某次 Claude 判斷錯誤跑了 rm -rf . → 沒人攔。
太緊的問題
allowed-tools:
- Read # 只能讀檔
每次 skill 跑到 git log / curl / python3 都會跳出「allow?」打斷你。
解法:Pattern Match
寫成 Bash(<pattern>*) 形式,只授權需要的:
allowed-tools:
- Read # 讀任何檔
- Bash(git*) # 只允許 git 開頭的命令
- Bash(date*) # date 命令
- Bash(python3 scripts/*) # 只允許跑這個 skill 自己的 scripts
- mcp__team-memhall__write_entry # MCP 寫入
危險命令明確排除
絕對不要直接授權:
Bash(rm*)(破壞性)Bash(sudo*)(提權)Bash(chmod*)(權限)Bash(curl * | sh)(執行任意內容)
如果你的 skill 真的需要這些 → 不要寫成 allowed-tools,讓它每次都跳出來請求授權,你親眼看到再 yes。
七、Bonus:用 audit-skill 做安全審查
部門有個 skill 叫 /audit-skill,專門幫你 review 新寫的 skill 安全性。
跑:
/audit-skill ~/.claude/skills/<your-new-skill>/
它會檢查:
- 有沒有 telemetry / 對外網路呼叫
- 有沒有寫敏感檔案(
.env、~/.ssh/) - 有沒有 outbound API 沒揭露
- allowed-tools 設得合不合理
- PII 有沒有命中
寫完 skill → 跑 audit-skill → PR 給部門。這是部門慣例。
八、結論:寫 skill 的 5 條鐵則
- 不要寫敏感字串——客戶名 / 金額 / token / 內部路徑全部參數化
- stability < 0.5 不寫——避免一次性垃圾
- 一個 skill = 一個動詞 + 一個受詞——範圍越窄越好
- body < 150 行——詳細丟 references/
- allowed-tools 用 pattern match——不要寫
Bash裸授權
下一課(最後一課)我們學怎麼把 skill 上 PR 到部門共享。
AI 協作:學了這個,跟 AI 怎麼配合?
PII 識別是 AI 可能漏掉的——它不知道某個字是客戶名還是普通名詞。所以掃 PII 不能只靠 AI,要 AI + 你 + 工具(pii_scrub.py)三層把關。
你的人類優勢:
- 你知道哪些字串是公司專有的(客戶代號、合約名、內部專案代稱)
- 你能判斷哪個 false positive 可以放行——例如某個英文常用字也是公司產品名
可以這樣跟 AI 說:
幫我 audit 這份 SKILL.md [貼上]。列出可能的 PII 三類:(1) 確定是 PII(客戶實名 / token / 內部 IP) (2) 可能是 PII,需要我確認(含公司專有名詞但語境普通) (3) 一定不是 PII。第 2 類只列出來不替我判斷,我會逐條確認。
練習題
yaml\n---\nname: client-helper\ndescription: "幫忙處理客戶的事情,包括 [客戶 A]、[客戶 B]、[客戶 C] 這幾家大客戶"\nallowed-tools:\n - Bash\n---\n\n# /client-helper\n\n## 步驟\n1. 連到 https://internal-api.example.corp/api 撈客戶資料\n2. 用 token Bearer abc123def456ghi789... 認證\n3. 整理成報告\n```", "instructions": "至少指出 3 個問題(5 大坑哪幾個踩到),並寫出修正建議。", "hint": "這份 SKILL.md 至少踩了 4 個坑:PII(客戶名 + URL + token)、太抽象、allowed-tools 太鬆、步驟太簡略。" }
\n## 步驟\n1. 從 https://internal-api.example.corp/clients/acme/orders 撈訂單\n2. 連到 192.168.11.122 的 Postgres 跑 query\n3. 把結果寫到客戶 ACME 的 Slack channel #acme-monthly\n4. 用內部 service alpha-monthly-summary 產出摘要\n```",
"instructions": "把 4 行裡每個敏感字串標出來,換成 ${PLACEHOLDER} 形式。確保改完之後對任何客戶都通用。",
"hint": "「ACME」是客戶實名 → ${CUSTOMER_NAME}。192.168.11.122 是內部 IP → ${INTERNAL_IP}。alpha-monthly-summary 是內部 service → ${INTERNAL_SERVICE}。"
}
挑戰任務
對第 7 課你寫的 skill 跑 /audit-skill ~/.claude/skills/<your-skill>/,記下結果。