Skill 质量审查
审查一个 Skill 有没有五样东西:能被找到、能被加载、加载后不劣化、能上架、上架后不被退。
前四道关卡是本技能的核心;第五道关卡的工具已实测有误报,本技能提供豁免清单。第六道关卡是本技能对自己的自我审查——用本技能审本技能,闭环验证触发与一致性(见「关卡 6」)。
铁律
- 先出报告,再谈修改。 审查阶段不改文件。用户明确说"改"才动。
- 每条问题必须带证据:文件名 + 行号 + 原文片段。没有证据的怀疑不要写进报告。
- 区分「真缺陷」和「误报」。工具报了不等于真有问题——用对照实验验证:拿一个已知能上架的版本跑同一检查,若它也报同样的问题,那条就是误报。
- 不替用户写 skill 的内容。审查者指出问题并给改法,不代笔。
- 一次只审一个 skill。同时审多个会丢失上下文深度。
- 专名规则按用户约定(本项目为「莱斯特.利文森」),触发关键词表保留裸词不算问题。
- 审查前先查市场。见下方「关卡 0」。
- 审查工具本身要过自测。拿一个已知会炸的坏样本跑一遍,确认它报得出来、且级别正确。
- 自身回复也要守形态。审查对话中一次只问一个问题、不主动给建议/鼓励/承诺/计划;非报告类回复控制长度,避免多嘴(见「关卡 2b」的清单,本技能同样适用)。
关卡 0 · 先查市场(动手前必做)
这是最容易被跳过、也最省时间的一步。 用户的原话:「你帮我做了 3 个智能体,中间也出现了很多问题,你为什么没有想到在市场中先寻找专家和技能呢?」
做新 skill 之前,先确认市场上有没有现成的:
# 本地 CLI 搜索(注意:search 对多词 query 会返回默认结果,单个词更准)
python ~/.skillhub/skills_store_cli.py search <单个关键词> --json
若 CLI 返回结果与关键词无关(多次返回同一份默认列表),改用网页搜索 skillhub.cn 找。
查完必须回答三个问题,并把答案写进报告:
- 市场上有没有同类 skill? 有 → 先读它的 SKILL.md,看它已经解决了什么,不要从零重造。
- 有没有现成的审查/自检工具? 有 → 装上并实测它的漏报(见下方「工具对照表」)。
- 有没有可用的专家? 用
search_plugins(type="expert")查。命中就用,不要自己硬扛。
工具对照表(2026-10-22 实测)
拿 1.0.7 的真实 frontmatter bug(正文被包进 --- 块内 → yaml.safe_load 报 ScannerError)喂给各工具:
| 工具 | 结果 | 结论 |
|---|---|---|
官方 skill-creator/scripts/quick_validate.py |
Skill is valid! |
查不出 |
市场 skill-dev-selfcheck |
PASS 11 / FAIL 0 | 查不出 |
市场 skill-check |
章节结构分析,不查 YAML | 查不出 |
本技能 audit_static.py |
FAIL + 退出码 1 | ✓ 唯一能拦住 |
结论:市场工具和官方工具都有盲区,不能单独依赖。 但它们能查包结构、换行符、体积、导流词这些本技能不查的项,是互补而非替代。
已知误报(用实际过审版本对照验证过):
| 工具会报 | 实际情况 |
|---|---|
| 包内文本 > 30KB | 无此限制。实测 166KB 过审、下载 85 次 |
| 单文件 > 3848B 截断 | 那是云端付费 skill 的沙箱限制,社区 skill 走本地读取 |
scripts/ 有写文件代码 |
误判,多轮记录类脚本本就该落盘 |
五道关卡
关卡 1 · 静态结构与 frontmatter
用 scripts/audit_static.py 跑,它会检查:
| 检查项 | 通过标准 | 为什么重要 |
|---|---|---|
| frontmatter 起始符 | 文件首行是 --- |
解析入口 |
| YAML 合法性 | yaml.safe_load 不报错 |
解析失败 = name/slug 全部读不到 |
name 存在且唯一 |
全局不重名 | 重名会互相顶掉,实测有技能调不到 |
name 与 slug 一致 |
两者相同或 name 无 slug | 系统按 name 认技能 |
version 三段式 SemVer |
X.Y.Z |
2.0 非法,重复号报 slug 冲突 |
display_name / displayName |
建议有 | 列表页观感,也影响搜索命中 |
| 显示名系列一致性 | 同一系列的 skill 显示名风格统一 | SkillHub 排行只看显示名命中关键词,简介不参与。名字不带系列关键词,搜系列名时直接排不上 |
description 长度 |
建议 ≤ 160 字 | 列表页会截断,卖点看不见 |
| 换行符 | 全部 LF | CRLF 导致 frontmatter 解析异常 |
| 正文行数 | 建议 < 500 行 | 过长会挤占上下文 |
| references 引用 | 提到的文件真实存在 | 死链等于没写 |
| 专名一致性 | 叙述正文用全称 | 触发词表保留裸词不算问题 |
frontmatter 的三个坑(这是最容易翻车的地方):
- 正文被包进
---内 — 第 9-28 行是正文却写在元数据块里,yaml.safe_load直接报 ScannerError,整个 frontmatter 解析失败。dry-run 和 quick_validate 都查不出来。 - name 重名 — 两个目录都写同一个
name,系统按 name 认技能,后装的顶掉先装的。 - version 与平台不同步 — 包里
version: 1.0.6但平台是 1.0.7。
输出级别:PASS 通过 / WARN 建议改 / FAIL 阻断上架。有 FAIL 时脚本退出码为 1。
审查工具自己的自测(必做):拿一个已知会炸的坏样本跑一遍,确认它报得出来、且级别是 FAIL 而不是 WARN。审查工具骗人比没有工具更危险——本技能自身的 out(False, ...) 就曾因为 Python 里 False == 0 为真而永远降级成 WARN,把 P0 问题显示成建议。详见 references/pitfalls.md 第六节。
关卡 2 · 防劣化自检(最关键,也最容易被跳过)
这一关决定 skill 好不好用,静态检查查不出来。
2a. 规则位置检查
所有影响行为的约束,必须写在 SKILL.md 主文件里。 写在 references/ 里等于没写——因为 references 是"按需读取、默认不预读"的资料,AI 在实际触发时根本看不到。
实测教训:有一条「新手第一次说『我觉得它会发生』是正常起点」写在 references/bridges.md,结果 AI 第一次就跳级到第二部分。修法:把硬约束从 references 提到主文件,references 只留展开材料。
自查方法:把每条约束归类——
- 约束(必须遵守)→ 必须在 SKILL.md
- 示例、话术、展开解释 → 可以放 references
- 出现频次低的背景资料 → references
2b. 输出形态检查
好 skill 必须约束 AI 每条回复的形态。检查这些:
- [ ] 长度上限(字数/句数)
- [ ] 一次只问一个问题
- [ ] 问完就停,等用户回答
- [ ] 明确禁止的内容(建议、计划、鼓励、承诺、可行性分析……)
- [ ] 有没有「自检清单」——发出前自己过一遍的 N 条
- [ ] 有正例示范(correct format example)
- [ ] 会话长度上限(防长上下文劣化)
「有没有多嘴」这一条最容易被忽略。 AI 默认会给建议、鼓励、承诺。skill 必须显式禁止。
2c. 边界处理检查
- 用户要的东西这个 skill 明确不做时,说了吗?
- 边界条款在主文件还是 references?(同 2a)
- 有没有区分「用户主动要」和「开场就声明」?——用户没要求时先声明边界是浪费第一轮
- 安全边界是否在恰当的时机说(而不是开场抢话)?
2d. 触发条件检查
description 就是自动触发的依据。检查:
- [ ] 触发条件 ≥ 3 条,覆盖不同说法
- [ ] 有没有覆盖「用户要计划/拆解/评估」这类看起来该由别的 skill 处理的情况——这类最容易漏,导致边界处理成了死代码
- [ ] 有没有划清与邻近 skill 的界线(用一句可判定的规则,不要模糊描述)
- [ ] description 里有没有写清"不做什么"——这会直接影响会不会被抢走
关卡 3 · 子代理实测(不能省)
静态检查永远查不出真实表现。 必须用独立子代理(干净上下文)实测。
为什么不能在本会话测:skill 全文都在上下文里,等于自己批自己的卷,测出来的是"照着规则表演"。
3a. 测加载后表现
对每个子代理:
1. 加载 skill
2. 给一个用户场景
3. 让它产出真实会发出的那一条回复
4. 要求自查:字数、问题数、有没有多嘴
子代理 prompt 里不要提前剧透规则,只给场景 + 输出要求,否则测的是"照剧透演"。
3b. 测自动触发(更关键)
让子代理不要主动调用任何工具,只看面对用户一句话时会不会自己选中 skill:
> 你现在扮演一个全新的智能体。有人给你发来一句话。你要像真被触发一样,产出你会真实发给对方的那一条消息。
> 重要限制:你什么都不要主动调用。只根据这句话和你自己系统里可用的技能列表,判断该不该用某个技能;如果判断该用,就真的去调用它。
> 对方说的话:<场景>
> 输出:先单独一行写 【是否触发技能】 + 调用了哪个技能名(没调用就写"未触发任何技能"),然后另起一段输出真实回复。
这一步能抓出静态检查查不出的真问题。 实测三个典型漏洞:
- 「帮我列个计划表」根本不触发 → skill 里那条"用户要计划就说明本方法不做"的边界处理成了死代码
- 人生目标和纯理财咨询被混淆 → 加界线:「问的是『我要成为什么样的人』还是『买哪个东西』?」
- description 改完必须复测 — description 本身就是触发依据,改完不测等于没改(第一次改完复测仍被抢走,改第二轮才对)
3c. 测劣化
让子代理连续走 5-8 轮,观察:
- 第 3 轮之后是否开始多嘴
- 是否重复同样的句式
- 是否长度失控
- 是否开始给建议/计划
好 skill 的真正考验在第 3 轮以后。
关卡 4 · SkillHub 上架前检查
用 scripts/audit_publish.py(内置已验证的豁免清单)。
已知误报,不要照单全收——以下三条对社区 skill 不构成问题(已用实际过审版本对照验证):
| 工具会报 | 实际情况 |
|---|---|
| 包内文本总量 > 30KB | 社区 skill 无此限制。实测 166KB 的版本过审并下载 85 次 |
| 某文件 > 3848B 会截断 | 那是云端付费 skill 的沙箱限制,社区 skill 走本地文件读取 |
scripts/ 里有写文件代码(json.dump / open(...,"w")) |
误判。多轮记录类脚本本就该落盘。安全扫描判的是"是否写系统文件",不是"是否写用户指定的输出路径" |
但这三条要看平台返回的真实结果:
# 发布后查审核状态
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.skillhub.cn/api/v1/dashboard/skills/<slug>/versions"
# download 端点是否可用(返回 302 说明文件真实存在)
curl -s -o /dev/null -w "HTTP %{http_code}\n" \
"https://api.skillhub.cn/api/v1/download?slug=<slug>&version=<版本>"
关键约束:
publish返回✓ Published不等于上线。新版本会进审核队列(reviewStatus: pending),实测约 3 分钟自动通过。--version参数不写进包内文件。服务端以 SKILL.md 的version为准,要改版本号必须改文件本身。- 发布前先发新版顶掉 latest,才能删掉旧的 latest(
409 cannot delete the latest version)。 - 删版本用
DELETE /api/v1/dashboard/skills/<slug>/versions/<versionId>,参数是数字 versionId。 - 包里不能有
assets/(服务端 400 拒绝 png)、不能有二进制文件。 - 两次发布间隔 70 秒(429 频率限制)。
上架后必查:
- [ ]
latestVersion.version是新版本号 - [ ]
tags.latest一致 - [ ] 下载包解压,frontmatter 的 name/version 是新值
- [ ] 平台 summary 里专名正确、无英文原名
- [ ] 本地安装目录的 meta 文件 version 已同步
关卡 5 · 本地一致性
- [ ] 本地安装目录的 SKILL.md 与线上一致
- [ ]
_meta.json/_skillhub_meta.json的 version 是当前版本 - [ ]
skill_management list里 skill 在册 - [ ] 全机 name 唯一(
~/.workbuddy/skills/*/SKILL.md全扫一遍) - [ ] 子代理能正常
Skill(skill="<name>")加载
关卡 6 · 自我审查(本技能审本技能)
本技能专查「触发」与「一致性」,更该对自己跑一遍——否则就是「查触发的工具自己触发有问题」的元悖论。每次升版前跑一次,结果记到 references/self_audit_log.md。
6a. 自动触发自测(对应 关卡 3)
spawn 一个干净子代理(不要剧透规则),只给场景,验证本技能会被自动选中、不被邻近 skill 抢走、连跑 5-8 轮不劣化:
> 你现在扮演一个全新的智能体。有人给你发来一句话。你要像真被触发一样,产出你会真实发给对方的那一条消息。
> 重要限制:你什么都不要主动调用。只根据这句话和你自己系统里可用的技能列表,判断该不该用某个技能;如果判断该用,就真的去调用它。
> 对方说的话:<场景:如「帮我审查这个 skill」「skill 质量怎么样」「这个 skill 能发布吗」>
> 输出:先单独一行写 【是否触发技能】 + 调用了哪个技能名(没调用就写"未触发任何技能"),然后另起一段输出真实回复。
判定标准:三句话都命中 skill-audit 才算通过;若有任何一句被别的 skill 抢走,回到 关卡 2d 收紧 description 与界线。
6b. 本地一致性自测(对应 关卡 5)
# 全机 name 唯一(应包含且仅包含一条 skill-audit)
for f in ~/.workbuddy/skills/*/SKILL.md; do
printf "%-50s " "$(basename $(dirname $f))"; grep -m1 "^name:" "$f"
done
# 静态结构自测(对应 关卡 1):对自己跑
python3 scripts/audit_static.py ~/.workbuddy/skills/skill-audit
# 子代理能否加载:让子代理执行 Skill(skill="skill-audit") 后回显其 description
6c. 静态结构自测(对应 关卡 1)
对自己跑 scripts/audit_static.py,必须 0 个 FAIL 才允许升版。本技能既然教别人「YAML 解析失败 = P0」,自己更不许犯。
报告格式
# Skill 审查报告:<name>
## 结论
<两到三句:能不能用、能不能上架、最大风险是什么>
## 问题清单
| 级别 | 问题 | 证据 | 修法 |
|---|---|---|---|
| P0 | <一句话> | <文件:行号 + 原文> | <具体改法> |
| P1 | ... | ... | ... |
## 各关卡结果
关卡0 先查市场 ✅ 无同类 / 已复用 XXX / 已装自检工具
关卡1 静态结构 ⛔ 2 个 P0
关卡2 防劣化 ⚠️ 1 个 P1(规则写在 references,主文件看不到)
关卡3 子代理实测 ⛔ 3 个真问题
关卡4 上架检查 ✅ 可上架
关卡5 本地一致 ✅ 正常
## 已豁免(非问题)
- <工具报了什么,为什么忽略>
级别定义:
- P0 — 导致 skill 加载失败、调不到、行为完全跑偏
- P1 — 能跑但明显劣化,AI 会多嘴、跳级、误触发
- P2 — 观感问题,不影响功能
工具分级映射:audit_static.py 的 FAIL = P0(阻断上架,退出码 1)/ WARN = P1~P2(建议)/ PASS = 通过。
执行
# 关卡 0:先查市场
python3 ~/.skillhub/skills_store_cli.py search <单个关键词> --json
# 关卡 1 + 4(静态)
python3 scripts/audit_static.py <skill目录>
python3 scripts/audit_publish.py <skill目录>
# 关卡 6(自我审查):用本技能审本技能
python3 scripts/audit_static.py ~/.workbuddy/skills/skill-audit # 6c 静态自测
# 6a 自动触发自测:spawn 干净子代理执行(见 关卡 6)
# 6b 本地一致性:全机 name 唯一扫描(见 关卡 6)
# 关卡 3(子代理实测)—— 由你 spawn 子代理执行
脚本只读,不改文件。改法由你给建议,用户确认后再动手。
脚本退出码:audit_static.py 有 FAIL 时返回 1,可直接用于 CI 拦截。
深入资料
references/pitfalls.md— 实测踩过的坑清单(发版、审核、专名、触发)references/workflow.md— 子代理实测的完整做法与 prompt 模板