从第一性原理 深度解析Claude Agent Skills底层原理

Claude Agent Skills 底层原理深度解析

Claude 的 Agent Skills(技能)系统,本质上是一套基于提示词的元工具架构,用于扩展大模型的能力边界。它不像传统的函数调用或代码执行那样直接干活,而是通过提示词扩展上下文修改来影响 Claude 处理后续请求的方式------整个过程不写一行可执行代码。

本文从第一性原理出发,拆解 Claude Agent Skills 系统的内部架构:一个叫做 "Skill" 的元工具,专门负责往对话上下文里注入特定领域的提示词。文章以 skill-creatorinternal-comms 这两个技能为案例,从文件解析到 API 请求结构,再到 Claude 的决策逻辑,把整个生命周期完整地走一遍。

原文:https://leehanchung.github.io/blogs/2025/10/26/claude-skills-deep-dive/

Claude Agent Skills 整体概览

Claude 通过 Skills 来提升特定任务的处理效果。所谓技能,就是一些文件夹,里面装着 Claude 按需加载的指令、脚本和资源。整套系统采用声明式、基于提示词的机制 来完成技能的发现和调用------AI 模型(Claude)根据系统提示词里的文字描述,自己决定要不要调用某个技能。代码层面完全没有算法选路或意图识别,决策完全发生在 Claude 的推理过程中。

技能不是可执行代码,不会跑 Python 或 JavaScript,背后也没有 HTTP 服务器或函数调用。它们也不是硬编码在 Claude 系统提示词里的,而是以专门的提示词模板形式存在,在被调用时往对话上下文里注入特定领域的指令,同时修改执行上下文(工具权限、模型切换等)。

当用户发送请求时,Claude 同时收到三样东西:用户消息、可用工具(Read、Write、Bash 等),以及 Skill 工具。Skill 工具的描述里包含了所有可用技能的列表(名称 + 描述)。Claude 用语言理解能力把用户意图和技能描述做匹配。比如你说"帮我创建一个处理日志的技能",Claude 看到 internal-comms 技能的描述,认出来匹配,就会调用 Skill 工具并传入 command: "internal-comms"

术语说明

  • Skill 工具 (大写 S)= 管理所有技能的元工具,出现在 Claude 的 tools 数组里
  • skills (小写 s)= 具体的单个技能,如 pdfskill-creatorinternal-comms,是 Skill 工具加载的专用指令模板

下图直观展示了技能的调用流程:

技能选择机制在代码层面没有任何算法路由或意图分类 。Claude Code 不用向量嵌入、分类器或正则匹配来决定调用哪个技能。系统把所有技能格式化成文本描述,嵌入 Skill 工具的提示词里,让语言模型自己判断。这是纯粹的 LLM 推理,没有 regex,没有关键词匹配,没有 ML 意图检测,决策完全发生在模型的前向传播里,而不是应用代码。

技能被调用后,系统走一个简单的流程:加载 markdown 文件(SKILL.md)→ 展开成详细指令 → 作为新的用户消息注入对话上下文 → 修改执行上下文(允许的工具、模型选择)→ 带着这套丰富的环境继续对话。这和传统工具(执行后返回结果)有本质区别------技能是在为 Claude 做好准备,而不是直接解决问题。

下表列出了传统工具和技能的核心差异:

维度 传统工具 技能
执行模型 同步、直接 提示词扩展
目的 执行具体操作 引导复杂工作流
返回值 即时结果 对话上下文 + 执行上下文变更
示例 ReadWriteBash internal-commsskill-creator
并发安全 通常安全 不是并发安全的
类型 各种 始终为 "prompt"

如何构建 Agent Skills

接下来结合 Anthropic 技能仓库里的 skill-creator 技能,看看技能到底怎么构建。

核心理解:技能 = 提示词模板 + 对话上下文注入 + 执行上下文修改 + 可选的数据文件和 Python 脚本

每个技能都定义在一个叫 SKILL.md 的 markdown 文件里(大小写不敏感),可以附带放在 /scripts/references/assets 下的辅助文件------包括 Python 脚本、Shell 脚本、字体定义、模板等。skill-creator 技能包含 SKILL.mdLICENSE.txt,以及 /scripts 目录下的几个 Python 脚本。

