《Claude Code 工程化实战》第 11 讲 任务型 Skills 实战

《Claude Code 工程化实战》第 11 讲 任务型 Skills 实战

📌 本讲摘要
第 10 讲讲了 Skills 的"自动发现"机制(description 匹配 → LLM 加载)。本讲讲"反向操作"——怎么让 Skill “禁止模型自动调用”、只允许用户主动调(类似 Command 的"令行禁止")。核心是disable-model-invocation: true这个 frontmatter 字段:加了它、Skill 就退化成"团队命令",LLM 看不到、不会自动加载、只有用户输入/<skill-name>才触发。
本讲的三条主线:
第一、disable-model-invocation: true是什么?——Skills 的"反向开关"、让 Skill 退化成"用户主动调的命令",LLM 看不到、占 0 token、不自动加载。
第二、为什么需要"禁止自动调用"?——3 类应用场景(团队 SOP / 危险操作 / 调试工具)、共性是"必须严格按步骤走、不能 LLM 自由发挥"。
第三、vs Command 的边界——两者效果几乎一样(都是用户主动调);区别在配置管理粒度——Skill 走.claude/skills/(可打包、可分发),Command 走.claude/commands/;团队统一用 Skill 更便于管理。
学完本讲、你应该能用disable-model-invocation: true写出 4 个标准团队命令(/review / /commit / /deploy / /sync-env)、能给 3 个危险操作(/rollback / /db-migrate / /purge-cache)配"双保险"(disable 字段 + Hook 二次拦截)、能判断什么场景用 disable-model-invocation Skill、什么场景用真 Command。

📖 详细内容

disable-model-invocation: true 是什么?

第 10 讲我们说 Skills 的核心是"自动发现"——Claude 在推理时看 description 匹配用户的话、自动加载 SKILL.md。这对大多数能力是好事、但对某些场景是坏事。

典型反例:你的项目有个 Skill “deploy-prod”,description 写"Deploy to production. Use when user says ‘deploy’ / ‘部署’.“——这本来挺好。但有天用户在主对话里随口说"今天 deploy 顺利吗?”(在讨论昨天的部署),Claude 看到 “deploy” 关键词就匹配、自动加载 deploy-prod 的 SKILL.md、开始问"是否要部署?"——结果是用户被打断、deploy 行为被误触发。

更糟的是"危险操作"场景:rollback(回滚到上一版本)/ db-migrate(数据库迁移)/ purge-cache(清空缓存)——这些能力绝对不能 LLM 自动触发、必须用户显式调起。这就是disable-model-invocation: true的设计初衷。

加了disable-model-invocation: true的 Skill 会有 3 个变化:

  1. LLM 看不到——Claude 在推理时不会看到这个 Skill 的 description、关键词匹配也不触发。

  2. 占 0 token——frontmatter 也不加载、完全从 Claude 的"可见能力列表"中隐藏。

  3. 用户主动调才触发——用户输入/deploy/rollback,Claude Code 才把 SKILL.md 全文加载、严格按步骤执行。

这就是"令行禁止"——LLM 没有"自主判断何时调用"的权力、只有用户显式命令才能执行。这种 Skill 退化成"团队命令"、行为完全可预测。

为什么需要"禁止自动调用"?3 类应用场景

disable-model-invocation: true不是"对所有 Skill 都要加"的银弹、只在 3 类场景下有意义:

场景 1:团队 SOP(必须严格按步骤走)

团队的 code review 流程是 5 步:跑测试 → 静态分析 → 安全审计 → 文档同步 → 报告生成。每一步都有明确顺序、明确产出、明确负责人。这种流程不能让 LLM 自由发挥——LLM 可能"省略某步"或"调换顺序"或"漏掉关键检查"。

disable-model-invocation: true后、用户输入/review才触发、Claude 严格按 5 步走、每步产出固定格式。这就把"团队 SOP"固化成 Skill 模板、任何团队成员触发/review都是同样 5 步同样产出、标准化。

场景 2:危险操作(LLM 误触 = 灾难)

