033、Skill 系统入门:定义、触发与编写第一个 Skill

033、Skill 系统入门:定义、触发与编写第一个 Skill

上周五凌晨两点,我在调试一个诡异的 CI 失败——Claude Code 在生成 Kubernetes 部署清单时,突然开始用 YAML 写起了莎士比亚十四行诗。service 字段变成了“thou shalt expose port 8080”,replicas 被写成“three score and ten”。排查了半天,发现是某个同事在 .claude/skills 里塞了一个“poetic-mode”的 Skill,触发条件写的是“当用户提到 deploy 时”。这玩意儿没被 review 就合并了,结果整个团队被坑了一整晚。

Skill 系统是 Claude Code 最容易被低估的能力,也是翻车率最高的功能。它本质上是一种“行为插件”——不是改模型权重,而是通过定义触发条件和响应逻辑,让 Claude 在特定场景下执行你预设的操作。今天我们就从踩坑开始,把 Skill 的机制、触发规则和编写规范彻底讲透。

Skill 到底是什么

别被名字唬住。Skill 就是一个 JSON 或 YAML 文件,放在项目根目录的 .claude/skills/ 下。Claude Code 启动时会扫描这个目录,把每个 Skill 注册到它的“行为库”里。当用户输入匹配了某个 Skill 的触发条件,Claude 就会执行该 Skill 定义的动作——可能是执行一段 shell 命令、调用一个 API、或者修改对话上下文。

我习惯把 Skill 理解为“AI 的肌肉记忆”。你不需要每次告诉它“用 pytest 跑测试”,只要写一个 Skill,以后提到“跑测试”它就自动执行 pytest -v --tb=short。但问题在于,触发条件写得太宽泛,就会像我们那个“poetic-mode”一样,把整个对话带偏。

触发机制:别让 Skill 变成幽灵

Skill 的触发分两种:显式触发和隐式触发。显式触发是用户主动调用,比如输入 /run-tests;隐式触发是 Claude 根据对话上下文自动匹配。新手最容易在隐式触发上翻车。

隐式触发的核心是 trigger 字段,它支持三种模式:

  1. 关键词匹配trigger: "deploy" 会匹配任何包含“deploy”的输入。这太危险了——用户说“别 deploy”,它照样触发。
  2. 正则表达式trigger: "/deploy\s+(staging|production)/i" 更精确,但写不好会漏匹配。
  3. 语义匹配trigger: { type: "semantic", prompt: "用户想要部署应用" } 最灵活,但需要调阈值,默认 0.7 的相似度经常误触。

我的经验是:优先用显式触发,除非你非常确定隐式触发的边界。显式触发就是在 Skill 文件名里加 @ 符号,比如 run-tests@v1.yaml,用户输入 /run-tests 才会激活。这能避免 90% 的误触发问题。

编写第一个 Skill:从需求到文件

假设我们要写一个 Skill:当用户说“检查代码风格”时,自动运行 flake8 并格式化输出结果。

.claude/skills/ 下创建 lint-checker.yaml

# 别这样写:trigger: "检查代码风格"  # 太宽泛,用户说"帮我检查一下代码风格"就匹配不上
name: "lint-checker"
description: "运行 flake8 检查 Python 代码风格,输出带行号的问题列表"
trigger: 
  type: "semantic"
  prompt: "用户想要检查 Python 代码的 lint 问题"
  threshold: 0.8  # 这里踩过坑:默认 0.7 会匹配到"检查代码质量",调高到 0.8 更安全
