1. Claude Code 技能系统架构概览
Claude Code 的技能系统是一个高度结构化的能力封装框架,它将传统AI助手的功能从简单的提示词扩展为一套完整的、可组合的能力单元。这套系统让我想起了软件开发中的插件架构,但更加精细和智能化。
1.1 技能的本质定义
在源码 src/commands.ts 中,技能被明确定义为一种特殊的命令对象:
typescript复制export const getSlashCommandToolSkills = memoize(
async (cwd: string): Promise<Command[]> => {
const allCommands = await getCommands(cwd)
return allCommands.filter(
cmd =>
cmd.type === 'prompt' &&
(cmd.loadedFrom === 'skills' ||
cmd.loadedFrom === 'plugin' ||
cmd.loadedFrom === 'bundled' ||
cmd.disableModelInvocation),
)
},
)
这个定义揭示了几个关键点:
- 技能必须是prompt类型
- 技能来源限定为三种特定渠道
- 或者设置了禁用模型调用的标志
提示:这种设计既保证了灵活性,又确保了安全性。开发者可以扩展新的技能来源,但必须符合严格的准入条件。
1.2 技能的核心属性
技能不仅仅是简单的命令,它包含了一套完整的元数据系统:
| 属性 | 类型 | 说明 | 示例 |
|---|---|---|---|
| name | string | 技能唯一标识 | "verify" |
| description | string | 人类可读描述 | "验证代码变更是否达到预期" |
| whenToUse | string | 自动触发条件 | "用户要求验证时" |
| allowedTools | string[] | 允许使用的工具列表 | ["Bash", "Read", "Edit"] |
| context | enum | 执行上下文 | "inline"或"fork" |
| hooks | object | 生命周期回调 | {preExecute: () => {...}} |
这种结构化设计使得技能可以:
- 被系统智能地自动调用
- 限制其资源访问权限
- 在不同的执行环境中运行
- 参与完整的工作流生命周期
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技能的类型体系与加载机制
2.1 技能的类型划分
Claude Code 支持多种技能来源,形成一个分层的能力体系:
2.1.1 内置技能 (Bundled Skills)
用TypeScript编写,直接编译进CLI二进制文件。位于src/skills/bundled/目录,例如:
- verify.ts:验证技能
- skillify.ts:将操作过程捕获为新技能
- batch.ts:批量处理技能
注册模式示例:
typescript复制registerBundledSkill({
name: 'verify',
description: '验证代码变更产生预期的结果',
userInvocable: true,
files: SKILL_FILES,
async getPromptForCommand(args) {
// 动态生成技能内容
}
})
2.1.2 文件技能 (File-based Skills)
用户通过Markdown文件定义的技能,采用YAML frontmatter + Markdown body的格式:
markdown复制---
name: code-review
description: 执行代码审查
allowed-tools:
- Read
- Grep
when_to_use: 当用户请求代码审查时
context: fork
---
# Code Review Skill
## 审查标准
1. 检查代码风格一致性
2. 验证业务逻辑正确性
3. 识别潜在性能问题
这种设计实现了机器可读的元数据和人类友好的说明文档的统一。
2.2 技能的加载流程
技能加载采用memoize缓存机制,确保高性能:
typescript复制export const getSlashCommandToolSkills = memoize(
async (cwd: string): Promise<Command[]> => {
const allCommands = await getCommands(cwd)
return allCommands.filter(/* 过滤条件 */)
}
)
关键设计特点:
- 延迟加载:启动时只加载元数据,内容按需读取
- Token估算优化:基于frontmatter而非完整内容
- 错误隔离:单个技能加载失败不影响整体系统
3. 技能的执行架构
3.1 统一的SkillTool入口
所有技能通过SkillTool执行,确保一致的接口和安全控制:
typescript复制export const inputSchema = z.object({
skill: z.string().describe('技能名称'),
args: z.string().optional().describe('可选参数')
})
执行流程分为几个关键阶段:
- 输入验证
- 权限检查
- 上下文准备
- 实际执行(inline或fork模式)
3.2 两种执行模式
3.2.1 Inline模式
在当前对话上下文中直接执行,技能内容会被展开为用户消息:
typescript复制const processedCommand = await processPromptSlashCommand(
commandName,
args,
commands,
context
)
return {
newMessages: processedCommand.messages,
contextModifier(ctx) {
// 调整工具权限
}
}
3.2.2 Fork模式
创建独立的子代理执行,拥有自己的上下文和资源预算:
typescript复制async function executeForkedSkill(command, args, context) {
const agentId = createAgentId()
const { promptMessages } = await prepareForkedCommandContext(...)
for await (const message of runAgent({
agentDefinition: baseAgent,
promptMessages,
toolUseContext: context,
override: { agentId }
})) {
// 处理进度消息
}
return {
agentId,
result: extractResultText(agentMessages)
}
}
Fork模式特别适合:
- 长时间运行的任务
- 需要隔离环境的操作
- 资源密集型工作流
3.3 防止重复调用机制
通过COMMAND_NAME_TAG标签避免技能被重复调用:
typescript复制export const getPrompt = () => `
- 如果看到<${COMMAND_NAME_TAG}>标签,
表示技能已加载 - 直接遵循指令即可,
无需再次调用此工具
`
这种设计有效防止了:
- 无限循环调用
- 资源浪费
- 上下文污染
4. 权限与安全模型
4.1 多层权限检查流程
权限检查采用分层设计:
- Deny规则检查(最高优先级)
- 特定用户组自动放行
- Allow规则检查
- 安全属性自动放行
- 默认询问用户
typescript复制function checkPermissions() {
// 1. 检查deny规则
const denyRules = getRuleByContentsForTool(..., 'deny')
// 2. 特殊用户组检查
if (isRemoteCanonicalSkill) return ALLOW
// 3. 检查allow规则
const allowRules = getRuleByContentsForTool(..., 'allow')
// 4. 安全属性检查
if (skillHasOnlySafeProperties(command)) return ALLOW
// 5. 默认询问用户
return ASK_USER
}
4.2 安全属性白名单
SAFE_SKILL_PROPERTIES定义了自动放行的安全属性:
typescript复制const SAFE_SKILL_PROPERTIES = new Set([
'type',
'progressMessage',
'contentLength',
'model',
'effort',
// ...其他安全属性
])
任何不在白名单中的属性都会触发用户授权流程,这种设计确保了:
- 新属性的默认安全
- 透明的权限管理
- 可扩展的安全模型
4.3 MCP技能的特殊处理
来自Model Context Protocol的远程技能有额外限制:
- 禁止内联shell命令执行
- 禁用敏感变量替换
- 特殊的命令解析逻辑
typescript复制if (loadedFrom !== 'mcp') {
finalContent = await executeShellCommandsInPrompt(finalContent)
}
5. 高级特性与最佳实践
5.1 条件技能机制
技能可以根据工作上下文自动激活:
markdown复制---
name: react-review
paths:
- "**/*.tsx"
- "**/*.jsx"
---
激活流程:
- 监控文件访问事件
- 匹配路径模式
- 动态加载相关技能
- 加入当前会话上下文
5.2 动态技能发现
系统会智能发现项目中的技能目录:
code复制/project/
.claude/skills/ # 项目级技能
src/
.claude/skills/ # 组件特定技能
发现算法特点:
- 向上遍历目录树
- 遵守gitignore规则
- 按深度排序(最深优先)
5.3 技能预算系统
严格的上下文窗口管理:
typescript复制export const SKILL_BUDGET_CONTEXT_PERCENT = 0.01
export const DEFAULT_CHAR_BUDGET = 8_000
优化策略:
- 基于frontmatter估算token
- 重要技能优先
- 最近使用技能缓存
6. 实战经验与避坑指南
6.1 技能设计最佳实践
- 保持单一职责:每个技能应专注于解决一个特定问题
- 明确触发条件:精确的whenToUse描述减少误触发
- 合理设置上下文:计算密集型使用fork模式
- 版本控制:通过version字段管理技能演进
6.2 常见问题排查
问题1:技能未被识别
- 检查文件位置和命名规范
- 验证frontmatter格式
- 确认技能目录未被gitignore
问题2:权限被拒绝
- 检查SAFE_SKILL_PROPERTIES白名单
- 验证userInvocable和disableModelInvocation设置
- 查看deny规则冲突
问题3:性能问题
- 避免在frontmatter中放置大段文本
- 对于复杂技能使用fork模式
- 合理设置effort级别
6.3 调试技巧
- 使用
debug.ts技能查看内部状态 - 检查
~/.claude/logs中的详细日志 - 通过
getSlashCommandToolSkills直接验证技能加载 - 使用
verify技能检查配置有效性
7. 扩展与集成
7.1 插件技能开发
创建第三方技能的基本步骤:
- 实现插件接口
- 定义技能元数据
- 打包发布到插件市场
- 处理权限和安全性
7.2 与现有工具链集成
- 版本控制:通过git hooks自动同步技能
- CI/CD:使用verify技能作为质量关卡
- 监控:通过hooks系统集成APM工具
7.3 自定义工作流
组合多个技能创建复杂工作流:
markdown复制---
name: pr-workflow
kind: workflow
steps:
- skill: code-review
- skill: run-tests
- skill: deploy-preview
---
这种设计模式可以构建出:
- 代码审查流水线
- 自动化部署流程
- 质量门禁系统
8. 架构演进与未来方向
当前架构的几个显著优势:
- 灵活性:支持多种技能来源和类型
- 安全性:精细的权限控制模型
- 性能:智能的加载和执行策略
- 可扩展性:清晰的插件接口
可能的演进方向:
- 技能市场与共享机制
- 可视化技能编排工具
- 基于使用的技能推荐
- 跨团队技能协作
在实际项目中,我们团队采用这套系统后,开发效率提升了约40%,特别是代码审查和自动化测试方面。一个典型的例子是,我们将常见的代码审查点封装成技能后,新成员的代码质量从第一天就达到了团队标准。
关键建议:开始时从小而精的技能入手,逐步构建技能库。我们最初只创建了5个核心技能,但随着时间推移,这个数字自然增长到了50+,覆盖了80%的日常开发场景。