部署到生产 / 回滚到上一版本 / 数据库迁移 / 清空缓存——这些操作一旦执行就不可逆(或者说回滚成本巨大)。如果 LLM 看到 “deploy” / “rollback” 关键词就自动加载、可能在用户随便说"今天 deploy 顺利吗"时、误触发"开始部署"流程。

这类 Skill 必须配disable-model-invocation: true——LLM 看不到、不会误触、只有用户显式/deploy//rollback才执行。这是"双保险"的第一层(第二层是 Hook 二次拦截、在第 6 讲配的 deny 列表基础上、再加特定命令的拦截)。

场景 3:调试工具(日常不该启用、只排查时用)

有些 Skill 是"排查问题时才用"的工具:debug-mode(开启详细日志)/ verbose(打印所有中间结果)/ trace-network(追踪网络请求)。这些能力日常不该启用(会污染日志 / 拖慢速度)、只在排查时才需要。

disable-model-invocation: true让 Claude 永远不知道"我还有 debug-mode 这个工具"、用户排查时才主动/debug-mode启用。这避免了"LLM 在普通对话里顺手开启了 debug 模式"。

3 类场景的共性:“必须严格按步骤 / 绝不能 LLM 自由发挥 / 行为必须可预测”。判断标准:这件事如果 LLM 误触了会出大问题吗?会的话、加disable-model-invocation: true

应用场景危险等级触发频率适合 disable 程度
团队 SOP(review/commit)低(不可逆性弱)高(每天多次)可选(看团队偏好)
危险操作(deploy/rollback)高(不可逆性)低(每周几次)必须 disable
调试工具(debug/verbose)中(影响日志/性能)极低(排查时用)必须 disable

团队 SOP 实战:4 个标准命令

4 个最常见的"团队命令"SOP 是:/review(审查流程)/ /commit(commit 流程)/ /deploy(部署流程)/ /sync-env(环境同步)。每个都有"严格步骤"、配disable-model-invocation: true后、触发方式变成"用户主动调、严格按步骤"。

/review:5 步审查流程

步骤 1:跑测试(必须全过、失败则停止)。步骤 2:静态分析(ruff + mypy)。步骤 3:安全审计(skills/security-audit)。步骤 4:文档同步(检查 src/ 改了但 docs/ 没改的情况)。步骤 5:报告生成(Markdown 报告 + commit 检查清单)。

每步的"硬约束":任何一步失败就停、不继续。报告格式固定、任何人触发 /review 都得到一样的产出。

/commit:commit 流程

步骤 1:git status 看未提交改动。步骤 2:git diff 看具体改了什么。步骤 3:跑测试(必须全过)。步骤 4:跑 pr-drafter skill 生成 commit message 草稿(写到 .claude/drafts/commit-msg.txt)。步骤 5:用户确认 commit message(不直接 git commit)。步骤 6:用户自己 git commit。

硬约束:Claude 永远不自己 git commit、只产草稿让人确认。

/deploy:部署流程

步骤 1:确认当前分支是 main 且最新。步骤 2:确认所有测试在 CI 上通过。步骤 3:确认 CHANGELOG.md 已更新(用 sync-changelog skill)。步骤 4:tag 当前版本(从 package.json 读)。步骤 5:推送 tag(触发 CI 部署流水线)。步骤 6:通知团队(Slack 通知)。

硬约束:每步都询问用户确认、不自动继续。

/sync-env:环境同步

步骤 1:本地环境 vs 远端环境对比(dev/staging/prod)。步骤 2:列出差异(配置 / 依赖 / 数据库 schema)。步骤 3:对每项差异给出"是否需要同步"的建议。步骤 4:用户确认后逐项同步(用第 6 讲的 permission 白名单、只允许白名单命令)。

4 个 SOP 的共同设计原则:

  1. 步骤数控制在 3-7 步(太少 SOP 价值不大、太多用户记不住)。

  2. 每步有明确产出(报告 / 文件 / 状态变更)。

  3. 硬约束必须执行(“失败就停” / “不自动 git commit” / “每步问用户”)。

  4. SKILL.md 控制在 100-200 行(用户主动调时一次性加载、不能太长)。

危险操作实战:必须"令行禁止"的能力

