news 2026/10/2 20:14:12

Claude Skills 从原理到实战:SKILL.md 与 MCP 的完全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Claude Skills 从原理到实战:SKILL.md 与 MCP 的完全指南

1. 为什么你的 Claude Code 总是“记不住”团队规范

先说一个我踩过的坑。团队里定好了接口返回必须带trace_id、日志必须用loguru、目录必须按domain/service/repo分层,结果每次让 Claude Code 写代码,它都按自己的习惯来,我得在 prompt 里把规范复述一遍。复述十几次之后我意识到:这不是模型的问题,是我把“程序性知识”当成了“一次性指令”。

Claude Skills 解决的正是这件事。它是一套可复用的技能包机制,把某个领域的操作流程、判断规则、辅助脚本打包成一个标准文件夹,Claude 在启动时只读取每个技能的元数据(大约 100 Token),当你的任务描述命中技能描述时,才把完整的SKILL.md指令加载进来,脚本和参考文档再按需读取。这个机制叫渐进式披露(Progressive Disclosure),也是 Skills 和普通 Prompt 模板最本质的区别——它不占常驻上下文,却能随时被唤醒。

它适合谁?三类人最该用:一是团队里负责定规范的人,把规范写成 Skill 后所有人共享;二是经常做重复性文档处理、代码审查、数据清洗的开发者;三是已经在用 MCP 接外部工具、但发现“工具会调了、流程还是乱的”的团队。Skills 管“怎么做”,MCP 管“能调什么”,两者是互补关系,不是替代关系。

这篇会从SKILL.md的声明结构讲起,拆开加载流程,说清 Skills 与 MCP 的协作边界,然后给你一份可复制的模板和目录结构,最后用一次真实任务验证技能到底有没有被正确触发。中间涉及模型调用的部分,我会用 TaoToken 的 API 来做验证,因为它的接口和 Anthropic 官方格式一致,调试起来省事。

2. SKILL.md 声明结构与渐进式加载流程拆解

2.1 一个合规 Skill 的目录长什么样

Claude Code 识别技能靠的是目录约定,不是配置文件注册。默认扫描路径是~/.claude/skills/,每个子文件夹就是一个技能,文件夹名必须和SKILL.md里的name字段一致,否则不加载。这是我实测下来最容易翻车的地方——名字对不上,技能静默失效,没有任何报错。

~/.claude/skills/ └── team-code-review/ ├── SKILL.md # 必需,入口文件 ├── scripts/ │ ├── check_naming.py # 命名规范检查 │ └── scan_layering.sh # 分层结构扫描 ├── references/ │ ├── naming_rules.md # 命名规则细则 │ └── error_codes.md # 团队错误码对照 └── assets/ └── review_template.md

SKILL.md分两段:顶部是 YAML 前置元数据,下面接 Markdown 指令正文。元数据里name和description是必填,description直接决定技能会不会被触发,写法上要包含具体场景词,别写“处理文件”这种宽泛描述。

2.2 渐进式披露的三层加载

理解加载时机,才能理解为什么可以装几十个技能还不卡。

层级加载时机Token 量级内容
元数据层会话启动约 100/技能name、description、version
指令层任务命中描述时5k 词以内SKILL.md 正文流程
资源层指令中显式引用时按需scripts、references、assets

关键点在第二层到第三层的跳跃:SKILL.md正文里不要把所有细节都写进去,而是写“遇到命名问题查references/naming_rules.md”,让模型自己决定要不要读。这样指令层能保持精简,资源层几乎不占常驻开销。

2.3 Skills 与 MCP 的协作边界

很多人把这两个搞混。MCP 是 Model Context Protocol,解决的是“模型怎么调用外部工具和数据源”,比如查数据库、调内部 API、读实时监控。Skills 解决的是“模型按什么流程做事”,比如代码审查先查命名再查分层最后查错误码。

协作方式是这样的:Skill 的指令里可以写“调用 MCP 提供的query_metrics工具获取近一小时错误率”,于是 Skill 负责编排流程,MCP 负责执行外部调用。反过来,MCP 单独用的时候,模型知道有这个工具,但不知道什么时候该用、用完怎么处理结果,这部分“判断逻辑”就交给 Skill。

一句话边界:MCP 提供能力,Skill 提供判断。纯流程任务(文档格式化、代码规范检查)不需要 MCP;需要实时数据或外部系统的任务,才在 Skill 里挂 MCP 调用。

2.4 元数据字段的写法要点

description是触发开关,写法上建议“动作 + 对象 + 场景词”。比如“检查 Python 代码的命名规范与目录分层,当用户要求代码审查或提交前检查时启用”。这里“代码审查”“提交前检查”就是触发词,用户说“帮我 review 一下这段代码”时能命中。

allowed-tools是可选的权限声明,写上Read, Bash, Python表示这个技能允许用这些工具。不写的话默认继承会话权限。企业环境里建议显式声明,避免技能意外获得写文件或网络访问权限。

3. 可复制的 SKILL.md 模板与目录配置

3.1 完整 SKILL.md 模板

下面这份是我在团队里实际用的代码审查技能,你可以直接复制改。注意 YAML 的缩进和---分隔符,格式错了整个技能不加载。