技能从多个来源被发现和加载:用户设置(~/.config/claude/skills/)、项目设置(.claude/skills/)、插件提供的技能,以及内置技能。Claude Desktop 也支持上传自定义技能:

构建技能最重要的概念是「渐进式披露」(Progressive Disclosure)------只展示足够帮助 Agent 决定下一步做什么的信息,等需要时再揭示更多细节:

  1. 先披露 Frontmatter:最少信息(名称、描述、许可证)
  2. 选定技能后,加载 SKILL.md:全面但聚焦
  3. 技能执行过程中,按需加载辅助资产、参考文档和脚本

SKILL.md

SKILL.md 是技能提示词的核心,遵循两段式结构:frontmatter(前置元数据)和正文内容。Frontmatter 配置技能怎么跑 (权限、模型、元信息),正文内容告诉 Claude 做什么。Frontmatter 是用 YAML 写的文件头。

复制代码
┌─────────────────────────────────────┐
│ 1. YAML Frontmatter(元数据)        │ ← 配置
│    ---                              │
│    name: skill-name                 │
│    description: 简要描述             │
│    allowed-tools: "Bash, Read"      │
│    version: 1.0.0                   │
│    ---                              │
├─────────────────────────────────────┤
│ 2. Markdown 正文(指令)              │ ← 给 Claude 的提示词
│                                     │
│    目的说明                          │
│    详细指令                          │
│    示例和规范                        │
│    步骤流程                          │
└─────────────────────────────────────┘
Frontmatter 各字段详解

skill-creator 的 frontmatter 为例:

yaml 复制代码
---
name: skill-creator
description: 创建有效技能的指南。当用户想创建新技能(或更新现有技能)时使用本技能。
license: 完整条款见 LICENSE.txt
---

name(必填) :技能名称,同时也是 Skill 工具里的 command 参数值。

description(必填) :技能功能的简要说明,是 Claude 判断何时调用该技能的主要信号。措辞要清晰、面向行动------"当用户想创建新技能时使用"这类表述,能帮助 Claude 把用户意图准确映射到技能能力上。系统会自动在描述后追加来源信息(如 "(plugin:skills)"),方便在多技能并存时区分不同来源。

when_to_use(未文档化,可能已废弃或尚未发布) :这个字段在代码库里大量出现,但官方文档里没有任何记录,可能是废弃中的功能、内部实验性特性,或尚未正式发布的功能。建议 :用详细的 description 字段代替,不要在生产环境里依赖 when_to_use

目前代码里,当 when_to_use 存在时,会被拼接到 description 后面:

javascript 复制代码
function formatSkill(skill) {
  let description = skill.whenToUse
    ? `${skill.description} - ${skill.whenToUse}`
    : skill.description;
  return `"${skill.name}": ${description}`;
}

license(可选):许可证,不多解释。

allowed-tools(可选) :定义技能可以无需用户审批直接使用的工具,支持通配符。skill-creator 用的是 "Read,Write,Bash,Glob,Grep,Edit"。常见错误是列出所有工具,这既带来安全风险,也破坏了权限模型。原则是:只写技能真正需要的工具。

yaml 复制代码
# ✅ 多工具
allowed-tools: "Read,Write,Bash,Glob,Grep,Edit"

# ✅ 只允许特定 git 子命令
allowed-tools: "Bash(git status:*),Bash(git diff:*),Read,Grep"

# ❌ 不必要的权限暴露
allowed-tools: "Bash,Read,Write,Edit,Glob,Grep,WebSearch,Task,Agent"

model(可选):指定技能使用的模型,默认继承当前会话的模型。复杂任务可以请求更强的模型。

yaml 复制代码
model: "claude-opus-4-20250514"  # 使用指定模型
model: "inherit"                 # 继承会话当前模型(默认)

versiondisable-model-invocationmode(可选)version 用于版本追踪;disable-model-invocation 设为 true 时,技能不会出现在 Skill 工具的列表里,只能由用户手动通过 /skill-name 调用,适合危险操作或需要明确用户确认的交互流程;mode 设为 true 时,技能会显示在技能列表顶部的"Mode Commands"区域,适合用来建立特定操作上下文的技能,比如 debug-mode、expert-mode 等。