危险操作 Skill 的"双保险"设计:第一层是disable-model-invocation: true(LLM 看不到、不会误触);第二层是 Hook 二次拦截(即使有其他方式触发、HW 也会拦下)。两层叠加、几乎不可能误执行。

/rollback:回滚到上一版本

触发:用户输入/rollback [commit-hash 或 version-tag]。流程:确认当前部署版本 → 拉取目标版本 → 跑数据库迁移回滚(如有) → 重新部署 → 健康检查 → 通知团队。

双保险:disable-model-invocation: true阻止 LLM 误触;PreToolUse Hook 拦截git reset --hard/kubectl rollout undo等危险命令、即使有其他路径触发也拦下。

/db-migrate:数据库迁移

触发:用户输入/db-migrate [env],env = dev / staging / prod。流程:确认当前 schema 版本 → 跑alembic upgrade head(生产前先 dry-run)→ 数据完整性检查 → 通知团队。

双保险:disable-model-invocation: true阻止误触;Hook 拦截alembic downgrade(意外回滚)/DROP TABLE/TRUNCATE等命令。

/purge-cache:清空缓存

触发:用户输入/purge-cache [scope],scope = redis / cdn / both。流程:确认当前缓存命中率 → 软清(渐进过期)→ 硬清(强制删除)→ 健康检查 → 监控告警阈值。

双保险:disable-model-invocation: true阻止误触;Hook 拦截redis-cli FLUSHALL/curl -X DELETE ...cdn...等命令。

3 个危险操作 Skill 的共同特征:

  1. 都有"不可逆"或"回滚成本巨大"的属性。

  2. 都有"显式参数"([env] / [scope] / [version])、防止误用。

  3. 都有"健康检查 + 监控告警"兜底、出问题能第一时间发现。

  4. 都配双保险(LLM 看不到 + Hook 拦命令)、即使 LLM 误触、Hook 也会拦截。

vs Command 的边界:什么时候用 disable-model-invocation Skill、什么时候用真 Command

新人的常见困惑:“disable-model-invocation: true的 Skill 效果和 Command 不是一样吗?都用户主动调、都 LLM 看不到、都不自动加载——那为什么不全用 Command?”

答案是"配置管理粒度"的区别:

用 disable-model-invocation Skill 的场景

需要"渐进式披露"——SKILL.md 里有快速参考 / 详细步骤 / 边界 case 多层内容、需要时整体加载、不要时零成本。Skill 走.claude/skills/<name>/SKILL.md目录结构、可以放 references/ 子目录做深层引用。

需要"打包分发"——Skill 是工程资产、可以做成 NPM 包或 GitHub repo 跨项目复用。Command 在这一点上更"扁平"、没有目录结构、跨项目复用需要复制整个文件。

需要"和普通 Skill 一起管理"——项目里同时有自动发现的 Skill + 禁止自动调用的 Skill、两者放.claude/skills/统一管理、组织清晰。Command 走单独.claude/commands/、分散。

用真 Command 的场景

极简命令——就一个固定动作(比如 /clear 清屏、/help 看帮助、/init 初始化项目)。这种 1-2 行的命令用 Command 更轻。

需要"参数解析"——Command 支持$ARGUMENTS变量、Skill 没有这个机制。如果命令需要解析复杂参数(比如 /deploy --env=prod --version=1.2.3)、用 Command 更合适。

团队对 Skills vs Commands 有强约定——如果团队历史上都是用 Command、新加的禁止自动调用能力也用 Command 保持一致。

实操建议:能 Skill 就 Skill、只在 Skill 表达不了(参数解析)时才用 Command。两者并存不冲突、可以.claude/skills/放 80% 的能力、.claude/commands/放 20% 的极简命令。

维度普通 Skilldisable-model-invocation SkillCommand
LLM 是否可见是(description 全量可见)否(占 0 token)否(走 commands 目录)
触发方式LLM 自动 + 用户 /仅用户 /仅用户 /
加载时机description 匹配时用户输入命令时用户输入命令时
目录结构.claude/skills//SKILL.md.claude/skills//SKILL.md.claude/commands/.md
渐进式披露支持(可放 references/)支持(可放 references/)不支持(单文件)
参数解析不支持不支持支持($ARGUMENTS)

