首页 › tutorials › 正则表达式工作台Skill开发实战

概述

本教程面向希望从零掌握 Claude Code 自定义 Skill 开发的工程师。你将从"能力建模"出发,亲手构建一个名为 regex-workbench(正则表达式工作台)的完整、可运行的生产级 Skill,覆盖 SKILL.md 元数据设计、渐进披露、动态上下文注入、捆绑脚本、触发控制、隔离执行与评测分发全链路。学完后你能独立设计、实现、测试并分发任何领域的自定义 Skill。

前置条件


一、Skill 的本质:基于渐进披露的能力单元

在动手之前,必须先建立正确的心智模型。Skill 的官方定义是:一个目录 + 一个 SKILL.md 入口文件,外加若干可选的支撑文件。它的核心价值不在于"写一段提示词",而在于渐进披露(Progressive Disclosure)——只在真正需要时才把完整内容载入上下文。

这与 CLAUDE.md 形成关键对比:

维度 CLAUDE.md Skill
载入时机 每个会话常驻上下文 仅在被触发时载入完整正文
适合内容 简短的事实、约定、不变量 多步流程、长参考资料、可执行脚本
Token 成本 持续消耗 触发前几乎为零(仅 description 常驻)
触发方式 被动 可由用户 /skill-name 或模型自动触发

一条经验法则:当 CLAUDE.md 中某一段从"事实"长成了"流程",就把它抽成 Skill。

Skill 存放位置决定其作用范围,这是第二个必须记住的规则:

层级 路径 作用范围
企业(Managed) 由托管设置下发 全组织所有用户
个人(Personal) ~/.claude/skills/<name>/SKILL.md 你自己的所有项目
项目(Project) <repo>/.claude/skills/<name>/SKILL.md 仅当前项目
插件(Plugin) <plugin>/skills/<name>/SKILL.md 启用该插件处,命名空间隔离

当同名冲突时,优先级为 企业 > 个人 > 项目。本教程为方便跨项目复用,把 regex-workbench 放在个人级。


二、能力建模:先想清楚再写第一行

新手最常见的错误是打开编辑器就写 SKILL.md。正确的顺序是先回答三个设计问题:

问题一:这是"参考资料型"还是"任务型" Skill?

regex-workbench 是混合型:既要注入"如何解读正则"的知识(参考型),又要有"测试 → 解释 → 优化"的明确流程(任务型)。我们让它在两个方向都能触发。

问题二:谁来触发?

这是 Skill 设计中影响最大、却最容易被忽视的决策。三个旋钮组合出四种行为:

配置 用户可触发 模型可触发 description 是否常驻
默认 ✅ ✅ ✅ 常驻
disable-model-invocation: true ✅ ❌ ❌ 不常驻
user-invocable: false ❌ ✅ ✅ 常驻
两者都设 仅作为被预加载的背景知识

regex-workbench 让用户随时调用,也允许模型在用户问正则问题时自动加载——所以用默认配置。

问题三:description 能否撑起自动匹配?

Skill 列表中的 description + when_to_use 合计上限为 1,536 字符,且整体受列表预算约束(默认为模型上下文窗口的 1%)。预算超限时,用得最少的 Skill 的 description 会被优先截断。所以 description 必须把最关键的用例放在最前面,关键词要覆盖用户会自然说出口的词。

常见问题:Skill 该触发时不触发?→ 用 /doctor 检查预算是否溢出、description 是否被截断;并把关键词前移。不该触发却乱触发?→ 收窄 description,或加 disable-model-invocation: true。


三、搭建骨架:SKILL.md 与目录结构

先建目录与文件树:

mkdir -p ~/.claude/skills/regex-workbench/scripts
mkdir -p ~/.claude/skills/regex-workbench/examples

目标结构:

regex-workbench/
├── SKILL.md          # 入口(必需):元数据 + 核心流程
├── reference.md      # 渐进披露:正则速查表与陷阱(按需加载)
├── examples.md       # 渐进披露:已解案例(按需加载)
└── scripts/
    └── test.js       # 捆绑脚本:测试引擎(被执行,不载入上下文)

