为什么你写的Agent Skill总被模型忽略?缺的不是Prompt技巧,是文档规范
我检查了自己 11 个 Agent Skill 的使用统计。有一个数据让我愣了几秒。
创建几天了,使用次数:0。
不是模型不够聪明。不是 Prompt 写得差。是那个 Skill 的文档写成了"自嗨型说明书"——Agent 根本不知道什么时候该用它。
它负责的是 Gateway 配置——启动、排查、调试消息平台连接,是我日常最高频的操作之一。但 Agent 一次都没调用过它。
我翻出它的 SKILL.md,看了 30 秒就找到了原因。
它的 trigger 写了三个词:"gateway"、"启动 gateway"、"gateway 配置"。而我有另一个 Skill,trigger 里也写了 "gateway setup"、"gateway 配置"。两个 Skill 的触发条件几乎一样。
Agent 面对两个"声称能做同一件事"的 Skill,不知道该选谁。于是它做了最省事的选择——两个都不选。
改了文档之后,同一个 Skill 开始被正常调用。
这篇文章不讲 prompt 怎么写。讲一个更根本的问题:你的 SKILL.md 不是一篇"给 AI 的指令",是一份"给 Agent 的接口文档"。文档结构不对,prompt 写得再好也没用。
——————————————————————————————
SKILL.md 就是一份 API 文档
Agent 读取 SKILL.md 的方式,跟开发者阅读 API 文档的方式完全一致。它不是在"理解你写了什么",它是在做一件事:在当前对话里扫描所有可用的接口,匹配最合适的那个。
把 Skill 想象成一个 API 端点,四要素的对应关系一目了然:
|
API 文档里有什么 |
SKILL.md 里对应什么 |
它回答的问题 |
|
端点 URL,比如 GET /users/{id} |
triggers 列表 |
"什么时候调用我?" |
|
请求/响应说明 |
description |
"我能做什么,返回什么?" |
|
错误码 |
边界声明 |
"什么时候不要调用我?" |
|
curl 命令示例 |
对话示例 |
"用起来到底长什么样?" |
大部分 Skill 被 Agent 忽略,不是因为 prompt 写得不够好,而是因为四个要素里面至少缺了两个。就像一个 API 文档没有端点 URL 也没有错误码——开发者找不到入口,调错了也不知道为什么。
不同 Agent 平台的 SKILL.md 格式略有差异(有些只有 name + description,有些有独立的 trigger 列表),本文以 Hermes Agent 为例,但四要素原则通用。
下面逐个拆解。
——————————————————————————————
规范一:Trigger 要精确到"场景",不是"关键词"
这是最致命的死因。所以我放第一个讲,也给最多篇幅。
用 API 来类比:端点写成 GET /users 和写成 GET /users?role=admin&status=active。后者更精确,但调用率反而更高——因为调用者看完就知道"这就是我要的接口"。
Skill 的 trigger 同理。你写得越模糊,Agent 越不敢用。
反面案例:两个 trigger 重叠的 Skill。
Skill A 的 trigger:
- "gateway"
- "启动 gateway"
- "gateway 配置"
Skill B 的 trigger:
- "gateway setup"
- "gateway 配置"
- "gateway 连接"
用户说了一句"gateway 启动报错"。两个 Skill 的 trigger 都匹配了。Agent 面临一个二选一:它不知道这两个 Skill 有什么区别,也不知道该用哪个来解决"启动报错"这个问题。
Agent 的选择逻辑很简单——如果两个候选看起来都能用,且无法判断优劣,就降低调用概率。两个都不选,比选错更安全。
结果:Skill A 使用次数 0。
正面案例:精确到"动作 + 内容类型"的 trigger。
Skill C 的 trigger:
- "用户分享了一份职业转型计划"
- "用户问'这个方向可行吗'并附上了具体方案"
- "用户提供了自我评估数据,想匹配市场机会"
每一条都包含了两层信息:用户做了什么(分享了计划 / 问了可行性 / 提供了数据)+ 涉及什么内容(职业计划 / 具体方案 / 评估数据)。Agent 几乎不可能误判。
可操作原则:
1. 每条 trigger 至少包含"动作 + 内容类型",不要只放关键词
2. 写完后检查:跟其他 Skill 的 trigger 有没有重叠?有重叠就必须加限定词区分
3. 删除宽泛词("配置""管理""优化""排查"),改成具体场景("配置文件报错""启动失败排查""端口冲突")
一个简单的自查方法:把你的 trigger 列表读一遍,想象自己是 Agent——看到这些 trigger,你能确定"这个 Skill 和另一个有什么区别"吗?如果不能,Agent 也不能。
——————————————————————————————
规范二:Description 要写"能做什么",不是"是什么"
继续用 API 打比方。两份 API 描述:
"Returns user data."
"Returns user profile including name, email, and role. Use this when you need to display user info in a dashboard or verify permissions."
后者没有多写任何技术细节,只是多说了两件事:输出具体包含什么、什么场景用它。开发者看完就知道什么时候该调。
反面案例:只说了"是什么"。
Skill D 的 description:
管理、配置和排查 Agent 本身。
Agent 读完知道:哦,这个 Skill 跟 Agent 管理有关。但知道这个有什么用?它不知道什么时候该用——用户说"帮我查一下配置",该用这个还是用另一个?用完了能得到什么——一条命令、一个配置文件、还是一段解释?
正面案例:写了"能做什么 + 产出什么 + 什么场景"。
Skill E 的 description:
帮用户把模糊的业务需求拆解成清晰的自动化工作流。输出可直接在 Coze、Dify、n8n 等平台落地的节点图和工作流描述。
三句话把三件事全讲清楚了:
- 输入:模糊的业务需求
- 输出:节点图 + 工作流描述(可直接落地)
- 场景:用户想在 Coze/Dify/n8n 等平台搭自动化
Agent 读完就知道"用户说我想自动化 XX 流程 → 找 Skill E"。
一个简单的检验方法:把 description 里的 Skill 名字遮住,只看剩下的文字。 如果看完还是不知道"当前这个对话该不该用这个 Skill",说明你写的是产品简介,不是触发条件。
可操作原则:每条 description 必须回答三个问题:
1. 用户给我什么?(输入)
2. 我产什么结果?(输出)
3. 什么场景用我,而不是其他 Skill?
——————————————————————————————
规范三:边界声明——"什么时候不要用我"
API 文档如果没有错误码,调用者调错了只能猜。SKILL.md 如果没有边界声明,Agent 在不该出现的场景里强行输出——用户看到的结果就是"这 AI 怎么这么蠢"。
正面案例。
Skill F 的 SKILL.md 里专门有一节叫"诚实边界",明确列了这个 Skill 做不到什么。Skill G 在注意事项里写了一行:"如果用户问的是纯技术问题,切换回正常模式。"
就一行字。但它阻止了一个经典翻车场景:用户问"这个 bug 怎么修",Agent 还在用温柔共情的语气回复"听起来不容易"。读者会直接关掉页面。
反面案例:完全没有边界声明。
大部分 Skill 根本没写这节。结果就是:
- 用户问技术问题 → Skill J 还在温柔共情
- 用户想快速解决 → Skill H 开始长篇大论
- 用户只想查一个命令 → Skill I 开始拆解整个业务流程
Agent 不是故意的。是你没告诉它"什么时候该闭嘴"。
可操作原则:加一节"何时不应触发"或"注意事项"。三种写法:
- 排他声明:"只用于 X,不用于 Y"(如"只负责运行时排错,不负责初始配置")
- 依赖声明:"需要先配置 X 才能用"(适用于有前置依赖的 Skill)
- 替代声明:"如果是 Y 场景,用其他 Skill"(解决 trigger 重叠最有效)
至少写两件事:
1. 什么场景下,即使用了 trigger 匹配,也不该激活
2. 这个 Skill 明确做不到什么
——————————————————————————————
规范四:示例——给 Agent 一个"参考答案"
Stripe 的 API 文档最有名的是什么?不是参数说明有多详细——是每个端点都有一个可以复制粘贴的 curl 命令。
开发者不需要理解,照着跑就行。Agent 也一样。
正面案例。
Skill G 在正文最后给了一段完整的对话示例——用户说什么,Agent 应该回什么。Agent 读到这一段时,不需要"理解"什么叫友好回复,它直接看到了一个标准答案。
反面案例:有方法论,没示例。
很多 Skill 洋洋洒洒写了流程、设计哲学、方法论框架,但到了最关键的地方——"用户输入 X,我该输出 Y"——没了。Agent 读完整篇 SKILL.md 的感受是"这个 Skill 理念很好",但不知道具体怎么用。
一个微型对比:
Before(没有示例):
用户:"gateway 启动报错"
→ Agent:不确定这个 Skill 具体怎么处理,没调用
After(加了示例):
用户:"gateway 启动报错"
→ Skill 读取 gateway 日志 → 定位到端口冲突 → 返回:netstat -ano | findstr :8080
加了示例之后,Agent 不需要猜测"排查故障"具体意味着什么——它有了一个可直接套用的模板。
可操作原则:至少给一个完整的输入→输出示例。 不一定覆盖所有情况,但要给 Agent 一个"标准答案"当参照。Agent 对示例的跟随度,远高于对文字描述的跟随度。
——————————————————————————————
一个 Skill 的完整改造:四要素 Before / After
回到开篇那个 0 次调用的 Skill。
我把它按四个规范完整改了一遍。下面是改造前后的对照:
|
要素 |
Before(使用次数:0) |
After |
|
Trigger |
"gateway"、"启动 gateway"(跟 Skill B 重叠) |
"gateway 启动报错"、"gateway 端口冲突"、"gateway 连接超时"——精确到故障场景,去除了跟 Skill B 的重叠 |
|
Description |
"配置、启动、停止和调试 Gateway 消息平台"——只说了是什么 |
"当需要启动 gateway 服务、排查连接失败、或诊断消息平台通信问题时使用。注意:平台接入凭证(App ID / Token)的配置请用 Skill B。"——说了场景 + 产出 + 边界 |
|
边界声明 |
无 |
"本 Skill 不负责飞书/Telegram/Discord 的 App ID 配置(用 Skill B),也不涉及代码项目开发。" |
|
示例 |
无 |
用户:"gateway 启动后飞书收不到消息" → 检查运行状态 → 验证 webhook 配置 → 返回具体修复命令 |
改造前:Agent 面对它和 Skill B,不知道有什么不同、不知道该选谁、不知道选完能干什么。结果使用次数 0。
改造后:trigger 精确到具体故障场景,description 直接告诉 Agent"注意——如果你要配飞书 App ID,别找我,找 Skill B",示例给出了标准处理流程。
——————————————————————————————
改完文档之后
改完文档之后,Agent 开始调用那个 Skill 了。但不是每次都调。有时我写了完美的 trigger,它还是选了另一个 Skill。
写 SKILL.md 的时候,假设读它的 Agent 对这个 Skill 一无所知,只有 3 秒钟决定要不要用它。这 3 秒里,description 决定生死。它只看你写下来的东西。
文档规范解决的是"能不能被找到"的问题。但被找到之后呢?当 11 个 Skill 同时在场,Agent 怎么排序、怎么决定优先级——那涉及 Skill 的检索和加载机制。这是我接下来要去搞清楚的事。
——————————————————————————————
附:SKILL.md 四要素自检清单
复制这段,逐项对照你自己的 SKILL.md 打勾:
### Trigger(端点路由)
☐ 每个 trigger 至少包含"动作 + 内容类型",而非单个关键词
☐ 没有两个 trigger 含义重复
☐ 与其他 Skill 的 trigger 有明显区分度(用 grep 检查重叠)
### Description(接口说明)
☐ 写了"我接收什么输入"
☐ 写了"我产出什么输出"
☐ 写了"什么场景用我,而不是其他 Skill"
### 边界声明(错误码)
☐ 有"何时不应触发"或"注意事项"小节
☐ 写了至少一条"即使用了 trigger 匹配也不该激活"的场景
☐ 写了至少一条"这个 Skill 明确做不到"的事
### 示例(curl 命令)
☐ 有至少一个"用户输入 → Skill 输出"的完整示例
☐ 示例覆盖了最常见的触发场景
更多推荐

所有评论(0)