--- name: team-code-review description: 检查 Python 代码的命名规范、目录分层与错误码使用,当用户要求代码审查、提交前检查或 review 时启用 version: 1.0.0 license: MIT allowed-tools: Read, Bash, Python --- # 团队代码审查技能 ## 功能说明 对指定 Python 文件或目录执行三项检查:命名规范、目录分层、错误码使用。 输出结构化审查报告,标注问题等级(error/warning/info)。 ## 操作流程 1. 确认待审查路径,若用户未指定则询问 2. 执行 `scripts/check_naming.py` 检查命名规范 3. 执行 `scripts/scan_layering.sh` 检查目录分层 4. 对照 `references/error_codes.md` 检查错误码使用 5. 汇总结果,按 error > warning > info 排序输出 ## 判断规则 - 命名问题查 `references/naming_rules.md`,不要凭记忆判断 - 分层问题:domain 层不得 import service 层 - 错误码:所有 raise 必须使用团队错误码,禁止裸 Exception ## 异常处理 - 路径不存在:提示用户确认路径 - 非 Python 文件:跳过并说明 - 脚本执行失败:输出错误码,建议手动检查 ## 输出格式 ### 代码审查报告 #### error(必须修复) - 文件:行号 - 问题描述 #### warning(建议修复) - 文件:行号 - 问题描述

3.2 辅助脚本的接口约定

脚本放在scripts/下,用相对路径调用。关键是输出要标准化,方便模型解析。下面这个命名检查脚本输出 JSON,模型读起来不会歧义。

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """命名规范检查,输出 JSON 格式结果""" import argparse import json import re import sys from pathlib import Path SNAKE_CASE = re.compile(r"^[a-z][a-z0-9_]*$") CAMEL_CASE = re.compile(r"^[A-Z][a-zA-Z0-9]*$") def check_file(path: Path) -> list: issues = [] for i, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1): if line.strip().startswith("def "): name = line.strip()[4:].split("(")[0] if not SNAKE_CASE.match(name): issues.append({"line": i, "level": "error", "msg": f"函数名 {name} 应为 snake_case"}) if line.strip().startswith("class "): name = line.strip()[6:].split("(")[0].split(":")[0] if not CAMEL_CASE.match(name): issues.append({"line": i, "level": "error", "msg": f"类名 {name} 应为 CamelCase"}) return issues if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--path", required=True) args = parser.parse_args() target = Path(args.path) if not target.exists(): print(json.dumps({"error": "路径不存在"}, ensure_ascii=False)) sys.exit(1) result = {"file": str(target), "issues": check_file(target)} print(json.dumps(result, ensure_ascii=False, indent=2))

3.3 部署到 Claude Code

把整个team-code-review文件夹复制到~/.claude/skills/下,重启 Claude Code。验证是否加载成功,可以在会话里问“你现在有哪些技能”,或者直接触发一次审查任务看它是否自动调用脚本。

如果你是通过 API 方式接入,需要在请求头里带上 Skills 相关的 beta 标记。用 TaoToken 的 API 时,Base URL 填https://taotoken.net/api,Key 在控制台生成,模型 ID 选 Claude 系列即可。请求体里skills字段指向技能目录的挂载路径。

{ "model": "claude-sonnet-4-20250514", "max_tokens": 4096, "messages": [ {"role": "user", "content": "审查 /workspace/demo.py 的代码规范"} ], "skills": [ {"type": "custom", "path": "/root/.claude/skills/team-code-review"} ] }

注意path必须是容器内可访问的绝对路径,本地开发时就是你机器上的实际路径。模型 ID 和路径这两项填错,技能不会触发,但请求本身可能返回 200,所以一定要看返回内容里有没有走审查流程。

4. 验证技能被正确触发的完整请求

4.1 准备测试文件

写一个故意违规的 Python 文件,包含驼峰函数名、错误的分层 import、裸 Exception。

# demo.py from service.user_service import get_user # 违规:domain 不应 import service def getUserName(userId): # 违规:函数名应为 snake_case try: return get_user(userId).name except Exception: # 违规:应使用团队错误码 return None

4.2 发起请求并观察加载行为

用 curl 发一次请求,重点看返回里有没有出现脚本执行结果和错误码对照。

curl https://taotoken.net/api/v1/messages \ -H "x-api-key: $TAOTOKEN_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "max_tokens": 4096, "messages": [{"role": "user", "content": "审查 /workspace/demo.py"}], "skills": [{"type": "custom", "path": "/root/.claude/skills/team-code-review"}] }'

4.3 成功结果的判断标准

技能被正确触发时,返回内容应该包含三样东西:一是命名问题(getUserName应为get_user_name),二是分层问题(domain 层 import service 层),三是错误码问题(裸 Exception)。如果只返回了泛泛的“代码看起来有问题”,说明技能没触发,模型在凭自己的知识回答。

另一个判断信号是脚本调用痕迹。check_naming.py输出的 JSON 里issues数组会被模型引用,返回里能看到具体的行号和问题描述。如果返回里完全没有行号级别的细节,大概率是description没命中,或者SKILL.md的 YAML 格式有问题导致整个技能没加载。