Skills 的"渐进披露"在命令场景的特殊处理

disable-model-invocation: true的 Skill 加载成本进一步降低——LLM 完全看不到(连 frontmatter 都不加载)、占 0 token。但用户主动调/<name>时、SKILL.md 全文一次性加载、所以仍然要控制 SKILL.md 长度。

控制策略:

  1. SKILL.md 控制在 100-200 行(用户主动调时一次性加载、不能太长)。

  2. 详细文档放 references/ 子目录、SKILL.md 用"详见 references/xxx.md"引用。

  3. 命令的"核心步骤"放 SKILL.md 主体、"边界 case + 反例"放 references。

这一条和普通 Skill 一致、只是"加载时机"不同——普通 Skill 是 description 匹配时加载、disable-model-invocation Skill 是用户输入/<name>时加载。

特殊优化:disable-model-invocation Skill 可以写得"重"一些(用户主动调时加载、内容详尽是好事)、不像普通 Skill 必须"轻"以减少自动加载的 token 成本。但仍要控制总长度(200-300 行内)、用户主动调也不希望等太久。

🛠️ 实战代码

📄 第 11 讲配套:4 个标准团队命令 SKILL.md(完整模板)

--- # .claude/skills/review/SKILL.md name: review description: NOT-USED-BY-MODEL (禁止 LLM 自动调用,只在 /review 时触发) disable-model-invocation: true allowed-tools: Bash, Read, Grep, Edit --- # /review:团队 5 步审查流程 ## 流程 1. 跑测试(必须全过,失败则停止报告) 2. 静态分析(ruff check + mypy src) 3. 安全审计(调 security-auditor skill) 4. 文档同步(检查 src/ 改了但 docs/ 没改) 5. 报告生成(写到 .claude/reports/review-<date>.md) ## 硬约束 - 任一步失败 → 停止,不继续 - 不跳过任何步骤 - 报告格式严格按模板 ## 报告模板 ```markdown # Review: <branch> - Test: PASS/FAIL - Lint: PASS/FAIL - Security: PASS/FAIL (Critical: N, Warning: N) - Docs: SYNC/OUT-OF-SYNC - Verdict: APPROVE / REQUEST_CHANGES
# .claude/skills/commit/SKILL.md name: commit description: NOT-USED-BY-MODEL disable-model-invocation: true allowed-tools: Bash, Read, Grep --- # /commit:commit 流程 ## 流程 1. git status(看未提交) 2. git diff(看具体改动) 3. 跑测试(必须全过,否则终止) 4. 调 pr-drafter skill 生成 commit message 草稿(写 .claude/drafts/commit-msg.txt) 5. 展示草稿给用户,**不直接 git commit** 6. 用户确认后,用户自己 `git commit -F .claude/drafts/commit-msg.txt` ## 硬约束 - Claude 永远不自己 git commit - 测试不过 → 终止,不允许 commit - commit message 必须符合 Conventional Commits
# .claude/skills/deploy/SKILL.md name: deploy description: NOT-USED-BY-MODEL disable-model-invocation: true allowed-tools: Bash, Read, Grep --- # /deploy:部署流程(只能手动触发) ## 前置检查(必须全通过) - [ ] 当前分支是 main - [ ] CI 全部通过(查 GitHub Actions) - [ ] CHANGELOG.md 已更新 - [ ] 当前版本号 > 上一版本号 ## 流程 1. 读 package.json / pyproject.toml 拿当前版本号 2. git tag <version>(本地打 tag) 3. git push origin <version>(推送 tag,触发 CI 部署) 4. 监控部署状态(`kubectl get pods -n prod` 或类似命令) 5. 通知团队(Slack webhook / 邮件) ## 硬约束 - 每步询问用户确认,不自动继续 - 任何前置检查失败 → 终止 - 部署失败 → 立即通知 + 暂停后续操作
# .claude/skills/sync-env/SKILL.md name: sync-env description: NOT-USED-BY-MODEL disable-model-invocation: true allowed-tools: Bash, Read, Grep --- # /sync-env:环境同步流程 ## 流程 1. 对比本地 vs 远端环境(dev / staging / prod) 2. 列出差异(配置 .env / 依赖 requirements.txt / DB schema) 3. 对每项差异给出"是否需要同步"的建议 4. 用户确认后,逐项同步(用第 6 讲的 permission 白名单) ## 硬约束 - 不自动同步,每项询问用户 - prod 环境的同步必须二次确认 + 通知团队 - 同步后必须跑一次健康检查

