Claude Agent Skills第一性原理深度解析

最近看到一篇关于Claude Skills的质量非常高的文章, 标题:Claude Agent Skills: A First Principles Deep Dive 链接:https://leehanchung.github.io/blogs/2025/10/26/claude-skills-deep-dive/
长话多说:ClaudeSkills是什么?
最近看到一篇关于Claude Skills的质量非常高的文章,
标题:Claude Agent Skills: A First Principles Deep Dive 链接:https://leehanchung.github.io/blogs/2025/10/26/claude-skills-deep-dive/

笔者读完,高度概括下,Claude Agent Skills 的第一性原理(First Principles)可以概括为:基于提示词的动态上下文注入与元工具架构(Prompt-based Dynamic Context Injection & Meta-Tool Architecture)。
简单来说,Claude 的 Skills不是一段在该模型之外运行的可执行代码(如 Python 函数),而是一段在需要时被“植入”到模型大脑中的高阶指令(Prompt)。
下面我将从四个核心维度拆解其第一性原理:
1. 本质:是“提示词扩展”,而非“代码执行”
- 传统观念:通常认为 Tool/Function Calling 是“模型调用一个外部函数,函数运行代码并返回结果”。
- Skill 的原理:Skill 是一份 Markdown 文件(
SKILL.md)。当 Skill 被调用时,系统并不会去“运行”这个 Skill,而是读取这个文件,将其中的大量指令、工作流和知识“展开”并“注入”到当前的对话历史中。 - 一句话总结:Skill 不直接解决问题,而是通过注入提示词,瞬间把 Claude 变成解决该问题的专家,让 Claude 自己去解决问题。
2. 架构:元工具(Meta-Tool)与纯 LLM 推理
- Meta-Tool 设计:Claude 的 Prompt 里并没有塞入所有 Skill 的具体指令(那样会撑爆 Context Window)。相反,它只有一个名为
Skill的元工具(Meta-Tool)。 - 渐进式披露(Progressive Disclosure):
- Claude 只看到所有 Skill 的名称和简介(Description)。
- Claude完全依靠自身的语言理解能力(LLM Reasoning)来判断用户意图是否匹配某个 Skill 的简介。
- 这里没有硬编码的路由(Router)、正则表达式或分类器。决策完全发生在 Transformer 的前向传播中。
3. 核心机制:双重上下文注入(Dual Context Injection)
当一个 Skill 被选中时,它会执行两个层面的“修改”操作:
A. 对话上下文注入 (Conversation Context Injection)
这是 Skill 最独特的地方。为了解决“既要让用户知道发生了什么,又不能让几千字的提示词刷屏”的矛盾,系统使用了双通道消息机制:
- 显性消息(Metadata):给用户看,例如
<command-message>The "pdf" skill is loading</command-message>。 - 隐性消息(Meta-Prompt):带有
isMeta: true标记。这是包含SKILL.md完整内容的巨大提示词(可能几千字)。它被发送给 API 进入 Claude 的短期记忆,但在用户界面上是隐藏的。
B. 执行上下文修改 (Execution Context Modification)
Skill 不仅注入文字,还动态改变 Claude 的权限环境:
- 工具权限:临时授予特定的工具权限(如
allowed-tools: "Bash(git:*)"),而无需用户反复确认。 - 模型切换:某些 Skill 可以强制切换模型(例如从 Sonnet 切换到 Opus 以进行深度推理)。
4. 运作流程的本质
整个过程可以看作是一个“动态加载特定领域大脑”的过程:
1.用户请求:“帮我分析这个 PDF。”
2.LLM 决策:看到Skill工具里有pdf技能的描述,决定调用command: "pdf"。
3.系统介入:
- 读取
pdf/SKILL.md。 - 生成一条给用户的“正在加载...”消息。
- 生成一条给 AI 的“你现在是 PDF 专家,你的工作流是 1,2,3...”的隐藏消息。
- 修改当前 Session 的权限,允许使用 Bash 中的 PDF 工具。
4.LLM 执行:带着新注入的记忆(Prompt)和新获得的权限(Tools),Claude 仿佛变了一个人(Agent),开始执行具体的 Bash 命令来处理 PDF。
Claude Agent Skills 的第一性原理是通过“元工具”动态地将“静态的知识文件(Markdown)”转化为“动态的对话上下文(Prompt)”。
它并没有创造新的“程序执行”方式,而是极其聪明地利用了 LLMIn-Context Learning(上下文学习)的能力,实现了功能的无限扩展和按需加载。
Skills和Prompts有什么区别?
Claude 的Agent Skills与传统的/之前的提示语(Prompts,通常指 System Prompts 或初始 User Prompts)有着根本性的区别。
虽然 Skills 的本质依然是“提示词”(它们不是可执行代码,而是 Markdown 文件中的指令),但它们在架构、加载方式和作用范围上实现了质的飞跃。
可以用一个形象的比喻来概括:
- 之前的提示语(Previous Prompts):就像是一个全科医生。他在上岗前(对话开始时)背熟了一本厚厚的医学通识手册,在整个诊疗过程中都依赖这本手册的知识。如果手册太厚,他会记不住;如果手册没写的病,他看不了。
- Claude Agent Skills:就像是一个懂得随时呼叫专家的全科医生。他平时只带一本薄薄的通讯录(Skill 列表)。当遇到特定难题(比如需要做心脏手术)时,他会立刻呼叫一位心脏外科专家(加载 Skill),这位专家带着全套专业设备和详细手术指南(完整的 Skill 提示词和工具权限)介入,手术完成后专家离开,医生恢复常态。
以下是具体的深度对比:
1. 加载机制:静态持久 vs. 动态按需 (The Core Difference)
这是最核心的区别。
- 之前的提示语 (Static & Persistent):
- 机制:在对话开始时一次性全部输入给模型(通常在
system消息中)。 - 特点:全局生效,贯穿整个对话始终。
- 缺点:如果你要让 AI 具备十种复杂的专业能力,你需要把这十种能力的详细指南都塞进初始提示语中。这会导致上下文窗口(Context Window)迅速膨胀,不仅昂贵,而且过长的提示语会让模型“抓不住重点”,导致指令遵循能力下降。
- Agent Skills (Dynamic & On-Demand):
- 机制:采用了“渐进式披露 (Progressive Disclosure)”的设计。
- 特点:在初始状态下,Claude 的上下文中并不包含Skill 的详细指令。它只看到了一个包含所有可用 Skill 名称和简短描述的列表(存在于一个名为
Skill的元工具描述中)。 - 触发:只有当 Claude 自己判断需要使用某个技能来解决当前问题时(例如用户要求“分析这个 PDF”),系统才会动态地将该技能对应的庞大、详细的提示词文件(
SKILL.md)注入到当前的对话上下文中。 - 优势:极大节省了上下文空间,让模型在平时保持轻量级,只在需要时“变身”为专家。
2. 架构位置:系统层 vs. 元工具层
- 之前的提示语:
- 通常直接位于 API 请求的
system字段,或者对话历史最开始的user消息中。它们是对话的基础设定。 - Agent Skills:
- 不在 System Prompt 中。
- 它们“寄生”在一个特殊的元工具(Meta-Tool)——即
Skilltool——的描述字段里。 - Skill 的本质是一个提示词模板的容器和调度器。
3. 作用范围:仅对话上下文 vs. 双重上下文修改
之前的提示语通常只能改变模型的“对话上下文”,即告诉它“你是什么角色,你要怎么说话”。但 Skills 能做更多:
- 之前的提示语:
- 作用:设定人设、规则、输出格式。它告诉模型“你应该怎么做”。
- Agent Skills:
- 作用:不仅注入了详细的操作指南(改变对话上下文),它还具备修改执行上下文(Execution Context)的能力。
- 关键区别:Skill 可以动态地改变 Claude 的权限。例如,一个普通的对话可能不允许 Claude 随便运行 Bash 命令,但当
pdfSkill 被加载时,该 Skill 可以临时授予 Claude 使用Bash(pdftotext:*)的权限。甚至,Skill 还可以要求切换到更强大的模型(如从 Sonnet 切到 Opus)来执行当前任务。
4. 可见性与交互模式
- 之前的提示语:
- 通常对用户是隐藏的(System Prompt),或者是用户自己输入的。交互模式简单直接。
- Agent Skills:
- 对用户可见:它会发送一条简短的元数据消息(如“正在加载 PDF 技能...”),让用户知道发生了什么。
- 对用户隐藏(对 AI 可见):它会发送一条带有
isMeta: true标记的、包含数千字详细指令的消息给 API。这条消息是真正指导 Claude 工作的核心,但用户在界面上看不到。 - 双通道通信:为了解决“既要向用户展示进度,又要向 AI 注入大量指令而不刷屏”的矛盾,Skill 采用了巧妙的设计。
下面是两者的总结对比:

简单来说,Skills 是将领域专家的知识模块化,并将其变成了一种可以动态“插拔”的提示词包,同时赋予了这个包修改系统运行环境的能力。
接下来是正文开始:
Claude 的智能体Skills系统是一套基于提示词的复杂元工具架构,它通过注入专门的指令来扩展大型语言模型 (LLM) 的能力。与传统的函数调用或代码执行不同,Skills通过提示词扩展和上下文修改来改变Claude 处理后续请求的方式,而无需编写可执行代码。
本文将从第一性原理深入剖析 Claude 的智能体Skills系统,并详细阐述其架构:一个名为“Skills”的工具充当着元工具,负责将领域特定的提示词注入到对话上下文中。我们将以skill-creator(Skills创建器)和internal-comms(内部沟通)Skills为例,详细解析其完整生命周期,包括文件解析、API 请求结构以及 Claude 的决策过程。
Claude 智能体Skills概述
Claude 利用Skills来提升特定任务的执行效果。Skills被定义为包含指令、脚本和资源的文件夹,Claude可以在需要时加载它们。Claude 采用声明式、基于提示词的系统来实现Skills的发现和调用。AI 模型(Claude)根据系统提示中提供的文本描述来决定是否调用Skills。在代码层面,不存在算法驱动的Skills选择或 AI 驱动的意图检测。所有的决策都完全基于Skills描述,在 Claude 的推理过程中完成。
Skills并非可执行代码。它们不运行 Python 或JavaScript,背后也没有 HTTP 服务器或函数调用。它们也没有硬编码到 Claude 的系统提示中。Skills存在于 API 请求结构中独立的部分。
那么,Skills到底是什么?Skills是专门的提示词模板,用于将领域特定指令注入到对话上下文中。当一个Skills被调用时,它会修改对话上下文(通过注入指令提示词)和执行上下文(通过改变工具权限并可能切换模型)。Skills不是直接执行操作,而是扩展成详细的提示词,这些提示词会为 Claude 解决特定类型的问题做好准备。每个Skills都作为对 Claude 可见工具架构的动态添加项而出现。
当用户发送请求时,Claude 会收到三类信息:用户消息、可用的工具(例如 Read、Write、Bash 等)以及Skills工具。Skills工具的描述包含一个格式化的列表,其中列出了所有可用的Skills及其名称、描述和其他字段的组合。Claude 读取这个列表,并利用其固有的语言理解能力,将用户的意图与Skills描述进行匹配。例如,如果您说“帮我为日志创建一个Skills”,Claude 会看到internal-commsSkills的描述(“当用户想使用其公司喜欢的格式编写内部通信时”),识别出匹配项,然后使用command: "internal-comms"调用Skills工具。
术语说明:
Skills工具(首字母大写) = 管理所有Skills的元工具。它出现在 Claude 的tools数组中,与 Read、Write、Bash 等工具并列。- Skills(首字母小写) = 诸如
pdf、skill-creator、internal-comms等的单个Skills。这些是Skills工具加载的专用指令模板。
以下是 Claude 如何使用Skills的更直观表示。

Claude Skill Flowchart
Skills选择机制在代码层面没有算法路由或意图分类。Claude 代码不使用嵌入 (embeddings)、分类器(classifiers) 或模式匹配 (pattern matching) 来决定调用哪个Skills。相反,系统将所有可用Skills格式化为文本描述,并将其嵌入到Skills工具的提示词中,让 Claude 的语言模型做出决策。这是纯粹的 LLM 推理。没有正则表达式 (regex),没有关键词匹配,也没有基于机器学习的意图检测。决策发生在 Claude 通过 Transformer 的正向通道内部,而不是在应用程序代码中。
当 Claude 调用一个Skills时,系统遵循一个简单的工作流程:加载一个 Markdown 文件 (SKILL.md),将其扩展成详细指令,将这些指令作为新的用户消息注入到对话上下文中,修改执行上下文(允许使用的工具、模型选择),然后在这个富化的环境中继续对话。这与传统工具根本不同,传统工具会执行并返回结果。Skills是为 Claude 解决问题做准备,而不是直接解决问题。
下表有助于更好地辨析工具 (Tools) 和Skills (Skills) 及其能力之间的区别:

构建智能体Skills
现在我们来探讨如何构建Skills,我们将以 Anthropic Skills库中的skill-creatorSkills 作为案例进行分析。提醒一下,智能体Skills是由指令、脚本和资源组成的结构化文件夹,智能体可以动态发现和加载它们,以更好地完成特定任务。Skills通过将您的专业知识打包成可组合的资源提供给 Claude,从而扩展了 Claude 的能力,将通用智能体转变为符合您需求的专业智能体。
关键洞察:Skills = 提示词模板 + 对话上下文注入 + 执行上下文修改 + 可选数据文件和 Python脚本
每个Skills都定义在一个名为SKILL.md(不区分大小写) 的 Markdown 文件中,并可选择与捆绑文件一起存储在/scripts、/references和/assets目录下。这些捆绑文件可以是 Python 脚本、Shell 脚本、字体定义、模板等。以skill-creator为例,它包含SKILL.md、用于许可证的LICENSE.txt,以及/scripts文件夹下的几个 Python 脚本。skill-creator没有/references或/assets目录。

skill-creator package
Skills可以从多个来源发现和加载。Claude 代码会扫描用户设置 (~/.config/claude/skills/)、项目设置 (.claude/skills/)、插件提供的Skills以及内置Skills,来构建可用Skills列表。对于 Claude 桌面版,我们可以按如下方式上传自定义Skills。