接着写 SKILL.md。它由两部分组成:--- 之间的 YAML 元数据,以及其后的 Markdown 正文。

---
name: regex-workbench
description: Build, test, explain, and optimize regular expressions. Use when the user wants to write or debug a regex, test a pattern against sample strings, explain what a pattern matches, or fix a regex that doesn't match as expected. Also use for extracting, validating, or replacing text with patterns.
argument-hint: [pattern] [flags]
allowed-tools: Bash(node *) Bash(cat *)
---

正文遵循"陈述做什么,而非叙述如何/为什么"的极简原则——因为一旦 Skill 被触发,其正文会作为单条消息常驻整个会话,每一行都是反复出现的 token 成本。

# 正则表达式工作台

当用户需要编写、调试或优化正则时,按以下流程工作。

## 1. 收集输入
- 用户提供的模式(pattern)、标志(flags,如 `g`、`i`、`m`)以及待测字符串。
- 如果用户只给了自然语言需求(如"匹配中国大陆手机号"),先写出候选模式并说明推理过程。

## 2. 运行测试引擎
把候选字符串写入临时文件,调用捆绑脚本获取结构化匹配结果:
​```bash
node ${CLAUDE_SKILL_DIR}/scripts/test.js "PATTERN" "FLAGS" /tmp/regex-subject.txt
​```
脚本输出 JSON:每个匹配的文本、起始下标、捕获组,以及按行统计的命中数。

## 3. 解释模式
逐段拆解模式,说明每个锚点、字符类、量词、分组的作用。遇到贪婪/惰性量词、回溯陷阱时主动提示风险(详见 reference.md)。

## 4. 给出可执行的改进
如果未命中、误命中或存在灾难性回溯风险,给出修正版模式并说明理由。优先推荐更安全、可读性更强的写法。

## 资源
- 完整速查表与陷阱清单见 [reference.md](reference.md)
- 已解案例(邮箱、IPv4、日期)见 [examples.md](examples.md)

预期结果:保存后,在任意项目里启动 Claude Code,输入 /regex 应在自动补全中看到该 Skill;或直接问"帮我写个正则匹配手机号",模型应自动加载它(无需重启——Claude Code 会实时监听 Skill 目录的 SKILL.md 文本变更)。

常见问题: - 改了不生效?注意实时检测只覆盖 SKILL.md 文本。如果是插件型 Skill,改了 hooks/、.mcp.json 需运行 /reload-plugins。新建一个会话启动时不存在的顶层 skills 目录,则需要重启。 - /regex-workbench 找不到?命令名取自目录名而非 name 字段(除非是插件根 SKILL.md)。 - 路径斜杠不要写死:始终用 ${CLAUDE_SKILL_DIR} 引用捆绑文件,这样无论装在个人级、项目级还是插件级都能正确解析。


四、渐进披露:把参考资料拆出去

如果正则的所有速查表都塞进 SKILL.md,正文会膨胀,每次触发都付出昂贵的常驻成本。正确做法是拆分到 reference.md,仅在 Claude 判断需要时才读取。

reference.md 节选(按需载入,不计入常驻成本):

# 正则速查表与陷阱

## 量词
- `*`(0+)、`+`(1+)、`?`(0/1)、`{n,m}`(n 到 m 次)
- 默认**贪婪**,会尽可能多匹配;加 `?` 变惰性(`.*?`)。

## 灾难性回溯
形如 `(a+)+b` 的嵌套量词在输入不匹配时可能引发指数级回溯。
对策:使用占有量词 `a++b` 或原子分组。

## 边界
- `^` / `$` 匹配行首尾;`m` 标志下按行匹配。
- `\b` 词边界,`\B` 非词边界。

## Unicode
默认 `.` 不匹配换行;需匹配所有字符用 `[\s\S]` 或 `s` 标志。
匹配中文范围:`[\u4e00-\u9fa5]`。