SKILL.md 正文内容

Frontmatter 之后就是 markdown 正文------技能被调用时 Claude 实际收到的提示词。写好技能提示词的关键是保持聚焦,用渐进式披露:核心指令放在 SKILL.md 里,详细内容引用外部文件。

推荐的内容结构:

markdown 复制代码
---
# Frontmatter
---

# [一两句话说清楚目的]

## 概述
[技能做什么、什么时候用、提供什么]

## 前置条件
[需要的工具、文件或上下文]

## 指令

### 第一步:[第一个动作]
[命令式指令]

### 第二步:[下一个动作]
...

## 输出格式
## 错误处理
## 示例
## 资源

提示词写作最佳实践 :保持在 5000 词以内(约 800 行);用祈使句("分析代码......"),不用第二人称("你应该分析......");详细内容引用外部文件而不是全部内嵌;路径用 {baseDir} 变量,绝不硬编码绝对路径。

复制代码
❌ Read /home/user/project/config.json
✅ Read {baseDir}/config.json

打包资源文件

技能真正强大之处在于能把支持资源一并打包。标准结构如下:

复制代码
my-skill/
├── SKILL.md              # 核心提示词和指令
├── scripts/              # 可执行的 Python/Bash 脚本
├── references/           # 加载到上下文的文档
└── assets/               # 模板和二进制文件

为什么要打包? 保持 SKILL.md 简洁(5000 词以内)能避免撑爆 Claude 的上下文窗口。打包资源允许提供详细文档、自动化脚本和模板,只在需要时按需加载。

  • scripts/:Claude 通过 Bash 工具运行的可执行代码------自动化脚本、数据处理器、验证器等。适合复杂的多步骤操作、数据转换、API 交互,或者任何用代码比用自然语言更精确的任务。

  • references/:Claude 通过 Read 工具读入上下文的文档------markdown 文件、JSON Schema、配置模板等。适合详细文档、大型模式库、检查清单、API Schema,或者任何对 SKILL.md 来说太冗长但任务必需的文本内容。

  • assets/:Claude 只引用路径、不读取内容的模板和二进制文件------HTML 模板、CSS 文件、图片、配置样板、字体等。

references/assets/ 的核心区别:references/ 里的文本内容会被加载进 Claude 的上下文(消耗 token),assets/ 里的文件只是路径引用,不加载进上下文。


常见技能模式

模式一:脚本自动化

把复杂计算任务卸载给 scripts/ 目录里的 Python 或 Bash 脚本。

markdown 复制代码
运行 scripts/analyzer.py 分析目标目录:
`python {baseDir}/scripts/analyzer.py --path "$USER_PATH" --output report.json`
解析生成的 report.json,呈现分析结果。
模式二:读取-处理-写入

最简单的模式------读取输入、按指令转换、写出结果。适合格式转换、数据清洗或报告生成。

模式三:搜索-分析-报告

用 Grep 搜索代码库中的模式,读取匹配文件获取上下文,分析发现,生成结构化报告。

模式四:命令链式执行

执行一系列前后依赖的命令序列,常见于类似 CI/CD 的工作流。

高级模式:向导式多步工作流、模板化生成、迭代精化、上下文聚合
  • 向导式多步工作流:把复杂流程拆成若干阶段,每个阶段结束后等待用户确认再继续,适合安装向导、配置工具等场景。
  • 模板化生成 :从 assets/ 加载模板,填入用户提供或生成的数据,写出结果。适合报告生成、样板代码创建等。
  • 迭代精化:先做广泛扫描,再对发现的问题做深度分析,一轮一轮逐步深入。适合代码审查、安全审计等。
  • 上下文聚合:从多个来源(README、package.json、git 历史等)收集信息,综合成连贯全貌。

Agent Skills 内部架构

Skills 对象设计

传统工具(Read、Bash、Write)执行离散操作,返回即时结果。技能的工作方式完全不同:它不直接执行操作,而是把专用指令注入对话历史,同时动态修改 Claude 的执行环境。这通过两条用户消息实现------一条包含用户可见的元数据,一条包含发送给 Claude 的完整技能提示词(对 UI 隐藏)------并通过修改 Agent 上下文来变更权限、切换模型、调整思考 token 参数。

