假设桌面 Agent 已经拥有 read、bash、edit 等工具。现在希望它学会“代码审查”:
每次审查都先理解变更目标,再检查正确性、安全、测试和兼容性,最后按严重度给出带源码位置的结论。
工具能让 Agent 读取和修改代码,却不会自动教会它怎样做一次高质量审查。把完整流程塞进 System Prompt 又会让所有请求长期携带一大段无关规则。
Skill 用来填补这个空白:它把某类任务的方法、流程和专业知识包装成可按需加载的能力包。
1. 从一个失败的设计开始
最直接的做法是把规则写进 System Prompt:
你是桌面 Agent。
做代码审查时必须:
1. 阅读变更目标……
2. 检查……
3. 运行……
(还有 200 行)
这会产生三个问题:
- 用户只是问一句普通问题,也要发送全部审查规则;
- 多种专业能力会让 Prompt 越来越大;
- 更新审查流程必须修改 Agent 的全局身份配置。
flowchart LR
P["固定 System Prompt"] --> C1["普通对话也携带审查规则"]
P --> C2["能力越多,Context 越大"]
P --> C3["难以独立版本化和分发"]
Skill 把“始终知道有这项能力”和“真正使用完整流程”分开。
2. Pi 对 Skill 的定义
Pi 文档把 Skill 定义为按需加载的、自包含的能力包。它可以包含:
- 专业工作流;
- 环境准备说明;
- 辅助脚本;
- 参考文档;
- 模板和静态资源。
一个典型目录:
code-review/
├── SKILL.md
├── scripts/
│ └── collect-diff.sh
├── references/
│ └── security-checklist.md
└── assets/
└── review-template.md
其中只有 SKILL.md 是核心入口,其余结构由 Skill 自己约定。
3. Skill 的两阶段上下文
Pi 启动时不会把所有 SKILL.md 正文都放进 System Prompt。Resource Loader 先加载元数据;
只有 read 是 Active Tool,且 Skill 没有设置 disable-model-invocation 时,这份元数据才会
进入模型可见的 System Prompt 目录:
<available_skills>
<skill>
<name>code-review</name>
<description>审查代码变更……</description>
<location>/.../code-review/SKILL.md</location>
</skill>
</available_skills>
任务匹配后,Agent 才用 read 读取完整文件。以下自动匹配链都以这两个可见性条件为前提。
sequenceDiagram
participant L as Resource Loader
participant P as System Prompt
participant A as Agent
participant F as SKILL.md
L->>P: 可见 Skill 的名称 + 描述 + 位置
P->>A: 可用能力目录
A->>A: 当前任务匹配 code-review
A->>F: read 完整指令
F-->>A: 工作流、边界、资源引用
这叫 Progressive Disclosure,渐进式披露。
4. 它怎样减少长期 Context
假设有 20 个 Skill,每个正文 1500 Token:
全部常驻:约 30,000 Token
只放元数据:远小于完整正文
实际任务:再加载匹配 Skill 的正文
Pi 的源码体现了这个分层:
loadSkillFromFile()解析 Frontmatter,形成轻量Skill元数据;- 有
read且 Skill 允许模型调用时,formatSkillsForPrompt()才把name、description、location输出到 System Prompt; - 模型自动选择时,再通过
read获取全文; - 用户显式输入
/skill:name时,AgentSession 才读取正文并展开到输入。
节省的不是文件存储,而是每次模型请求都要携带的长期上下文。
5. Skill 不是 Tool
Tool 是可执行接口:
{
name: "read",
description: "Read a file",
parameters: { /* JSON Schema */ },
execute: async (...) => { /* ... */ },
}
Skill 通常是一份给模型阅读的 Markdown 工作流。它自身没有统一的 execute()。
Tool:能做什么动作
Skill:遇到这类任务时,应该怎样组织动作
代码审查 Skill 可能要求依次使用:
read理解代码;bash运行静态检查;- 搜索工具找调用方;
- 最后输出审查结论。
真正执行副作用的是 Tool,不是 Skill 文件。
6. Skill 也不只是“一段 Prompt”
从传给模型的角度,SKILL.md 的正文确实会成为上下文。但把 Skill 简化为 Prompt 片段会漏掉
它的包结构和运行约定:
- 它有可发现的名称和描述;
- 它有自己的基准目录;
- 相对路径必须从 Skill 目录解析;
- 它可以引用脚本、模板和长篇参考资料;
- 它能单独安装、启用、诊断和分发;
- 它可以选择不允许模型自动调用。
因此更准确的理解是:
Skill 是以指令为入口、可携带资源的能力包。
7. Skill 与 System Prompt 的区别
| 对比 | System Prompt | Skill |
|---|---|---|
| 作用范围 | Agent 的基础身份和长期规则 | 某类任务的专业方法 |
| 加载方式 | 每次请求都在 Context 中 | 可见元数据随 System Prompt 常驻,正文按需 |
| 数量 | 通常一个动态构建结果 | 可以有很多 |
| 复用方式 | 通过配置组合 | 能作为独立目录或包分发 |
| 典型内容 | 角色、安全边界、环境 | 步骤、检查单、脚本和模板 |
项目中“禁止修改生产密钥”是长期约束,适合 AGENTS.md 或 System Prompt;“怎样审查
OAuth 回调”是特定任务方法,更适合 Skill。
8. Skill 与 Extension 的区别
Extension 会进入 coding-agent 的运行机制,可以注册:
- Tool;
- Command;
- Event Handler;
- Provider;
- 资源发现逻辑;
- Prompt 改写逻辑。
Skill 默认只是模型可读取的工作流,不直接获得这些运行时钩子。
flowchart TD
NEED["新增能力需求"] --> Q{"需要改变运行机制吗?"}
Q -->|"只需要方法、知识、步骤、资源"| S["Skill"]
Q -->|"需要事件、命令、工具或生命周期控制"| E["Extension"]
E --> ES["Extension 也可以分发 Skill"]
如果“错误日志分析”只需要读取日志、识别模式和输出报告,用 Skill 即可。若需要持续订阅 系统日志、注册新的流式工具或拦截 Provider 请求,则需要 Extension。
9. 四种机制放到同一个例子
桌面 Agent 要做安全代码审查:
| 机制 | 在例子中的职责 |
|---|---|
| System Prompt | 遵守项目规则,不泄露密钥,高风险操作先确认 |
| Tool | 读文件、搜索引用、执行测试 |
| Skill | 安全审查步骤、威胁清单、报告格式 |
| Extension | 在工具调用前做审批,注册内部扫描器,记录审计事件 |
它们不是互斥方案,而是不同层次的组合。
10. 自动匹配依赖 Description
在 read 已启用且 Skill 允许模型调用时,Pi 才在 System Prompt 中暴露它的 Description,
并告诉模型:
任务与描述匹配时,用 read 加载 Skill 文件。
因此 Description 不是给人看的装饰,而是模型的路由信息。
较差:
description: Helps with reviews.
较好:
description: Reviews code changes for correctness, security,
regressions, and missing tests. Use when asked to review a
diff, pull request, patch, or implementation.
后者同时说明“做什么”和“什么时候用”,模型更容易正确选择。
11. 自动选择不是确定性路由
模型看到元数据后是否真的调用 read,仍是模型行为。Pi 文档明确提醒:模型并不总会自动
加载匹配 Skill。
所以宿主需要区分:
- 自动建议:让模型依据 Description 判断;
- 显式调用:用户输入
/skill:name; - 产品强制:宿主在已知工作流中直接把 Skill 内容加入输入或用 Extension 约束。
Skill 本身不是一个保证百分之百命中的规则引擎。
12. 显式调用发生了什么
用户输入:
/skill:code-review 检查当前改动
AgentSession._expandSkillCommand():
- 按名称查找已加载 Skill;
- 同步读取 Skill 文件;
- 去掉 Frontmatter;
- 包装成带名称和位置的
<skill>Block; - 告诉模型相对引用的基准目录;
- 把用户参数附在 Block 后。
这条输入随后作为普通 User Message 进入 Agent。
显式调用和自动匹配的差别是:前者由 AgentSession 展开正文,后者由模型看到目录后自行
调用 read。
13. disable-model-invocation
Skill Frontmatter 可以设置:
disable-model-invocation: true
formatSkillsForPrompt() 会过滤这类 Skill,所以模型不会在可用目录中看到它;用户仍可通过
/skill:name 显式调用。
适用场景:
- 可能产生昂贵操作;
- 只有用户明确要求才能执行;
- Description 容易与普通任务误匹配;
- 需要把启动权保留给 UI 或用户。
这只是隐藏自动发现,不是安全沙箱。Skill 仍可能指导模型执行高风险 Tool。
14. Skill 是能力分发机制
桌面 Agent 通常有多个项目、团队和角色。Skill 的文件包形式带来:
- 用户级复用:个人所有项目可用;
- 项目级共享:随仓库分发团队流程;
- 包级分发:Extension 或 npm Package 携带 Skills;
- 显式路径:宿主按配置装配能力;
- 跨 Harness 复用:符合 Agent Skills 约定的目录可以被其他实现读取。
它比修改主程序更轻,也比复制粘贴 Prompt 更容易追踪来源。
15. 项目级 Skill 的信任边界
Skill 可以指示模型运行脚本,也可能包含恶意指令。Pi 文档要求在使用前审查内容。
项目级 .pi/skills 和祖先 .agents/skills 只有在项目受信任后才会作为自动资源进入。
但“被加载”不等于“安全”:
- 脚本仍应经过审查;
- Tool 权限仍应最小化;
- 高风险副作用仍应审批;
- 不应把 Skill 当作越过 Tool 安全策略的通道。
flowchart LR
SK["Skill 指令"] --> MODEL["模型决定调用 Tool"]
MODEL --> POLICY["宿主权限 / 审批"]
POLICY -->|允许| TOOL["Tool 执行"]
POLICY -->|拒绝| STOP["停止并说明"]
16. 一个桌面 Agent 的使用过程
用户问:
请审查我刚改的登录逻辑。
完整过程可以是:
read已启用,且 System Prompt 中已有可见code-review的名称、描述和位置;- 模型判断任务匹配;
- 模型调用
read读取SKILL.md; - Skill 要求先读取 Diff 和认证模块背景;
- 模型使用现有 Tool 收集证据;
- Skill 引用安全检查单,模型按需继续读取;
- 模型按规定格式输出问题;
- 整个过程仍运行在同一个 Agent Loop 和 Session 中。
Skill 没有创建第二个 Agent,也没有绕过对话历史。
17. 什么时候不该创建 Skill
以下情况通常不需要 Skill:
- 一次性、很短的用户要求:直接 User Prompt;
- 所有任务都必须遵守的规则:System Prompt 或项目 Context;
- 需要新的外部动作:Tool;
- 需要拦截生命周期或修改运行时:Extension;
- 只有一条简单固定模板:Prompt Template 可能更直接。
判断标准不是“内容能否写成 Markdown”,而是它是否代表可复用的特定任务方法。
18. 常见误区
“装了 Skill 就新增了一个 Tool”
错误。Skill 通常指导模型使用已有 Tool。
“所有 Skill 正文都会常驻 Context”
错误。默认常驻的是轻量目录,正文按需加载。
“Description 随便写也没关系”
错误。自动匹配主要依据 Description。
“Skill 自动选择是确定性的”
错误。它仍依赖模型判断;显式调用更确定。
“disable-model-invocation 能阻止执行”
错误。它只把 Skill 从模型可见目录中隐藏,仍允许显式调用。
“Skill 可以替代 Tool 的权限控制”
错误。Skill 是指令,安全边界仍必须在 Tool 和宿主层实施。
19. 本章小结
- Skill 解决“如何完成某类任务”,Tool 解决“能执行什么动作”;
- Skill 是带元数据、相对路径和资源的能力包,不只是散落的 Prompt;
- Pi 在
read启用且 Skill 允许模型调用时,用可见元数据常驻、正文按需读取实现渐进式披露; - Description 是自动匹配的路由信息,但模型选择不是确定性规则;
/skill:name会由 AgentSession 显式读取并展开正文;disable-model-invocation隐藏自动发现,不构成安全权限;- System Prompt、Tool、Skill、Extension 各自承担不同层次;
- 用户级、项目级和 Package Skill 让它适合作为桌面 Agent 的能力分发方式;
- Skill 可能携带可执行脚本,必须结合项目信任、Tool 权限与审批。
20. 自测
- 为什么不应把所有专业流程都写进 System Prompt?
- Skill 与 Tool 的根本区别是什么?
- Pi 的渐进式披露包含哪两个阶段?
- Description 为什么会影响自动触发?
- 自动匹配与
/skill:name在正文加载上有什么区别? disable-model-invocation能否作为权限控制?- 什么需求更适合 Extension 而不是 Skill?
- 项目已经受信任后,为什么仍要审查 Skill?