Claude Desktop Skill
注意:构建Skills最重要的概念是渐进式披露(Progressive Disclosure)—— 只显示足够的信息来帮助智能体决定下一步做什么,然后在需要时才揭示更多细节。对于智能体Skills而言,它会:
- 披露 Frontmatter:最少信息(名称、描述、许可证)
- 如果选择了某个
Skills,加载SKILL.md:全面但重点突出 - 然后随着
Skills的执行,加载辅助资源、参考文件和脚本
编写 SKILL.md 文件
SKILL.md是Skills提示词的核心。它是一个 Markdown 文件,遵循“前言 (frontmatter)”和“内容 (content)”两部分结构。前言配置Skills如何运行(权限、模型、元数据),而 Markdown 内容则告诉 Claude 做什么。Frontmatter 是用 YAML 编写的 Markdown 文件头部。
┌─────────────────────────────────────┐
│ 1. YAML Frontmatter (元数据) │ ← 配置
│ ---│
│ name: Skills名称 │
│ description: 简要概述 │
│ allowed-tools: "Bash, Read" │
│ version: 1.0.0 ││ --- │
├─────────────────────────────────────┤
│ 2. Markdown 内容 (指令) │ ← Claude 的提示词
│ │
│ 目的解释 │
│ 详细指令 │
│示例和指导 │
│ 分步步骤 │
└─────────────────────────────────────┘
Frontmatter (前言)
前言部分包含控制 Claude 如何发现和使用Skills的元数据。例如,以下是skill-creator的前言:
---
name: skill-creator
description: 用于创建高效Skills的指南。当用户想要创建新Skills(或更新现有Skills)以通过专业知识、工作流或工具集成来扩展 Claude 的能力时,应使用此Skills。
license: 完整条款请参见 LICENSE.txt
---
让我们逐一探讨前言的各个字段。

