Appearance
Claude Code 的 Subagent、Command、Skill 三件套是互补而非竞争的关系:Command 是用户显式触发的工作流入口,Skill 是 Claude 可以自动感知的可复用过程,Subagent 是在独立上下文中自主执行的执行单元。三者最核心的区别是触发方式和上下文归属。
Claude Code 三件套对比:何时用 Subagent、何时用 Command、何时用 Skill
一眼对比
| Subagent | Command | Skill | |
|---|---|---|---|
| 文件位置 | .claude/agents/<name>.md | .claude/commands/<name>.md | .claude/skills/<name>/SKILL.md |
| 用户可见 | 无 / 菜单入口 | 有 /command-name | 有 /skill-name(可隐藏) |
| Claude 自动触发 | 是(via description) | 否(永远需要用户触发) | 是(via description) |
| 独立上下文 | 始终隔离 | 否(共享主会话) | 否(除非 context: fork) |
| 可预加载 Skills | 是(skills: 字段) | — | — |
| 持久记忆 | 是(memory: 字段) | — | — |
| 工具限制 | tools: / disallowedTools: | allowed-tools: | allowed-tools: |
| 模型覆盖 | model: | model: | model: |
| 动态内容注入 | 否 | !`command` | !`command` |
何时用哪个
用 Subagent 当:
- 任务需要自主多步探索、决策和执行,不需要用户每步确认
- 不想让中间过程(文件读取、搜索、错误重试)污染主会话上下文
- 需要不同工具集或权限模式(如只读探索 vs 自动接受编辑)
- 任务可以后台或并行执行
- 需要跨 session 积累知识(
memory:字段)
典型例子:weather-agent——自主调用 API 获取数据,在独立上下文中运行,使用预加载的 skill 作为领域知识。
用 Command 当:
- 需要用户明确触发的工作流入口
- 工作流涉及编排其他 Agent 和 Skill
- 不希望 content 常驻上下文(Command 内容只在用户调用
/command-name时才注入) - 工作流中有与用户交互的节点(AskUserQuestion)
典型例子:weather-orchestrator——用户触发,询问 C/F 偏好,调度 Agent 和 Skill。
用 Skill 当:
- 希望 Claude 自动感知并调用,无需用户显式输入命令
- 任务是可以从多个 Command、Agent 或 Claude 本身调用的通用过程
- 需要通过
paths:glob 按文件路径按需激活 - 需要作为Agent 领域知识预加载(
user-invocable: false)
典型例子:weather-svg-creator——用户说"生成天气卡片"时 Claude 自动调用;也可被 Command 显式调用。
三件套的自动触发规则
| 机制 | 能否自动触发 | 如何防止 |
|---|---|---|
| Subagent | 是(description 中写 "PROACTIVELY") | 弱化或移除 description |
| Command | 否——永远需要用户输入 / | N/A |
| Skill | 是(description 语义匹配) | 设 disable-model-invocation: true |
上下文隔离规则
| 机制 | 运行在独立上下文? | 配置方式 |
|---|---|---|
| Subagent | 始终隔离 | 内置行为 |
| Command | 从不隔离 | N/A |
| Skill | 可选 | 设 context: fork |
实战案例:同一任务的三种实现
任务:用户问"现在几点了?"——在 PKT(UTC+5)时区获取并显示当前时间。
| 实现方式 | 会自动触发吗? | 为什么 |
|---|---|---|
time-command | 不会 | Command 永远不自动触发,用户必须明确输入 /time-command |
time-agent | 可能会 | Agent 的 description 匹配到用户意图,Claude 可能通过 Agent 工具调用它。但代价是启动独立上下文,对这个简单任务偏重 |
time-skill | 最可能 | Skill 的 description 精确描述触发场景,Claude inline 调用,无额外上下文开销 |
Claude 的选择优先级(当多个机制都匹配时):
1. Skill(inline,无上下文开销) ← 首选
2. Subagent(独立上下文,更重) ← 任务复杂时
3. Command(永远不自动触发) ← 仅用户显式调用Frontmatter 快速对比
yaml
# Subagent
---
name: my-agent
description: Use this agent PROACTIVELY when...
tools: Read, Write, Edit, Bash
model: sonnet
maxTurns: 10
permissionMode: acceptEdits
memory: user
skills:
- my-skill
---
# Command
---
description: 用途说明
argument-hint: [参数提示]
allowed-tools: Read, Edit, Bash(gh *)
model: haiku
---
# Skill
---
name: my-skill
description: 当用户要求...时使用此 skill
disable-model-invocation: false
user-invocable: true
context: fork
model: sonnet
paths: "src/**/*.ts,src/**/*.tsx"
---FAQ
Q: Skill 和 Command 用户都可以调用,核心区别是什么? A: 上下文注入时机。Skill 的 content 在 session 启动时就注入上下文,Claude 可以随时语义匹配自动调用;Command 的 content 只在用户显式输入 /command-name 时才注入。想让 Claude 自动判断何时执行——用 Skill;需要用户明确控制入口——用 Command。
Q: Subagent 和主会话中 Claude 直接执行有什么本质区别? A: Subagent 拥有完全独立的上下文窗口,所有中间工具调用(文件读取、搜索、死胡同)都不出现在主会话中,主会话只看到最终结果。这使得主会话保持干净,上下文不被大量中间步骤浪费。
Q: 如果 skill 设了 disable-model-invocation: true,用户还能用吗? A: 可以,用户仍然可以手动输入 /skill-name 触发。disable-model-invocation: true 只阻止 Claude 自动调用,不影响用户主动调用。