Skill 运行机制
Skill 是给 AI Agent 使用的可复用能力说明书。它的作用不是让所有工具都常驻在模型上下文里,而是先让模型看到可用 Skill 的标题和描述,再在真正需要时展开完整说明。
外脑的 Skill 参考 Claude Code 和 Codex 的 Skill 经验:渐进式披露、按需加载、加载一次后进入后续上下文。但外脑的运行环境是 Flow Run,每次 Run 都有明确的工作流边界,所以 Skill 不是全局随意可用,而是由当前 Flow 中的 Tools 或 Allow Tools 声明决定。
用户看到的结构
一个 Skill 在项目中表现为独立文件夹:
my-skill/
├── SKILL.md
├── references/
├── scripts/
└── assets/SKILL.md 是必需文件。references/、scripts/、assets/ 是可选资源层;系统不要求默认创建所有空目录。当前导入和新建流程会把核心 Skill 文档放进独立文件夹,后续可以继续补充资源文档、脚本或资产。
SKILL.md 中通常包含:
- 标题:Skill 的名字。
- 描述:告诉 AI 这个 Skill 适合解决什么问题。
- Allow Tools:声明这个 Skill 内部可以调用哪些 Flow、Skill 或 MCP 工具。
- 正文:真正展开后给 AI 阅读的完整操作规则。
标题和描述是第一层信息。正文和资源文件是按需展开的信息。
Flow 如何声明 Skill
在工作流里,Skill 必须先被声明,才可能被当前 Run 使用:
Tools / Allow Tools
- type: skill
- id: <Skill 文档 ID>
- label: <显示名称>
Generation / Structure
- AI 看到可用 Skill 的标题和描述
- AI 判断需要时调用 loadSkill这和外部工具的全局 Skill 列表不同。外脑里每个 Flow Run 都是一个独立上下文,当前 Run 只能看到这个工作流声明过的 Skill。这样可以让工作流作者明确控制 AI 能调用什么,也避免不相关 Skill 污染上下文。
渐进式加载
运行时分三层:
| 层级 | 内容 | 何时进入上下文 |
|---|---|---|
| L1 元数据 | skillId、标题、描述 | Tools / Allow Tools 声明后进入稳定上下文 |
| L2 正文 | SKILL.md 展开的完整说明 | AI 第一次调用 loadSkill 时追加 |
| 资源层 | references、scripts、assets 中的内容 | 由 Skill 正文和具体工具按需使用 |
AI 一开始只看到 Skill 是什么,不会立刻读完整文档。只有当它判断当前任务需要某个 Skill 时,才调用:
{
"skillId": "skill_<documentId>",
"query": "本次调用背景,可选"
}skillId 使用 skill_ 加文档 ID 的格式,例如 skill_abc123。这个格式用于内部稳定识别,也能满足模型工具名对字符的限制。
Active 的生命周期
Skill 的 Active 状态属于一次 Flow Run,不只是某个 Generation 的临时状态。
当 AI 调用 loadSkill 后,系统会做三件事:
- 把展开后的 Skill 正文追加到 Run 历史中,事件类型是
skill_expanded。 - 把这个 Skill 标记为 Active,让 Skill 内声明的 scoped tools 变成可调用。
- 保持原来的可调用工具列表不变,不回头修改之前的 Tools / Allow Tools 内容。
这样设计的好处是:前半段上下文稳定,缓存命中不会被破坏;同时后续 Generation 或 Structure 仍然能在 Run 历史里看到已经展开过的 Skill。
如果后续调用 exitSkill,系统会写入 skill_unloaded,并让最近一次激活的 Skill scoped tools 不再可用。但 Run 历史里已经展开过的 Skill 内容不会被删除,因为后续上下文仍需要知道之前发生了什么。
与 Tools 的关系
Tools Block 和 Allow Tools Block 负责声明“当前上下文允许哪些工具”。Skill 负责把“某一类任务应该怎么做”的说明书按需交给 AI。
两者配合时:
- Tools / Allow Tools 先声明可用 Skill。
- AI 看到 Skill 的标题和描述。
- AI 需要时调用
loadSkill。 - Skill 展开后,内部声明的 scoped tools 才能被调用。
- 如果 AI 没有激活 Skill 就直接调用 scoped tool,运行时会返回 tool error。
这不是为了让 AI 多一步操作,而是为了保持上下文稳定、减少无关内容,并让每个 Flow Run 的能力边界可控。
与外部 Skill 标准的关系
外脑 Skill 的用户心智尽量接近 Claude Code / Codex:独立文件夹、SKILL.md 必需、标题描述用于触发判断、正文按需展开、资源按需使用。
内部实现不要求使用外部工具的目录地址。外脑会把 Skill 存为项目内的文档快照,并在 Flow Run 中按工作流声明加载。未来如果需要迁移给 Codex、Claude Code 等外部系统使用,应通过兼容导出层把内部 Skill 导出成标准 Skill 目录。
验证重点
完整验证 Skill 功能时,不只要看文档能否创建,还要确认整条 Run 链路:
- Skill 文档能创建并放进独立文件夹。
- 工作流能通过 Tools / Allow Tools 声明这个 Skill。
- AI Block 能看到 Skill 的标题和描述。
loadSkill后 Run 历史出现skill_expanded。- 后续 AI Block 能看到已经展开过的 Skill。
- Active 后 scoped tools 可调用,未 Active 时不能绕过调用。
exitSkill后 scoped tools 失效,但历史展开内容保留。- resume 后能恢复 Skill 历史和 Active 状态。
这些验证项是 Skill 可用性的主标准。
项目内提供了手动 E2E 命令:
pnpm skill:e2e这个脚本会创建一次性测试账号和临时项目,写入一个主 Flow、一个 Skill、一个 Skill 内部 workflow 工具,并通过 /runs 新协议执行。它会检查 loadSkill、skill_expanded、scoped tool 调用,以及 globalctx-events 中是否能回放展开后的 Skill。运行前需要后端 API、Redis 和 backend worker 可用;如当前环境有多个模型,可用 WAINAO_SKILL_E2E_MODEL_ID 指定支持 tools 的模型。