Claude Skills Frontmatter
name(必填)
不言自明,是Skills的名称。Skills的name在Skills工具中用作command。
Skills的name在Skills工具中用作command。
description(必填)
description字段提供了Skills功能的简要概述。这是 Claude 判断何时调用Skills的主要依据。在上面的示例中,描述明确指出“当用户想要创建一个新Skills时,应该使用此Skills”——这种清晰、面向行动的语言有助于 Claude 将用户意图与Skills能力进行匹配。
系统会自动向描述附加来源信息(例如"(plugin:skills)"),这有助于在加载多个Skills时区分不同来源的Skills。
when_to_use(未记录——可能已废弃或为未来功能)
⚠️ 重要提示:when_to_use字段在代码库中大量出现,但未在任何官方 Anthropic 文档中提及。此字段可能是:
- 正在逐步淘汰的废弃功能
- 尚未正式支持的内部/实验性功能> * 尚未发布但已规划的功能
建议:请使用详细的description字段作为替代。在when_to_use出现在官方文档之前,请避免在生产Skills中使用它。
尽管未被官方文档记载,when_to_use目前在代码库中的工作方式如下:
function formatSkill(skill) {
let description = skill.whenToUse
?`${skill.description} - ${skill.whenToUse}`
: skill.description;
return `"${skill.name}": ${description}`;
}
当when_to_use存在时,它会以连字符分隔符附加到description后面。例如:
"skill-creator": 创建结构良好、可复用的Skills... - 当用户希望构建包含脚本、参考资料或资产的自定义Skills包时
这个组合字符串就是 Claude 在Skills工具的提示词中看到的内容。然而,由于此行为未被文档化,它可能会在未来的版本中改变或移除。更安全的方法是直接将使用指南包含在description字段中,如上述skill-creator示例所示。
license(可选)
不言自明。
allowed-tools(可选)
allowed-tools字段定义了Skills可以在未经用户批准的情况下使用哪些工具,类似于 Claude 的 allowed-tools。
这是一个逗号分隔的字符串,将被解析为允许的工具名称数组。您可以使用通配符来限制权限范围,例如,Bash(git:*)仅允许 git 子命令,而Bash(npm:*)允许所有 npm 操作。skill-creatorSkills使用了"Read,Write,Bash,Glob,Grep,Edit",赋予了它广泛的文件和搜索能力。一个常见的错误是列出所有可用工具,这会造成安全风险并破坏安全模型。
只包含您的Skills实际需要的内容——如果只是读写文件,"Read,Write"就足够了。
# ✅ skill-creator 允许使用多个工具
allowed-tools: "Read,Write,Bash,Glob,Grep,Edit"
# ✅仅限特定的 git 命令
allowed-tools: "Bash(git status:*),Bash(git diff:*),Bash(git log:*),Read,Grep"
# ✅ 仅限文件操作
allowed-tools:"Read,Write,Edit,Glob,Grep"
# ❌ 不必要的攻击面
allowed-tools: "Bash,Read,Write,Edit,Glob,Grep,WebSearch,Task,Agent"
# ❌包含所有 npm 命令的不必要攻击面
allowed-tools: "Bash(npm:*),Read,Write"
model(可选)
model字段定义了Skills可以使用的模型。它默认为继承用户会话中的当前模型。对于代码审查等复杂任务,Skills可以请求更强大的模型,例如 Claude Opus 或其他开源中文模型,懂得都懂。
model: "claude-opus-4-20250514" # 使用特定模型
model: "inherit" # 使用会话的当前模型 (默认)
version、disable-model-invocation和mode(可选)
Skills支持三个可选的前言字段,用于版本控制和调用控制。version字段(例如version: "1.0.0")是一个用于跟踪Skills版本的元数据字段,从前言中解析但主要用于文档和Skills管理目的。
disable-model-invocation字段(布尔值)阻止 Claude 通过Skills工具自动调用该Skills。当设置为true时,该Skills将从显示给 Claude 的列表中排除,并且只能由用户通过/skill-name手动调用,这使其非常适合危险操作、配置命令或需要明确用户控制的交互式工作流。
mode字段(布尔值)将Skills归类为修改 Claude 行为或上下文的“模式命令”。当设置为true时,该Skills会出现在Skills列表顶部的特殊“模式命令”部分(与常规实用Skills分开),使其对于像调试模式 (debug-mode)、专家模式 (expert-mode) 或审查模式 (review-mode) 这样建立特定操作上下文或工作流的Skills来说非常突出。
SKILL.md 提示词内容
前言之后是 Markdown 内容——当Skills被调用时,Claude 实际接收到的提示词。在这里您可以定义Skills的行为、指令和工作流程。编写有效Skills提示词的关键是保持专注并使用渐进式披露:在SKILL.md中提供核心指令,并引用外部文件以获取详细内容。
以下是建议的内容结构:
---
# 前言在此
---
# [简要目的声明- 1-2 句话]
## 概述
[此Skills的功能,何时使用,提供什么]
## 前提条件
[所需工具、文件或上下文]
## 指令
### 步骤 1:[第一个操作]
[命令式指令]
[必要时提供示例]
### 步骤 2: [下一个操作]
[命令式指令]
### 步骤 3: [最终操作]
[命令式指令]## 输出格式
[如何构建结果]
## 错误处理
[出现故障时的处理方法]
## 示例
[具体使用示例]
## 资源
[如果捆绑了 scripts/、references/、assets/,请在此处引用]
例如,skill-creatorSkills包含以下指令,详细说明了创建Skills所需的工作流步骤。
## Skills创建流程
### 步骤 1:通过具体示例理解Skills
### 步骤 2:规划可复用Skills内容
### 步骤 3:初始化Skills
### 步骤 4:编辑Skills
### 步骤 5:打包Skills
```当 Claude 调用此Skills时,它会收到整个提示词作为新指令,并预置基本目录路径。`{baseDir}` 变量解析为Skills的安装目录,允许 Claude 使用 Read 工具加载参考文件:`Read({baseDir}/scripts/init_skill.py)`。这种模式使主提示词保持简洁,同时按需提供详细文档。
**编写提示词内容的最佳实践:**
* 保持在 5,000 字(约 800 行)以内,以避免上下文过载
* 使用命令式语言(“分析代码以…”),而不是第二人称(“你应该分析…”)
* 引用外部文件以获取详细内容,而不是将所有内容嵌入其中
* 路径使用 `{baseDir}`,切勿硬编码绝对路径,例如 `/home/user/project/`
❌ Read /home/user/project/config.json ✅ Read {baseDir}/config.json
当Skills被调用时,Claude 只能访问 `allowed-tools` 中指定的工具,并且如果前言中指定,模型可能会被覆盖。Skills的基本目录路径会自动提供,使得捆绑资源可访问。
### 将资源与您的Skills捆绑
当您将支持资源与 `SKILL.md` 捆绑在一起时,`Skills` 变得强大。标准结构使用三个目录,每个目录都有其特定用途:
my-skill/ ├── SKILL.md # 核心提示词和指令 ├── scripts/ # 可执行的 Python/Bash 脚本 ├── references/ # 加载到上下文中的文档 └── assets/ # 模板和二进制文件
**为什么要捆绑资源?** 保持 `SKILL.md` 简洁(低于 5,000 字)可以防止 Claude 的上下文窗口过载。捆绑资源让您可以提供详细的文档、自动化脚本和模板,而不会使主提示词臃肿。Claude 仅在需要时通过渐进式披露加载它们。
#### `scripts/` 目录
`scripts/` 目录包含 Claude 通过 Bash 工具运行的可执行代码——自动化脚本、数据处理器、验证器或代码生成器,它们执行确定性操作。
例如,`skill-creator` 的 `SKILL.md` 引用脚本如下:
从头开始创建新Skills时,请务必运行init_skill.py脚本。该脚本方便地生成一个新的模板Skills目录,其中自动包含Skills所需的一切,使Skills创建过程更加高效和可靠。
用法:
scripts/init_skill.py <skill-name> --path <output-directory>
该脚本会:
- 在指定路径创建Skills目录
- 生成带有适当前言和待办事项占位符的 SKILL.md 模板
- 创建示例资源目录:scripts/、references/ 和 assets/
- 在每个目录中添加可自定义或删除的示例文件
当 Claude 看到这条指令时,它会执行python {baseDir}/scripts/init_skill.py。{baseDir}变量会自动解析为Skills的安装路径,使Skills在不同环境中可移植。
scripts/的用途:用于复杂的、多步骤操作、数据转换、API 交互,或任何需要精确逻辑的任务,这些逻辑用代码表达比用自然语言表达更清晰。
references/目录
references/目录存储 Claude 在引用时会加载到其上下文中的文档。这些是文本内容——Markdown 文件、JSON 模式、配置模板或任何 Claude 完成任务所需的文档。
例如,mcp-creator的SKILL.md引用如下:
#### 1.4 学习框架文档
**加载并阅读以下参考文件:**
- **MCP 最佳实践**:[📋 查看最佳实践](./reference/mcp_best_practices.md) - 所有 MCP 服务器的核心指南
**对于 Python 实现,还需加载:**
- **Python SDK 文档**:使用 WebFetch 加载 `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`
- [🐍 Python 实现指南](./reference/python_mcp_server.md) - Python 特定的最佳实践和示例**对于 Node/TypeScript 实现,还需加载:**
- **TypeScript SDK 文档**:使用 WebFetch 加载 `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`
- [⚡ TypeScript 实现指南](./reference/node_mcp_server.md) - Node/TypeScript 特定的最佳实践和示例
当 Claude 遇到这些指令时,它会使用 Read 工具:Read({baseDir}/references/mcp_best_practices.md)。内容会被加载到 Claude 的上下文 (context) 中,提供详细信息而不会使 SKILL.md 变得混乱。
references/的用途:用于详细文档、大型模式库、清单、API 模式或任何过于冗长而不适合放入SKILL.md但对任务必要的文本内容。
assets/目录
assets/目录包含模板和二进制文件,Claude 通过路径引用它们但不将其加载到上下文中。可以将其视为Skills的静态资源,例如 HTML 模板、CSS 文件、图片、配置样板文件或字体。
在SKILL.md中:
使用 {baseDir}/assets/report-template.html 中的模板作为报告结构。
参考 {baseDir}/assets/diagram.png 中的架构图。
Claude 看到文件路径但不会读取内容。相反,它可能会将模板复制到新位置,填充占位符,或者在生成输出中引用该路径。
assets/的用途:用于 HTML/CSS 模板、图像、二进制文件、配置模板或任何 Claude 通过路径操作而不是读取到上下文中的文件。
references/和assets/之间的关键区别在于:
references/: 通过 Read 工具加载到 Claude 上下文中的文本内容。assets/: 仅通过路径引用,不加载到上下文中的文件。
这种区别对于上下文管理很重要。references/中的 10KBMarkdown 文件在加载时会消耗上下文 token。assets/中的 10KB HTML 模板则不会。Claude 只知道路径存在。
最佳实践:始终使用{baseDir}表示路径,切勿硬编码绝对路径。这使得Skills可以在用户环境、项目目录和不同安装之间移植。
常见的Skills模式
如同万事万物皆工程,理解常见的模式有助于设计有效的Skills。以下是工具集成和工作流设计中最有用的模式。
模式 1:脚本自动化
用例:需要多个命令或确定性逻辑的复杂操作。
此模式将计算任务卸载到scripts/目录中的Python 或 Bash 脚本。Skills提示词指示 Claude 执行脚本并处理其输出。

Claude Skill Script Automation
SKILL.md 示例:
在目标目录上运行 scripts/analyzer.py:
`python {baseDir}/scripts/analyzer.py --path "$USER_PATH" --output report.json`
解析生成的 `report.json` 并呈现分析结果。
所需工具:
allowed-tools: "Bash(python {baseDir}/scripts/*:*), Read, Write"
模式 2:读取 - 处理 - 写入 (Read - Process - Write)
用例:文件转换和数据处理。
最简单的模式——读取输入,按照指令转换,写入输出。适用于格式转换、数据清理或报告生成。

Claude Skill Read Process Write
SKILL.md 示例:
## 处理工作流
1. 使用 Read 工具读取输入文件
2. 根据格式解析内容
3. 按照规范转换数据
4. 使用 Write 工具写入输出
5. 报告完成情况并提供摘要
所需工具:
allowed-tools: "Read, Write"
模式3:搜索 - 分析 - 报告 (Search - Analyze - Report)
用例:代码库分析和模式检测。
使用 Grep 在代码库中搜索模式,读取匹配文件以获取上下文,分析发现,并生成结构化报告。或者,搜索企业数据存储以获取数据,分析检索到的数据以获取信息,并生成结构化报告。

Claude Skill Search Analyze Report
SKILL.md 示例:
## 分析过程
1. 使用 Grep 查找相关代码模式
2. 读取每个匹配的文件
3. 分析漏洞
4. 生成结构化报告
所需工具:
allowed-tools: "Grep, Read"
4:命令链执行 (Command Chain Execution)
用例:具有依赖关系的多步操作。
执行一系列命令,其中每个步骤都依赖于上一步的成功。常见于类似 CI/CD 的工作流。

SKILL.md 示例:
执行分析管道:
npm install && npm run lint && npm test
报告每个阶段的结果。
所需工具:
allowed-tools: "Bash(npm install:*), Bash(npm run:*), Read"
高级模式
精灵式多步工作流 (Wizard-Style Multi-Step Workflows)
用例:需要在每个步骤中进行用户输入的复杂流程。
将复杂任务分解为离散的步骤,并在每个阶段之间进行明确的用户确认。适用于设置向导、配置工具或引导式流程。
SKILL.md 示例:```
工作流
步骤 1: 初始设置
- 询问用户项目类型
- 验证先决条件是否存在
- 创建基本配置 在继续之前等待用户确认。
步骤 2: 配置
1. 呈现配置选项 2. 要求用户选择设置 3. 生成配置文件 在继续之前等待用户确认。
步骤 3: 初始化
- 运行初始化脚本2. 验证设置成功
- 报告结果
#### 基于模板的生成 (Template-Based Generation)
**用例**:根据 `assets/` 中存储的模板创建结构化输出。
加载模板,用用户提供或生成的数据填充占位符,然后写入结果。常用于报告生成、样板代码创建或文档。
**SKILL.md 示例**:
生成过程
1.从 {baseDir}/assets/template.html 读取模板
2.解析用户需求
3.填充模板占位符:
- → 用户提供的名称
- → 生成的摘要
- → 当前日期
4.将填充后的模板写入输出文件
5.报告完成情况
#### 迭代优化 (Iterative Refinement)
**用例**:需要多次传递且深度逐渐增加的流程。
首先进行广泛分析,然后对识别出的问题进行逐步深入的探究。适用于代码审查、安全审计或质量分析。
**SKILL.md 示例**:
迭代分析
第一次遍历: 全面扫描
1.在整个代码库中搜索模式 2. 识别高级别问题 3. 对发现结果进行分类
第二次遍历: 深入分析
对于每个高级别问题:
- 读取完整文件上下文
- 分析根本原因
- 确定严重性
第三次遍历: 建议
对于每个发现:
- 研究最佳实践
- 生成具体修复方案
- 预估工作量
呈现包含所有发现和建议的最终报告。
#### 上下文聚合 (Context Aggregation)
**用例**:结合来自多个来源的信息,以建立全面的理解。
从不同的文件和工具中收集数据,综合成一个连贯的整体。适用于项目摘要、依赖分析或影响评估。
**SKILL.md 示例**:
上下文收集
- 阅读项目 README.md 以获取概述
- 分析 package.json 以获取依赖项
- Grep 代码库以查找特定模式
- 检查 git 历史记录以了解最近的更改
- 将发现结果综合为连贯的摘要
##智能体Skills内部架构
在介绍了Skills的概述和构建过程之后,我们现在可以深入探讨Skills的底层工作原理。Skills系统通过元工具架构运行,其中一个名为 `Skill` 的工具充当所有单个Skills的容器和调度器。这种设计从实现和目的上都将Skills与传统工具区分开来。
> `Skills` 工具是一个管理所有Skills的元工具。
### Skills对象设计
`Read`、`Bash` 或 `Write` 等传统工具执行离散动作并返回即时结果。Skills的运作方式不同。它们不是直接执行动作,而是将专门的指令注入到对话历史中,并动态修改 Claude 的执行环境。这通过两条用户消息实现——一条包含用户可见的元数据,另一条包含完整的Skills提示词(对 UI 隐藏但发送给 Claude)——并通过改变智能体的上下文来修改权限、切换模型和调整Skills使用期间的思维 token 参数。

