1. 问题从哪里开始
理解 Agent Skill(智能体技能)最常见的误区,是把它想象成”给模型装了个插件”或”让模型学会了新本事”。这两种直觉都不准确。
真正需要先接受的前提是:Skill 从头到尾没有触及大语言模型(LLM)本身——它不修改任何一个模型权重,不改变模型的推理过程,也不是模型”内部”的一部分。一个 Skill 最终对模型产生影响的唯一途径,和一段普通提示词(prompt)完全一样:变成 token,进入上下文窗口(context window),被同一次前向推理(forward pass)读取。
所以要真正搞懂 Skill 是什么,不能停留在”它是一种能力封装”这种模糊说法:
- 它到底以什么形式存在于磁盘上?
- 它以什么角色(role)、在什么时机进入上下文窗口?
- 它和普通 prompt、和 system prompt、和 tool call、和 MCP 到底是什么关系?
我们可以通过这几个问题来搞懂skill。
本质上,Skill 是一套围绕”上下文窗口”这一稀缺资源做加载调度的机制,而不是一样神秘的新东西。
2. Skill 的起源:谁提出的,为了解决什么
Agent Skills 这一概念由 Anthropic 在 2025 年 10 月正式提出,并很快演变成一个跨平台的开放格式——微软 Copilot Studio、GitHub Copilot、Cursor、Gemini CLI 等生态随后都采用或兼容了这套思路。
它要解决的,是纯 prompt 工程在规模化时的三个结构性痛点:
| 纯 prompt 的痛点 | 具体表现 | Skill 的对策 |
|---|---|---|
| 不可复用 | 每次做同类任务都要重新粘贴一大段指令 | 把流程写一次,存成文件,到处调用 |
| 占满上下文 | 想让模型”随时会做” N 种任务,就得把 N 套完整指令全塞进 system prompt,窗口被撑爆 | 平时只暴露一行简短描述,用到才展开 |
| 要人手动触发 | 用户得自己判断”这次该用哪套指令” | 由编排器(orchestrator)根据描述自动选择 |
简单来说:Skill 是把 prompt 工程”产品化”了——加上了持久化、按需加载、自动路由,以及(关键的)可选的代码执行能力。
3. Skill 到底是什么:定义与形式
从底层来讲,一个 Skill 就是磁盘上的一个文件夹。文件夹里必须有一个 SKILL.md 文件,可选地附带脚本、参考文档、模板等资源。
一个完整 Skill 在磁盘上长这样:
pdf-skill/ ← 整个 Skill 就是一个文件夹├── SKILL.md ← 核心:元数据(标题)+ 正文(指令)├── scripts/ ← 可执行脚本│ ├── fill_form.py│ └── merge_pdf.py├── references/ ← 参考文档│ └── pdf_spec_notes.md└── assets/ ← 模板 / 静态素材 └── letterhead_template.pdfSKILL.md 本身内部又分两部分:
---name: pdf-form-fillerdescription: 当用户需要填写或处理 PDF 表单时使用 ← 元数据(标题)---# 填写 PDF 表单 ← 正文(指令)1. 读取用户提供的字段数据2. 调用 scripts/fill_form.py 完成填充3. 细节规格见 references/pdf_spec_notes.md...它把”某一类任务该怎么做”的流程性知识固化下来,让一个通用模型在需要时表现得像某个领域的专家。
4. 三层结构:渐进式披露(Progressive Disclosure)
Skill 最核心的设计,是把内容分成三层,按需逐层加载。这套机制叫渐进式披露,目的只有一个:省上下文窗口。
| 层级 | 内容 | 加载时机 | Token 成本 |
|---|---|---|---|
| L1 元数据 | frontmatter 里的 name + description(约几十 token) | 启动时常驻,让模型”知道有这本书” | 极小,一直付 |
| L2 正文 | SKILL.md 的完整 Markdown 指令 | 仅当任务匹配时才注入 | 触发才付 |
| L3 资源 | scripts/ references/ assets/ 里的文件 | 按需读取或执行 | 见第 9、11 节 |
用一个类比贯穿理解:
- L1 元数据 = 一本书的书名 / 目录里的一行标题——“第 7 章:如何填 PDF 表单”。
- L2 正文 = 第 7 章的完整内容。平时不翻,真要做这件事时才翻到那一页读进来。
- L3 资源 = 附录里的计算器和详细规格表。你用计算器算,但不需要把它的电路图背下来。
正因如此,有 50 个 Skill,平时只占 50 行简短描述的成本(几百 token),而不是 50 套完整指令。模型在有限窗口里能”认识”上百种能力,却不必时刻背着它们的全文。
flowchart TD A[会话启动] --> B[L1: 50 行 description 常驻 system] B --> C{用户提出需求} C -->|匹配到某 Skill| D[L2: 该 Skill 正文动态注入] D --> E{正文里引用了资源?} E -->|要执行脚本| F[L3 scripts: 窗口外运行, 只回填结果] E -->|要查参考| G[L3 references: 按需读取部分进窗口] E -->|不需要| H[直接完成任务]5. 例子:生成规范 Excel
用同一个任务对比”纯 prompt”和”Skill”,能立刻看清差别。任务是:把一批数据做成一张格式规范的 Excel 表。
方案 A — 纯 Prompt(每次手敲):
请帮我生成 Excel。要求:- 表头加粗、底色深蓝、白字- 冻结首行,数字列右对齐保留 2 位小数- 金额列用千分位,列宽自适应- 用 openpyxl 输出到 output.xlsx数据如下:...下次再做同类任务,这段又得从头贴一遍。
方案 B — Skill(建一次,长期复用):
xlsx-skill/├── SKILL.md # name + description + 上面那套格式规范└── scripts/ └── format_table.py # 真正干活的代码之后你只需说”把这批数据做成 Excel”,模型读到 L1 描述判断匹配,把 L2 正文拉进来,再调用 format_table.py 完成——那段格式规范再也不用手敲。
6. Skill vs Prompt:本质相同,定位不同
两者本质上都是”外部输入”:都不改变模型权重,都以 token 进入上下文,由同一次推理处理。 从这个意义上说,它们和微调(fine-tuning)、RLHF 这种真正改动参数的手段有本质区别——后者才”触及根本”。
但在”外部提示”这个大类里,两者定位差别很清楚:
| 维度 | Prompt | Skill |
|---|---|---|
| 形态 | 一段即时文本 | 一个文件夹(SKILL.md + 可选资源) |
| 生命周期 | 一次性,用完即弃 | 持久化,跨会话 / 跨项目复用 |
| 加载方式 | 写多少就全量进窗口 | 渐进式披露,平时只占一行描述 |
| 触发者 | 人手动输入 | 模型 / 编排器自主判断何时调用 |
| 能力边界 | 纯文本,不能自带可执行代码 | L3 可附带脚本,能被执行 |
| 类比 | 口头临时交代一件事 | 一本写好、需要时才翻的操作手册 |
关键区别不在”是否触及模型”,而在”复用性 + 加载机制 + 谁来触发 + 能否外挂执行”。 Skill 可以粗略理解成”被规范化、模块化、按需加载的 prompt 仓库”,外加一层纯 prompt 做不到的可执行能力。
7. Skill 是不是 system prompt?
既然skill是以prompt的形式出现在上下文,那么它的role是什么,是system prompt吗?
答案是:不完全等于,但有交集,而且必须精确措辞。
先厘清 “system prompt” 到底指什么。在一次推理里,送进上下文窗口的文本按**角色(role)**分层:
| 角色 | 内容 | 特点 |
|---|---|---|
| System | 人设、全局规则、可用工具 / 技能清单 | 常驻、权威最高、用户一般看不到 |
| User | 用户当前的话 | 逐轮变化 |
| Assistant | 模型自己的回复 | 逐轮生成 |
所谓 system prompt,就是 System 角色那一段,而它的定义里隐含了”静态常驻”。
Skill 的两层内容,落点不同:
- L1 元数据(那行描述) → 确实被塞进 System 区并常驻,让模型一直知道有哪些技能可选。这部分算 system prompt 的一部分。
- L2 正文 → 触发后动态注入。它以 System 级的权威进入,但它是”会进出的”,不是一开始就钉在那儿的固定 prompt。
所以严谨的表述是:
L2 正文是”动态注入的 system 级指令片段”,而不是”一段动态的 system prompt”。
而且要记住:Skill ≠ 只有正文。它还有 L3 那层——那是窗口外的可执行代码,根本不是 prompt。所以”本质上是一种 prompt”这句话只覆盖了 L1 + L2。
8. 动态注入 vs 静态注入:区别到底在哪
这是理解 Skill 机制的核心:
对模型的单次前向推理来说,“一开始注入”和”运行时注入”没有任何区别。 模型只看它这一刻窗口里有什么 token,token 不带时间戳,模型无从分辨哪段是开机就有、哪段是刚才才塞的。
那区别在哪?在整场多轮对话里,这段文本存在多久、占用多少、由谁决定。
| 一开始注入(静态) | 运行时注入(动态) | |
|---|---|---|
| 进入时机 | 会话启动,第 0 轮就在 | 某轮触发条件满足才加入 |
| 存在时长 | 全程常驻,每一轮都在 | 用完可撤走,只在相关轮次占用 |
| 谁决定 | 系统预先写死 | 编排器根据当前需要临时决定 |
| Token 成本 | 每一轮都重复付这份钱 | 只在需要的轮次付 |
一个推演最能说明问题。假设有 50 个 Skill、对话进行 10 轮:
- 若全部静态注入:每一轮窗口都背着 50 套完整正文(比如 5 万 token),被重复喂 10 次,而大部分这次根本用不上——纯浪费,上下文窗口很快撑满。
- 若动态注入:任何一轮窗口里只有”50 行索引 + 当前用得上的那 1 套正文”,省下 90%+ 的空间。
动态注入最大的价值是”可逆、可调度”:
系统能用有限窗口支撑海量能力——模型平时只背一份薄目录,真要用哪一章,编排器现场翻开塞给它,用完合上。
9. L3 资源:不进窗口,怎么执行?
这里要破除第二个误区:“进上下文”和”被执行”是两条完全独立的路径。 上下文窗口是给模型”读”的;执行是在模型之外的机器上”跑”的。
模型本身不运行任何代码。 LLM 是个文本预测器,只会输出 token。真正干活的是它旁边的运行环境(runtime / sandbox / 工具执行器)。流程是:
① 模型在 L2 正文里读到:"调用 scripts/format_table.py 处理数据"② 模型据此输出一个动作指令 token: { "tool": "bash", "command": "python scripts/format_table.py data.csv" }③ 外部执行器收到 → 在沙箱里真正运行那个 .py 文件④ 脚本跑完,把【结果】(成功/报错/输出值)作为文本回填进上下文窗口⑤ 模型读到结果,继续下一步所以进出上下文的到底是什么,要分清:
| 东西 | 进上下文吗 | 说明 | |
|---|---|---|---|
| 脚本的文件名 / 调用指令 | ✅ 进 | 模型需要知道”有这工具、怎么调” | |
| 脚本的源代码内容 | ❌ 不进 | 那几百行代码模型不用读 | |
| 脚本的运行结果 | ✅ 进 | 成功 / 失败 / 输出值,回填给模型看 |
bash 与 MCP tool:两种执行路径
L3 的”让机器跑”本质就是工具调用(tool calling),而 bash 和 MCP tool 是它下面的两种实现路径,不是二选一的对立关系。
| Bash / 代码执行工具 | MCP tool | |
|---|---|---|
| 本质 | 授予模型一个”执行 shell 命令”的通用工具 | 授予模型一批”预定义好的具体工具” |
| 粒度 | 粗、万能——一个 bash 能干任何事 | 细、专用——每个 tool 一个明确 schema |
| 跑在哪 | Agent 自带的代码沙箱 | 外部 MCP server 进程里 |
| 典型场景 | Skill 自带脚本、临时计算、文件操作 | 连数据库、调外部 API、访问企业系统 |
分工大致是:
- Skill 的 L3 脚本 → 走 bash / 代码执行:处理”技能包自带、本地就能算的活”。Anthropic 官方的 Agent Skills 设计里,L3 资源就是靠代码执行工具跑的,不依赖 MCP。
- MCP tool → 走 MCP 协议:处理”要连出去的活”。
而且两者可嵌套:一个 Skill 的 L2 正文完全可以写”第 2 步:调 MCP 的 query_db 取数;第 3 步:用本地脚本 format.py 排版”。它们都只是 L2 指令层可调度的”执行手段”。
bash 跑在哪台机器上
执行环境由”承载这个 Agent 的宿主”提供,而不是模型自带。
| 产品形态 | bash / 代码跑在哪 | 环境性质 |
|---|---|---|
| 云端 Agent 服务 | 服务商后端起的一次性容器 / 微型 VM | 云端沙箱,任务结束即销毁 |
| Claude Desktop 客户端 | 自身不带通用沙箱,靠外挂 MCP server | 执行落到 server 所在处(可能是你本机) |
| Codex CLI / Claude Code | 直接跑在你本机的 shell | 你的真实电脑,有真实文件访问权 |
| IDE 插件(Copilot / Cursor) | 通常在你本地工作区执行 | 你的开发机环境 |
10. role 的定义权与生效层级
一个更底层的问题:注入进上下文的那段东西,role 到底是谁定的、在哪一层生效?这要拆成两个不同的问题。
role 的”格式 / 字段” —— 定义权在 API 协议层
role: "system" / "user" / "assistant" / "tool" 这套词汇表,由模型提供商的 API 规范定义。你(调用方)只能从它允许的 role 里挑,不能自己发明一个 role: "boss" ,API 会报错。所以”有哪些 role 可选”的定义权在接口层。
role 的”效力 / 权威” —— 影响在模型端(训练里)
为什么 system 比 user 权威?这个高低次序是谁赋予的?
答案是:在模型端,通过训练固化的。
关键在于理解:对底层 Transformer 来说,输入其实是一整条被”拼平”的 token 序列,role 不是独立信道,而是被编码成特殊标记塞进序列里的:
<|system|> 你要遵守... <|end|><|user|> 帮我做... <|end|><|assistant|> ...那些 <|system|> <|user|> 是特殊 token / 分隔标记。模型之所以”知道” system 那段更权威,不是因为字段名有魔力,而是在**训练阶段(instruction tuning + RLHF)**被喂了海量样本,反复学到:“当 system 段与 user 段冲突时,优先服从 system。“
| 层面 | 定义权在哪 |
|---|---|
| role 有哪些、字段叫什么、格式 | API 协议层 |
| role 之间的权威高低、谁压谁 | 模型端,由训练固化 |
| 把 role 转成模型能读的形式(套 chat template、加特殊 token) | 中间的 serving 层 |
拿一个没经过对齐训练的裸 base model,给它标 role: system,它根本不会因此更服从——因为它没被训练过”要尊重 system”。可见 role 的效力不在字段本身,而在模型学没学过。
那 Skill 正文注入时是什么 role
这是实现相关的,但有一点确定:它绝不会是 user(否则会被后续 user 输入覆盖,且角色语义错乱),一定在”权威侧”。主流实现有几种:
| 注入方式 | 具体 role | 场景 |
|---|---|---|
| 合并 / 追加进 system | system | 直接把正文拼进或作为额外一条 system message |
| 通过”读 skill 文件”工具拿到 | tool / function | Anthropic 式 Agent Skills 常接近这种,复用读文件管线 |
| developer 分层体系 | developer | 部分新体系用它承载”应用级指令”,介于 system 与 user 之间 |
所以:Skill 正文以 “system 级的权威” 进入上下文永远成立;但它在消息数组里挂的字面 role,取决于产品是”直接当 system 拼进去”还是”当作一次工具读取的返回”。
11. L3 的 reference 如何参与上下文
L3 内部还要再分”读”和”跑”两种命运——第 9 节讲的是”跑”(脚本),这里讲”读”(参考资料)。
核心区别
| L2 正文 | L3 reference | |
|---|---|---|
| 进场方式 | Skill 一触发,系统主动注入 | 模型读了 L2 后,自己决定要不要读 |
| 主动权 | 编排器 / 系统 | 模型自己 |
| 类比 | 翻开书直接看到第 7 章开头 | 第 7 章写”详见附录 B”,模型再翻附录 B |
具体流程——它走的是和 L3 脚本执行一模一样的工具调用管线,只不过脚本是”跑”、reference 是”读”:
① 模型读到 L2 正文:"详细规格见 references/spec.md"② 模型判断:这次任务需要这个细节③ 模型输出动作 → { "tool": "read_file", "path": "references/spec.md" }④ 外部执行器读取该文件 → 把内容(或指定的某几段)作为【结果】回填⑤ 这段文本进入上下文,role 通常是 tool,模型接着用所以 reference 回填进上下文时,最典型的 role 是 tool(工具返回结果)——因为它复用了现成的文件读取管线,和 L3 脚本共用一套机制。同样,这也是实现相关的:少数实现会直接把内容拼进 system 上下文,role 就成了 system。
reference 常常不是全量加载。它的价值恰恰在于可以只读需要的片段——带 offset 的部分读取,或先读目录 / 摘要再决定深入哪段。这就是**“更深一层的渐进式披露”**
12. 核心结论
-
Skill 从头到尾没有触及 LLM 本身。 它不改权重、不改推理,最终只是以 token 进入上下文窗口,和普通 prompt 走同一条路。它与微调 / RLHF 有本质区别。
-
Skill 由 Anthropic 于 2025 年 10 月提出,现已成为跨平台开放格式。 它把 prompt 工程”产品化”,解决了纯 prompt 的三大痛点:不可复用、占满上下文、要人手动触发。
-
一个 Skill 就是一个文件夹,核心是
SKILL.md,内容分三层元数据(常驻的”书名”)、L2 正文(动态注入的”章节内容”)、L3 资源(窗口外的脚本 / 参考 / 素材)。 -
渐进式披露是它的灵魂。 平时只暴露 L1 的简短描述,匹配到任务才注入 L2;省的是上下文窗口这一稀缺资源的调度效率,而非模型的理解力。
-
“动态注入”与”静态注入”对模型单次推理无区别(token 不带时间戳),区别在多轮对话中”存在多久、占多少、谁调度”——静态是纹身,动态是便利贴。
-
L1 + L2 本质是”动态加载的 system 级提示”;L3 不是提示,是窗口外的可执行资源。 L3 内部又分两种命运:脚本”给机器跑”(bash 或 MCP,不进窗口,只回填结果),参考资料”给模型读”(按需读片段进窗口,role 通常是 tool)。
-
role 的词汇表由 API 定义,role 的权力由训练在模型端刻死。 Skill 正文以 system 级权威进入上下文永远成立,但其字面 role(system / tool / developer)取决于具体产品实现,唯一确定的是它绝不是 user。
Skill 不是一样神秘的新东西,而是一套围绕上下文窗口做加载调度的机制——用一个静态常驻的”书名”(L1)在 system 里挂号,用到时把”正文”(L2)以 system 级权威动态注入,必要时再指挥窗口外的脚本(L3)去干活。读的归读,跑的归跑,谁都不挤占本就稀缺的上下文窗口。