实测下来,从发起请求到拿到结构化报告大约 8 到 15 秒,取决于文件大小和脚本执行时间。如果超过 30 秒还没返回,检查脚本里有没有死循环或者网络请求。

5. 常见报错与排查对照

5.1 技能完全不触发

最典型的表现是模型正常回答,但没有任何脚本调用痕迹。排查顺序:先确认文件夹名和name字段是否完全一致,大小写敏感;再检查SKILL.md顶部的---是否成对出现,YAML 缩进是否用了 Tab(必须用空格);最后看description里有没有用户实际会说的触发词。

如果用的是 API 方式,检查skills数组里的path是否是容器内绝对路径。本地路径和容器路径不一致是高频错误,比如你本地是/Users/you/.claude/skills/,容器里可能是/root/.claude/skills/。

5.2 报错 401 或 local proxy failed

401通常是 Key 没带对或者过期。检查请求头里是x-api-key而不是Authorization: Bearer,Anthropic 格式用的是前者。如果返回local proxy failed,说明请求根本没到服务端,检查 Base URL 是否写成了https://taotoken.net/api,末尾不要多加/v1,SDK 会自己拼。

5.3 报错 reading choices 或返回结构异常

reading choices这类报错一般出现在用 OpenAI 格式的 SDK 去调 Anthropic 接口时。Anthropic 的返回结构是content数组,不是choices。如果你用的是 OpenAI SDK,需要把 Base URL 指向兼容层,或者直接换用 Anthropic SDK。用 TaoToken 时,模型对话页面可以直接测试接口连通性,省去本地调试环境的时间。

5.4 OAuth 相关报错

Claude Code 本地登录用的是 OAuth 流程,如果报 OAuth 错误,通常是本地凭证过期。重新执行登录命令即可。如果是 API 方式接入,不涉及 OAuth,走的是 Key 认证,两者不要混用。混用的典型症状是本地能跑、API 报 401,或者反过来。

5.5 脚本执行失败但技能触发了

技能触发说明元数据和指令层加载正常,问题出在资源层。检查scripts/下的脚本有没有执行权限(chmod +x),依赖库是否安装(PyPDF2、pdfplumber这类要显式装),以及allowed-tools里有没有声明Bash或Python。没声明的话脚本调用会被权限拦截。

6. 把技能目录纳入版本管理的实践

技能目录本质就是文件,直接扔进 Git 仓库跟团队共享是最省事的做法。我的做法是在项目根目录建skills/文件夹,每个技能一个子目录,然后在 CI 里加一步校验:检查每个SKILL.md的 YAML 能否解析、name是否和文件夹名一致、description是否非空。这三项过了,基本不会出现静默失效。

共享方式有两种:一是团队成员各自把skills/软链到~/.claude/skills/,改一处全局生效;二是通过 API 部署时把skills/目录挂载进容器。前者适合本地开发,后者适合 CI 或服务端场景。

如果你还在用 MCP 接外部工具,建议把“什么时候调哪个工具”的判断逻辑抽出来写成 Skill,MCP 只保留工具本身。这样工具升级不影响流程,流程调整也不用动工具配置。两者解耦之后,维护成本会低很多。

需要生成 API Key 或者查看接入文档,可以从控制台和文档页入手;想先验证模型对技能描述的理解是否准确,用模型对话页面发几条测试指令最快;如果是要长期跑编码 Agent 任务,Coding Plan 的额度模型更适合持续调用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 20:14:04

【码动四季】科研里的很多弯路,都是从没有先做最小测试开始的——一次 Codex 多模型接入踩坑记录:把 auth.json 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 20:14:01

ETL数据同步实践:从增量抽取到幂等写入的完整踩坑记录

这个项目是去年我接手的一个数据同步平台,一条从订单库、CRM库、财务系统到统一汇总库的ETL链路。上线前没人觉得它复杂,就是"定时把数据搬过来",可真到做增量抽取、字段映射、幂等写入、失败重试这些环节时,我发现自己…

作者头像 李华
网站建设 2026/10/2 20:13:55

Cursor MCP终极指南:TaoToken统一Key接入与本地调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 20:13:47

HoloCubic_AIO ESP32存储管理完整指南:5个防Flash与RAM溢出的实用技巧

HoloCubic_AIO ESP32存储管理完整指南:5个防Flash与RAM溢出的实用技巧 【免费下载链接】HoloCubic_AIO HoloCubic超多功能AIO固件 基于esp32-arduino的天气时钟、相册、视频播放、桌面投屏、web服务、bilibili粉丝等 项目地址: https://gitcode.com/GitHub_Trendi…

作者头像 李华
网站建设 2026/10/2 20:13:28

MySQL EXPLAIN中Impossible WHERE的真相:优化器如何提前识破空结果

去年排查线上对账任务时,我遇到过一个非常典型的"幽灵问题":某张核心表里明明有数据,SQL 结果集却是空的。没有任何报错,不超时,也没有慢查询记录,日志里干干净净。把 EXPLAIN 拉出来&#xff0c…

作者头像 李华