返回

Claude Code 源码分析 8:Skills 技能系统实现原理

深入分析 Claude Code 的 Skills 技能系统,包括技能的定义、加载、触发机制和执行流程。这是 Claude Code 实现可复用 AI 工作流的核心。

本章概述

系列目录:Claude Code 源码分析系列索引

Skills 技能系统是 Claude Code 实现可复用 AI 工作流的核心机制,它允许用户定义和调用预配置的 AI 行为模式。

你将学到

  • ✅ 技能系统的架构设计
  • ✅ 技能定义与加载
  • ✅ 技能触发机制
  • ✅ 技能执行流程
  • ✅ 内置技能分析

技能系统概览

flowchart TB
    subgraph SkillSystem["技能系统"]
        A[技能定义] --> B[技能加载]
        B --> C[技能注册]
        C --> D[技能触发]
        D --> E[技能执行]
    end
    
    subgraph Sources["技能来源"]
        F[内置技能] --> G[bundled/]
        H[本地技能] --> I[.claude/skills/]
        J[远程技能] --> K[Marketplace]
    end
    
    subgraph Trigger["触发机制"]
        L[显式调用] --> M[/skill-name]
        N[自动触发] --> O[关键词匹配]
        P[Hook 触发] --> Q[事件监听]
    end
    
    A --> F
    D --> L

核心文件结构

src/
├── skills/                     # 技能系统
│   ├── bundled/               # 内置技能
│   │   ├── index.ts
│   │   ├── commitSkill.ts
│   │   ├── initSkill.ts
│   │   └── ...
│   └── AGENTS.md
├── utils/skills/              # 技能工具
│   ├── skillChangeDetector.ts
│   └── ...
├── commands/skills/           # /skills 命令
│   └── index.ts
└── tools/SkillTool/           # SkillTool 实现
    └── SkillTool.ts

技能定义

技能结构

// types/command.ts - Skill 类型
export type PromptCommand = {
  type: 'prompt'
  name: string
  description: string
  progressMessage: string
  source: 'builtin' | 'skills' | 'plugin' | 'bundled'
  
  // 提示词生成
  getPromptForCommand(
    args: string,
    context: ToolUseContext
  ): Promise<ContentBlockParam[]>
  
  // 可选配置
  allowedTools?: string[]
  model?: string
  effort?: EffortValue
  hooks?: HooksSettings
  paths?: string[]
  context?: 'inline' | 'fork'
  agent?: string
}

技能定义文件

技能通常定义在 Markdown 文件中,包含 YAML frontmatter:

---
name: commit
description: Create a git commit with a descriptive message
model: sonnet
allowedTools:
  - Bash(git add:*)
  - Bash(git status:*)
  - Bash(git commit:*)
---

## Context

Current git status: !`git status`
Current git diff: !`git diff HEAD`

## Task

Create a git commit with a descriptive message following conventional commits format.

技能加载

技能发现

// utils/skills/skillLoader.ts
export async function discoverSkills(): Promise<Skill[]> {
  const skills: Skill[] = [];
  
  // 1. 加载内置技能
  const bundledSkills = await loadBundledSkills();
  skills.push(...bundgedSkills);
  
  // 2. 加载本地技能
  const localSkills = await loadLocalSkills();
  skills.push(...localSkills);
  
  // 3. 加载插件技能
  const pluginSkills = await loadPluginSkills();
  skills.push(...pluginSkills);
  
  return skills;
}

async function loadLocalSkills(): Promise<Skill[]> {
  const skillsDir = path.join(process.cwd(), '.claude', 'skills');
  
  if (!existsSync(skillsDir)) {
    return [];
  }
  
  const files = await glob('**/*.md', { cwd: skillsDir });
  const skills: Skill[] = [];
  
  for (const file of files) {
    const skill = await parseSkillFile(path.join(skillsDir, file));
    if (skill) {
      skills.push(skill);
    }
  }
  
  return skills;
}

技能解析

