MCP、Skills、Subagent 到底该用哪个

AI 编程MCPAgent

你想给 agent 加点东西。

可能是让它能查公司内部的订单系统,可能是让它写发布说明时别再每次都要你贴一遍格式规范,也可能是让它去翻一遍全仓库、告诉你某个废弃接口还剩多少调用点。你打开文档,看到三个候选:MCP、Skills、Subagent。

翻完之后你更糊涂了。三份文档都在说自己能”扩展 AI 的能力”,都能连工具、都能带来新行为、都能装在 .claude/ 目录下。它们看起来像是同一个问题的三种答案,于是你开始纠结该选哪一个。

这个纠结的前提就是错的。它们不是三选一,因为它们根本不在同一层。

这篇短文只做一件事:给你一条能在 30 秒内走完的判断路径,外加一张四场景决策表和五条最常见的误用。读完你不会成为这三种机制的专家,但你会知道下一次该往哪个方向走。

它们不在同一层

一个把三者搅在一起的真实需求

假设你要做这么一件事:让 agent 从内部订单系统拉出上周的退款记录,按团队约定的格式写一份周报,而且不要在写周报的过程中把主对话塞满几千行原始数据。

这一句需求里其实藏着三个完全不同的缺口:

  • 够不着内部订单系统——那是一个需要鉴权的内部 HTTP 服务,模型没法凭空访问。
  • 不知道你们周报长什么样——章节顺序、金额单位、哪些字段必须脱敏,这些规矩只存在于你同事的脑子和一份 Confluence 页面里。
  • 不该把几千行退款明细留在主对话里——那些明细只是中间材料,最后进周报的可能就十几行。

三个缺口,三种机制,正好一一对应。把它们当成三个候选方案去比较,是因为你还没把缺口拆开。

用三个动词记住它们

最省事的记法是三个动词:

MCP 给它手,Skill 给它规矩,Subagent 给它一间独立的房间。

展开一点:

MCP(Model Context Protocol) 是一个开放协议,用来把 AI 应用连到外部系统——数据库、内部 API、文件系统、第三方 SaaS。官方自己的比喻是”AI 应用的 USB-C 口”:定义一次接口,各种客户端都能插。它解决的是够不着的问题。没有 MCP,agent 再聪明也拿不到你内网里的那张表。

Skill(Agent Skill) 是一个可以被发现、被按需加载的指令包。最小形态就是一个带 YAML frontmatter 的 SKILL.md,里面写清楚这件事该怎么做、按什么标准做、有哪些坑。它可以附带脚本和参考文件。它解决的是不知道怎么做的问题——能力本来就有,缺的是流程和规矩。

Subagent(子代理) 是一个在独立上下文窗口里跑的执行体。配置同样是带 frontmatter 的 Markdown,放在 .claude/agents/(项目级)或 ~/.claude/agents/(用户级)。它可以被限定工具、限定模型、限定权限。它解决的是这件事不该在主对话里做的问题。

三层对照表

三种机制分属三个层次

图:注意三者在纵向上是叠起来的,不是横向并排的三个选项。一个复杂需求经常同时用到三层。