在 SKILL.md 末尾用相对链接显式声明这些文件的存在与用途,Claude 才知道"何时去读"。这是渐进披露的契约:入口只放导航,细节放支撑文件。官方建议 SKILL.md 控制在 500 行以内。


五、动态上下文注入:让 Skill 拿到"现况"

Skill 的强大之处在于它不只是静态文本。!command`` 语法会在发送给 Claude 之前执行命令,并把输出原地替换进正文——Claude 看到的是数据本身,而非命令。

这对 regex-workbench 意味着:当用户在工作目录里有一份需要被正则处理的样本文件时,可以直接把它的内容注入:

## 当前工作区候选样本
!`cat data/sample.log 2>/dev/null | head -50`

执行规则:

变量替换同样重要。完整清单:

变量 含义
$ARGUMENTS 调用时传入的全部参数
$ARGUMENTS[N] / $N 第 N 个参数(0 基)
$name 在 arguments 声明的命名参数
${CLAUDE_SKILL_DIR} Skill 所在目录,引用捆绑脚本必用
${CLAUDE_SESSION_ID} 当前会话 ID,可用于日志/临时文件
${CLAUDE_EFFORT} 当前 effort 级别(low/medium/high/xhigh/max)

常见问题:在受控企业环境里,管理员可通过托管设置 "disableSkillShellExecution": true 一键禁用所有用户/项目/插件级 Skill 的 shell 执行,占位符会被替换为提示文本而不运行命令。


六、捆绑脚本:用 Node 写测试引擎

Skill 可以捆绑任意语言的脚本,赋予 Claude 超越单条提示词的能力。这是 regex-workbench 的核心——一个结构化、可复现的测试引擎。

scripts/test.js 完整实现:

#!/usr/bin/env node
// 用法: node test.js "<pattern>" "<flags>" <subject-file|->"
// 输出 JSON:匹配文本、下标、捕获组、按行命中统计。
const fs = require("fs");
const [, , pattern, flags = "", file] = process.argv;

const result = { ok: true, pattern, flags, matches: [], summary: {} };

// 读取待测文本:支持文件路径或 "-" 从 stdin
let subject = "";
if (!file) {
  result.ok = false;
  result.error = "缺少待测文本参数(文件路径或 - 表示 stdin)";
  console.log(JSON.stringify(result, null, 2));
  process.exit(0);
}
subject = file === "-" ? fs.readFileSync(0, "utf8") : fs.readFileSync(file, "utf8");

try {
  const re = new RegExp(pattern, flags);
  const lines = subject.split(/\r?\n/);

  if (flags.includes("g")) {
    let m, count = 0;
    while ((m = re.exec(subject)) !== null) {
      result.matches.push({ match: m[0], index: m.index, groups: m.slice(1) });
      count++;
      if (m.index === re.lastIndex) re.lastIndex++; // 避免零宽匹配死循环
      if (count >= 1000) { result.truncated = true; break; }
    }
    result.summary.globalMatches = count;
  } else {
    const m = re.exec(subject);
    if (m) result.matches.push({ match: m[0], index: m.index, groups: m.slice(1) });
  }

  const lineRe = new RegExp(pattern, flags.includes("g") ? flags.replace("g", "") : flags);
  result.summary.linesMatched = lines.filter(l => lineRe.test(l)).length;
  result.summary.totalLines = lines.length;
} catch (e) {
  result.ok = false;
  result.error = e.message;
}

console.log(JSON.stringify(result, null, 2));

要点说明:

  1. 结构化输出:脚本输出 JSON,Claude 无需"猜测"匹配结果,可直接据此推理与解释。
  2. 零宽死循环防护:对全局量词加 lastIndex++,防止 a* 这类模式卡死。
  3. 路径无关:调用方用 ${CLAUDE_SKILL_DIR}/scripts/test.js,配合 allowed-tools: Bash(node *) Bash(cat *) 免确认执行。