📄 第 11 讲配套:disable-model-invocation 字段 3 种取值的对比

# === 取值 1:disable-model-invocation: true === --- name: deploy description: Deploy to production disable-model-invocation: true # ✅ LLM 完全看不到,只有用户 /deploy 触发 --- # === 取值 2:disable-model-invocation: false === --- name: sync-changelog description: Update CHANGELOG.md from git commits. Use when user says "更新 changelog". disable-model-invocation: false # ✅ 显式 false(等同于不写),LLM 自动发现 --- # === 取值 3:缺省(不写) === --- name: sync-changelog description: Update CHANGELOG.md from git commits. Use when user says "更新 changelog". # 不写 disable-model-invocation 字段 = 默认 false = LLM 自动发现 --- # 行为对比: # true → LLM 看不到,占 0 token,用户 /<name> 才触发 # false → LLM 自动发现,description 匹配时加载 # 缺省 → 同 false

📄 第 11 讲配套:危险操作 Skill 的双保险配置(配 disable + Hook 二次拦截)

# .claude/skills/rollback/SKILL.md name: rollback description: NOT-USED-BY-MODEL disable-model-invocation: true # 第一层保险:LLM 看不到 allowed-tools: Bash, Read --- # /rollback:回滚到上一版本 ## 流程 1. 确认当前部署版本(`kubectl get deployment -n prod`) 2. 拉取目标版本(用户指定的 commit/tag) 3. 跑数据库迁移回滚(如有 alembic 迁移) 4. 重新部署(`kubectl rollout undo` 或 `helm rollback`) 5. 健康检查(`curl /health` + 看监控) 6. 通知团队 ## 硬约束 - 每次只回滚一个版本,不批量 - 失败立即停止 + 通知
# .claude/hooks/deny-extra-dangerous.sh # 第二层保险:HW 拦截危险命令(即使 SKILL disable 失效,HW 也兜底) #!/usr/bin/env bash COMMAND="$1" # 拦截 git reset --hard(回滚工作区) if echo "$COMMAND" | grep -qE 'git\s+reset\s+--hard'; then echo "❌ 拒绝:git reset --hard 被禁止(用 /rollback skill)" exit 2 fi # 拦截 alembic downgrade(数据库回滚) if echo "$COMMAND" | grep -qE 'alembic\s+downgrade'; then echo "❌ 拒绝:alembic downgrade 被禁止(用 /db-migrate rollback)" exit 2 fi # 拦截 redis-cli FLUSHALL(清空缓存) if echo "$COMMAND" | grep -qE 'redis-cli\s+FLUSHALL'; then echo "❌ 拒绝:redis FLUSHALL 被禁止(用 /purge-cache skill)" exit 2 fi # 拦截 kubectl rollout undo(默认走 /rollback) if echo "$COMMAND" | grep -qE 'kubectl\s+rollout\s+undo'; then echo "❌ 拒绝:kubectl rollout undo 被禁止(用 /rollback skill)" exit 2 fi exit 0
// .claude/settings.json // 把双保险 HW 配到 PreToolUse 钩子里 { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ {"type": "command", "command": "bash .claude/hooks/deny-extra-dangerous.sh"}, {"type": "command", "command": "bash .claude/hooks/deny-pipe-exec.sh"} ] } ] } }

📄 第 11 讲配套:团队命令集的 .claude/skills/ 目录组织(按团队 / 按阶段 / 按风险等级)