// utils/skills/skillParser.ts
export async function parseSkillFile(filePath: string): Promise<Skill | null> {
  const content = await readFile(filePath, 'utf-8');
  
  // 解析 frontmatter
  const { data: frontmatter, content: body } = matter(content);
  
  // 验证必需字段
  if (!frontmatter.name || !frontmatter.description) {
    logError(`Invalid skill file: ${filePath}`);
    return null;
  }
  
  return {
    name: frontmatter.name,
    description: frontmatter.description,
    model: frontmatter.model,
    allowedTools: frontmatter.allowedTools,
    hooks: frontmatter.hooks,
    source: 'skills',
    getPromptForCommand: async (args, context) => {
      // 处理技能模板
      const processedBody = await processSkillTemplate(body, context);
      
      return [{
        type: 'text',
        text: processedBody
      }];
    }
  };
}

技能触发机制

显式触发

// 用户通过 /skill-name 调用
/skills/my-skill arg1 arg2

// SkillTool 处理
export async function callSkill(params: SkillParams) {
  const skill = findSkill(params.skillName);
  if (!skill) {
    throw new Error(`Skill ${params.skillName} not found`);
  }
  
  const prompt = await skill.getPromptForCommand(params.args, context);
  return await callClaudeAPI({
    messages: prompt,
    model: skill.model,
    tools: skill.allowedTools
      ? filterTools(skill.allowedTools)
      : getAllTools()
  });
}

自动触发(关键词)

// utils/skills/autoTrigger.ts
const TRIGGER_KEYWORDS: Record<string, string[]> = {
  'commit': ['commit', 'git commit', 'create commit'],
  'test': ['test', 'run tests', 'pytest'],
  'review': ['review', 'code review', 'pr review']
};

export function shouldAutoTrigger(
  input: string
): string | null {
  const lowerInput = input.toLowerCase();
  
  for (const [skill, keywords] of Object.entries(TRIGGER_KEYWORDS)) {
    for (const keyword of keywords) {
      if (lowerInput.includes(keyword)) {
        return skill;
      }
    }
  }
  
  return null;
}

// 在对话中检测
export function detectSkillInConversation(
  messages: Message[]
): string | null {
  const lastMessage = messages[messages.length - 1];
  if (lastMessage?.role === 'user') {
    return shouldAutoTrigger(lastMessage.content);
  }
  return null;
}

Hook 触发

// utils/hooks/registerFrontmatterHooks.ts
export async function registerFrontmatterHooks(
  skill: Skill
): Promise<void> {
  if (!skill.hooks) {
    return;
  }
  
  for (const [event, command] of Object.entries(skill.hooks)) {
    registerHook(event as HookEvent, async (context) => {
      // 执行 hook 命令
      await executeBashCommand(command, context);
    });
  }
}

// Hook 事件类型
type HookEvent = 
  | 'pre_tool_use'
  | 'post_tool_use'
  | 'pre_edit'
  | 'post_edit'
  | 'session_start'
  | 'session_end'

技能执行流程

sequenceDiagram
    participant User as 用户
    participant CLI as Commander
    participant SkillTool as SkillTool
    participant Parser as 技能解析
    participant Claude as Claude API
    
    User->>CLI: /skill-name args
    CLI->>SkillTool: call({skillName, args})
    SkillTool->>SkillTool: 查找技能
    
    alt 找到技能
        SkillTool->>Parser: getPromptForCommand(args, context)
        Parser->>Parser: 解析模板
        Parser->>Parser: 执行嵌入命令
        Parser-->>SkillTool: 提示词
        
        SkillTool->>Claude: 调用 API
        Claude-->>SkillTool: 响应
        
        alt 包含工具调用
            loop 工具调用循环
                SkillTool->>SkillTool: 执行工具
                SkillTool->>Claude: 发送结果
                Claude-->>SkillTool: 响应
            end
        end
        
        SkillTool-->>CLI: 最终结果
        CLI-->>User: 显示结果
    else 未找到
        SkillTool-->>CLI: 错误
    end

内置技能分析

Commit 技能

// skills/bundled/commitSkill.ts
export const commitSkill: Skill = {
  name: 'commit',
  description: 'Create a git commit with a descriptive message',
  progressMessage: 'creating commit',
  source: 'bundled',
  allowedTools: [
    'Bash(git add:*)',
    'Bash(git status:*)',
    'Bash(git commit:*)'
  ],
  
  async getPromptForCommand(args, context) {
    const gitStatus = await context.executeTool('Bash', {
      command: 'git status'
    });
    
    const gitDiff = await context.executeTool('Bash', {
      command: 'git diff HEAD'
    });
    
    return [{
      type: 'text',
      text: `## Git Context

Status:
${gitStatus}

Changes:
${gitDiff}

## Task

Create a commit with a message following conventional commits format. 
Focus on the "why" not the "what".
${args ? `Additional context: ${args}` : ''}`
    }];
  }
};

