使用 Claude Code 进行 Agentic 编码——理解 Agent Skills

0 阅读31分钟

Agent skills 是 Anthropic 团队在 2025 年 10 月引入的一种机制,用来扩展 AI agent 的能力。Skills 允许把能力打包成结构化单元,其中既可以包含自定义工作流,也可以包含面向特定任务的指令,从而让 agent 能执行更复杂、更有协同性的任务。通过把定义好的行为封装起来,skills 让 agent 的能力不再局限于一般性的推理。Claude 还可以根据 skill 的 description 字段是否与当前对话上下文匹配,自动调用相应 skill。

本章将深入讨论 agent skills 这一概念,帮助你清晰理解它是什么,以及为什么它会在构建更强大 agent 系统时变得如此重要。

本章会采用分层展开的方式来讲 skills。我们会先从基础概念和实际用法讲起,包括它在 Claude Code 这样的环境中如何使用,以及在 LangChain DeepAgents(https://docs.langchain.com/oss/python/deepagents/overview)这类工具中如何工作。然后,我们会进一步下探到底层,分析 skill 被调用时,context 是如何在 agent 内部流动的,从而说明系统在内部究竟是如何运作的。最后,我们会通过一个真实 agent 中的 skill 实现,把这些视角整合起来。目标不仅是理解“怎么用 skills”,更要理解它们背后的设计与动机,从而建立一个完整、扎实并具备技术深度的认知模型。

Skills 背后的一个核心概念,是 渐进式披露(progressive disclosure) 。Skills 并不会被永久加载到 agent 的活动上下文中。相反,系统只会在某个 skill 与当前任务真正相关时,才把它加载进来。这种设计避免了无关指令进入工作上下文,有助于在推理过程中维持清晰性。本章后面,我们会进一步讨论:这种动态加载在 skill 被调用时究竟是如何发生的,以及它会如何影响 agent 内部的上下文流动。

本章将涵盖以下主题:

  • Agent skills 的 gist
  • 深入理解 agent skills
  • 将 agent skills 与其他 agent 原语进行比较

Agent Skills 的 gist

这一节里,我们会先让 agent skills 真正跑起来,并展示如何把它们用进自己的工作流。我们会比较完成同一个任务的两种方式:一种是不使用 skills,另一种是使用 skills。这样,我们就能非常直观地看到 agent 在这两种情况下分别会如何表现。

先进入仓库,并切换到 hookhub 分支,然后打开 commit 列表。选择那条名为 improved hook c ard and hero with multi agent working 的 commit。它会作为我们的起始点。

由于后面还会继续添加新的 commit,分支历史会继续向前发展。但我们这里必须从这个确切的 commit 开始。复制它的 hash,打开 IDE,然后切换到对应分支与 commit:

git switch project/hookhub c125545ca118f51c07eb6defe61ba727dbf05788

切换完成后,会出现一个新的 hookhub 目录。这个目录里包含了前面章节中已经开发好的所有代码。

进入这个目录,并安装依赖:

cd hookhub
npm install

安装完成后,启动开发服务器:

npm run dev

此时,HookHub 应用已经在本地 3000 端口跑起来了。这样,我们就恢复到了演示所需的那个精确基线状态。

image.png

图 9.1 —— 在本地运行的 HookHub

场景 1:不使用 Skills 来做样式适配

图 9.1 里的 UI 是故意做得比较朴素的。假设现在我们希望 HookHub 应用采用一种特定视觉风格,并且与 Anthropic 的设计语言保持完全一致。

如果不使用 skills,我们可以直接 prompt:

Make this web app Anthropic style.

此时,这个仓库里并没有任何关于 Anthropic 品牌规范的引用。于是,agent 会先扫描项目文件,甚至还会去抓取 anthropic.com 上的信息。它会从实时网站中动态推导设计语言,然后开始落地改动。

这种方式确实可行。agent 会更新背景颜色、调整字体,并做一系列视觉层面的微调。最终效果会非常接近 Anthropic 的审美,这本身已经说明它能力很强。

但问题在于:每次重复这个任务时,agent 都要重新去抓取并推导一遍同样的设计语言。如果这个工作流反复执行,那么同样的上下文收集过程就会不断重复。

一种可能的解决方案,是直接把这套设计语言塞进 CLAUDE.md 文件里。但问题也很明显:这样一来,这些上下文就会附着到每一条 prompt 上,包括那些只做后端任务、根本不需要这类前端品牌信息的场景。这会带来不必要的上下文膨胀,并最终让上下文质量退化。

场景 2:使用 Skills 来做样式适配

Skills 提供了一种更优雅的解法。我们可以创建一个 skill,用来描述 Anthropic theme 的设计语言。以后每当我们在做前端工作时,Claude Code 就可以选择这个 skill,使用它,并动态加载所需的设计上下文。下面我们就来看这件事是怎么完成的。

打开 Anthropic 官方的 example skills 仓库:https://github.com/anthropics/skills。每一个 skill 都位于自己独立的目录中。找到 brand-guidelines 这个 skill,并查看它的 SKILL.md 文件。

本章中的一部分示例改编自 Anthropic Skills 仓库(https://github.com/anthropics/skills),该仓库基于 Apache License 2.0 授权。具体实现和行为可能会随着时间继续演化。

一个 skill 可能不止包含 Markdown 文件,还可以包含脚本、可执行程序以及结构化资源。在这个例子里,SKILL.md 文件定义了 Anthropic 官方的品牌颜色、字体规范和设计工件。

这个文件一开始会有 front matter。只有这一部分会在 skill 被选中时注入到 agent 的 system prompt 中。 至于后面 Markdown 中那些详细的品牌规范,则只会在 skill 真正被激活时才加载进 prompt。

这和我们前面在 subagent 中看到的那种按需加载机制是同一种思想。上下文是条件式注入的,而不是全局永久挂载的。

如果是通过 Claude Code 官方 marketplace 安装的 skill,那么只要上游有了新版本,Claude Code 会在启动时自动更新。至于第三方 marketplace skill,则可能需要手动更新,或者通过 /plugin 做显式自动更新配置。

在 Claude Code 中安装 Skills

为了让我们的 coding agent 具备这些 skills,可以把 Anthropic skills 仓库添加成一个 marketplace plugin:

/plugin add marketplace anthropic/skills

Claude Code 会把这个仓库 clone 到本地的 .claude/plugins 目录下。

接着运行 /plugins 来确认安装结果,并浏览可用 plugins。你会看到两类内容:

  • Document skills,也就是一些文档处理能力,例如 Excel 和 PowerPoint 相关技能
  • Example skills,其中就包括前面看到的 brand-guidelines skill

这里有一个值得注意的细节:当 Claude(不是 Claude Code)最初宣布支持创建 deck 和文档时,它其实是和 skills 一起发布的。原因就在于:这些能力在内部其实也是用 agent skills 构建的。也就是说,生成文档和演示文稿的能力,底层用的正是我们现在正在讨论的这套 skills 机制。

把 example skills 安装好。安装完成后,重启 Claude Code,再问:

Which skills do you have?

这时,agent 就会列出当前可用的 skills,其中包括接下来要用到的 brand-guidelines

image.png

图 9.2 —— Claude 列出已安装的 skills,其中包括 brand-guidelines

启用 Skills 后做样式适配

清空上下文,然后重新开启一个新的 Claude 实例。接着发出下面这个请求:

Can you make sure that the logo is according to Anthropic brand?

agent 会先扫描仓库,然后请求权限以使用 brand-guidelines 这个 skill。skill 的 description 会显示出来。批准它。

一旦批准,Claude 就会动态加载 brand-guidelines 目录进入上下文。只有相关的 Markdown 文件会被注入进来。这些额外上下文会使 agent 能按照官方品牌定义去调整设计。

这里最关键的一点是:这类上下文是动态加载的,不会永久附着到每一条 prompt 上。 这种渐进式上下文加载机制,会让工作中的 context window 更干净、更高效。这种做法也就是前面提到的 progressive disclosure

如果你希望某个 skill 只能通过 slash command 手动调用,而不能被 Claude Code 自动触发,那么可以在 skill 的 frontmatter 中加上:

disable-model-invocation: true

改动应用完成后,执行构建流程:

npm run build

然后重启开发服务器:

npm run dev

现在,更新后的设计应该已经有了一些更细微的变化,包括字体调整和更贴近品牌规范的样式。这里的重点并不是肉眼上一定要看到多大差异,而是展示:通过 skill,我们实现了受控的上下文注入

image.png

图 9.3 —— 通过 skills 应用 brand-guidelines 样式后的 HookHub 界面

Skills 并不只局限于静态 Markdown 上下文。有些 skill 还会带可执行脚本。

比如 skill-creator 这个例子。它的目录中就包含多个 Python 脚本。在对应的 SKILL.md 中,agent 会被明确告知:它可以去执行这些脚本。

脚本可以用 Python、Bash、JavaScript 或环境里支持的任意语言来写。只要它们的行为在 skill 定义中被清楚描述,agent 就可以把它们当成确定性工具来使用。

这种方式可以构建出非常结构化的工作流。如果某些流程能够被写成确定性脚本,那么它们就可以被封装进一个 skill,变成更高阶能力的一部分。之后,agent 就能通过执行这些脚本序列,并组合它们的输出,来完成更复杂的任务。

深入理解 Agent Skills

这一节,我们会进一步深入 agent skills,引入 custom skills,并且看一个 skill,它不仅有一个 SKILL.md 文件,还带有 agent 可执行的辅助脚本来帮助完成任务。

我们要分析的这个 skill 托管在一个在线仓库中。我们会把它下载下来,集成到本地,然后继续对它进行修改和增强,让它更符合我们的需要。这个过程正好可以体现 skills 在设计结构化 agent workflow 时所提供的灵活性。

浏览 Claude Skills Marketplace

我们从一个叫 claude-skills-marketplace 的仓库开始:
https://github.com/mhattingpete/claude-skills-marketplace/tree/main
这个仓库采用 Apache 2.0 许可证。它包含了一系列 Claude Code skills,可以下载下来并集成进 Claude Code,或者集成进其他支持 skills 的 agent 环境,例如 Claude Desktop 或 LangChain DeepAgents。它只是若干 Claude Code skills 仓库中的一个代表。

这个仓库里包含多个可安装的 skill,它甚至也可以像前一节那样,通过 plugin system 被加到 Claude Code 里作为一个 marketplace。

Engineering Workflows 这一栏里,我们能找到一个名叫 git-pushing 的 skill。它的设计目的,是帮助把代码推送到 GitHub。

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
---
name: git-pushing
description: Stage, commit, and push git changes with conventional commit messages. Use when user wants to commit and push changes, mentions pushing to remote, or asks to save and push their work. Also activates when user says "push changes", "commit and push", "push this", "push to github", or similar git workflow requests.
---

# Git Push Workflow

Stage all changes, create a conventional commit, and push to the remote branch.

## When to Use

Automatically activate when the user:
- Explicitly asks to push changes ("push this", "commit and push")
- Mentions saving work to remote ("save to github", "push to remote")
- Completes a feature and wants to share it
- Says phrases like "let's push this up" or "commit these changes"

## Workflow

**ALWAYS use the script** - do NOT use manual git commands:

```bash
bash skills/git-pushing/scripts/smart_commit.sh

With custom message:

bash skills/git-pushing/scripts/smart_commit.sh "feat: add feature"

Script handles: staging, conventional commit message, Claude footer, push with -u flag.


打开这个 skill 的 `SKILL.md` 文件后,可以看到它的 description 大致是这样:

- 暂存、提交并推送 Git 改动,并使用 conventional commit message  
- 当用户想要 commit 并 push、提到 push 到远端,或者说要保存工作时使用这个 skill  

位于文件顶部的 YAML front matter,是**唯一会被加载进 Claude Code agent 的 system prompt 的部分**。文件其余部分,则只有在这个 skill 真正被选中执行时才会被读取。

## Skills 中的“有倾向性的工作流”

在 `SKILL.md` 的 workflow 部分,我们可以看到:agent 被明确要求**始终使用一个名为 `smart_commit.sh` 的脚本**。

```text id="52vo8p"
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
---
name: git-pushing
description: Stage, commit, and push git changes with conventional commit messages. Use when user wants to commit and push changes, mentions pushing to remote, or asks to save and push their work. Also activates when user says "push changes", "commit and push", "push this", "push to github", or similar git workflow requests.
---

# Git Push Workflow

Stage all changes, create a conventional commit, and push to the remote branch.

## When to Use

Automatically activate when the user:
- Explicitly asks to push changes ("push this", "commit and push")
- Mentions saving work to remote ("save to github", "push to remote")
- Completes a feature and wants to share it
- Says phrases like "let's push this up" or "commit these changes"

## Workflow

**ALWAYS use the script** - do NOT use manual git commands:

```bash
bash skills/git-pushing/scripts/smart_commit.sh

With custom message:

bash skills/git-pushing/scripts/smart_commit.sh "feat: add feature"

Script handles: staging, conventional commit message, Claude footer, push with -u flag


这个脚本里才真正包含 Git 的执行逻辑,例如 `git add``git status``git commit` 等操作。这个 skill 的作者故意**限制主 agent 不去直接执行原始 Git 命令**,而是要求它只能通过指定脚本完成流程。

这正好说明了一个关键点:**Skills 可以编码“有明确偏好”的 workflow。** 如果一个团队希望所有 commit 都遵循某种固定结构或流程,那么这些逻辑就可以被封装进一个 skill。这样,agent 就会以一种受控方式获得这项能力。

## 审查脚本`scripts` 目录中,我们可以找到 `smart_commit.sh`。这个脚本定义了具体的 Git 执行流程。只有当 agent 决定使用 `git-pushing` 这个 skill 时,它才会去运行这个脚本。

这个脚本中包含真正的执行逻辑:它会按顺序运行一组 Git 命令,例如暂存改动、检查状态、以特定信息提交。主 agent 使用这个 skill 时,预期动作就是去运行这个脚本。关键点在于:**只有在 skill 被选中之后,agent 才会“知道”这个脚本的存在。** 也就是说,这个脚本也属于 skill context 的一部分,只会在被调用时进入上下文。

和前面看到的 `brand-guidelines` skill 相比,这个 skill 不只是提供参考内容,它还带有可执行辅助脚本来帮助完成任务——在这里,任务就是 commit 并 push 代码到 GitHub。

这种“脚本可执行”的能力给了我们很大灵活性。只要我们能把某些 workflow 用确定性代码表达出来,就可以把它们封装进 skill 中。以后 agent 完成工作流时,就不是临时 improvisation 一串手工命令,而是通过执行这些脚本来完成。

虽然这看起来和 MCP 有点像,但底层机制并不一样。**MCP** 用来打通 API 调用和外部服务通信,而 **skills** 是通过注入结构化上下文,以及可选的脚本暴露,来提供能力。

## 创建一个项目级自定义 Skill

切换到 `project/skills` 分支。要创建一个项目级 skill,我们会把它定义在 `.claude` 目录中,从而把它限定在当前仓库作用域内。

创建如下结构:

```text id="08zj33"
.claude/
  skills/git-pushing/
    scripts/
      smart_commit.sh   
    SKILL.md

它应该长成下面这样:

image.png

图 9.4 —— 本地 git-pushing skill 的目录结构

这个结构与 marketplace 中的 skill 结构保持一致。

把 GitHub 仓库里的 SKILL.mdsmart_commit.sh 内容,分别复制到本地对应文件中。SKILL.md 里引用的是 scripts/smart_commit.sh,所以保持相同目录结构可以保证兼容性。

到这一步,这个 skill 就已经完整地在本地复刻好了。

image.png

图 9.5 —— 本地 SKILL.md 引用 smart_commit.sh 自动化脚本

虽然它也可以通过 plugin system 来安装,但手工复制的方式能给我们更大的定制自由。

使用这个自定义 Skill

从项目目录中打开一个 Claude Code 会话,然后输入:

List available skills.

此时,新建的项目级 git-pushing skill 会和之前安装的 marketplace skills 一起显示出来。

接着输入:

push changes

Claude 会询问你是否要使用 git-pushing 这个 skill。批准之后,它会加载 SKILL.md,并得出一个结论:它必须执行 smart_commit.sh

也就是说,它不会自己去逐条执行 Git 命令,而是直接去运行那个脚本。

在某些情况下,这个脚本可能会因为 Git 错误而失败。如果发生这种事,Claude 并不会直接停住,而是会回退到自己的默认推理模式。它会分析当前仓库状态,建议执行 git add -A,然后用自己的逻辑构造 commit,再手工执行 push。

这意味着:即便 skill 里的脚本失败了,Claude 仍然能用它的默认行为去恢复并完成任务。 这一点非常重要,因为它说明 skills 并不会替代 agent 的推理能力。当一个 skill 失败时,Claude 仍然可以退回自己的基础能力,继续把事情做完。

如果脚本执行失败,那么最后的 commit 就不是通过这个 skill 生成的,而是通过 Claude 默认逻辑生成的。这一点很关键。Skills 提供的是结构化 workflow,但它们不会移除 agent 本身的通用推理能力。 如果脚本化 workflow 出了问题,agent 仍然能尝试兜底。

理解了这一点之后,我们就可以继续往下:开始修改 skill 本身的行为。

编辑 Skill 的行为

SKILL.mdWhen to Use 段落中,再加上一个额外触发短语,比如 "push to remote"

 ## When to Use

Automatically activate when the user:
- Explicitly asks to push changes ("push this", "commit and push", "push to remote")
- Mentions saving work to remote ("save to github", "push to remote")
- Completes a feature and wants to share it
- Says phrases like "let's push this up" or "commit these changes"

同时要注意:从文件开头到 closing --- 为止的内容,属于 YAML frontmatter,它会被注入进 agent 的 system prompt。closing --- 之后的内容,则只有在 skill 被激活时才会被加载。

 ---
name: git-pushing
description: Stage, commit, and push git changes with conventional commit messages. Use when user wants to commit and push changes, mentions pushing to remote, or asks to save and push their work. Also activates when user says "push changes", "commit and push", "push this", "push to github", or similar git workflow requests.
---

# Git Push Workflow

Stage all changes, create a conventional commit, and push to the remote branch.

## When to Use

Automatically activate when the user:
- Explicitly asks to push changes ("push this", "commit and push", "push to remote")
- Mentions saving work to remote ("save to github", "push to remote")
- Completes a feature and wants to share it
- Says phrases like "let's push this up" or "commit these changes"

为什么这里要特别强调这件事?因为我们刚刚其实是在 SKILL.mdWhen to Use 段落里编辑了一句 "push to remote",但这一段并不属于 YAML frontmatter

只有文件最顶部的 YAML front matter,才会在每次请求时注入进 agent 的 system prompt。其余内容,在 skill 尚未被选中之前,对 agent 是不可见的。

这意味着,我们刚才做的那处修改,根本不会影响 skill 的选择决策

现在我们清空上下文,确保会话是干净的,然后输入:

push to remote

Claude 仍然会询问是否使用 git-pushing skill。但这并不是因为我们新加的那句 "push to remote" 起了作用,而是因为原来的 frontmatter 本来就已经把这个 skill 描述为负责 commit-and-push 操作了。于是,“push to remote” 在语义上本身就已经足够接近 “push changes” 或 “push to GitHub” 这类说法,因此 Claude 依旧能匹配到它。

这里真正重要的是:

Skill 的选择,完全由 front matter 驱动。
也就是说,agent 是通过 YAML block 中的 namedescription 来匹配用户意图的。closing --- 之后的内容,在选择阶段根本不起作用。

只有当 skill 已经被选中之后,Claude 才会继续加载 SKILL.md 其余部分,包括 workflow 指令和脚本引用。

这就是 progressive disclosure 模型:

  1. agent 总是先看到 front matter
  2. 基于它来决定是否激活某个 skill
  3. 只有在决定激活之后,才加载完整 skill 上下文和附加指令

所以,我们刚才的修改其实是冗余的,因为它放在了不会参与选择过程的那一部分里。

这个点理清之后,我们再继续,去修改脚本本身的行为。

开启 Skill 的自动批准

现在,我们已经理解了 skill selection 的工作机制。接下来考虑一个新场景:

假设 skill 能正确触发,但每一次使用它时,Claude 都要停下来问你:是否批准执行这个脚本

这样的话,即便 workflow 已经被打包进了一个 skill,整个过程仍然会充满摩擦。每次 commit-and-push 都要人工确认。如果我们的目标是打造一条流畅、带明确偏好的 workflow,那么反复确认本身就抵消了很多价值。

所以,下一步的重点就不是“让 skill 如何被选中”,而是“skill 被选中以后,如何执行”。也就是说:能不能让这个 skill 在执行时不再每次都请求批准

在确认这个 skill 能正确触发之后,选择那个允许 Claude Code 今后使用这个 skill 时不再重复询问批准的选项。

这样做之后,Claude 会去更新 settings.local.json

这一点很重要。

真正发生变化的,并不是 skill 本身。skill 的定义文件没有变。变化的是本地配置:当这个特定 skill 再次被选中时,它将可以直接执行,而不需要再交互确认。

也就是说,这里其实涉及两层权限:

  • 是否允许激活 skill
  • 是否允许执行 skill 中定义的脚本

打开自动批准之后,以后这两步的确认都可以省掉。

现在,当你再执行:

push to remote

Claude 就会立刻加载这个 skill,并直接执行 smart_commit.sh,而不会再询问你。skill 里定义的 workflow 也就真正成为了一条自动化流程。

等脚本成功执行完后,我们再去看生成出来的 commit。

image.png

图 9.6 —— smart_commit.sh 自动化脚本生成的 commit message

你会发现,这条 commit message 很简陋。它只是简单报告:“更新了多少个文件”。

这并不是 AI 生成的消息。

如果你去检查 smart_commit.sh,就会发现 commit message 是通过一段静态 shell 逻辑拼出来的:它会统计修改了多少文件,然后把这个数字填进一个固定消息模板里。整个脚本里根本没有调用 Claude。也就是说,虽然这个 workflow 是被一个 skill 包起来的,但这个 workflow 的“智能程度”,完全取决于脚本本身的实现。

这其实是一个非常重要的区分:skill 并不天然等于 AI 驱动逻辑。
skill 只是一个打包机制。它里面既可以装纯确定性脚本,也可以装 AI 调用,或者两者混合。

当前这条 workflow 很确定性,也很简单。所以我们准备把它升级掉。

修改脚本,让它调用 Claude CLI

现在,我们让 Claude 去修改 smart_commit.sh,使它在生成 commit message 时调用 Claude Code CLI。

Prompt 如下:

can u please edit @.claude/skills/git-pushing/scripts/smart_commit.sh to use Claude Code cli to create the commit message like a pirate?

这样一来,整个 workflow 的性质就会发生变化。

之前,脚本只是用静态 shell 逻辑生成 commit message。
而现在,它会做这些事:

  • 脚本调用 claude -p,并传入一个 prompt
  • -p 参数表示 Claude 会以 prompt mode 运行:接收查询,把响应打印到 stdout,然后退出
  • Claude CLI 会动态生成 commit message
  • 脚本再把这段输出用于 git commit 命令

这样,我们实际上就构建出了一套分层系统

  1. 主 Claude Code agent 选择这个 skill
  2. skill 运行 smart_commit.sh
  3. 脚本自己再去调用 Claude CLI
  4. Claude CLI 负责生成 commit message
  5. 脚本继续完成 commit 与 push

这就是一种“组合”:

  • skill 负责编排一个确定性执行流
  • 脚本负责编排一次 AI 调用
  • AI 调用负责生成结构化输出
  • 脚本再消费这个输出

现在再运行:

push to remote

这时,我们就会在 commit message 中看到一种“海盗语气”的表达。

image.png

图 9.7 —— Skill 内部调用 Claude CLI 来生成 AI 风格的 commit message

这就说明:脚本已经成功在内部调用了 Claude CLI。

也就是说,我们已经把原本纯静态 workflow,升级成了一条混合型 workflow:既有确定性执行,又有 AI 生成。

故意破坏预期结构

接下来,我们做一个实验:如果目录结构不再符合 skill 预期,会发生什么?

先回到 IDE,故意把结构“弄坏”。把 smart_commit.shscripts 目录中挪出来,直接移到 git-pushing 目录根下,然后把 scripts 目录整个删除掉。

此时,目录结构就不再符合 SKILL.md 中写的那个路径了。skill 定义原本期待脚本位于 skills/git-pushing/scripts/ 下,但现在文件实际出现在了 skills/git-pushing/ 根目录中。也就是说,skill 中声明的路径已经不准确,仓库结构从严格意义上看已经被我们弄得“不一致”了。

在结构不匹配之后再执行 Skill

先清空上下文,确保会话是全新的。

然后输入:

push to remote

Claude Code 会照样选中 git-pushing skill,并继续尝试执行脚本。

即便当前目录结构已经不再符合 SKILL.md 里写的路径,这个脚本仍然有可能正常执行成功

image.png

图 9.8 —— 修改目录结构后,git-pushing skill 仍然能够运行

这一点很关键。之所以 skill 还能工作,是因为 skill 最终本质上还是在向 agent 注入上下文与指令。虽然 SKILL.md 里的路径写错了,但 agent 本身会去检查仓库结构,并在新位置把 smart_commit.sh 找出来。也就是说,这个路径不匹配并不会自动阻断执行。agent 会把“去运行 smart_commit.sh”理解成一个目标,然后自己在项目里搜索文件,找到之后执行。

所以,即使我们把声明结构弄坏了,只要目标文件还在仓库中某处,整个 workflow 仍然能完成。

为什么 Skill 依然能工作?

原因就在于:skills 不是一种对精确文件路径的刚性绑定。 它们更像是一种带上下文的指令集。即便上下文里引用的路径不准确,只要 agent 还能通过检查项目结构把目标文件找出来,它就可以恢复并继续执行。

换一个场景想:如果 smart_commit.sh 被彻底删除了,会怎样?

这时就不存在任何可供 agent 定位和执行的脚本文件了,workflow 也就真的无法执行了。这个例子正好展示了边界在哪里:

  • 如果只是结构不一致,但文件还存在,agent 往往能自我恢复
  • 如果文件根本不存在,那执行就会失败

在隔离的 Subagent Context 中运行 Skill

默认情况下,skill 会在当前会话上下文中执行。
但它也可以通过下面这个 frontmatter 配置,在一个隔离的 subagent context 中运行:

---
context: fork
agent: Explore
---

context 被设为 fork 时,Claude 会在一个独立执行分支中运行这个 skill。这样可以让中间推理过程和工具调用与主会话隔离开来。

agent 字段则决定由哪一类 subagent 来负责执行这个 skill(例如 ExplorePlan)。

如果你还希望这个 skill 只能通过 slash command(例如 /skill-name)来触发,而不是被 Claude Code 自动触发,那么可以在 frontmatter 中加上:

disable-model-invocation: true

将 Agent Skills 与其他 Agent 原语进行比较

这一节,我们会把 agent skills 和其他 agent 原语——例如 MCP、subagents、memory 和 slash commands——做一个对比。比较重点会放在:上下文管理、上下文工程,以及执行流上。

Agent Skills 与 MCP

Agent skills 和 MCP server 都是现代 agent toolkit 中非常重要的组成部分,但它们解决的是不同层级的问题,运行在不同层面的 context architecture 上。

Agent skills 更像是程序性知识容器(procedural knowledge containers) 。它们本质上是一些目录,里面装着指令、脚本和资源,用来教 AI agent 以一致方式完成某类专门任务。这里的关键词是 一致性。借助 skill,我们把某个 workflow 封装起来,然后交给 agent,这样它就能按预先定义好的方式去完成任务。

从上下文工程的视角看,skills 的核心机制是 progressive disclosure

当一个支持 skills 的 agent——例如 Claude Code 的 coding agent——开始一个新 session 时,它首先加载的只是每个 skill 的简短 description 和名字。这个阶段的 context 成本很低。通常来说,不管 skill 内部有多复杂,每个 skill 大概只消耗 100 到 200 tokens 左右。

只有当某个 skill 与当前任务相关,并且这个判断由 agent 自己做出之后,SKILL.md 中的完整说明才会被加载进上下文。再进一步,只有当 skill 被真正使用,并且 agent 决定去执行脚本时,对应脚本才会被加载。如果一个 skill 里包含多个脚本,那么没有被用到的那些脚本是不会进入上下文的。也正因为这种渐进式加载机制,skills 在上下文效率上是非常高的。

再来看 MCP。

在 MCP 架构里,工具定义和 server 规范通常在会话一开始就被预加载。这会直接影响上下文效率。举个例子:仅仅 5 个 MCP server,就可能在第一条 prompt 发出之前先消耗掉 50,000 tokens

MCP 解决的是另一个问题:它的作用是把 agent 连接到外部资源上。这才是 MCP server 的核心目的。

而 skills 解决的是不同的问题:它让 agent 能够以一致、结构化的方式去执行专门任务。

所以,虽然它们都属于 agent 原语,但作用层次并不相同。

调用方式与执行方式的差异

不管是 skills 还是 MCP tools,它们最终都是由 agent 根据自己判断来决定要不要调用的。agent 会基于各自的 description,判断 skill 或 MCP tool 是否与当前任务相关。

因此,从调用机制来看,两者是相似的:都是 agent 自己评估能力是否与任务匹配。

一个很有意思的实验是:把同一个能力分别实现两遍——一遍做成 skill,一遍做成由 MCP server 暴露出来的 MCP tool。然后观察 agent 在真实使用中会更倾向于选哪个。这能帮助我们理解它是如何在这些原语之间做推理的。

但在执行方式上,两者差别就明显了:

  • 对于 MCP,执行发生在 MCP server 内部。这个 server 可能跑在本地,也可能部署在云端。
  • 对于 skills,执行通常发生在主 agent thread 内部。skill 中定义的脚本,是在 agent 的主执行流中直接运行的。
  • 不过,如果 skill 的 frontmatter 指定了 context: fork,那么这个 skill 就会在一个隔离的 subagent context 中运行,而不是在主 agent 中内联执行。

这个执行位置的差异,在做系统架构思考时非常重要。

Agent Skills 与 Subagents

Agent skills 和 subagents 的相似之处在于:它们都允许我们为特定任务定义一套专门化指令。一个 skill 包含结构化说明和可选脚本,而 subagent 也可以有自己的一整套指令定义。

但它们之间的关键区别在于:上下文隔离。

Subagents 运行在自己独立、全新的 context window 中。它们特别适合处理那些长跨度任务,因为如果这些任务直接丢给主 agent,就很容易把主上下文膨胀得过大。

而 skills 则不同。skills 是运行在主 agent 的上下文中的。当一个 skill 被调用时,它的说明会被加载进当前已有的 context window,而不是进入一个独立上下文。

无论是 skill 还是 subagent,最终都是由主 agent 决定是否调用的。主 agent 要么决定把任务委派给一个 subagent,要么决定用某个 skill 在自己的执行流中完成这件事。

从灵活性和可控性来看,subagents 提供的自由度更高。借助 subagents,我们可以非常灵活地调整 system prompt,并针对特定任务做精细化定制。skills 则不同,它们最终仍然运行在主 agent 的 system prompt 之下,而这个主 system prompt 通常由厂商控制,不太容易被改动。

可以把它归纳成一条经验法则:

  • 如果任务很重,并且有明显风险会让主上下文膨胀,那更适合用 subagent
  • 如果目标是给 agent 增加某项可重复使用的专业能力,或者强制它对某类经常性任务遵守特定方法论,那更适合用 skill

二者都是非常有价值的原语,但它们处于不同的上下文与执行模型中。默认情况下,skills 会在主 agent 中内联运行,而 subagents 会在隔离上下文里执行。
不过,skill 也可以通过 context: fork 改成在一个轻量隔离上下文中运行,这时它会更像一个 subagent,只是配置控制能力仍然更弱一些。

为了把 skills 和 subagents 放回 Claude Code 更大的整体模型中,下面这张表还把它们与 MCP servers、slash commands 进行了横向比较。

维度SkillsMCPSubagentsSlash commands
Purpose标准化任务执行方式连接外部服务将工作委派给隔离 agent用户触发的快捷命令
Context loading先加载 front matter,真正使用时再加载完整内容会话一开始就加载工具定义每次运行都有全新上下文完整 prompt 直接注入
Trigger由 agent 决定由 agent 决定由主 agent 做 delegation用户显式运行 /command
Execution location主 agent threadMCP server(本地或远程)隔离的 subagent context主 agent thread
Context isolation与主上下文共享在外部执行完全隔离与主上下文共享
Scripts没有没有
Failure handlingagent 会退回默认推理agent 处理 server 错误主 agent 重试或调整没有
Best use可重复 workflow外部 API / 服务长跨度任务快速动作
Context efficiency高(惰性加载)低(工具预加载)高(把工作卸载出去)低(每次完整 prompt 注入)
Customization完全可控由 server 定义灵活有限

表 9.1 —— Agent 原语比较

总结

在本章中,我们从实践和架构两个层面系统地探索了 agent skills。我们首先通过 HookHub 的例子,对比了“直接 prompt agent”与“把结构化行为封装成 skill 再调用”这两种方式,从而建立了对 skills gist 的直观理解。随后我们观察到:skills 能通过 渐进式上下文加载,只在真正需要时把相关说明注入进来,而不会把主 context window 无意义地撑大。

接着,我们继续深入:创建了一个自定义的项目级 skill,把辅助脚本集成了进去,对 skill 的行为进行了修改,甚至进一步让它去调用 Claude CLI。通过这些实践,我们看到 skills 不仅能打包具有明确偏好的 workflow,还能把确定性执行与 AI 生成输出结合起来;同时,在脚本失败时,agent 也依然能够回退到默认推理路径继续完成任务。

最后,我们又把 agent skills 放回更大的 agentic landscape 中,与 MCP、subagents 等其他原语进行了比较,厘清了它们在上下文架构、执行流与控制方式上的不同。

到这里,我们不仅已经具备了“会使用 skills”的能力,也建立起了一个比较清晰的心智模型:理解 skill 在内部是如何工作的,以及在设计更强大、更高 context efficiency 的 agent 系统时,应该在什么情况下使用它。

在下一章中,我们将学习:如何在桌面应用中使用 Claude Code。