MCPSkillSubagent
所在层连接层知识与流程层执行与上下文层
回答的问题agent 能碰到什么?agent 知道该怎么做吗?这件事在哪个窗口里做?
典型形态一个 server 进程 + 一组工具/资源一个 SKILL.md 目录一个 .claude/agents/*.md
带来的是新的动作能力新的判断标准与步骤新的上下文边界
常驻成本高:工具定义每一轮都在上下文里低:只有 name + description 常驻低:只有 description 常驻
谁来触发模型按需调用工具模型按 description 判断是否加载模型自动委派或你显式指定

最后两行是这张表里最值得记的部分。常驻成本的差别不是细节,它经常直接决定选型。

Skill 的低成本来自渐进式披露的三层设计:元数据层(name 和 description)常驻系统提示,让模型能判断这个技能相不相关;命中之后才加载核心的 SKILL.md;真正用到时才去读附属文件。所以你可以挂几十个技能而不明显加重上下文。

MCP 没有这个待遇。一个 MCP 服务器接进来,它暴露的所有工具定义就常驻在每一轮的上下文里。接三个服务器,四十多个工具定义,你还没说话就已经花掉了一大块预算。

一个反直觉的推论:如果你要固化的是”怎么做”而不是”能做”,用 Skill 通常比用 MCP 便宜一个数量级——哪怕这两条路都能实现同样的效果。

动手:给你手上的需求拆缺口

拿你现在最想让 agent 做但做不好的一件事,写下三行:

  1. 它够不着什么?(写不出来就说明不缺 MCP)
  2. 它不知道什么规矩?(写不出来就说明不缺 Skill)
  3. 这件事会产生多少你其实不想看的中间材料?(很少的话就不缺 Subagent)

检查点:如果三行里你有两行写”没有”,说明这个需求只需要一种机制。能被一种机制解决的事,不要用三种。

三个问题,30 秒定位

为什么”看功能对比”选不出来

大部分对比文章会给你一张功能表:能不能调用外部 API、能不能带脚本、能不能限制权限。看完你会发现三者的勾都打得差不多——因为它们确实都能”间接实现”对方的一部分效果。你可以把一段流程包成 MCP 工具,也可以在 Skill 里写一段 curl 去调外部服务。

能不能做,和该不该这么做,是两件事。按功能选会选不出来,按缺口选一秒就定。

三个问题的顺序不能换

三问决策路径

图:三个问题是串行的,前一个答”是”就先解决前一个。顺序换了会得出错误结论。

问题一:模型现在够得着这件事吗?

够不着——需要访问一个它无法触达的系统、需要凭证、需要一个只有你们内网才有的接口——那就是 MCP 的活。这一步和”怎么做得好”无关,先把手接上。

够得着(读写本地文件、跑 shell、调公开 HTTP)就往下走。

问题二:它做出来的东西符合你的标准吗?

不符合——格式不对、漏了必要步骤、不知道你们的边界条件——那就是 Skill 的活。把标准写进 SKILL.md,让它每次自己带上。

符合就往下走。

问题三:做这件事会产生大量你不需要看到的中间材料吗?

会——要翻几十上百个文件、要读一大堆日志、要跑一轮完整测试再看输出——那就是 Subagent 的活。让它在自己的窗口里翻,只把结论带回来。

三个问题都答”否”,说明你不需要加任何机制,你需要的是把话说清楚。这种情况比想象中常见。

顺序为什么重要

试着把问题二提到前面:你会发现”输出不符合标准”这个症状,在”根本够不着数据”的情况下也会出现——它拿不到数据,只能编,编出来的当然不符合标准。这时候你去写 Skill,写多细都没用。

同理,把问题三提到最前面,你会倾向于给每件事都开一个子代理。子代理确实能让主对话干净,但它看不到你和主 agent 的对话,只能靠 description 和任务描述交接。该用 MCP 的场合开子代理,等于换了个房间继续够不着。

动手:走一遍你自己的三问

把上一章拆出来的缺口套进三问,写下你的判断和一句理由。理由必须能说清”为什么不是另外两个”。

检查点:如果你的理由是”这个看起来更强大”或者”这个更新”,重走一遍——这两条都不是判断依据。

四个场景走一遍

场景表

场景与机制的对应

图:注意最后一行——真实需求经常横跨两层,这时候不是二选一,是分工。

场景缺口在哪选什么为什么不是另外两个
让 agent 查内部订单系统的实时数据够不着MCPSkill 写得再细也变不出访问权限;子代理和主 agent 一样够不着
让 agent 按团队格式写发布说明不知道规矩Skill它本来就能读 git log、能写文件,不缺手;这件事产出很短,不需要单开窗口
扫全仓找某个废弃接口还剩多少调用点中间材料太多Subagent它有 Grep 和 Read,不缺手也不缺规矩,缺的是别把 800 个文件的内容倒进主对话
把 Figma 设计稿转成符合团队规范的组件够不着 + 不知道规矩MCP + Skill设计稿在 Figma 里(MCP 接),组件规范在你们脑子里(Skill 写),两个缺口都要补

第三个场景值得多说两句

扫全仓这件事,是子代理最典型的用武之地,也最容易做错。

做错的方式是:开了子代理,但没规定回传格式。于是它老老实实翻完 40 个文件,然后把它读到的内容大段大段倒回主对话——你什么都没省下,还多付了一遍。

规定回传格式是写子代理最关键的一步。 一个能用的最小配置长这样:

---
name: v1-usage-scanner
description: 扫描仓库中对废弃 v1 结算接口的调用点,只回传结构化清单。当需要统计某个 API 的使用范围时使用。
tools: Read, Grep, Glob
disallowedTools: Write, Edit
model: sonnet
---

你负责在仓库中定位对 v1 结算接口的调用。

只回传以下格式,不要附带文件原文、不要附带你的搜索过程:

| 文件路径 | 行号 | 调用的方法 | 迁移难度(低/中/高) | 一句话说明 |

如果超过 30 处,只列出难度为"中"和"高"的,并在末尾给出总数。

注意两件事:tools 收窄到只读三件套、disallowedTools 明确挡掉写操作——一个负责调查的子代理不该有能力改代码。这些字段名会随版本变化,动手前用当前官方文档核对一遍。

一个不该用任何机制的场景

有人想给 agent 加一个”每次改完代码自动跑格式化”的能力,于是开始纠结做成 MCP 还是 Skill。

两个都不对。这件事不需要模型判断——改完就该跑,没有例外。凡是不需要判断的确定性动作,都应该用钩子(hook)在工具调用后自动执行,而不是交给模型去记得。三问路径里没有钩子,是因为它压根不在”扩展模型能力”这条线上。

站内《给 AI 写规矩》系列有钩子的完整实现,这里只提醒你别把确定性的事交给概率性的机制。

动手:给四个场景各改一个变体

把上面四个场景各改动一个条件,看结论会不会翻转。例如:如果订单系统改成一份每天导出的本地 CSV,第一行还需要 MCP 吗?

检查点:第一行的答案应该翻转成”都不需要”——本地文件它够得着。如果你还是想接 MCP,说明你在按”看起来更专业”选型。

组合用法与五个常见误用

一次任务里三者各自站在哪

一次任务里三种机制的位置

图:三者不抢位置。MCP 在最外面接系统,Skill 在中间约束怎么做,Subagent 在旁边开一间独立的房间。

回到开头那个周报需求,完整的组合是这样的:

  1. MCP 接内部订单系统,提供一个 list_refunds 工具。
  2. Subagent 拿着这个工具去拉上周所有退款记录、做初步归类,只回传一张不超过 30 行的汇总表。几千行明细留在它自己的窗口里。
  3. Skill 在主对话里被触发,按团队周报格式把那 30 行汇总写成成稿,顺带处理脱敏规则。

三者各干各的,没有一处重叠。这才是它们的正常关系。

五个常见误用

误用一:把本该是 Skill 的流程包成 MCP 服务器。 你写了一个 MCP server,暴露一个 generate_release_notes 工具,内部其实就是拼一段提示词。代价是这个工具定义从此常驻在每一轮上下文里,而它一周才用一次。同样的效果用 Skill 实现,平时只占 name + description。

误用二:把本该是 MCP 的访问写进 Skill。 反过来也一样糟:在 SKILL.md 里写一段带 API token 的 curl。凭证进了一个会被加载进上下文的文本文件,鉴权、重试、错误处理全靠模型现场发挥。需要凭证和连接管理的事,交给 MCP。

误用三:什么都开子代理。 隔离不是免费的。子代理靠并行确实能解决单个窗口装不下的问题,但代价是 token 用量可能成倍上升——有公开的多 agent 研究系统给出的量级是单 agent 的十几倍。加上摘要必然丢信息、子代理看不到你和主 agent 的讨论,短任务开子代理往往是净亏。

误用四:子代理的 description 越写越长。 子代理的 description 是常驻主上下文的——模型要靠它判断该不该委派。官方给的经验值是所有子代理的 description 合计控制在 15000 token 以内。挂十几个子代理、每个 description 写成一段说明书,你会在还没开始干活的时候就先烧掉一块预算。

误用五:MCP 服务器只装不卸。 装的时候一个个装,从来不卸。半年后四十多个工具定义常驻,其中一半功能重叠。这里有一条很好用的判据:如果人类工程师都说不清该用哪个工具,不能指望 agent 做得更好。 定期问一遍每个服务器”这个月用过吗”,没用过就按项目切走。

一张自检表

检查项不合格的信号
常驻工具数量超过 20 个,且你说不出其中三个的确切用途
MCP 服务器有服务器一个月没被调用过
Skill 触发率写了技能但模型从不主动加载(说明 description 没写清触发场景)
子代理回传子代理返回的内容超过 2000 token,或包含大段文件原文
子代理 description全部 description 加起来超过 15000 token
机制错配有确定性动作(格式化、检查)是靠模型”记得做”的

动手与检查点

打开你当前项目,数三个数:常驻工具几个、技能几个、子代理几个。然后对照上表逐行走一遍。

检查点:如果你连”常驻工具几个”都数不出来,那不是选型问题,是可见性问题——先去把上下文里装了什么盘点清楚。站内《上下文工程》第 2 章给了一份可以直接填的盘点表。

下一步

这条选型路径解决的是”该用哪个”。真正决定 agent 好不好用的,是这三种机制加起来在你的上下文里占了多少、留下的空间够不够干正事。那是另一个更大的题目。

  • 想系统学怎么管上下文预算:站内《上下文工程》系列
  • 想动手做出技能、子代理和钩子:站内《给 AI 写规矩》系列
  • 想先补基础:主站《什么是上下文窗口》

参考资料

三种机制的字段名、默认值与上限都会随版本变化。动手前请以你当前使用版本的官方文档为准。