特性 普通工具 技能工具
本质 直接执行 提示词注入 + 上下文修改
消息角色 assistant→tool_use / user→tool_result 多条,含隐藏的 skill prompt
复杂度 简单(3-4 条消息) 复杂(5-10+ 条消息)
上下文 静态 动态(每轮修改)
Token 开销 极少(约 100 token) 显著(每轮 1500+ token)

Skill 元工具的结构:

javascript 复制代码
{
  name: "Skill",
  inputSchema: { command: string },  // 如 "pdf"、"skill-creator"
  outputSchema: { success: boolean, commandName: string },
  prompt: async () => fN2(),         // 动态生成技能列表
  validateInput, checkPermissions, call
}

prompt 字段是 Skill 工具区别于其他工具的关键:它不是固定字符串,而是运行时动态构建的描述------聚合所有可用技能的名称和描述,形成 <available_skills> 列表。这正是渐进式披露的体现:初始上下文里只加载最少的元信息,Claude 选定技能后才加载完整提示词,避免上下文膨胀。

技能列表不在系统提示词里,而是在 tools 数组中作为 Skill 工具描述的一部分。完整 API 请求结构大致如下:

json 复制代码
{
  "model": "claude-sonnet-4-5-20250929",
  "system": "You are Claude Code...",
  "messages": [...],
  "tools": [
    {
      "name": "Skill",
      "description": "Execute a skill...\n\n<available_skills>\n...",
      "input_schema": {
        "type": "object",
        "properties": { "command": { "type": "string" } }
      }
    },
    { "name": "Bash", ... },
    { "name": "Read", ... }
  ]
}

<available_skills> 部分在每次 API 请求时动态重建,受 15000 字符的 token 预算限制,这也迫使技能作者写出简洁的描述。

对话上下文与执行上下文注入的设计

技能用 role: "user" 消息而不是 role: "system" 消息,是有原因的。系统消息具有全局持久性,会影响整个对话,而技能需要的是临时、局部的行为变更------skill-creator 应该只影响当前任务,不应该让 Claude 在整个会话里都变成 PDF 专家。用 role: "user" + isMeta: true 让技能提示词作为用户输入出现,保持临时性。

技能调用时,系统向对话历史注入两条独立的用户消息,通过 isMeta 标志控制是否在 UI 中显示:

第一条消息(isMeta: false,用户可见):简短的状态指示,告知用户哪个技能正在加载。格式如:

xml 复制代码
<command-message>The "pdf" skill is loading</command-message>
<command-name>pdf</command-name>

第二条消息(isMeta: true,用户不可见):完整的技能提示词,发送给 API 但不显示在 UI。通常 500 到 5000 词,包含任务上下文、工作流程、可用工具、输出格式、环境路径等。

为什么要两条消息而不是一条?因为这两条消息服务于完全不同的受众:

维度 元数据消息 技能提示词消息
受众 人类用户 Claude(AI)
目的 状态透明度 指令引导
长度 ~50-200 字符 ~500-5000 词
格式 结构化 XML 自然语言 Markdown
可见性 应该可见 应该隐藏

合并成一条消息的话,只能二选一:要么把几千词的 AI 内部指令全倒进用户聊天记录,让 UI 无法使用;要么全部隐藏,用户完全不知道系统在做什么。两条消息的拆分,优雅地解决了透明度和清晰度的矛盾。

除了核心的元数据和技能提示词,技能还可以条件性地注入附件消息(诊断信息、文件引用等)和权限消息(当技能指定了 allowed-tools 或模型覆盖时)。


案例:完整执行生命周期

以用户说"从 report.pdf 中提取文本"为例,走一遍完整流程:

阶段一:发现与加载(启动时)

Claude Code 启动时,并行扫描所有技能来源:用户命令、技能和插件、插件命令、内置命令,构建可用技能列表。每个技能文件被解析为包含名称、描述、允许工具、模型配置、提示词内容等字段的对象。

阶段二:Turn 1 ------ 用户请求与技能选择

