目录概要
- 接着上一篇的疑问
- 历史背景:为什么会演化出三个相似的东西
- 一张表看清三者本质
- 三个维度深入对比
- 经典场景:"现在几点了?"------谁响应?
- 决策树:遇到需求到底选哪个?
- Frontmatter 对比速查
- 混编:三者如何组合使用
1. 接着上一篇的疑问
上一篇扫完 6 个核心概念之后,我留了一个尾巴------Command、Agent、Skill 这三个东西看起来都是一段提示词,都能封装工作流,到底有啥区别?这篇就把这个尾巴接上。
这三者不仅名字容易混,frontmatter 字段还有大量重叠------都有 name、description、allowed-tools、model------光看一个文件内容,你甚至分不出这是 command 还是 skill。更要命的是,它们的触发时机、上下文隔离、状态持久化等行为差异,在官方文档里是分散描述的,你很难在一个地方拿到清晰对比。
这篇的三个部分:
- 历史------为什么会演化出三个,不是一个
- 对比学习------三者在各维度上的差异
- 选择决策------遇到需求怎么判断用哪个
2. 历史背景:为什么会演化出三个相似的东西
不感兴趣历史的可以直接跳到第 3 节。但我个人觉得,理解演化路径之后,三者的定位会清晰很多------它们不是拍脑袋造的,是一步一步解决真实问题迭代出来的。
2.1 最早只有 Commands
Claude Code 最早的扩展机制只有 slash commands。
那时候很朴素:想复用工作流就写个 .md,里面放提示词,然后用 /name 触发。跟 textexpander、shell alias 都没啥区别。
Commands 解决的问题很直白:避免重复打字。但很快就暴露出短板:
- Claude 不会主动用 :你不输入
/xxx,Claude 永远想不到去用 - 污染上下文:一个复杂 command 几百行提示词塞进主对话,越用越慢
- 没有记忆:每次白板开始,学不到东西
2.2 Subagents 诞生------解决复杂任务
Boris Cherny 在一些公开访谈里反复提到一个观点:不要让一个复杂任务污染主对话。
为了这件事,Subagents 诞生了。Subagent 的设计哲学是:
一个 subagent 就是一个有独立人格、独立上下文、独立工具权限的"员工"。
独立上下文] Agent -.只返回结果.-> Main Agent --> T[自己的工具集] Agent --> M[自己的 memory] Agent --> S[自己的 skills]
它解决了:
- 隔离:子任务不污染主对话
- 自主:Claude 自己判断什么时候派遣 subagent(靠 description 匹配)
- 专业化:每个 subagent 有专属工具、模型、权限
但 Subagents 太重了。对于"现在几点了?"这种问题,启动一个独立上下文的 agent,就像叫一个专职员工去接一杯水------成本完全不匹配。
2.3 Skills 诞生------轻量级可复用知识
Anthropic 内部用 Claude Code 时发现,大量的场景是:
"我想让 Claude 做某件事时按某个方法做,但不值得起一个 agent。"
比如:
- 生成 SVG 时按公司设计规范
- 调用内部 API 时按错误处理约定
- 写 commit message 时按项目风格
这些都是可复用的知识片段,不是独立任务。于是 Skills 出现了。
Skills 的关键创新是"渐进式揭露 "------一个 skill 是一个目录,不是单个文件。SKILL.md 只放"何时用、怎么用"的摘要,具体参考资料、脚本、示例分散在子目录里,用的时候再读。
简述 + 何时触发
默认加载] B[references/api.md
用时才加载] C[scripts/validate.py
用时才执行] D[examples/case1.md
参考示例] A -.用到时读.-> B A -.用到时跑.-> C A -.用到时看.-> D
2.4 为什么不把三者合并?
我其实也想过这个问题------为什么不设计一个统一的 "Extension" 类型,用几个布尔字段开关?
答案是:三者的心智模型完全不同,强行合并反而更难学。
- Command 是"用户主动触发的工作流入口 "------心智模型是按钮
- Skill 是"可复用的知识/流程 "------心智模型是工具箱里的工具
- Agent 是"有独立人格的员工 "------心智模型是员工
按钮、工具、员工,这三个词你一听就知道用法不同。但如果把它们合成一个叫 "Extension" 的东西然后用布尔字段区分,反而让人每次都要脑补"这东西现在是按钮还是员工"。
这跟编程语言设计里"正交性 vs 简单性"是一个老问题------Anthropic 选择保留三个清晰的心智模型,承担额外的概念负担换取更低的使用负担。
3. 一张表看清三者本质
这张表是全篇精华,建议截图保存。
| 维度 | Command | Agent | Skill |
|---|---|---|---|
| 心智模型 | 按钮 | 员工 | 工具 |
| 文件位置 | .claude/commands/<name>.md |
.claude/agents/<name>.md |
.claude/skills/<name>/SKILL.md |
| 运行上下文 | 内联(共享主对话) | 独立子上下文 | 内联(默认) |
| 用户主动触发 | ✅ /command-name |
❌ 不出现在 / 菜单 |
✅ /skill-name(除非 user-invocable: false) |
| Claude 自动触发 | ❌ 永远不会 | ✅ 通过 description 匹配 |
✅ 通过 description 匹配 |
| 独立上下文窗口 | ❌ | ✅ 完全隔离 | ❌(除非 context: fork) |
| 预加载其他 skills | ❌ | ✅ skills: 字段 |
❌ |
| 持久化 memory | ❌ | ✅ memory: user/project/local |
❌ |
| 可限制工具权限 | ✅ allowed-tools: |
✅ tools: / disallowedTools: |
✅ allowed-tools: |
| 可指定模型 | ✅ | ✅ | ✅ |
| 典型场景 | 团队共享工作流入口 | 复杂自主任务 | 可复用的知识片段 |
4. 三个维度深入对比
4.1 上下文维度
这是三者最本质的区别。
内联在主上下文] SKILL[Skill 执行
内联在主上下文] end AGT[Agent 执行
独立上下文] Main -. 派遣任务 .-> AGT AGT -. 只返回结果 .-> Main style AGT fill:#faa,stroke:#f00 style CMD fill:#afa,stroke:#0a0 style SKILL fill:#aaf,stroke:#00f
一个权衡:
- 内联(Command/Skill):快、轻,但会占用主上下文 token
- 隔离(Agent):慢、重,但不污染主上下文
一条实用经验------如果一个任务的中间推理过程很长(比如读十几个文件才能下判断),用 Agent;如果只是"应用一下模板"或"按某个方法做一件事",用 Skill。
4.2 触发维度
用户有输入 /xxx 吗?] Check --> C2[检查 Skills
有 description 匹配?] Check --> C3[检查 Agents
有 description 匹配?] C1 -->|没| X1[Commands 不触发] C2 -->|time-skill 匹配| Y1[✅ Skill 候选] C3 -->|time-agent 匹配| Y2[Agent 候选] Y1 --> Pick[Claude 选最轻的] Y2 --> Pick Pick --> Use[用 time-skill] style X1 fill:#fcc style Y1 fill:#cfc style Use fill:#ff9
Claude 的默认优先级:
- Skill(内联,最便宜)← 优先
- Agent(独立上下文,贵)← Skill 不够用时
- Command(永不自动触发)← 只等用户主动输入
4.3 状态维度
| Command | Agent | Skill | |
|---|---|---|---|
| 单次执行内的状态 | ✅ | ✅ | ✅ |
| 跨会话记忆 | ❌ | ✅ memory 字段 |
❌ |
| 预加载其他知识 | ❌ | ✅ skills 字段 |
❌ |
唯一有持久化人格的是 Agent。这也是为什么 "code reviewer" 这种长期积累风格偏好的角色,最适合做成 Agent。
5. 经典场景:"现在几点了?"------谁响应?
这个仓库里恰好有三个同主题的 extension(有的是演示用的),完美的对照实验:
time-command(Command)time-agent(Agent)time-skill(Skill)
当用户说"现在几点了?"时:
| 机制 | 会触发吗? | 为什么? |
|---|---|---|
time-command |
❌ | Command 不会自动触发,必须输入 /time-command |
time-agent |
候补 | description 也匹配,但 Skill 更轻------主对话直接内联算出来就够了,没必要开独立上下文。Skill 存在时,Agent 优先级更低 |
time-skill |
✅ 首选 | description 匹配 + 内联执行 + 零上下文开销 |
如果你把 "time" 这个需求实现成 agent 而不是 skill,那就是高射炮打蚊子。
6. 决策树:遇到需求到底选哪个?
才触发吗?} Q1 -->|是| CMD[选 Command
工作流入口] Q1 -->|否| Q2{任务复杂度?} Q2 -->|轻量 单一能力| Q3{需要隔离上下文?} Q2 -->|复杂 多步自主| Q4{需要持久化记忆
或预加载知识?} Q3 -->|否| SKILL[选 Skill] Q3 -->|是| SKILL_F[选 Skill
设置 context: fork] Q4 -->|否| AGT[选 Agent 基础版] Q4 -->|是| AGT_P[选 Agent
+ memory + skills] style CMD fill:#afa style SKILL fill:#aaf style SKILL_F fill:#aaf style AGT fill:#faa style AGT_P fill:#faa
6.1 实战四问
遇到新需求时,顺次问四个问题:
谁触发?
- 用户主动 → Command
- Claude 判断 → Skill / Agent
任务多重?
- 几十 token 的轻操作 → Skill
- 多步推理、读大量文件、调 API → Agent
要不要记住东西?
- 每次白板 → Skill / Command
- 跨会话记忆 → Agent(
memory字段)
会不会被 agent 调用?
- 是 → 做成 Skill(可通过
skills:预加载到 agent) - 否 → 根据其他条件决定
7. Frontmatter 对比速查
三个 frontmatter 有很多字段重名,但语义不同。这里只给最小常用集------完整的 13 个 Command 字段会在 04 篇逐一拆解,Agent/Skill 的完整字段表也会在对应的深入篇补齐。这里够用就行。
Command
yaml
---
description: Do something useful
argument-hint: [issue-number]
allowed-tools: Read, Edit, Bash(gh *)
model: sonnet
---
(还有 disable-model-invocation、user-invocable、name 等另外 9 个字段------04 篇细讲。)
Agent
yaml
---
name: my-agent
description: Use this agent PROACTIVELY when...
tools: Read, Write, Edit, Bash
disallowedTools: Bash(rm *)
model: sonnet # haiku / sonnet / opus / inherit
maxTurns: 10
permissionMode: acceptEdits
memory: user # user / project / local
skills:
- my-skill
mcpServers:
- playwright
background: false
isolation: worktree
color: cyan
---
Skill
yaml
---
name: my-skill
description: Do X when user asks for Y
argument-hint: [file-path]
disable-model-invocation: false
user-invocable: true
allowed-tools: Read, Grep, Glob
model: sonnet
context: fork
agent: general-purpose
---
字段含义对照(同名不同义)
| 字段 | Command | Agent | Skill |
|---|---|---|---|
name |
文件名 | 必须显式声明 | 显式或文件夹名 |
description |
描述(可选) | 触发匹配用,必写 | 触发匹配用,必写 |
allowed-tools |
允许的工具 | 用 tools 字段 |
允许的工具 |
model |
模型别名 | 模型别名或 inherit |
模型别名 |
8. 混编:三者如何组合使用
最经典的组合是 Command → Agent → Skill 三层编排。
(Command) participant AGT as weather-agent
(Agent) participant PS as weather-fetcher
(预加载 Skill) participant API as Open-Meteo API participant SK as weather-svg-creator
(Skill) User->>CMD: /weather-orchestrator CMD->>User: 摄氏还是华氏? User->>CMD: 摄氏 rect rgb(250, 200, 200) Note over CMD,AGT: Agent 阶段 独立上下文 CMD->>AGT: Agent 工具调用 AGT->>PS: 读取预加载指令 PS-->>AGT: API 调用方法 AGT->>API: GET current temperature API-->>AGT: 26°C AGT-->>CMD: temperature=26, unit=C end rect rgb(170, 170, 255) Note over CMD,SK: Skill 阶段 内联执行 CMD->>SK: Skill 工具调用 SK->>SK: 生成 SVG + output.md SK-->>User: 文件已生成 end
这里用了两种 skill 调用模式:
- Agent Skill 模式 :
weather-fetcher通过 agent frontmatter 的skills:字段预加载到 agent 上下文 - 直接 Skill 模式 :
weather-svg-creator由 command 通过Skill工具直接调用
这两种模式同样是 skill,使用方式完全不同------这在下一篇拆 weather system 源码时会看得很清楚。
三者的分工
到这里,Command/Agent/Skill 三者的差异和选型逻辑就讲完了。
简单复盘一下------三者不是三个并列的功能,而是演化路径上的三个阶段 :Commands 解决"少打字",Subagents 解决"任务隔离",Skills 解决"轻量知识复用"。三个心智模型各司其职------按钮、员工、工具,你记住这三个词,基本不会选错。
选型四问也很直白:谁触发?多重?要记忆吗?被谁调用? 顺次答完就有答案。
抽象讲完了,该看具体执行了。
Footnotes
参考资料
- Claude Code Skills --- Docs
- Claude Code Sub-agents --- Docs
- Claude Code Slash Commands --- Docs
- Skills Best Practice
- Commands Best Practice
- Sub-agents Best Practice