新增 Skill
对应源码
| 扩展环节 | 源码 |
|---|---|
| Skill 发现和加载 | nanobot/agent/skills.py::SkillsLoader |
| Skill 写入模型上下文 | nanobot/agent/context.py::ContextBuilder.build_system_prompt |
| Skill 文件契约 | nanobot/skills/*/SKILL.md、nanobot/skills/README.md |
| Skill 命令和工具发现 | nanobot/command/builtin.py、nanobot/agent/tools/search.py |
| 验证 | tests/agent/test_skills_loader.py、tests/command/test_skill_command.py |
学习目标
读完后,你应当能够:
- 解释 Skill 与 Tool 的权限边界;
- 创建能被
SkillsLoader发现的目录; - 理解 workspace override、requirements、always 和渐进加载;
- 用行为实验验证 Skill,而不是只检查 Markdown 存在。
前置知识
- 知道 system prompt 会影响模型决策,但不能提供新的执行权限;
- 理解 ContextBuilder 的组成;
- 能写清楚步骤、停止条件和验证标准。
1. Skill 是可加载的操作说明
Skill 的核心文件是:
<workspace>/skills/<skill-name>/SKILL.md内置 Skill 位于:
nanobot/skills/<skill-name>/SKILL.md它教 Agent 如何组合已有 Tool、何时询问用户、如何验证结果。它本身不执行 Python,也不会绕过 Tool 安全边界。
2. 发现与覆盖
SkillsLoader.list_skills():
- 扫描 workspace skills;
- 扫描 builtin skills;
- 同名时 workspace 版本覆盖 builtin;
- 移除
disabledSkills中的名称; - 默认过滤 requirements 未满足的 Skill。
Skill 的运行身份来自目录名。frontmatter 的 name 适合说明和兼容,但当前加载路径按 <目录名>/SKILL.md 查找。
flowchart TD A["workspace/skills"] --> C["按目录名合并"] B["nanobot/skills"] --> C C --> D["workspace 同名优先"] D --> E["disabledSkills 过滤"] E --> F["requirements 过滤"] F --> G["ContextBuilder"]
3. 一个最小 frontmatter
---
name: explain-session
description: Guide the agent to inspect and explain one nanobot Session safely.
metadata:
nanobot:
requires:
bins:
- rg
env: []
---正文至少应说明:
- 何时使用;
- 需要哪些输入;
- 操作顺序;
- 哪些步骤只读;
- 什么时候必须询问用户;
- 完成条件;
- 失败时如何收敛。
4. requirements 的当前实现边界
SkillsLoader._check_requirements() 当前实际检查:
requires.bins:shutil.which();requires.env:环境变量是否存在。
内置 Skill metadata 中还可能出现 os 等字段,但从当前 _check_requirements() 无法证明它会按 OS 过滤。文档若需要声称 OS gating,应先补实现和测试,不能只凭 frontmatter 推断。
get_skill_requirements() 会返回:
- bins/env;
- missing_bins/missing_env。
5. always 与渐进加载
ContextBuilder 分两类处理:
always Skill
frontmatter 顶层 always: true,或 metadata.nanobot.always 为真且 requirements 满足时,get_always_skills() 会把完整正文直接加入 system prompt。
普通 Skill
build_skills_summary() 只加入:
- 名称;
- description;
- 路径;
- availability。
模型需要时再用文件读取能力加载完整 SKILL.md。这就是渐进加载。
always会持续占用上下文只有每次 Turn 都必须遵守的短规则才适合 always。领域工作流、罕见平台操作和长教程应保持按需加载。
6. 写作结构
一份适合 Agent 的 Skill 通常比给人看的长教程更明确:
# Skill 名称
## Use when
## Do not use when
## Inputs
## Procedure
## Safety boundaries
## Verification
## Failure handling重要原则:
- 步骤要可观察,不写“妥善处理”;
- 明确只读与写入;
- 明确需要批准的动作;
- 不鼓励绕过 Tool 错误;
- 不把凭据示例写成真实值;
- 说明结果验证,而不只说明如何执行。
7. 什么时候需要附带脚本
Skill 目录可以包含 scripts/、references/ 等资源。适合附脚本的情况:
- 机械操作复杂且容易拼错;
- 多次执行应保持一致;
- 可写成小而可测试的 helper。
但脚本仍需通过现有 Tool 执行,并受 workspace、shell、权限和依赖约束。Skill 不能把脚本变成可信代码。
8. 验证一个 Skill
结构验证
SKILL.md可被读取;- YAML 可解析;
- description 非空且能区分触发场景;
- requirements 能正确显示 unavailable;
- workspace 同名覆盖符合预期。
行为验证
用一个固定任务观察:
- system prompt 的 skills summary 是否出现它;
- 模型是否在适用场景读取完整 Skill;
- 是否按步骤使用正确 Tool;
- 是否在写入前停下询问;
- 是否执行验证;
- 不适用场景是否没有误触发。
模型行为存在随机性,测试应把 loader/context 的确定性部分与真实模型 smoke test 分开。
9. 源码与测试
源码:
nanobot/agent/skills.py::SkillsLoadernanobot/agent/context.py::ContextBuilder.build_system_promptnanobot/skills/README.mdnanobot/skills/*/SKILL.md
测试:
tests/agent/test_skills_loader.pytests/command/test_skill_command.pytests/tools/test_search_tools.py中 disabled Skill 相关用例
10. 最小修改范围
workspace Skill 通常只需:
workspace/
└── skills/
└── <name>/
└── SKILL.md只有要随 nanobot 发布时,才放入 nanobot/skills 并检查 wheel include、内置文档和相邻测试。
自检
- Skill 为什么不能新增文件读取权限?
- workspace 与 builtin 同名时谁优先?
metadata.os是否已被当前 loader 强制检查?- 哪类 Skill 不适合
always: true?
下一篇:接入 MCP