来源:互联网 更新时间:2026-06-19 13:48
如何写出稳定可靠、触发精准的AI Skill?这篇文章分享的,是从10万行代码实践中提炼出来的专业方法论。
核心内容:
1. Skill的准确定义与核心结构 2. 入门级与专业级Skill的对比分析 3. 从脚本到专业工作手册的进阶路径
有没有过这种经历:给AI Agent写了一个Skill,它能跑,但总是触发不准、执行不稳、隔两天就出bug?就好比做菜——照着网上的菜谱做,味道是有了,但总觉得跟大厨做的差了点什么。
差的那点东西,就是
维护过一个10万行级别的Skill(WeWrite公众号全流程助手),从最初的一个简单脚本一路迭代至今。过程中踩过的坑、总结出的方法论,今天系统性地梳理出来。
30秒版本:
它不是提示词(prompt),也不是API文档,而是一份
一个Skill的物理结构大概长这样:
my-skill/
├── SKILL.md # 核心指令(必需)
├── scripts/ # 可执行脚本
│ └── helper.py
├── references/ # 参考文档
│ ├── api.md
│ └── best-practices.md
└── templates/ # 模板文件
└── output.md
SKILL.md是唯一必需的文件,其他都是辅助。但
用两个真实案例来说明差距。
这是一个查询AI资讯的Skill,核心功能正确,结构也算清晰。它的frontmatter长这样:
---
name: aihot
description: AI HOT 资讯查询 Skill。当用户想知道"今天 AI 圈有什么"时使用。
---
工作流部分只有一段核心命令:
since=$(date -u -v-24H +%Y-%m-%dT%H:%M:%SZ)
curl -s "https://aihot.virxact.com/api/public/items?mode=selected&since=$since"
同样是完成一个任务,WeWrite这个公众号写作Skill多了不少东西:
| 维度 | 入门级 (aihot) | 专业级 (WeWrite) |
|---|---|---|
| Frontmatter | name + description | 完整元数据 + tags + related_skills + version |
| 触发条件 | 一句话描述 | 20+ 触发关键词 + 反向触发词(何时不 |
| 工作流 | 1 个主路径 | 8 步流水线,每步有输入输出定义 |
| 错误处理 | 无 | 每个步骤有 fallback + 已知坑位手册 |
| 辅助文件 | 无 | references/ (7个文档) + scripts/ (5个脚本) + personas/ (人格库) |
| 验证方法 | 手动测试 | 自动化质量检查(禁用词扫描、human-ness 评分) |
| 迭代机制 | 无 | history.yaml 记录每篇文章的元数据,避免重复 |
这是最重要,也最容易被忽视的部分。
name 和 description。入门级写法:
---
name: my-skill
description: 帮我做 X 事
---
问题在于:太泛了。"帮我做X事"可以匹配任何请求,结果要么是
专业级写法:
---
name: commit-message-generator
description: |
Use when the user wants to generate conventional commit messages based on
staged git changes. Covers feat/fix/docs/refactor/test/chore types.
Triggers on: "commit message", "生成提交信息", "git commit", "提交说明".
Do NOT use for: general text writing, PR descriptions, or changelogs.
version: 1.2.0
author: your-name
license: MIT
metadata:
hermes:
tags: [git, commit, conventional-commits, automation]
related_skills: [github-pr-workflow, github-code-review]
---
关键改进在哪里:
入门级的指令通常是段落式的:
先拉数据,然后处理一下,最后输出
问题在于,Agent对"处理一下"的理解可能跟你完全不同。
专业级用的是
| 参数 | 值 | 说明 |
|---|---|---|
| 端点 | /api/public/items |
主数据接口 |
| mode | selected |
精选模式(默认) |
| since | 动态计算 | 最近 24 小时 |
# 计算时间窗口(兼容 macOS 和 Linux)
if [[ "$OSTYPE" == "darwin"* ]]; then
since=$(date -u -v-24H +%Y-%m-%dT%H:%M:%SZ)
else
since=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)
fi
curl -sH "User-Agent: $UA" \
"https://example.com/api/public/items?mode=selected&since=$since&take=50"
{id, title, category, url, published_at}。下一步将输出传入Step 2进行过滤。
注意这几个细节:
入门级Skill假设一切顺利。专业级Skill假设
下面是一段pitfalls章节的写法示例——每个坑都按"现象→原因→处理"三段式展开:
items 数组为空,但HTTP状态码是200。原因:时间窗口内无数据,或 since 参数格式错误。
# 检查返回是否为空
response=$(curl -s "...")
count=$(echo "$response" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))")
if [ "$count" -eq 0 ]; then
echo "⚠️ 无数据,尝试扩大时间窗至 7 天"
since=$(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)
# 重试...
fi
直接curl返回403 Forbidden。原因:API端点有UA黑名单。处理:所有curl必须带浏览器UA。
中文显示乱码。原因:远程终端locale不是UTF-8。处理:传递数据用纯ASCII JSON文件,不在命令行中硬编码中文。
SKILL.md有
当Skill复杂度上升时,解决方案不是把SKILL.md写得更长,而是
professional-skill/
├── SKILL.md # 核心(控制在 8-15K 字符)
├── references/
│ ├── api-reference.md # API 完整文档
│ ├── error-codes.md # 错误码对照表
│ └── best-practices.md # 最佳实践
├── scripts/
│ ├── validate.sh # 自动化验证脚本
│ └── deploy.sh # 部署脚本
└── templates/
└── output-template.md # 输出模板
SKILL.md里只保留简短引用指向细节,比如API文档部分可以这样写:
详见 `references/api-reference.md`,覆盖以下端点:
- 数据采集(3 个端点)
- 内容发布(2 个端点)
- 媒体上传(1 个端点)
| 端点 | 用途 | 认证 |
|---|---|---|
/api/data |
数据采集 | 无 |
/api/publish |
发布内容 | OAuth |
/api/media |
上传图片 | OAuth |
专业Skill都有自检能力。最基础的是
--- 开头,无前导空白行name ≤ 64 字符,仅小写字母 + 连字符description ≤ 1024 字符,包含触发词 + 反向触发词curl 命令都带了正确的 User-Agentrelated_skills 引用的 Skill 确实存在进阶做法是写一个
#!/usr/bin/env python3
"""Skill 质量检查工具"""
import yaml, re, pathlib
def validate_skill(skill_path: str) -> dict:
path = pathlib.Path(skill_path)
content = path.read_text()
issues = []
# 检查 1: frontmatter 格式
if not content.startswith("---"):
issues.append("❌ 必须以 --- 开头")
# 检查 2: description 长度
fm = yaml.safe_load(content.split("---")[1])
desc_len = len(fm.get("description", ""))
if desc_len > 1024:
issues.append(f"❌ description {desc_len} 字符,超过 1024 限制")
# 检查 3: 代码块数量(教程型 Skill 要求 ≥ 5)
code_blocks = re.findall(r"```[\s\S]*?```", content)
if len(code_blocks) < 5:
issues.append(f"⚠️ 只有 {len(code_blocks)} 个代码块,建议 ≥ 5")
# 检查 4: 是否有 pitfalls 章节
if "## Common Pitfalls" not in content and "## pitfalls" not in content.lower():
issues.append("⚠️ 缺少 pitfalls 章节")
return {
"skill": skill_path,
"valid": len([i for i in issues if i.startswith("❌")]) == 0,
"issues": issues,
"stats": {
"size_chars": len(content),
"code_blocks": len(code_blocks),
"has_pitfalls": "pitfalls" in content.lower(),
}
}
if __name__ == "__main__":
import sys, json
result = validate_skill(sys.argv[1] if len(sys.argv) > 1 else "SKILL.md")
print(json.dumps(result, indent=2, ensure_ascii=False))
运行效果:
$ python3 validate_skill.py SKILL.md
{
"skill": "SKILL.md",
"valid": true,
"issues": [],
"stats": {
"size_chars": 12458,
"code_blocks": 7,
"has_pitfalls": true
}
}
理论讲完了,动手写一个。场景:
mkdir -p commit-gen/{scripts,references,templates}
touch commit-gen/SKILL.md
---
name: commit-message-generator
description: |
Use when user wants to generate conventional commit messages from staged
git changes. Supports feat/fix/docs/refactor/test/chore/style/ci/perf/revert
types. Triggers on: "commit message", "提交信息", "git commit", "生成提交",
"commit msg". Do NOT use for: PR descriptions, changelogs, release notes.
version: 1.0.0
author: your-name
license: MIT
metadata:
hermes:
tags: [git, commit, conventional-commits, automation]
related_skills: [github-pr-workflow]
---
Skill的主体部分从获取diff开始。如果没有staged变化,先提示用户 git add:
git diff --cached --no-color
然后根据变更内容判断commit type:
| 变更特征 | type | 示例 |
|---|---|---|
| 新功能/新文件 | feat |
feat: add user login endpoint |
| Bug 修复 | fix |
fix: null pointer in auth middleware |
| 文档变更 | docs |
docs: update API reference |
| 重构(不改变行为) | refactor |
refactor: extract validation logic |
| 测试相关 | test |
test: add coverage for auth flow |
| 构建/CI 相关 | ci |
ci: upgrade node version to 20 |
| 性能优化 | perf |
perf: reduce DB queries by 50% |
生成的commit message遵循Conventional Commits规范:第一行 type(scope): subject(≤ 50字符),第二行空行,正文可选(说明why不是what),页脚可选(Breaking Change / Closes #123)。示例输出:
feat(auth): add OAuth2 Google login
- Integrate with Google Identity Platform
- Support token refresh flow
- Add unit tests for token validation
Closes #42
最后用户确认后执行:
git commit -e -F /tmp/commit-msg.txt
git add 就触发了Skill。处理:检测staged变化数量,为0时提示而非报错。
Verification Checklist:
-e flag 允许用户编辑运行验证:
python3 scripts/validate_skill.py commit-gen/SKILL.md
最后,给你一个速查表。下次写Skill的时候逐项打勾:
| 层次 | 检查项 | 入门 | 专业 |
|---|---|---|---|
| Frontmatter | name/description 清晰 | ✅ | ✅ |
| 包含触发词 + 反向触发词 | ❌ | ✅ | |
| 有 version/author/metadata | ❌ | ✅ | |
| 结构 | 分步骤工作流 | ✅ | ✅ |
| 表格定义参数 | ❌ | ✅ | |
| 代码块可直接运行 | ⚠️ | ✅ | |
| 明确输入输出格式 | ❌ | ✅ | |
| 鲁棒性 | 有 pitfalls 章节 | ❌ | ✅ |
| 覆盖 ≥ 3 个错误场景 | ❌ | ✅ | |
| 兼容性处理(OS/版本) | ❌ | ✅ | |
| 工程化 | 拆分 references/ | ❌ | ✅ |
| 有验证脚本 | ❌ | ✅ | |
| 有历史记录机制 | ❌ | ✅ | |
| 总工作量 | 30 分钟 | 2-4 小时 |
如果你的Skill只用一次,入门级就够了。但如果它会被反复调用、给别人用、或者承载关键业务流程,花时间做到专业级是值得的——回报是调试时间的数量级减少。
本文基于Hermes Agent Skill系统(hermes.nousresearch.com)和WeWrite公众号流水线的实战经验写成。文中所有代码片段均可直接复制运行。
《Off Campus》第二季官宣:这对CP还在,但不再是主角
和平精英如何做到压枪稳-和平精英怎样才能压枪稳
客单价碾压宝马奥迪!极氪5月交付新车34377辆:连续4个月双增长
HBO 奇幻剧《龙之家族》第三季定档 6 月 22 日,最终预告片曝光喉道海战
币安Binance虚拟货币交易平台 币安官方APP安卓苹果下载入口
帅气继父网名女生可爱英文(精选100个)
帅到极致的网名女生霸气(精选100个)
DOTA2 TI时隔七年重返上海!门票6月10日开抢,国服享受优先购买!
蒙古上单是什么梗
韦一敏是什么梗
韩漫小少爷网名大全女生(精选100个)
网络热词聊污是什么意思
如何在夸克浏览器中开启网页视频的倍速播放功能?
欧易OKX官方网站直达入口 2026欧易官方App安卓版v7.1.0下载安装
抖音最火沙雕男生网名(精选100个)
作家助手如何上传自制封面 作家助手如何设置小说的封面
阿里发布Qwen3.7-Max大模型,全球第五、国产第一
金铲铲之战s17六暗星卡莎阵容玩法构筑指南
三角洲行动卡战备怎么弄 三角洲行动卡战备攻略
因空难被判“过失杀人罪” 空客、法航均被顶格处罚22.5万欧元
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc