上一篇写 MCP 的时候留了个尾巴——工具多了之后,模型选不对工具。这一篇就写这个问题,以及我目前看到的解法:Skill 系统。

先说结论:Skill 这层抽象不是"新技术",它就是软件工程里的模块化思想搬到了 Agent 领域。但什么时候该加这层、什么时候不该,我有自己的判断——写在这篇的最后。

问题是怎么暴露出来的

我的 Agent 最初只有四五个工具,模型选工具基本不出错。后来用 MCP 接入更多 Server,工具列表膨胀到三四十个。问题开始出现:

一开始我试图用"优化工具描述"解决——把每个工具的 description 写得更精确。有用,但天花板很低。描述写得再好,40 个工具的列表还是得全塞进上下文,模型还是要在 40 个选项里做选择。

这时候我意识到:问题不在工具本身,在工具的组织方式。

Skill 是什么:把"原子操作"打包成"能力包"

想到一个类比:操作系统的命令。

grep 是一个命令,find 是一个命令,xargs 是一个命令。但你日常工作不是一个个调命令——你用的是 shell 脚本。脚本把"grep 一批文件 → 提取结果 → 排序 → 去重 → 保存"这个组合封装成一个可复用的单元。

Skill 就是 Agent 世界的 shell 脚本。它把"调用哪些工具、按什么顺序、中间怎么处理"打包成一个有名字的能力。

一个 Skill 通常包含三部分:

1. 指令文档(给模型看的说明书)

一个 Markdown 文件,写清楚:这个 Skill 做什么、什么情况下用、接受什么输入、产出什么输出。注意——这个文档的读者是模型,不是人。所以写法上要"机器友好":条件判断清晰、输入输出明确、少用含糊的自然语言。

2. 脚本(可选的执行逻辑)

有些 Skill 需要跑具体代码——调 API、处理文件、执行一段 Python。这些实现在脚本里,被 Skill 系统管理。模型不用自己拼 API 请求,它只需要说"我要用这个 Skill,参数是这些"。

3. 参考资源(按需查阅的资料)

Skill 可以附一份参考文档——API 细节、领域知识、示例数据。关键点是:这些资源不塞进上下文。模型执行 Skill 时如果需要细节,再去查。这就是"按需加载"而不是"一次性全装"。

发现与路由:两级设计

有了 Skill 之后,"模型怎么知道有哪些 Skill"就成了新问题。

笨办法:把所有 Skill 的指令文档全塞进系统 prompt。Skill 少的时候行,多了照样爆窗口——和工具膨胀是同一个问题。

好一点的做法是两级路由:

这就像你不会把整个图书馆搬进书房——先看目录(注册表),找到要的那本书(选中 Skill),再从书架上取下来翻(加载全文)。上下文窗口就是书房,空间有限,必须精打细算。

Tool 回答"能做什么",Skill 回答"怎么做一件事"。前者是原子的,后者是有流程和上下文的。

Tool / Skill / Plugin 的边界

这三个词经常被混着用,我自己的区分方式:

三者是嵌套关系:一个 Plugin 可能包含多个 Skill,一个 Skill 可能调用多个 Tool。选哪个粒度取决于场景——简单操作用 Tool,复合任务用 Skill,完整产品用 Plugin。

设计 Skill 的几条经验(踩过坑之后的)

单一职责。一个 Skill 做一件事。我有个 Skill 的指令文档写到了 600 字,后来发现它在做两件事——拆成两个之后,模型的调用准确率反而上去了。

触发条件必须具体。"处理数据"这种描述必然导致误触发。要写成"当需要对 CSV 文件做统计汇总分析时使用"。模糊的描述就是给模型挖坑。

参考资源要结构化。附带的文档要有清晰的标题和关键词。一篇没有结构的"散文",模型检索效率极低。

给 Skill 加版本号。改了指令文档、加了新工具之后,版本号要变。不然出现"同样的调用昨天对今天错"时,你根本排查不出是哪次改动引入的。

留降级路径。Skill 内部失败时,要有明确的错误返回,让模型知道"这条路走不通,换一条",而不是拿一个空结果硬着头皮继续。

什么时候不该加 Skill 层

这是我最想说的部分。Skill 系统不是越早加越好。

如果你的 Agent 只有五六个工具、任务流程简单,加 Skill 层是过度设计——你引入了一个新的抽象层、一套新的管理机制,解决的问题却不存在。工具少的时候,直接精心写工具描述就够了。

我自己的触发标准是:当工具超过 15-20 个、模型开始频繁选错、上下文被工具描述吃掉超过 20% 时,才考虑引入 Skill 封装。

这个判断和软件工程里的经验完全一致——模块化是为了应对复杂度,但模块化本身也引入复杂度(接口设计、版本管理、路由逻辑)。只有当原始复杂度超过了模块化引入的复杂度,这层抽象才划算。

架构决策应该被问题驱动,不是被概念驱动。先痛了再重构,比预防性设计更靠谱。

还没想明白的问题

Skill 的粒度怎么拿捏?拆太细,Skill 数量膨胀,注册表本身变大;拆太粗,一个 Skill 干太多事,内部流程复杂、容易出错。"一个 Skill 做一件事"说起来容易,但"一件事"的边界在哪,我觉得还是要靠实践摸索。

Skill 之间能组合吗?现在我的 Skill 是独立调用的。但理论上一个 Skill 可以触发另一个 Skill(比如"分析报告"Skill 内部调用"数据查询"Skill)。这种嵌套会不会失控?目前没敢试,怕调试噩梦。

小结

Skill 系统的本质:给 Agent 加一层能力管理架构,解决"工具多了之后怎么组织、怎么发现、怎么复用"的问题。

它不是技术突破,是工程演进的必然——函数解决"能不能做",模块解决"怎么组织",Agent 领域走到了需要模块化的阶段。

如果你在搭自己的 Agent,我的建议是:先把 Tool 跑通,别急着建 Skill 系统。等"工具太多、模型乱选、上下文爆了"的痛真实出现了,再动手。这时候你知道要封装什么、怎么封装——因为痛过的地方就是边界该画的地方。