一、为什么需要 SKILL:工具解决"能做什么",不解决"怎么编排"

从 Agent 架构看,工具(OpenAI tools 协议 / MCP)解决的是原子能力的接入:查天气、读网页、查待办,每个工具一份 JSON Schema 声明,模型决定调用、Agent 本地执行、结果回写。但有两类问题是工具层天然承载不了的:

  • 编排经验无处沉淀。"出差前先看天气和当地新闻,再根据温度给穿衣建议"——这类"多个工具怎么组合着用"的流程知识,写不进工具声明,只能塞进 system prompt。场景一多,system prompt 变成大杂烩,每轮请求还全量消耗 token。
  • 确定性逻辑不该交给模型推理。"12°C 穿外套、29°C 穿短袖并带伞"这种规则判断,小模型"凭感觉"输出不稳定;"早报固定排版"这种格式约束,写进提示词模型也会偶尔走样。它们本质是代码,不是提示词。

SKILL(技能包)就是为此而生:把流程知识(提示词形态)与确定性逻辑(脚本形态)打包成目录,按需装载进上下文,执行仍复用 Agent 已有的工具。它在整个 Agent 技术栈里居于应用层:

  • 协议层:模型如何调工具——OpenAI tools 协议,事实标准
  • 接入层:工具从哪来——MCP,标准化的工具接入
  • 应用层:能力打包复用——SKILL,提示词 + 工具清单 + 使用说明的打包,本文主角

二、原理:渐进式披露与四阶段配合

2.1 一个完整技能 = 三件套

  • SKILL.md 的 frontmatter:name + description 两行元数据,注册阶段唯一被读取的部分
  • SKILL.md 正文:使用场景、操作步骤(调哪些工具、什么顺序)、输出格式、注意事项——命中后才注入
  • scripts/ 目录:确定性逻辑脚本(规则计算、模板渲染),执行时才参与,源码永不进上下文
  • 其他扩展文件(可选):输出模板、参考资料,步骤提到时才逐级装载
2.2 四阶段配合流程

  1. 注册(启动时,成本极低):扫描技能目录,只解析每个 SKILL.md 的 frontmatter,拼成"技能清单"注入 system prompt。几十个技能也就几百 token。
  2. 匹配(每轮对话,模型自主完成):用户提问后,模型对照清单里的 description 自行判断命中哪个技能。这一步没有额外调用,就是模型推理的一部分——路由决策被交给了模型本身。
  3. 装载(命中后,按需注入):模型调用 load_skill 把 SKILL.md 全文读入上下文,相当于临时追加一段领域专家指令;步骤里提到的扩展文件与脚本,再用对应工具逐级加载。
  4. 执行(复用已有工具):模型按说明书步骤调用业务工具、跑脚本,组织最终回答。SKILL 提供"怎么做",工具提供"能做什么",执行面一行不用改。
2.3 渐进式披露:用多少知识,付多少 token

上下文里与技能相关的内容分三级扩张:常驻的只有清单(几百 token),命中才注入说明书全文,扩展资料与脚本结果用到才装载。没命中的技能知识永远不进上下文——这是 SKILL 相对"全部写进 system prompt"的根本优势。

与相邻机制的边界:

机制提供什么注入时机扩展方式
Tool / MCP原子能力(函数签名)每轮全量放 tools 参数改代码或起新 Server
意图路由显式分发到专业 Agent每轮先过路由器写新规则、新 Agent
SKILL流程知识 + 确定性脚本命中才注入正文加一个目录,不改代码

三、实现细节:注册、装载、执行三件套

3.1 技能目录与 SKILL.md

以一个"出行简报"技能为例(查天气 + 查当地新闻 + 脚本算穿衣建议):

skills/
└── travel-briefing/
    ├── SKILL.md
    └── scripts/
        └── clothing-advice.js

---
name: travel-briefing
description: 生成指定城市的出行简报:实时天气、穿衣建议、当地相关新闻
---

# 出行简报

## 操作步骤
1. 调用 get_weather 查询目标城市天气,提取温度数值与天气现象
2. 调用 get_news 查询当地新闻(可与第 1 步并行)
3. 调用 run_skill_script 执行 clothing-advice.js,输入 {"temp": 温度, "weather": 天气现象}
4. 按输出格式整理:天气概况 + 穿衣建议(原样引用脚本输出)+ 当地近况

## 注意事项
- 天气和新闻必须来自工具结果,禁止编造

说明书写作有两条实战经验:步骤要写清每一步调什么工具(小模型会跳步),注意事项用禁止式措辞(如"禁止调用 read_url 读取正文"),约束力远强于建议式表述。

