Skip to content

技能系统:Agent 的训练手册

如果说 Agent Loop 是 Agent 的心跳,工具系统是它的双手,那技能系统就是一本训练手册

有了手,Agent 能读写文件、执行命令;但"能做什么"不等于"知道怎么做"。Git 提交规范、代码审查清单、部署流程——这些领域知识不能靠模型自己猜,需要被注入。

最直接的办法是把所有知识塞进系统提示。但过多技能或导致上下文巨量消耗,且大部分跟当前任务无关。

技能系统的解法是按需加载

系统提示只放名称和描述,需要时再加载完整内容。用到什么,注入什么。

第一阶段:系统提示(提供所有技能的名称及描述)
┌──────────────────────────────────────┐
│ Skills available:                    │
│ - git-workflow: Git 工作流规范       │  ~100 tokens/skill
│ - code-review: 代码审查清单          │
│ - deploy: 部署流程指南               │
└──────────────────────────────────────┘

第二阶段:按需加载(用到才给,高价值)
┌──────────────────────────────────────┐
│ 完整的技能内容...                    │  ~2000 tokens/skill
│ 步骤 1:检查分支命名规范             │
│ 步骤 2:验证 commit message 格式     │
│ ...                                  │
└──────────────────────────────────────┘

六层技能来源:谁说了算

Claude Code 的技能来自六个层级,按加载优先级排列(优先级从高到底):

优先级层级存放位置作用范围
1内置级编译进二进制开箱即用的核心技能
2管理策略级系统级目录企业版,企业管理员下发
3用户级~/.claude/skills/跨所有项目的个人偏好
4项目级.claude/skills/仅当前项目生效
5插件级插件目录插件自带的能力
6MCP 级MCP 服务器外部服务提供的远程技能

启动时,系统按上述顺序依次加载并去重。 需要注意:去重是基于文件路径,不是技能名称。不同来源提供的同名技能可以共存,只有同一个文件通过符号链接等方式出现在多个目录时才会去重。

技能生命周期:一个技能从加载到执行的全过程

技能不是"加载一次就完事"。它经历四个阶段:启动时进入名单、操作文件时被发现、更新技能列表、模型选中时执行完整内容。

技能系统的四阶段生命周期

第一阶段:启动时进入名单

Claude Code 启动时,扫描各来源目录,合并去重。技能按 paths 字段分成两类:

  • 无条件技能:没有 paths 字段,立即可用
  • 有条件技能:带 paths 字段(如 paths: ["src/**/*.ts"]),进入待命池

只有无条件技能注入系统提示,每轮对话开头都出现——但只有新增技能才会发送,已发送的不重复注入。列表预算约 8000 字符(上下文窗口的 1%),内置技能优先保留完整描述,其余按剩余空间均分。

第二阶段:操作文件时发现新技能

启动扫描只覆盖已知目录。某些子项目的 .claude/skills/ 不在其中。当模型操作文件(Read/Write/Edit)时,系统沿文件路径向上查找 .claude/skills/——走到哪,发现到哪。被 .gitignore 忽略的目录自动跳过。

新发现的技能同样按 paths 分类:无条件的直接加入可用列表,有条件的进入待命池。

同时检查待命池中的条件技能:如果操作的文件路径匹配某个技能的 paths 规则,该技能从待命池移入可用列表,后续对话中模型能看到它。一旦激活就永久有效——即使后续操作的文件不再匹配,也不会消失。

第三阶段:更新技能列表

每轮对话开始时,系统检查可用技能列表是否有变化——新发现的、新激活的、已发送过的都不再重复。新增技能注入一条系统提醒消息:

The following skills are available for use with the Skill tool:
- ts-checker: TypeScript 代码审查

第四阶段:模型选中,执行完整内容

模型从技能列表中选择技能,调用 SkillTool,传入技能名和参数。工具验证技能是否存在、用户是否授权后,按两种模式执行:

Inline(默认):技能内容直接注入当前对话,共享上下文和 token 预算。适合轻量任务。

Fork:在独立子代理中运行(Subagents 章节会介绍),独立上下文和 token 预算。适合长时间任务。

执行过程中通过参数替换获取用户传入的值:

  • $ARGUMENTS → 完整参数字符串
  • $1, $2 → 位置参数
  • 命名参数 → frontmatter 定义 arguments: file_path 时,$file_path 映射到对应值

替换顺序:命名参数 → 位置参数 → 完整参数 → 无占位符时追加末尾。

技能可限定允许的工具列表(allowed-tools)。代码审查技能只需读取和搜索,不需要写入和执行——最小权限原则。只包含只读工具的技能自动放行。

写一本自己的训练手册

技能格式:一个目录 + 一个 SKILL.md 文件。

Frontmatter 配置项

SKILL.md 的 YAML frontmatter 支持以下字段:

字段必需描述
nameSkill 列表中的显示名称。默认为目录名
description推荐功能说明和使用场景。Claude 用它决定何时调用。省略则取正文第一段
when_to_use何时调用的额外上下文(触发短语、示例请求),追加到 description 后,合并展示于技能列表中
argument-hint在输入框键入斜杠命令时,会作为浅灰色的占位符显示,用于提示该命令期望的参数内容
arguments命名位置参数,用于正文中的 $name 替换。按顺序映射到参数位置
disable-model-invocationtrue 阻止 Claude 自动加载,仅限 /name 手动触发。默认 false
user-invocablefalse/ 菜单隐藏,用于背景知识类技能。默认 true
allowed-tools技能激活时可免确认使用的工具列表
model覆盖当前轮次的模型,如 sonnethaikuinherit(保持当前)
effort覆盖工作力度:lowmediumhighxhighmax
context设为 fork 在独立子代理中运行
agentcontext: fork 时使用的子代理类型,比如 Explore、Plan
hooks限定于此技能生命周期的钩子
pathsGlob 模式,仅在处理匹配文件时激活
shell内联命令使用的 shell,bash(默认)或 powershell

完整示例

markdown
<!-- ~/.claude/skills/gen-api/SKILL.md -->
---
description: 生成 REST API 端点的完整代码骨架
when_to_use: 需要创建新的 API 端点时
arguments: method resource
argument-hint: "[GET|POST|PUT|DELETE] [resource-name]"
allowed-tools:
  - Read
  - Write
  - Grep
  - Glob
---

为资源 $resource 创建 $method 方法的 REST API 实现。

基于项目既有模式,生成以下文件:
1. 路由定义
2. 请求/响应类型
3. 控制器逻辑
4. 基本测试

参数按位置映射,顺序必须严格

/gen-api POST users   →  $method=POST,  $resource=users  ✓
/gen-api users POST   →  $method=users, $resource=POST   ✗(参数错位)

调用方式:

  • 手动触发:输入 /gen-api POST users
  • 自动触发:对模型说"帮我生成一个创建用户的 API",模型识别意图后自动调用该技能

参数不足 arguments 声明数量时,多余变量替换为空字符串。未使用 $name 占位符的多余参数会追加到内容末尾。

三条核心原则

一个技能只做一件事。 超过 200 行就该拆分。"全栈开发"技能不如"API 生成"、"组件生成"、"测试生成"三个独立技能。

描述要精确。 description 是模型选择技能的依据。模糊描述导致选错。"代码审查"比"帮助改进代码"好得多。

用条件技能减少噪音。paths 字段,只在操作匹配文件时激活。20 个技能不是问题,20 个同时出现在列表里才是。