actions:
  - type: "command"
    command: "flake8 . --max-line-length=100 --statistics"
    # 别这样写:command: "flake8 ."  # 没有参数,输出太啰嗦,用户会骂
    parse_output: true  # 让 Claude 解析输出结果,而不是直接扔给用户
  - type: "respond"
    template: |
      ## Lint 检查结果
      {{#if output.exit_code == 0}}
      ✅ 代码风格通过,没有发现问题。
      {{else}}
      ⚠️ 发现 {{output.line_count}} 个问题:
      ```
      {{output.parsed}}
      ```
      建议修复后再提交。
      {{/if}}

这个 Skill 的关键在于 parse_output: true。如果不加,Claude 会把 flake8 的原始输出直接贴出来——一堆文件名和行号,用户根本看不懂。加了之后,Claude 会解析输出,提取关键信息,按模板格式化。我见过有人在这里写 parse_output: false,结果每次跑完都要手动解释输出,Skill 的价值直接减半。

高级技巧:Skill 链与上下文传递

单个 Skill 能做的事有限。真正有用的是 Skill 链——一个 Skill 触发后,修改上下文,让另一个 Skill 接着触发。

比如我们想做一个“部署流水线”Skill:先跑测试,再构建镜像,最后部署。可以拆成三个 Skill:

# test-runner.yaml
name: "test-runner"
trigger: "/run-pipeline"
actions:
  - type: "command"
    command: "pytest -v --tb=short"
    set_context:
      tests_passed: "{{output.exit_code == 0}}"
      # 这里踩过坑:set_context 的变量名不要用特殊字符,否则后续 Skill 解析会炸
# docker-builder.yaml
name: "docker-builder"
trigger: 
  type: "context"
  key: "tests_passed"
  value: "true"
actions:
  - type: "command"
    command: "docker build -t myapp:latest ."
    set_context:
      image_built: "{{output.exit_code == 0}}"
# deployer.yaml
name: "deployer"
trigger:
  type: "context"
  key: "image_built"
  value: "true"
actions:
  - type: "command"
    command: "kubectl apply -f k8s/deployment.yaml"

这样,用户只需要输入 /run-pipeline,三个 Skill 就会按顺序执行。但有个坑:如果中间某个 Skill 失败,后面的不会自动停止。你需要手动在 set_context 里判断退出码,或者用 condition 字段控制执行条件。

调试 Skill:日志是你的朋友

Skill 出问题最难排查,因为它是隐式触发的。我一般会在 Skill 里加一个调试模式:

# 调试用,别提交到生产
name: "debug-skill"
trigger: "/debug-skill"
actions:
  - type: "command"
    command: "echo 'Skill triggered at $(date)' >> /tmp/claude-skill.log"
    # 别这样写:command: "echo 'debug'"  # 信息太少,根本看不出触发上下文
  - type: "respond"
    template: |
      当前上下文变量:
      - tests_passed: {{context.tests_passed}}
      - image_built: {{context.image_built}}
      - 用户输入: {{user_input}}

把这个 Skill 放在 .claude/skills/debug/ 目录下,Claude Code 会递归扫描。调试完直接删掉整个目录,不会影响生产 Skill。

个人经验:Skill 系统的三个铁律

  1. 触发条件宁可严格,不要宽松。一个 Skill 少触发几次,比误触发十次要好。误触发会污染对话上下文,让 Claude 产生幻觉。我们团队现在规定:所有隐式触发必须经过至少两个人 review,阈值不低于 0.85。

  2. Skill 文件必须版本控制.claude/skills/ 目录要提交到 Git,但 .claude/skills/debug/ 要加到 .gitignore。我见过有人把调试 Skill 提交上去,结果 CI 里每次构建都触发调试输出,日志文件涨到几个 GB。

  3. 每个 Skill 只做一件事。如果你发现一个 Skill 里写了三个 command,或者 template 超过 50 行,就该拆分了。Skill 链比大 Skill 更容易调试和复用。我们有个同事写了一个 200 行的 Skill,后来没人敢改,最后重写了六个小 Skill,维护成本直接降了 80%。

Skill 系统用好了,Claude Code 能从“对话助手”变成“自动化引擎”。但用不好,就是那个写十四行诗的 deploy 脚本——看起来有趣,实际上让人想砸键盘。下次我们聊聊 Skill 的权限控制和安全边界,那又是一个能写三篇的坑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值