| 特性 | 普通工具 (Normal Tool) | Skills工具 (Skill Tool) |
| :------------- | :------------------------------------- | :--------------------------------------- |
| **本质**| 直接动作执行器 | 提示词注入 + 上下文修改器 |
| **消息角色** | assistant → tool_use<br>user → tool_result | assistant → tool_use Skill<br>user → tool_result<br>user → skill prompt ← 注入! |
| **复杂度** | 简单 (3-4 条消息) | 复杂 (5-10+ 条消息) |
|**上下文** | 静态 | 动态 (每轮修改) |
| **持久性** | 仅工具交互 | 工具交互 + Skills提示词 |
| **Token 开销** |极小 (~100 tokens) | 显著 (每轮 ~1,500+ tokens) |
| **用例** | 简单、直接的任务 | 复杂、引导式的工作流 |
其复杂性相当显著。普通工具会生成简单的消息交换——一个助手工具调用,然后是用户结果。Skills会注入多条消息,在动态修改的上下文中运行,并携带大量 token 开销来提供指导 Claude 行为的专用指令。
理解 `Skills` 元工具的工作原理揭示了该系统的机制。让我们检查一下其结构:
Pd = { name: "Skill", // 工具名称常量:$N = "Skill"
inputSchema: { command: string // 例如:"pdf", "skill-creator" },
outputSchema: { success: boolean, commandName: string },// 🔑 关键字段: 这会生成Skills列表 prompt: async () => fN2(),
// 验证和执行 validateInput: async (input, context) => { /* 5 种错误代码/}, checkPermissions: async (input, context) => { /允许/拒绝/询问 */ }, call: async(input, context) => { /产出消息 + 上下文修改器 */ } }```
prompt字段将Skills工具与Read或Bash等其他具有静态描述的工具区分开来。Skills工具不使用固定字符串,而是使用一个动态提示词生成器,通过聚合所有可用Skills的名称和描述在运行时构建其描述。这实现了**渐进式披露 (progressive disclosure)**——系统只将最少的元数据(Skills名称和前言中的描述)加载到 Claude 的初始上下文中,提供足够的信息让模型决定哪个Skills符合用户意图。完整的Skills提示词只有在 Claude 做出选择后才加载,从而防止上下文膨胀,同时保持可发现性。
async function fN2() {let A = await atA(),
{
modeCommands: B,
limitedRegularCommands: Q
} = vN2(A),
G = [...B, ...Q].map((W) => W.userFacingName()).join(", ");
l(`Skills and commands included in Skill tool: ${G}`);
let Z = A.length - B.length,
Y = nS6(B),J = aS6(Q, Z);
return `在主对话中执行一个Skills
<skills_instructions>
当用户要求您执行任务时,检查下方可用的Skills是否能更有效地完成任务。Skills提供专业的能力和领域知识。
如何使用Skills:
- 仅使用Skills名称(不带参数)通过此工具调用Skills
- 当您调用Skills时,您将看到 <command-message>“{name}”Skills正在加载</command-message>
- Skills的提示词将展开并提供详细说明,指导如何完成任务
- 示例:
- \`command: "pdf"\` - 调用 pdf Skills- \`command: "xlsx"\` - 调用 xlsx Skills
- \`command: "ms-office-suite:pdf"\` - 使用完全限定名调用
重要事項:
- 仅使用 <available_skills> 中列出的Skills
- 不要调用已经在运行的Skills
- 不要将此工具用于内置 CLI 命令(例如 /help, /clear 等)
</skills_instructions>
<available_skills>
${Y}${J}
</available_skills>
`;
}
与某些助手(如 ChatGPT)将部分工具存储在系统提示词中不同,Claude 的智能体Skills不存储在系统提示词中。它们作为Skills工具描述的一部分存在于tools数组中。单个Skills的名称作为Skills元工具输入模式的command字段的一部分表示。为了更好地可视化其外观,下面是实际的 API 请求结构:
{
"model": "claude-sonnet-4-5-20250929",
"system": "你是一个名为 Claude Code 的 Anthropic 官方 CLI...",// ← 系统提示词
"messages": [
// ... 对话历史
{ "role": "user", "content": "帮我创建一个新Skills" }
],
"tools": [// ← 发送给 Claude 的工具数组
{
"name": "Skill", // ← 元工具
"description": "执行一个Skills...\n\n<skills_instructions>...\n\n<available_skills>\n...",
"input_schema": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "Skills名称(不带参数)"// ← 单个Skills的名称
}
}
}
},
{
"name": "Bash",
"description": "执行 bash 命令...",
//...
},
{
"name": "Read",
// ...
}
// ... 其他工具
]
}
<available_skills>部分存在于Skills工具的描述中,并为每个 API 请求重新生成。系统通过聚合当前加载的来自用户和项目配置、插件提供的Skills以及任何内置Skills来动态构建此列表,默认受 15,000 字符的 token 预算限制。此预算限制强制Skills作者编写简洁的描述,并确保工具描述不会使模型的上下文窗口过载。
Skills对话和执行上下文注入设计
大多数 LLM API 支持role: "system"消息,理论上可以携带系统提示。事实上,OpenAI 的 ChatGPT 在其系统提示中携带有默认工具,包括用于记忆的bio、用于任务调度的automations、用于控制画布的canmore、用于图像生成的img_gen、file_search、python和用于互联网搜索的web。最后,工具提示占其系统提示中 token 数量的约 90%。这可能有用,但如果我们需要加载大量工具和/或Skills到上下文中,则效率不高。
然而,系统消息具有不同的语义,使其不适合Skills。系统消息设置了在整个对话中持续存在的全局上下文,以比用户指令更高的权限影响所有后续轮次。
Skills需要临时、有范围的行为。skill-creatorSkills应该只影响Skills创建相关任务,而不是将 Claude 永久转变为会话其余时间的 PDF 专家。使用role:"user"和isMeta: true会使Skills提示作为用户输入出现在 Claude 中,使其保持临时性并局限于当前交互。Skills完成后,对话返回到正常的对话上下文和执行上下文,而没有残留的行为修改。
像Read、Write或Bash这样的普通工具具有简单的通信模式。当 Claude 调用Read时,它会发送一个文件路径,接收文件内容,然后继续工作。用户会在其会话记录中看到“Claude 使用了 Read 工具”,这已足够透明。该工具完成了一项任务,返回了一个结果,交互就此结束。Skills的运作方式根本不同。Skills不是执行离散操作并返回结果,而是注入全面的指令集,这些指令集会修改 Claude 对任务的推理和处理方式。这带来了普通工具从未面临的设计挑战:用户需要了解哪些Skills正在运行以及它们正在做什么,而 Claude 需要详细、可能冗长的指令才能正确执行Skills。如果用户在其聊天记录中看到完整的Skills提示,UI 将被数千字的内部 AI 指令所淹没。如果Skills激活完全隐藏,用户将无法了解系统正在代表他们做什么。解决方案是需要将这两个通信通道分离到具有不同可见性规则的不同消息中。
Skills系统在每条消息上使用isMeta标志来控制它是否显示在用户界面中。当isMeta: false(或当该标志被省略并默认为 false)时,消息会在用户看到的对话记录中呈现。当isMeta: true时,消息作为 Claude 对话上下文的一部分发送到 Anthropic API,但永远不会出现在 UI 中。这个简单的布尔标志实现了复杂的双通道通信:一个流供人类用户使用,另一个流供 AI 模型使用。这是元工具的元提示!
当Skills执行时,系统会向对话历史中注入两条独立的用户消息。第一条消息携带isMeta: false的Skills元数据,使其作为状态指示符对用户可见。第二条消息携带isMeta: true的完整Skills提示,将其从 UI 中隐藏起来,同时使其可供Claude 使用。这种分离通过向用户展示正在发生的事情而不让他们被实现细节所淹扰,解决了透明性与清晰度之间的权衡。
元数据消息使用简洁的 XML 结构,前端可以对其进行适当解析和显示:```javascript let metadata = [<command-message>${statusMessage}</command-message>,<command-name>${skillName}</command-name>, args ?<command-args>${args}</command-args>: null, ] .filter(Boolean) .join('\n');
// 消息 1: 没有 isMeta 标志 → 默认为 false → 可见 messages.push({ content: metadata,autocheckpoint: checkpointFlag, });
例如,当 PDF Skills激活时,用户会在其会话记录中看到一个简洁的加载指示:
“pdf”Skills正在加载pdfreport.pdf
这条消息有意保持最少信息——通常为 50 到200 个字符。XML 标签使前端能够使用特殊格式渲染它,验证是否存在 proper `<command-message>` 标签,并维护会话期间执行了哪些Skills的审计跟踪。由于 `isMeta` 标志在省略时默认为 false,因此此元数据会自动显示在 UI 中。
Skills提示消息采取相反的方法。它加载 `SKILL.md` 中的完整内容,可能会用额外的上下文进行增强,并明确设置 `isMeta:true` 以将其从用户处隐藏:
```javascript
let skillPrompt = await skill.getPromptForCommand(args, context);
// 如有需要,用前置/后置内容进行增强
let fullPrompt =prependContent.length > 0 || appendContent.length > 0
? [...prependContent, ...appendContent, ...skillPrompt]
: skillPrompt;
// 消息 2: 明确指定 isMeta: true→ 隐藏
messages.push({
content: fullPrompt,
isMeta: true, // 对 UI 隐藏,发送给 API
});
一个典型的Skills提示词有 500 到 5,000 字,它提供全面的指导来改变 Claude 的行为。PDF Skills提示词可能包含:
您是 PDF 文件处理专家。
您的任务是使用 pdftotext 工具从 PDF 文档中提取文本。
## 流程
1. 验证 PDF 文件是否存在
2. 运行 pdftotext 命令提取文本
3. 读取输出文件
4. 将提取的文本呈现给用户
## 可用工具您可以使用:
- Bash(pdftotext:*) - 用于运行 pdftotext 命令
- Read - 用于读取提取的文本
- Write - 如有需要,用于保存结果
## 输出格式
清晰格式化地呈现提取的文本。
基本目录:/path/to/skill
用户参数:report.pdf
此提示词建立了任务上下文,概述了工作流程,指定了可用工具,定义了输出格式,并提供了特定于环境的路径。带有标题、列表和代码块的 Markdown 结构有助于 Claude 解析和遵循指令。通过isMeta: true,整个提示词都会发送到 API,但绝不会使用户的会话记录混乱。除了核心元数据和Skills提示词之外,Skills还可以注入用于附件和权限的额外条件消息:
let allMessages = [
createMessage({ content: metadata, autocheckpoint: flag }), // 1. 元数据
createMessage({ content: skillPrompt, isMeta: true }), // 2. Skills提示词
...attachmentMessages, // 3. 附件(条件性)
...(allowedTools.length ||skill.model
? [
createPermissionsMessage({
// 4. 权限(条件性)
type: 'command_permissions',
allowedTools: allowedTools,
model: skill.useSmallFastModel ? getFastModel() : skill.model,
}),
]
: []),
];
附件消息可以携带诊断信息、文件引用或补充Skills提示的其他上下文。权限消息仅在Skills在前言中指定allowed-tools或请求模型覆盖时出现,提供修改运行时执行环境的元数据。这种模块化组合允许每条消息具有特定目的,并根据Skills的配置包含或排除,从而扩展了基本的两消息模式,以处理更复杂的场景,同时通过isMeta标志保持相同的可见性控制。
为什么是两条消息而不是一条?
单消息设计将迫使做出一个不可能的选择。将isMeta: false设置为false会使整个消息可见,从而将数千字的 AI 指令转储到用户的聊天记录中。用户会看到如下内容:
┌─────────────────────────────────────────────┐│ “pdf”Skills正在加载 │
│ │
│ 您是 PDF 文件处理专家。 │
│ │
│ 您的任务是使用 pdftotext 工具从 PDF │
│文档中提取文本。 │
│ │
│ ## 流程 │
│ │
│ 1. 验证 PDF 文件是否存在 │
│ 2. 运行 pdftotext命令提取文本 │
│ 3. 读取输出文件 │
│ ... [还有 500 多行] ... │
└─────────────────────────────────────────────┘
用户界面将变得无法使用,充满了本应是给 Claude 而非人类阅读的内部实现细节。或者,将isMeta: true设置为true会隐藏所有内容,对哪个Skills已激活或它收到了哪些参数都不透明。用户将无法了解系统正在代表他们做什么。
两条消息的分离解决了这个问题,通过为每条消息赋予不同的isMeta值。isMeta: false的消息 1 提供了面向用户的透明度。isMeta: true的消息 2 为 Claude 提供了详细指令。这种细粒度控制实现了透明度而没有信息过载。
这些消息也服务于根本不同的受众和目的:

代码库甚至通过不同的路径处理这些消息。元数据消息被解析以查找<command-message>标签,经过验证并格式化以在 UI 中显示。Skills提示消息直接发送到 API,不进行解析或验证——它是仅供 Claude 推理过程使用的原始指令内容。将它们组合在一起将违反单一职责原则,因为这会迫使一条消息通过两个不同的处理管道服务于两个不同的受众。
案例研究:执行生命周期
现在我们已经了解了智能体Skills的内部架构,接下来通过一个假设的pdfSkills作为案例研究,详细解析用户说“从 report.pdf 中提取文本”时发生的完整执行流程。

Claude Skill Execution Flow
阶段 1:发现与加载 (启动)
当 Claude Code 启动时,它会扫描Skills:
async function getAllCommands() {
// 并行地从所有来源加载
let [userCommands, skillsAndPlugins, pluginCommands, builtins] =
awaitPromise.all([
loadUserCommands(), // ~/.claude/commands/
loadSkills(), //.claude/skills/ + 插件
loadPluginCommands(), // 插件定义的命令
getBuiltinCommands(), // 硬编码命令
]);
return [...userCommands, ...skillsAndPlugins, ...pluginCommands,...builtins].filter(
(cmd) => cmd.isEnabled()
);
}
// 特定Skills加载
asyncfunction loadPluginSkills(plugin) {
// 检查插件是否有Skills
if (!plugin.skillsPath) return [];
// 支持两种模式:
// 1. skillsPath 中的根目录 SKILL.md
// 2. 带有 SKILL.md 的子目录
const skillFiles = findSkillMdFiles(plugin.skillsPath);
const skills = [];
for (const file of skillFiles) {
const content = readFile(file);
const { frontmatter, markdown } = parseFrontmatter(content);
skills.push({
type: 'prompt',
name: `${plugin.name}:${getSkillName(file)}`,
description: `${frontmatter.description} (plugin:${plugin.name})`,whenToUse: frontmatter.when_to_use, // ← 注意:下划线!
allowedTools: parseTools(frontmatter['allowed-tools']),
model: frontmatter.model === 'inherit' ? undefined : frontmatter.model,
isSkill: true,
promptContent: markdown,
// ... 其他字段
});
}
return skills;
}
对于 PDF Skills,这会产生:
{
type: "prompt",
name: "pdf",
description: "从 PDF 文档中提取文本 (plugin:document-tools)",
whenToUse: "当用户想要从 PDF 文件中提取或处理文本时",
allowedTools: ["Bash(pdftotext:*)", "Read", "Write"],
model: undefined, // 使用会话模型
isSkill: true,
disableModelInvocation:false,
promptContent: "您是 PDF 处理专家...",
// ... 其他字段
}
阶段 2:第 1 轮 - 用户请求与Skills选择
用户发送请求:“从 report.pdf 中提取文本”。Claude 收到此消息以及工具数组中的Skills工具。在 Claude 决定调用 pdf Skills之前,系统必须在Skills工具的描述中呈现可用Skills。
Skills过滤与呈现
并非所有已加载的Skills都会出现在Skills工具中。一个Skills必须在前言中包含description或when_to_use,否则将被过滤掉。过滤标准:
async function getSkillsForSkillTool() {const allCommands = await getAllCommands();
return allCommands.filter(
(cmd) =>
cmd.type === 'prompt' &&
cmd.isSkill === true &&
!cmd.disableModelInvocation &&
(cmd.source !== 'builtin' || cmd.isModeCommand === true) &&
(cmd.hasUserSpecifiedDescription || cmd.whenToUse) // ← 必须有一个!
);
}```
#### Skills格式化
每个Skills都为 `<available_skills>` 部分进行格式化。例如,我们假设的 `pdf` Skills可以格式化为:
`"pdf": 从 PDF 文档中提取文本 - 当用户想要从 PDF 文件中提取或处理文本时`
```javascript
function formatSkill(skill) {
let name = skill.name;
let description = skill.whenToUse
?`${skill.description} - ${skill.whenToUse}`
: skill.description;
return`"${name}": ${description}`;
}
Claude 的决策过程
现在,当用户提示:“Extract text from report.pdf”。Claude 收到包含Skills工具的 API 请求,读取<available_skills>,并进行推理(假设,因为我们看不到推理痕迹):
内部推理:
- 用户想要“从 report.pdf 中提取文本”
- 这是一项 PDF 处理任务
- 查看可用Skills...
- "pdf": 从 PDF 文档中提取文本 - 当用户想要从 PDF 文件中提取或处理文本时- 这匹配了!用户想要从 PDF 中提取文本
- 决策:调用Skills工具,命令为 "pdf"
请注意,这里没有算法匹配。没有词法匹配。没有语义匹配。没有搜索。这纯粹是 LLM 根据Skills描述对其决策进行的推理。完成后,Claude 返回一个工具使用:
{
"type": "tool_use",
"id": "toolu_123abc",
"name": "Skill",
"input": {
"command": "pdf"
}
}
阶段 3:Skills工具执行
Skills工具现在执行。这对应于序列图中的黄色“SKILL TOOL EXECUTION”(Skills工具执行)框,它在生成结果之前执行验证、权限检查、文件加载和上下文修改。
步骤 1:验证
asyncvalidateInput({ command }, context) {
let skillName = command.trim().replace(/^\//, "");
// 错误 1: 空
if (!skillName) return { result: false, errorCode: 1};
// 错误 2: 未知Skills
const allSkills = await getAllCommands();
if (!skillExists(skillName, allSkills)) {
return { result: false, errorCode: 2};
}
// 错误 3: 无法加载
const skill = getSkill(skillName, allSkills);
if (!skill) return { result: false, errorCode: 3 };
//错误 4: 模型调用已禁用
if (skill.disableModelInvocation) {
return { result: false, errorCode: 4 };
}
// 错误 5: 不是基于提示词的if (skill.type !== "prompt") {
return { result: false, errorCode: 5 };
}
return { result: true };
}
PDF Skills通过了所有验证检查 ✓
步骤 2:权限检查
async checkPermissions({ command }, context) {
const skillName = command.trim().replace(/^\//, "");
const permContext = (await context.getAppState()).toolPermissionContext;
// 检查拒绝规则
for (const [pattern, rule] of getDenyRules(permContext)) {
if (matches(skillName, pattern)) {
return{ behavior: "deny", message: "被权限规则阻止" };
}
}
// 检查允许规则
for (const [pattern, rule] of getAllowRules(permContext)) {
if(matches(skillName, pattern)) {
return { behavior: "allow" };
}
}
// 默认:询问用户
return { behavior: "ask", message: `执行Skills: ${skillName}` };
}
假设没有规则,系统会提示用户:“执行Skills:pdf?”
用户批准 ✓
步骤 3:加载Skills文件并生成执行上下文修改
通过验证和权限批准后,Skills工具加载Skills文件并准备执行上下文修改:
async *call({ command }, context) {
const skillName = command.trim().replace(/^\//, "");
const allSkills = await getAllCommands();const skill = getSkill(skillName, allSkills);
// 加载Skills提示
const promptContent = await skill.getPromptForCommand("", context);
// 生成元数据标签
const metadata = [`<command-message>“${skill.userFacingName()}”Skills正在加载</command-message>`,
`<command-name>${skill.userFacingName()}</command-name>`,
].join('\n');
// 创建消息
const messages = [
{ type: "user", content: metadata }, // 对用户可见
{ type: "user", content: promptContent, isMeta: true }, // 对用户隐藏,对 Claude 可见
// ... 附件、权限
];
// 提取配置
const allowedTools = skill.allowedTools || [];
const modelOverride = skill.model;
// 生成带有执行上下文修改器的结果
yield {
type: "result",
data: { success: true, commandName: skillName },
newMessages: messages,
// 🔑 执行上下文修改函数contextModifier(context) {
let modified = context;
// 注入允许的工具
if (allowedTools.length > 0) {
modified = {
...modified,
async getAppState() {
const state = await context.getAppState();
return {
...state,
toolPermissionContext: {
...state.toolPermissionContext,
alwaysAllowRules: {...state.toolPermissionContext.alwaysAllowRules,
command: [
...(state.toolPermissionContext.alwaysAllowRules.command || []),
...allowedTools, // ← 预批准这些工具
],},
},
};
},
};
}
// 覆盖模型
if (modelOverride) {
modified = {
...modified,
options: {
...modified.options,
mainLoopModel: modelOverride,
},
};
}
return modified;
},
};
}
Skills工具生成其结果,其中包含newMessages(元数据 + Skills提示 + 用于对话上下文注入的权限)和contextModifier(工具权限 + 用于执行上下文修改的模型覆盖)。这完成了序列图中的黄色“SKILL TOOL EXECUTION”框。
###阶段4:发送到 API (第一轮完成)
系统构建要发送到 Anthropic API 的完整消息数组。这包括对话中的所有消息以及新注入的Skills消息:
// 发送至 API 的第一轮完整消息数组
{
"model": "claude-sonnet-4-5-20250929",
"messages": [
{
"role": "user","content": "从 report.pdf 中提取文本"
},
{
"role": "assistant",
"content": [
{
"type": "tool_use","id": "toolu_123abc",
"name": "Skill",
"input": { "command": "pdf" }
}
]
},
{"role": "user",
"content": "<command-message>“pdf”Skills正在加载</command-message>\n<command-name>pdf</command-name>"
// isMeta: false (默认) - 在UI 中对用户可见
},
{
"role": "user",
"content": "您是 PDF 文件处理专家...\n\n## 流程\n1. 验证 PDF 存在\n2. 运行 pdftotext...",
"isMeta": true// 从 UI 隐藏,发送给 API
},
{
"role": "user",
"content": {
"type": "command_permissions",
"allowedTools": ["Bash(pdftotext:*)", "Read", "Write"],
"model": null
}
}
]
}

Turn1 Completion
上面显示了我们目前所做的。执行上下文修改器已应用,预先批准了Bash(pdftotext:*)、Read和Write以进行后续工具调用。请求已发送到 Anthropic API。这就完成了Skills执行。如果这是一个普通工具,我们已经全部完成。然而,Skills有所不同。智能体Skills只注入了对话上下文和执行上下文。这意味着我们仍然需要使用所有这些注入的上下文来调用 Claude 智能体,以完成用户的请求!
###阶段5:Bash 工具执行 (在Skills上下文中的工具使用!)
Claude 收到带有注入对话上下文的 API 响应。Skills提示词更改了 Claude 的行为,向其提供了:
- 专门的 PDF 处理指令(对话上下文)
- 预批准访问
Bash(pdftotext:*)、Read和Write工具(执行上下文) - 清晰的工作流程(对话上下文)
Claude 处理上下文并遵循 PDFSkills的工作流程:
我将从 report.pdf 中提取文本。让我处理文件。
[根据 PDF Skills的指示]
1. 验证 report.pdf 是否存在
2. 运行 pdftotext 命令提取文本
3. 读取输出文件
4. 向您呈现提取的文本
Claude 使用 Bash 工具(已预先批准,无需用户提示):
{
"type": "tool_use",
"id": "toolu_456def",
"name": "Bash",
"input": {
"command": "pdftotext report.pdf output.txt","description": "使用 pdftotext 从 PDF 中提取文本"
}
}
Bash 工具成功执行,返回结果。Claude 随后使用 Read 工具读取输出文件,并向用户呈现提取的文本。通过将指令注入对话上下文并修改工具权限的执行上下文,该Skills成功地指导了 Claude 完成了专门的 PDF 提取工作流。
结论:心智模型回顾
Claude Code 中的Skills是基于提示词的对话和执行上下文修改器,通过元工具架构工作:
关键要点:
- Skills是
SKILL.md文件中的提示词模板,而不是可执行代码。 Skills工具(首字母大写)是tools数组中的一个元工具,用于管理单个Skills,而不是存在于系统提示词中。- Skills通过注入指令提示词(通过设置
isMeta: true的消息)来修改对话上下文。 - Skills通过更改工具权限和模型选择来修改执行上下文。
- 选择过程通过LLM 推理完成,而非算法匹配。
- 工具权限通过执行上下文修改限定在Skills执行的范围内。
- Skills每次调用会注入两条用户消息——一条用于用户可见的元数据,一条用于发送给 API 的隐藏指令。
优雅的设计:通过将专业知识视为修改对话上下文的提示词和修改执行上下文的权限,而非执行代码,Claude Code实现了传统函数调用难以达到的灵活性、安全性和可组合性。
参考文献
- Introducing Agent Skills
- Equipping Agents forthe Real World with Agent Skills
- Claude Code Documentation
- Anthropic API Reference
- Official Documented FrontmatterFields
- Internal Comms Skill
- Skill Creator Skill
- ChatGPT 5 System Prompt(leaked, not official)
文章来自于“ChallengeHub”,作者 “致Great”。
相关主题
读完之后
加入 AINRK 交流群
了解加入交流群的方式,与更多 AI 从业者交流。




