avatar
原创2026/01/10

Claude Code Skill 原理

AI 总结

深入剖析 Claude Code 中 Skill(技能)的工作机制,涵盖 Skill 的目录结构与注册方式、意图匹配推理、read_file 延迟加载流程、Skill 指令如何注入 LLM 上下文,以及与 Anthropic Tool Use API 的完整调用链路。

Skill(技能)是 Claude Code 的领域知识模块。每个 Skill 将特定领域的操作指南封装为一个独立的 Markdown 文件(SKILL.md),按功能分目录存放。Claude Code 支持两个层级的 Skill 目录:

# 项目级:跟随仓库,团队共享
.github/skills/
├── openspec-propose/
│   └── SKILL.md
├── openspec-apply-change/
│   └── SKILL.md
└── openspec-explore/
    └── SKILL.md

# 用户级:跨项目生效,个人专属
~/.agents/skills/
└── find-skills/
    └── SKILL.md

Skill 的注册方式

Claude Code 启动时,会扫描上述目录,将每个 Skill 的元数据以 XML 块的形式注入 System Prompt:

<skills>
Here is a list of skills that contain domain specific knowledge on a variety of topics.
Each skill comes with a description of the topic and a file path that contains
the detailed instructions.
When a user asks you to perform a task that falls within the domain of a skill,
use the 'read_file' tool to acquire the full instructions from the file URI.
 
<skill>
  <name>openspec-propose</name>
  <description>
    Propose a new change with all artifacts generated in one step.
    Use when the user wants to quickly describe what they want to build...
  </description>
  <file>/path/to/.github/skills/openspec-propose/SKILL.md</file>
</skill>
 
<skill>
  <name>find-skills</name>
  <description>
    Helps users discover and install agent skills when they ask questions
    like "how do I do X", "find a skill for X"...
  </description>
  <file>/Users/benson/.agents/skills/find-skills/SKILL.md</file>
</skill>
</skills>

注意:此时 SKILL.md 的内容并没有被载入上下文,注入的只有名称、描述和文件路径。<skills> 块同时携带了一条明确指令——当任务匹配某个 Skill 时,主动用 read_file 工具去读取对应文件。这是整个 Skill 系统的核心设计:延迟加载(Lazy Loading)。

Skill 的触发流程

整个过程分为两个阶段:意图匹配和指令注入。

意图匹配

用户输入到达后,模型根据 <skills> 块中所有 Skill 的 <description>,判断当前请求是否命中某个 Skill。这本质上是一次语义推理,而非关键词搜索:

用户输入: "我想提一个新功能的改动方案"
    │
    ▼
模型匹配所有 Skill 描述
    │
    ├── openspec-propose:      "...generate a complete proposal..."  ✓ 匹配
    ├── openspec-apply-change: "...start implementing tasks..."      ✗
    └── find-skills:           "...discover and install skills..."   ✗
    │
    ▼
决策: 需要加载 openspec-propose

指令注入

意图匹配后,模型发出 read_file 工具调用,读取对应 SKILL.md 的完整内容:

{
  "type": "tool_use",
  "name": "read_file",
  "input": {
    "filePath": "/path/to/.github/skills/openspec-propose/SKILL.md",
    "startLine": 1,
    "endLine": 200
  }
}

工具返回全文后,Skill 的详细步骤被写入当前对话上下文,模型随即按照 Skill 中定义的流程逐步执行。

Tool Use API

Skill 的懒加载依赖 Anthropic 的 Tool Use(工具调用)能力。每次加载一个 Skill,底层完成一次完整的 API 往返。

第一次请求:模型决定调用工具

POST https://api.anthropic.com/v1/messages
 
{
  "model": "claude-sonnet-4-6",
  "tools": [
    {
      "name": "read_file",
      "description": "Read the contents of a file.",
      "input_schema": {
        "type": "object",
        "properties": {
          "filePath":  { "type": "string" },
          "startLine": { "type": "number" },
          "endLine":   { "type": "number" }
        },
        "required": ["filePath", "startLine", "endLine"]
      }
    }
  ],
  "messages": [
    { "role": "user", "content": "我想提一个新功能的改动方案" }
  ]
}

模型返回 stop_reason: "tool_use",表示它需要先读取文件才能继续:

{
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "text",
      "text": "我需要先读取 openspec-propose 的详细指引..."
    },
    {
      "type": "tool_use",
      "id": "toolu_01XYZ",
      "name": "read_file",
      "input": {
        "filePath": "/path/to/.github/skills/openspec-propose/SKILL.md",
        "startLine": 1,
        "endLine": 300
      }
    }
  ]
}