Init 技能

// skills/bundled/initSkill.ts
export const initSkill: Skill = {
  name: 'init',
  description: 'Initialize Claude Code in a project',
  progressMessage: 'initializing',
  source: 'bundled',
  allowedTools: ['*'],
  
  async getPromptForCommand(args, context) {
    return [{
      type: 'text',
      text: `## Task

Set up a minimal CLAUDE.md for this repository.

Steps:
1. Explore the codebase structure
2. Identify build/test/lint commands
3. Create CLAUDE.md with:
   - Project overview
   - Common commands
   - Architecture notes
   - Testing approach

Be concise - only include what Claude would get wrong without it.`
    }];
  }
};

Superpowers 集成

Superpowers 技能

Claude Code 支持 Superpowers 技能框架,这是一套预定义的 AI 工作流:

// skills/bundled/superpowers/
export const superpowersSkills = [
  {
    name: 'brainstorming',
    description: 'Brainstorm before writing code',
    trigger: 'before_coding'
  },
  {
    name: 'writing-plans',
    description: 'Create implementation plans',
    trigger: 'before_implementation'
  },
  {
    name: 'test-driven-development',
    description: 'Enforce TDD workflow',
    trigger: 'before_testing'
  },
  {
    name: 'systematic-debugging',
    description: 'Debug systematically',
    trigger: 'on_bug'
  }
];

技能链

// utils/skills/skillChain.ts
export async function executeSkillChain(
  chain: Skill[],
  context: SkillContext
): Promise<SkillResult> {
  let result: SkillResult = { success: true };
  
  for (const skill of chain) {
    // 检查前置条件
    if (!checkPrerequisites(skill, result)) {
      return {
        success: false,
        error: `Prerequisites not met for ${skill.name}`
      };
    }
    
    // 执行技能
    result = await executeSkill(skill, context);
    
    // 失败中断
    if (!result.success) {
      return result;
    }
  }
  
  return result;
}

技能最佳实践

1. 技能设计原则

// ✅ 好的技能设计
const goodSkill = {
  name: 'test',
  description: 'Run project tests',
  
  // 清晰的任务描述
  getPromptForCommand: async (args, context) => {
    // 收集上下文
    const testConfig = await detectTestFramework();
    
    return {
      type: 'text',
      text: `Run tests using ${testConfig.command}
            
Context:
- Framework: ${testConfig.framework}
- Config: ${testConfig.configPath}

${args ? `Filter: ${args}` : ''}`
    };
  }
};

2. 上下文收集

// ✅ 充分的上下文
async function collectContext(context: ToolUseContext) {
  return {
    git: {
      branch: await getBranch(),
      status: await getStatus()
    },
    project: {
      root: getProjectRoot(),
      language: detectLanguage()
    },
    env: {
      node: process.version,
      pwd: process.cwd()
    }
  };
}

3. 错误处理

// ✅ 健壮的技能
async function executeSkill(skill: Skill, context: Context) {
  try {
    const prompt = await skill.getPromptForCommand(context);
    return await callClaudeAPI(prompt);
  } catch (error) {
    if (error instanceof PermissionError) {
      return {
        success: false,
        error: 'Permission denied'
      };
    }
    throw error;
  }
}

小结

本章分析了 Claude Code 的 Skills 技能系统:

核心概念

概念 说明 应用场景
Skill 技能定义 可复用 AI 工作流
Trigger 触发机制 自动/手动调用
Hook 事件钩子 工具事件响应
Chain 技能链 多技能组合

架构优势

  1. 可复用 - 预定义工作流
  2. 可扩展 - 自定义技能
  3. 灵活 - 多种触发方式
  4. 可组合 - 技能链执行

学习收获

  • 🎯 技能设计 - 可复用 AI 工作流
  • 🔄 触发机制 - 自动/手动调用
  • 🔗 技能组合 - 链式执行
  • 📋 模板处理 - 动态提示词生成

系列导航

参考资源