Skip to content
learnspace
Go back

Skill 工程化:从一次性 prompt 到可复用知识

上两篇讲了 Rules 和 TTSR——它们解决的是”agent 必须遵守什么”。但约束只是底线。真正让 agent 效率飞升的,是另一面:把工作流固化成可复用知识

这就是 Skill 系统。

从 prompt 到 Skill

你跟 agent 协作一段时间后,会发现某些任务每次都要重复同一段上下文:

每次手动输入这些上下文,既慢又容易漏。Skill 的本质:把这段上下文写成文件,让系统按需自动加载。

跟 Rules 的区别一句话讲清:Rules 约束 agent 不能做什么,Skill 告诉 agent 怎么做什么。

Skill 长什么样

一个 Skill 就是一个目录,最少只需要一个文件:

.omp/skills/blog-ops/
├── SKILL.md ← 必须:指令 + 元数据
├── scripts/ ← 可选:可执行脚本
├── references/ ← 可选:参考文档
└── assets/ ← 可选:模板、图标等

SKILL.md 是带 YAML frontmatter 的 Markdown。下面是一个真实 Skill 的头部(省略正文):

---
name: blog-ops
description: "deploy、部署、上线、发布、同步、rollback、回滚、SSL、nginx、服务器、运维、blog.sh"
globs: ["scripts/**", "astro.config.*"]
---
# 运维指南
## 标准流程
### 1. 部署
$ bash scripts/deploy.sh

三个关键字段:

字段作用
nameSkill 标识符,skill://<name> 的寻址依据
description触发机制的核心——agent 根据这段文字决定是否加载
globs文件路径模式——注意:解析了但不用于 Skill 触发(那是 Rules 的事,详见下文)

description 不是给人看的文档——它是 agent 的决策依据。agent 在系统 prompt 里看到所有 Skill 的 name + description,根据当前任务决定是否用 skill://<name> 加载完整内容。

多源发现:Skills 从哪里来

跟 Rules 一样,omp 扫描多个位置发现 Skills——兼容主流 AI 编程工具的目录结构:

优先级来源扫描目录
100omp 原生.omp/skills/(向上遍历)、~/.omp/agent/skills/
90omp 插件<插件包>/skills/
80Claude Code.claude/skills/(向上遍历)、~/.claude/skills/
70Codex / Agents.codex/skills/.agent/skills/
30GitHub.github/skills/
5托管 Skills~/.omp/agent/managed-skills/

同名去重规则:高优先级赢。 你在 .omp/skills/blog-ops/.claude/skills/blog-ops/ 同时放了一个 Skill,omp 只加载前者(priority 100 > 80)。从 Cursor 或 Claude Code 转过来的 Skills 直接能用,不用迁移。

这个设计跟 Rules 兼容 .cursor/rules/.clinerules 是同一个思路:不强迫用户重写已有资产,用优先级解决冲突

发现流程本身也有容错:Skill 目录扫描有 5 秒超时,超时则回退到空列表——不会因为一个慢文件系统卡住整个启动。

三级渐进加载

这是 Skill 系统最关键的设计:不要一次全加载

级别内容加载时机大小
1. 元数据name + description始终在上下文里~100 词
2. SKILL.md 正文完整指令agent 决定触发时<500 行
3. 捆绑资源scripts/、references/、assets/按需读取不限

为什么这样设计?因为 context window 是稀缺资源。项目可能有十几个 Skill,如果全部完整加载,光 Skill 就占满上下文。三级加载让 agent 先看到”目录”(description),只在需要时才读”正文”(SKILL.md),更深层的参考资料用到才读。

举个例子。这个博客项目有 6 个 Skill:

blog-author → 写文章、改 frontmatter
blog-ops → 部署、运维、SSL
blog-series → 专栏连载
blog-component → 创建/修改 Astro 组件
blog-debug → 前端调试
blog-seo → SEO 优化

agent 每轮看到的是 6 条 description(总共约 200 词)。用户说”部署一下”,agent 匹配到 blog-ops 的 description 里有”部署”,才加载完整 SKILL.md。用户说”写一篇新文章”,匹配到 blog-author。两个 Skill 不会同时加载——除非任务确实涉及两方面。

为什么三级加载不会”丢失”

一个关键问题:agent 读了 Skill 正文(第二级),后面对话变长触发 compaction 时,Skill 内容会不会被压缩掉?

答案是不会。omp 的 compaction 系统有工具保护机制:通过 skill:// 协议读取的内容被标记为不可压缩、不可裁剪。agent 在第 5 轮读了 blog-ops 的完整指令,到第 50 轮 compaction 压缩了早期对话,blog-ops 的内容仍然保留在上下文里。

这个设计是三级加载能工作的底层保障。没有它,agent 读完 Skill 后聊了 20 轮,Skill 就被”挤”出去了——等于没读。

skill:// 本身是一个协议处理器(SkillProtocolHandler),不只是文件读取——它支持嵌套路径(skill://blog-ops/scripts/check.sh)、路径遍历防护(防止 ../../ 逃逸),甚至能在 bash 命令里自动展开为绝对路径。

globs 的误会

前面字段表里特别标了:globs 解析了但不用于 Skill 触发。这是个容易踩的坑。

很多人(包括我一开始)以为在 SKILL.md 里写 globs: ["src/**/*.astro"] 就能让 Skill 只在编辑 Astro 文件时触发——类似 TTSR 规则的作用域。不是的。 globs 字段在 Skill 里被解析、存储,但触发判断完全靠 agent 读 description 后自行决定。