用户发送"从 report.pdf 中提取文本"。Claude 在 API 请求里看到 Skill 工具,读取 <available_skills> 列表,用语言理解推理出 pdf 技能最匹配,返回工具调用:

json 复制代码
{
  "type": "tool_use",
  "name": "Skill",
  "input": { "command": "pdf" }
}

注意:这里没有任何算法匹配,纯粹是 LLM 在 transformer 前向传播中完成的推理。

阶段三:Skill 工具执行

依次经历三步:

验证:检查命令非空、技能存在、技能可加载、未禁用模型调用、类型为 prompt。

权限检查:匹配拒绝规则和允许规则,默认询问用户确认。

加载技能文件,生成执行上下文修改 :加载 SKILL.md 内容,构建两条用户消息(元数据 + 技能提示词),准备 contextModifier 函数(预批准 allowed-tools 里的工具,按需覆盖模型)。

阶段四:Send to API(Turn 1 完成)

系统把完整消息数组发送给 Anthropic API,包括对话历史、工具调用、元数据消息、隐藏的技能提示词消息、权限消息。执行上下文修改器同时生效,预批准 Bash(pdftotext:*)ReadWrite

这里要特别注意:如果是普通工具,到这里就结束了。但技能不一样------技能只是注入了对话上下文和执行上下文,还需要再次调用 Claude Agent,带着所有注入的上下文来完成用户的实际请求。

阶段五:Bash 工具执行(在技能上下文中的工具调用)

Claude 收到注入了技能提示词的 API 响应,技能上下文已经给了 Claude:

  • 专门的 PDF 处理指令(对话上下文)
  • 预批准的 Bash(pdftotext:*)ReadWrite 工具访问(执行上下文)
  • 清晰的工作流程指引(对话上下文)

Claude 按照 pdf 技能的工作流运行,调用 Bash 工具执行 pdftotext(无需用户二次确认),读取输出文件,将提取的文本呈现给用户。技能通过注入指令和修改工具权限,成功引导 Claude 完成了专业化的 PDF 提取工作流。


总结:核心心智模型

Claude Code 中的技能是基于提示词的对话与执行上下文修改器,通过元工具架构运作。几个核心结论:

  1. 技能是 SKILL.md 文件里的提示词模板,不是可执行代码
  2. Skill 工具 (大写 S)是 tools 数组里的元工具,管理所有个别技能,不在系统提示词里
  3. 技能通过注入指令提示词(isMeta: true 消息)修改对话上下文
  4. 技能通过变更工具权限和模型选择修改执行上下文
  5. 技能选择通过 LLM 推理完成,不是算法匹配
  6. 工具权限通过执行上下文修改器,作用域限定在技能执行期间
  7. 每次技能调用注入两条用户消息------一条用户可见的元数据,一条隐藏的指令发送给 API

这套设计的优雅之处 :把专业知识当作修改上下文的提示词 而不是执行操作的代码来处理,让 Claude Code 获得了传统函数调用难以实现的灵活性、安全性和可组合性。


参考资料

相关推荐
阿荻在肝了2 小时前
Agent学习五:LangGraph学习-节点与可控性
人工智能·python·学习·agent
x-cmd3 小时前
[260416] 谷歌 Chrome 推出 Skills 功能!帮你保存、复用提示词
前端·chrome·ai·自动化·agent·x-cmd·skill
飞龙14775657467503 小时前
Claude Code 神器 /simplify:让你的代码秒变专业级!
agent
haibindev3 小时前
Hermes Agent 一周暴涨五万 Star,但我劝你别急着追
agent·ai编程·ai agent·github trending
heytoo3 小时前
同一个模型,为什么结果差10倍?差的不是模型
前端·agent
阿杰学AI3 小时前
AI核心知识124—大语言模型之 智能体工程
人工智能·ai·语言模型·自然语言处理·agent·智能体·智能体工程
Flying pigs~~3 小时前
RAG 项目完整学习笔记与总结
agent·milvus·rag·智能体·检索增强生成
Pkmer4 小时前
Harness Engineering: 人类掌舵,智能体执行
llm·agent
前端双越老师4 小时前
OpenClaw 实战记录:前端 VS 全栈 招聘岗位分析
前端·agent·全栈