预期结果:在 SKILL.md 指引下,Claude 会先把候选字符串写入 /tmp/regex-subject.txt,再调用脚本。例如:

printf '13800138000\n010-12345678\ninvalid\n' > /tmp/regex-subject.txt
node ${CLAUDE_SKILL_DIR}/scripts/test.js "^1[3-9]\d{9}$" "" /tmp/regex-subject.txt

输出:

{
  "ok": true,
  "pattern": "^1[3-9]\\d{9}$",
  "matches": [{ "match": "13800138000", "index": 0, "groups": [] }],
  "summary": { "linesMatched": 1, "totalLines": 3 }
}

Claude 据此即可精确地"逐段解释 + 给出改进"。


七、触发控制:自动、手动与权限

随着 Skill 数量增长,必须精确控制"谁能触发"。除 disable-model-invocation 与 user-invocable 外,还有三个利器:

allowed-tools(预批准工具):列出该 Skill 激活时可免确认使用的工具。注意它不限制可用工具范围——所有工具仍可调用,只是被列出的免去逐次确认。

disallowed-tools(临时移除):从可用池中移除某些工具,适合自治型 Skill 强制约束(如后台循环禁用 AskUserQuestion)。该限制在用户发送下一条消息时清除。

paths(路径触发):Glob 模式限定——仅当编辑匹配文件时才自动加载。例如一个只在碰 SQL 文件时触发的审查 Skill:

paths: ["**/*.sql", "**/migrations/**"]

还可在 /permissions 用权限规则精细管控:

Skill(commit)          # 仅允许 commit 这一个
Skill(deploy *)        # 前缀匹配,禁用 deploy 及其参数

或用 skillOverrides(写入 .claude/settings.local.json,也可在 /skills 菜单按空格切换)把某个 Skill 设为 name-only(只留名不留描述,省预算)或 off(完全隐藏)。


八、隔离执行:context: fork + agent

当某个 Skill 需要做大量独立探索(如全仓库扫描)却不希望污染主对话上下文时,加 context: fork 让它在一个隔离的子代理中运行。其正文成为驱动子代理的任务,不访问主对话历史。

---
name: deep-scan
description: Thoroughly scan the codebase for a specific concern.
context: fork
agent: Explore
---
使用 Glob 与 Grep 定位 $ARGUMENTS 相关代码……

agent 可选内置的 Explore(只读、跳过 CLAUDE.md 与 git status,上下文极小)、Plan、general-purpose,或 .claude/agents/ 下的自定义子代理。注意:context: fork 只适合有明确任务的 Skill;若 Skill 只有"约定"而无任务,子代理会收到没有行动指令的指导而空手而归。


九、测试与评测:把 Skill 当软件工程对待

Skill 是代码,就要有测试。利用内置的 skill-creator(/skill-creator 或其命令)可生成评测用例并做方差分析。为 regex-workbench 设计三类用例:

用例 输入 期望
基础匹配 "匹配邮箱,测试 [email protected] 与 xx" 模式正确,准确区分匹配/不匹配
陷阱规避 "匹配 HTML 标签 <b>hi</b>" 提示避免贪婪 .* 误吞,给出非贪婪版
优化建议 "优化 (a|ab)* 类模式" 指出回溯风险,给出原子/占有写法

每个用例以"输入 → 期望行为"形式录入,skill-creator 会对多次运行做方差分析,帮助发现 description 触发不稳定或正文含糊的问题。迭代时遵循:先修 description(提升触发准确度)→ 再修正文(提升执行质量)→ 最后跑评测验证。

Skill 停止影响行为? 通常内容仍在,是模型选择了别的工具。优先强化 description;若需确定性,用 hooks 强制行为;若在压缩后失效,重新触发即可(压缩会按 5K/个、合计 25K token 预算重新挂载最近调用的 Skill)。


十、分发:从个人到组织


实战案例:完整的 regex-workbench 调用演示