Claude Code 在本地执行工具

收到 tool_use 响应后,Claude Code 在本地读取文件。这一步完全不经过 Anthropic 服务器,文件内容不会离开本机:

const content = fs.readFileSync(input.filePath, 'utf-8')
const lines   = content.split('\n')
const excerpt = lines.slice(input.startLine - 1, input.endLine).join('\n')

第二次请求:携带 Skill 内容继续推理

Claude Code 将文件内容封装为 tool_result,追加到对话历史后再次请求:

POST https://api.anthropic.com/v1/messages
 
{
  "messages": [
    {
      "role": "user",
      "content": "我想提一个新功能的改动方案"
    },
    {
      "role": "assistant",
      "content": [
        { "type": "text",     "text": "我需要先读取 openspec-propose 的详细指引..." },
        { "type": "tool_use", "id": "toolu_01XYZ", "name": "read_file", "input": { "..." } }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "tool_result",
          "tool_use_id": "toolu_01XYZ",
          "content": "# Skill: openspec-propose\n\n## Steps\n### 1. Interview the user\n..."
        }
      ]
    }
  ]
}

此时模型拥有完整的 Skill 指令,第二次响应中 stop_reason 变为 end_turn,正式开始执行任务。

SKILL.md 的典型结构

一个设计良好的 SKILL.md 会明确划分触发条件和执行步骤,让模型仅凭 <description> 就能做出是否触发的判断:

# Skill: openspec-propose
 
## When to use this skill
- User wants to propose a new feature or change
- User says "I want to build X" or "propose a change for Y"
 
## When NOT to use this skill
- User wants to implement (use openspec-apply-change instead)
- User wants to explore an idea (use openspec-explore instead)
 
## Steps
 
### 1. Interview the user
Gather requirements:
- What problem does this change solve?
- What is the expected outcome?
 
### 2. Generate the proposal
Create the following artifacts under `openspec/changes/<name>/`:
- `design.md`   — high-level design
- `spec.md`     — detailed specification
- `tasks.md`    — implementation tasks
 
### 3. Review with the user
Walk through the proposal and refine until approved.

"When to use" / "When NOT to use" 的分离设计是关键——它让 <description> 保持简短,模型只需读少量 token 就能完成意图判断,只有真正命中时才加载全文。

多 Skill 的调度

一个请求可能跨越多个 Skill。每个 Skill 的加载都是独立的一次工具调用往返:

tool_use: read_file(openspec-propose/SKILL.md)
    ↓
tool_result: [Skill A 全文]
    ↓
tool_use: read_file(find-skills/SKILL.md)
    ↓
tool_result: [Skill B 全文]
    ↓
stop_reason: end_turn — 根据所有 Skill 指令执行

每加载一个 Skill 增加两次 API 往返,同时 context window 的 token 消耗也随之增长。这正是延迟加载的价值所在——不相关的 Skill 内容始终不进入上下文。

Skill 与 RAG 的区别

Skill 系统与 RAG(Retrieval-Augmented Generation)在表面上都是"按需加载知识",但机制截然不同:

RAGSkill
检索方式系统自动,向量相似度模型主动决策(tool_use)
检索粒度文本块(chunk)整个 Skill 文件
内容形式非结构化知识片段结构化操作指南
可追溯性弱(近似匹配)强(精确文件路径)

RAG 擅长从海量文档中找到相关片段,而 Skill 是主动的、精确的能力模块调度——模型清楚地知道自己需要什么,并主动去取。

总结

Skill 的完整调用链路:

System Prompt 注入 <skills> 块(name + description + file path)
    │
    ▼
用户输入 → 模型语义匹配 → 命中目标 Skill
    │
    ▼
模型生成 tool_use: read_file(SKILL.md)
    │
    ▼
Claude Code 本地读取文件(不经过 Anthropic 服务器)
    │
    ▼
tool_result 携带 Skill 全文追加到 messages
    │
    ▼
第二次 API 请求 → 模型依照 Skill 指令执行任务

Skill 系统的精妙之处在于将知识存储与调度决策完全解耦:System Prompt 只承载元数据,完整的领域知识按需加载。模型只需要一句描述,就能在合适的时机自主决定是否读取完整指令——既节省 token,又保留对专项领域的完整操控能力。

点击播放