能力按需加载:从动态提示词到 Agent Skills

3 分钟阅读
·

本文是「Agent 开发实践与思考」系列第 18 篇。系列目录:

能力按需加载:从动态提示词到 Agent Skills

去年六月我写过一篇系统提示词膨胀的记录。当时的结论不太体面:业务规则一条条加,系统提示词从两百字涨到几千字,改一处全身发抖,能拿出的解法只是把内容分层、把规则写成可判定的句子。那是整理术,不是解法。病根那篇里也写了:所有能力都往一个上下文里塞,这条路走不下去,早晚要走向按需加载。

Anthropic 发布 Agent Skills 后,我在项目里用了两三周,第一感觉是这事我干过,只是干得土。这篇是对照笔记。

Skills 的形态

一个 Skill 就是一个文件夹。里面必须有一份 SKILL.md,文件头部是元信息,一个名字加一句话描述,正文是这份能力的完整说明。除此之外,文件夹里可以放任何东西:脚本、模板、参考文档、检查清单,模型用到时自己去读。

关键设计是渐进式披露。平时上下文里只有每个 Skill 的名字和那句描述,几十 token 一份,挂几十个 Skill 也吃不掉多少窗口。模型判断某个 Skill 和当前任务相关,才去读 SKILL.md 的正文。正文里如果引用了附件,比如一个模板文件或一个脚本,同样是用到才加载。一层一层,按需展开。

一个最小的例子:

---
name: weekly-report
description: 按团队口径生成周报,汇总本周代码变更、上线记录与风险项
---

# 周报生成

## 数据口径
- 代码变更以合并到主干的 MR 为准,不含未合并分支
- 风险项分两级:阻塞发布的记为 P0,其余记为 P1

## 输出
使用 template.md 中的格式,先列风险项,再列变更

结构就是这么简单。没有新协议,没有要学的格式,核心就是一个带元信息的 Markdown 加一目录散文件。正文可以写长,因为它平时不占上下文,真正要克制的是元信息:名字和一句话描述是模型决定加载与否的唯一依据,后面讲坑的时候会回到这一点。

另外一个容易忽略的变化是作者门槛。写 MCP Server 通常要实现服务并处理协议,写 Skill 主要是整理文档和流程,业务同学可以把岗位经验整理成 Agent 能用的内容。这两周我们团队里第一个非研发写的 Skill 已经出现了,内容是客服话术的检查清单,质量比研发代写的那版好,因为写的人是真正懂口径的人。

本质是把判断权还给模型

以前的思路是人来预测:这个 Agent 可能遇到哪些情况,把这些情况需要的知识全部预装进系统提示词。预装的代价我在膨胀那篇里算过,占窗口、稀释指令、每次调用都重新付费。更难受的是预装永远装不准:装少了模型抓瞎,装多了真正相关的规则被淹在一堆不相关的规则里,遵循度反而下降。

Skills 把这个判断倒了过来。人不预装知识,只提供一份目录,每份知识配一句简介,模型自己决定现在该翻哪一份。“什么时候用什么知识”这个判断,从人手里交还给模型。

这和我年初写 MCP 实战时抱怨的问题是同一个问题的两面。当时接了一堆 MCP server,光工具描述就吃掉上万 token,对策是按需挂载。工具要按需挂载,知识要按需加载,逻辑完全一样:上下文是稀缺资源,只放当下相关的。代价也一样,用时间换空间,模型要多调一次读文件的工具才能拿到全文。

这笔交换现在能算得过账,前提是模型足够强。“发现当前任务和某份知识相关、主动去读、读完照着做”,这三步对指令遵循和判断力的要求都不低。放在两年前,模型经常连”该去读一下说明”这一步都走不到,按需加载只会变成按需漏载。Skills 这个形态能成立,一半的原因在模型能力的进度上。

我自己在 Skills 之前做过一版土办法:在路由层按任务类型注入不同的提示词片段,客服类任务注入话术规范,查询类任务注入数据口径。这也是按需加载,但开关在路由代码里,分类是人预先拍好的,任务稍微跨界就注入错。Skills 相当于把开关从路由代码挪进了模型,分类从预设变成了现场判断,覆盖的场景一下宽了很多。

和工具、MCP 的分工

用下来我的理解是:工具管”能做什么”,Skill 管”怎么做”。这里说的是职责边界,不是协议层面的硬性规定。

MCP 是连接 Host 与工具或其他能力服务的协议。具体工具提供查询、发消息、读写文件等执行能力。Host/runtime 负责发现和注册这些能力、决定工具何时可用、执行调用并处理权限、结果和错误。Skill 是放在文件系统中的程序性知识:一件事按什么流程办、输出按什么格式、有哪些坑要避开。它通常由 Host/runtime 读取并注入上下文,不能单独提供工具执行能力。一个 Skill 可以指导模型调用多个工具。

拿生成周报举例。我把数据口径和输出模板写进一个 Skill:哪些变更算数、风险项怎么分级、排版用什么格式、发送前先给人过目。至于数据从哪来,那是工具的事,Skill 里写清楚”调某某工具取本周合并记录、调某某工具取发布流水”就行。执行链路是模型先读到周报 Skill,按里面的流程依次调两三个数据工具,拿到结果后按模板拼装。换一个团队复用,换的是 Skill 里那份口径文档,工具一层不动。

这个分工让两边更容易维护。工具描述主要说明能力、参数和约束,Skill 说明流程和业务标准。两者可以互相引用,但不要把完整业务流程塞进工具描述,也不要假定 Skill 自己能够替代工具或 Host/runtime 的执行逻辑。

和我自己做法的对照

说这事我干过,是因为项目里早就在用类似机制。团队用的 AI IDE 支持给 rules 文件配加载策略:常驻加载、按文件类型匹配加载、手动加载、模型按需加载。最后一种就是 Skills 的雏形,rule 文件平时只暴露一句描述,模型看描述决定要不要读全文。

今年在基建收敛的项目里我大量用了这个机制,把内部工具链的用法写成一组 rules,平时只占几行描述,AI 用到哪个库才去翻哪份文档。效果直接体现在上下文占用上:同一批规则从全量常驻改成按需加载之后,长任务里模型遗忘早期指令的情况少了很多,这和压缩、缓存那些手段省的是同一笔账。

但 rules 方案有两个短板。一是各家 IDE 的私有机制,写法、配置位置、加载策略互不通用,换个工具就要重新组织一遍。二是没有标准化的元信息和分发形态,别人想复用我的规则,得先理解我这套约定,规则和规则之间也没有统一的边界。

Skills 把这件事标准化了。文件夹加元信息,结构公开,能带脚本和模板,适合进入版本管理和分发。我自己写的 rules 迁移过去几乎没成本,因为思路本来就是同一个,Skills 只是给它定了规格。两者仍有边界:Rules 通常是 Host 根据文件、目录或显式操作加载的约束,Skills 是带有元信息和配套资源的可复用能力包,是否加载仍由具体 Host/runtime 的实现决定。Skills 不负责建立工具连接,也不等于 MCP Server。这是我觉得它值得写的原因:不是新能力,是旧实践的一种标准化,而标准化意味着能流通,别人可以整包拿走直接用。

两三周用下来,坑集中在三处。

第一处出现频率最高:描述写不好,模型该加载时不加载。在我使用的实现里,渐进式披露会让加载决策很依赖那一句描述,描述写差了,模型可能不会主动读取整份 Skill。具体加载策略仍取决于 Host/runtime。我写过一个文档处理 Skill,描述是”处理各类文档”,结果模型处理 Markdown 表格时根本想不到它。改成”转换与格式化 Markdown 表格,遇到表格结构问题时使用”之后就好了。这门手艺不新,和去年写工具描述的手艺是同一门:写清楚什么时候用、什么时候别用,比写清楚这是什么更重要。工具描述踩过的坑,在 Skill 描述上原样重来一遍。

第二处是 Skills 之间规则打架。两个 Skill 同时加载后,规则可能冲突:一个说输出要详细,一个说要精简,模型随机听一个,同一份输入两次跑出两种风格。我的对策是控制同时可能相关的 Skill 数量,有冲突的规则上收到全局提示词里,Skill 里只留不冲突的部分。这个问题会随 Skill 数量增长变严重,目前没有什么好的管理工具,主要靠装的时候克制。

第三处是安全。Skill 是提示词,也是代码。装一个第三方 Skill,等于把别人写的指令和脚本放进自己 Agent 的上下文和执行环境。之前提示词注入的教训直接适用:外部内容是不可信数据,工具返回和第三方文档都要当数据看,不能当指令听。我现在的做法是第三方 Skill 先通读一遍 SKILL.md 和附带脚本再启用,来源不明的不装。Skill 市场已经开始热闹了,这条要一直保持,供应链问题在提示词层面同样存在。

收尾

回头看这两年在上下文上做的事:提示词分层减少常驻内容,缓存减少重复计算,压缩减少需要保存的内容,Skills 则把能力说明按需放进上下文。方向是同一个,上下文里只留当下相关的东西。

提示工程刚流行的时候,大家比的是谁的提示词写得全。现在我的判断反过来:提示工程的归宿是不用全都提示。人负责把知识整理好、标清楚什么时候用,把”现在该用哪份”的判断留给模型。知识留在文件里,需要时才进上下文,这大概才是上下文管理该有的默认形态。


530 字 · 54 段落
xi ming

Written by xi ming You should follow him on Github

评论与讨论