3.2 注册:启动时扫描,只读 frontmatter
// 遍历技能目录,正则解析 --- 包裹块内的 name / description,不引入 yaml 依赖
const content = fs.readFileSync(skillFile, "utf-8");
const meta = content.match(/^---\n([\s\S]*?)\n---/)?.[1] ?? "";
const name = meta.match(/^name:\s*(.+)$/m)?.[1]?.trim();
const description = meta.match(/^description:\s*(.+)$/m)?.[1]?.trim();
SKILL_REGISTRY.set(name, { description, dir, content });

技能清单拼进 system prompt,并配一组使用规则,其中两条最关键:

  • 命中技能时,第一个工具调用必须是 load_skill——小模型对"先装载再执行"的顺序感不稳定,不给 few-shot 示例会跳过装载直接调业务工具;
  • 步骤要求跑脚本时必须真实执行,禁止自己编造脚本输出。
3.3 装载:load_skill / load_skill_file 长在 tools 协议上

"装载说明书"实现为两个普通本地工具,对模型完全透明——它只是又可调用两个函数,结果以 role=tool 回写进上下文:

  • load_skill(name):返回 SKILL.md 全文,并顺带列出附带文件与脚本清单(模型才知道后续还能装载、执行什么)
  • load_skill_file(name, file):读取扩展文件;路径经 normalize 后必须仍落在技能目录内(防 ../ 越权),且 scripts/ 下的脚本拒绝装载——脚本只能执行,读进上下文浪费预算还会诱导模型改写逻辑

装载结果末尾追加一句指令重申:"以上是说明书不是任务结果,必须逐步调用工具执行"。说明书全文很长,开头的 system 规则会被长上下文稀释,放在结果尾部提醒效果最好(近因效应)。

3.4 脚本执行:run_skill_script 的沙箱三件套

脚本在子进程中执行,安全防护三件套:

措施防什么
路径前缀校验脚本必须真实存在于该技能的 scripts/ 内,拒绝 ../ 越权
执行超时(到时杀进程)脚本死循环或挂起输入,不能把请求永久挂住
输出截断脚本可输出任意长文本,不截断会撞爆上下文预算

两个工程取舍值得记录:

  • 输入走 stdin 传 JSON,不走命令行参数:免去 shell 转义与注入面,脚本侧解析也简单——process.stdin 读完 JSON.parse 即可;
  • 扩展名白名单(.js 走 node、.py 走 python3,其余拒绝),错误也返回文本给模型自行修正。

脚本本身的定位是"确定性逻辑下沉",两个典型用途:

  • 规则计算:温度分段 → 穿衣建议。注意天气数据源常返回英文现象(如 Patchy rain nearby),正则要中英文双匹配,否则叠加提示(带伞)会静默丢失;
  • 模板渲染:早报正文(日期行 + 编号标题列表)格式写死在代码里,排版永不走样,模型只在末尾补一句问候。
3.5 执行:ReAct 循环一行不用改

工具循环与纯工具版完全同构(发请求 → 有 tool_calls 就执行并回写 → 再请求),装载与脚本只是多了几种工具。一次典型问答的轮次序列:

第 1 轮  load_skill(travel-briefing)          ← 匹配命中,装载说明书
第 2 轮  get_weather + get_news(并行)        ← 按步骤调业务工具
第 3 轮  run_skill_script(clothing-advice.js)  ← 规则计算下沉到脚本
第 4 轮  无 tool_calls,流式输出最终回答        ← 按说明书格式整理

四、踩坑记录:小模型的五个失控模式(实测)

用 1.7B 级本地模型实测,SKILL 链路有五类真实失败,每一类都有对应的工程加固:

失控模式根因加固手段
装载说明书后跳过工具,直接编造回答说明书全文稀释了开头的 system 规则装载结果末尾追加指令重申 + system prompt 用 few-shot 固定"先装载再执行"顺序
隔一轮就重复调用 load_skill 同一技能小模型记不住已装载状态请求级 Set 记录已装载技能,重复调用返回"已装载,请继续执行步骤"短句,不再重灌全文
把脚本名填进 name 字段(技能名/脚本名混淆)两个 name 概念在小模型处易混技能未找到时跨技能反查脚本真实归属,自动纠偏继续执行
用自己的话改写脚本输出,丢掉关键信息(如"带伞")模型有"润色"冲动脚本结果加"【脚本输出,请原样引用】"前缀标记,说明书同步要求原样引用
反复尝试装载不存在的文件名,耗尽全部轮次试错循环无收敛信号错误信息里明确"没有此文件、输出格式已写在说明书中、请直接输出最终回答",阻断循环

一个通用结论:面向小模型的 SKILL 系统,健壮性一半来自说明书怎么写(禁止式措辞、步骤原子化),另一半来自执行层的容错设计(去重、纠偏、阻断信号)——把模型的每次失误都当成一种输入来处理。

资料展示:
下面是我整理的AI大模型       学习资料和工具包预览,适合收藏后按主题逐步学习

Logo

更多推荐