globs 真正的用途在 Rules 那边:TTSR 规则用它限定监控范围(“这条规则只看 .ts 文件”)。Skill 和 Rules 共享 schema 定义,但触发机制完全不同:

RulesSkills
globs✅ 用于 TTSR 匹配范围❌ 解析了但不参与触发
触发依据condition + globs完全靠 description

写 Skill 时别指望 globs 帮你控制触发——把触发意图写进 description 才是正道。

Description 是触发的灵魂

写 Skill 最容易犯的错是 description 写得太泛或太窄:

太泛"处理博客相关任务"——什么都匹配,等于没匹配

太窄"执行 bash scripts/deploy.sh 部署脚本"——用户说”上线”就不触发

好的 description 是关键词覆盖 + 场景列举

description: "deploy、部署、上线、发布、同步、rollback、回滚、SSL、nginx、服务器、运维、blog.sh"

这段 description 的设计思路:

  1. 同义词铺满——“部署”、“上线”、“发布”、“deploy”,用户怎么叫都能命中
  2. 关联操作列出——rollback、SSL、nginx,覆盖运维场景的常见关键词
  3. 工具名提及——blog.sh,用户直接提工具名时也能触发

实际效果:用户说”帮我上线”、“部署一下”、“SSL 快到期了”、“blog.sh rollback”——这些都会触发 blog-ops,不会误触 blog-author。

渐进式 Skill 结构

当指令超过 500 行时,SKILL.md 本身要分层:

blog-series/SKILL.md ← 主文件:工作流 + 判断逻辑
blog-series/references/
├── series-mechanism.md ← 排序机制详解
└── frontmatter-spec.md ← frontmatter 规范

SKILL.md 里用清晰的指针告诉 agent 什么时候读哪个参考文件:

## 专栏机制速记
排序实现在 `src/utils/getSeriesPosts.ts`...
## 创作流程
### A. 新建专栏
1. 先想清楚弧线...
2. 参考 `references/frontmatter-spec.md` 写 frontmatter

这样 agent 在”新建专栏”场景下只读 SKILL.md + frontmatter-spec.md,不会加载”调整专栏结构”那段——如果那段在参考文件里的话。

从错误里长出 Skill

这个博客项目的 Skill 不是一开始设计好的,是从反复犯错里提炼的:

blog-ops 的由来:第一次部署时 agent 不知道要检查 SSL,直接 rsync 了。我骂了一句,然后把部署流程写成了 Skill。从此每次部署,agent 自动加载”先检查 SSL → build → rsync”的完整流程。

blog-series 的由来:agent 写第一篇专栏文章时把 series 字段拼错了(写成 serie),发布后 SeriesBadge 不显示。排查了半天。于是有了 blog-series——把专栏的机制速记、frontmatter 必填项、发布前检查清单全写进去。

blog-debug 的由来:调前端样式时 agent 反复在 AstroPaper 和 Starlight 两层之间迷路,不知道该改哪个 CSS 文件。于是有了 blog-debug——把双层主题架构的排查路径固化。

规律:好 Skill 不是预设的,是从 agent 犯错里长出来的。 第一次犯错就写 Skill,第二次就不会再犯。

Skill vs Rules:互补而非替代

容易混淆的一点:既然 Rules 也能注入约束,为什么还需要 Skill?

维度RulesSkills
目的约束:不能做什么赋能:怎么做什么
触发条件匹配(TTSR)或始终注入agent 按需加载
内容禁令 + 替代方案完整工作流
粒度一条规则 = 一个约束一个 Skill = 一个能力域

实际协作中两者叠加使用:

一个管底线,一个给路径。缺一个都会出问题。

Skill 工程化的几个原则

跑了几个月,总结了几条写 Skill 的经验:

1. Description 要”贪婪”

宁可多列几个同义词,也不要让 agent 漏触发。用户说”帮我发一下”,description 里没有”发”或”发布”,Skill 就白写了。

2. 正文要”讲为什么”

不要只写步骤,要写原因。agent 有理论心智——告诉它”先检查 SSL 是因为证书过期会导致全站 404”,比单纯写”先检查 SSL”更有效。agent 理解了原因,遇到变体情况也能自己判断。

3. 禁止事项要具体

跟 Rules 一样,Skill 里的”不要做 X”必须具体到可验证。“写好代码”没用,“禁止在文章正文里手写第 N 篇,交给 SeriesBadge 自动算”有用。

4. 捆绑脚本省 token

如果某个流程需要 agent 每次都写一段脚本(比如部署前的检查),不如直接把脚本放进 scripts/,Skill 里写”执行 bash scripts/blog.sh status”。agent 不用每次重写,token 省了,行为也稳定。

5. Skill 可以引用 Skill

blog-series 的开头写了”单篇文章的 frontmatter 规范参见 blog-author”。这避免了重复——两个 Skill 各管各的领域,交叉时互相引用而不是内容复制。

下一步

Rules 约束 agent 的行为边界,Skill 赋能 agent 的工作能力。但到目前为止我们讨论的都是单 agent 场景——一个 agent 独立完成所有任务。

当任务变复杂时,单 agent 会遇到瓶颈:上下文太长、工具调用太杂、子任务之间互相干扰。下一篇我们讲 omp 的多 agent 协作——怎么用 swarm 扩展让多个 agent 并行干活,以及什么时候多 agent 反而比单 agent 慢。


本文是「omp 编程工具使用探讨」专栏第 5 篇。文中的 Skill 示例全部来自这个博客的 .omp/skills/ 目录——它本身就是 Skill 工程化的实践产物。


Share this post:

Previous Post
TTSR 实时中断:让 agent 输出到一半自动回头