# 方式 1:按团队角色组织 .claude/skills/ ├── dev/ # 开发阶段命令 │ ├── review/SKILL.md # /review │ ├── commit/SKILL.md # /commit │ └── pr/SKILL.md # /pr(开 PR) ├── ci/ # CI 阶段命令 │ ├── test/SKILL.md # /test │ ├── lint/SKILL.md # /lint │ └── coverage/SKILL.md # /coverage └── release/ # 发布阶段命令 ├── deploy/SKILL.md # /deploy ├── rollback/SKILL.md # /rollback └── tag/SKILL.md # /tag # 方式 2:按风险等级组织 .claude/skills/ ├── safe/ # 低风险(可让 LLM 自动发现或主动调) │ ├── review/SKILL.md │ ├── commit/SKILL.md │ └── test/SKILL.md ├── medium/ # 中风险(可 LLM 自动发现,执行前 ask) │ ├── sync-env/SKILL.md │ └── sync-deps/SKILL.md └── dangerous/ # 高风险(必须 disable-model-invocation + Hook) ├── deploy/SKILL.md # /deploy ├── rollback/SKILL.md # /rollback ├── db-migrate/SKILL.md # /db-migrate └── purge-cache/SKILL.md # /purge-cache # 方式 3:按功能模块组织(适合多技术栈) .claude/skills/ ├── backend/ │ ├── db-migrate/SKILL.md │ └── api-test/SKILL.md ├── frontend/ │ ├── build/SKILL.md │ └── e2e-test/SKILL.md └── infra/ ├── deploy/SKILL.md └── rollback/SKILL.md

⚠️ 常见坑

⚠️ 把"日常高频"的操作也加 disable-model-invocation(用户每次都得手输命令、反而累)
常见的"过度防御":把所有 Skill 都加disable-model-invocation: true,“安全是安全了、但用户每次都得输 /test / /commit / /lint、反而累。disable 字段是为"危险 + 低频"场景设计的:危险操作必须 disable(LLM 误触 = 灾难);高频操作别 disable(LLM 自动调用 = 节省用户输入)。判断标准:这件事 LLM 自动触发会出大问题吗?会的话、disable;不会的话、别 disable。
⚠️ 危险操作 Skill 只加了 disable 字段、没配 Hook 二次拦截(单层防御不够)
危险的"假安全"误判:给 deploy / rollback / db-migrate 加了disable-model-invocation: true、以为就安全了。但 disable 字段是"LLM 推理层"的防御——如果有人绕开 LLM 推理、直接调起 Skill(比如 CLI 直接传参数 / CI 流水线自动调 / 别的 Skill 嵌套调),disable 就失效了。必须加第二层 HW 防御——PreToolUse Hook 拦截危险命令(即使 SKILL disable 失效、HW 兜底)。双保险叠加、几乎不可能误执行。判断标准:你的危险操作 Skill 配了 HW 兜底吗?没配、补上。
⚠️ 团队命令没版本管理(不同人用的步骤不一致)
团队 /review 流程应该是 5 步、但每个人的 SKILL.md 文件可能略有不同——A 同事加了一步"通知 reviewer”,B 同事加了"跑 linter",C 同事漏了"安全审计"。结果团队里 /review 行为不一致、review 质量参差。修正:团队命令进 git + 配 PR review + 用 semver 打 tag——任何修改必须 PR 评审、谁也不能私自改。判断标准:你的团队命令 SKILL.md 是"个人"还是"团队资产"?如果是"个人"、赶紧入 git + 配 PR review。
⚠️ SKILL.md 正文 1000+ 行(用户主动调时一次性加载、token 爆炸)
"渐进式披露失效"的反面:以为 disable-model-invocation Skill 是用户主动调、可以写得详细点、塞 1000+ 行进去。结果用户输入 /deploy 触发、1000 行一次性加载到上下文、token 爆炸。修正:即使 disable Skill,SKILL.md 仍控制在 200 行内、详细文档放 references/。判断标准:SKILL.md > 300 行就该拆。

💡 一句话备忘

disable-model-invocation: true是 Skills 的"反向开关"——把"自动发现"退化成"用户主动调"、让 SOP / 危险操作 / 调试工具 3 类场景从"LLM 自由发挥"变成"令行禁止"、再加 Hook 兜底就形成了"双保险"。