把上面所有片段组装起来,完整文件树与三份文件(SKILL.md、reference.md、scripts/test.js)即构成可发布的 Skill。下面是一次真实交互:

用户:帮我写一个正则,从日志里提取形如 2026-06-13T14:30:00 的时间戳,并解释。

模型自动加载 regex-workbench,执行流程:

  1. 写出候选模式 (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}),写入样本到临时文件。
  2. 调用 node ${CLAUDE_SKILL_DIR}/scripts/test.js "(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})" "g" /tmp/sample.log。
  3. 据 JSON 结果逐段解释:\d{4} 年份、- 字面量、T 分隔、捕获组 () 的作用。
  4. 给出改进版:若需限定范围可写成更严格的 (20\d{2}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}),并提示按 reference.md 的边界规则用 \b 避免误匹配。

整个过程中,reference.md 与 examples.md 仅在需要解释陷阱或展示范例时才被读取——这正是渐进披露把成本压到最低的体现。


工作流程图

flowchart TD
    A[用户需求/自然语言] --> B{匹配 description?}
    B -- 是 --> C[自动加载 SKILL.md 正文]
    B -- 否 --> U[用户手动 /regex-workbench]
    U --> C
    C --> D[收集 pattern/flags/subject]
    D --> E["动态注入 !cat 或读临时文件"]
    E --> F["运行捆绑脚本\n${CLAUDE_SKILL_DIR}/scripts/test.js"]
    F --> G[结构化 JSON 结果]
    G --> H{需解释陷阱?}
    H -- 是 --> I[按需读取 reference.md]
    H -- 否 --> J[逐段解释 + 给改进版]
    I --> J
    J --> K[返回用户]
    style F fill:#e1f5ff,stroke:#0288d1
    style I fill:#fff4e1,stroke:#f57c00
flowchart LR
    subgraph 常驻上下文[常驻 - 低成本]
        D1[description\n≤1536 字符]
    end
    subgraph 按需载入[按需 - 渐进披露]
        S1[SKILL.md 正文]
        S2[reference.md]
        S3[examples.md]
    end
    subgraph 被执行[执行 - 不进上下文]
        SC1[scripts/test.js]
    end
    D1 -->|触发| S1
    S1 -.引用.-> S2
    S1 -.引用.-> S3
    S1 ==>|Bash调用| SC1

常见问题排查总表

现象 根因 解决
Skill 不触发 description 关键词不匹配或被预算截断 /doctor 查预算;关键词前移;调高 skillListingBudgetFraction
Skill 乱触发 description 过宽 收窄描述或加 disable-model-invocation: true
命令名不对 取自目录名而非 name 重命名目录,或改用插件根 SKILL.md
找不到脚本 硬编码路径 统一用 ${CLAUDE_SKILL_DIR}/scripts/...
改了 hooks 不生效 实时检测仅覆盖 SKILL.md 文本 /reload-plugins
fork 后空手而归 只有约定无任务 补充明确任务指令再 fork
企业环境命令被禁 disableSkillShellExecution: true 改为不依赖 shell 注入的实现

延伸阅读


训练营适用性评估


参考来源

  1. Extend Claude with skills — Claude Code Docs — 官方 Skill 完整规范:frontmatter 字段、生命周期、渐进披露、动态注入、隔离执行。
  2. Claude Code Skill Frontmatter: Every YAML Option Explained — 全 frontmatter 字段(含 disable-model-invocation、user-invocable、allowed-tools、paths 等)逐一示例与取舍。
  3. Build a Claude Skill: YAML Frontmatter, SKILL.md Instructions, and Testing Guide — 从 YAML 到可运行工作流的动手构建指南。
  4. claude-code-skills.md — gregpriday/claude-code-docs (GitHub) — Skill 文件系统能力模型与渐进披露架构的社区整理。
  5. Agent Skills 开放标准 — Skill 跨多个 AI 工具复用的开放规范,Claude Code 在其上扩展了触发控制与子代理执行。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入