写给 Agent 的说明书:一份好的 Skill 文档长什么样
一、引子:Agent 不是不会做,是不知道你的环境
过去一年多,我给自己的 AI 助手写了十几份 Skill 文档——有操作浏览器抓数据的、有整理本地文件归档的、有跑固定分析流程的。写完回头看,同一个任务,"有没有一份写得好的 Skill"带来的差别,比"换一个更强的模型"大得多。
差别在哪里?不在模型会不会写代码。在于它知不知道:
- 这台机器是 Windows,
python要写成py,路径要用C:/而不是C:\; - 那个网站的登录态放在哪里,为什么你给的链接是一次性的;
- 这个接口的返回体里,
is_finish: 0表示"没做",而不是false; - 出现某个报错时,第一步不是重试,而是先看页面还在不在。
这些信息,人做一次就记住了,Agent 每次都是新人。Skill 文档的全部意义就是:把"只有干过才知道的事"沉淀下来,让下一次不必重头摸索。
下面是我踩完之后总结的 7 条规则。
二、规则一:description 决定"要不要加载",正文决定"能不能做成"
大多数 Agent 平台的加载机制是两段的:先只看 Skill 的一行描述,判断这个任务要不要把完整文档读进来;读进来之后,才看正文。
这意味着两个东西必须分开写:
- description 是广告,要写触发条件,不是功能列表。
- 正文是手册,要写操作细节,不写宣传语。
一个反例(我最早的写法):
description: 帮助处理数据文件
一个正面写法:
description: 把本地 JSON 收藏夹导出成可检索的 HTML 清单。
当用户说"整理收藏""把 XXX 导出成网页""生成清单"时使用;
不要用于在线抓取或 Excel 转换。
区别在哪里?第二种写了 什么时候用,还写了 什么时候不用。"什么时候不用"这半句常被忽略,但它能挡掉大量误触发——Agent 一旦误加载了不该用的 Skill,后面所有步骤都会被带偏。
三、规则二:把环境假设写死到能照着抄的程度
写文档的人总觉得"这个大家都知道"。Agent 不知道。
凡是涉及环境的,一律写具体值,不写抽象描述:
| 不要写 | 要写 |
|---|---|
| 用 Python 运行脚本 | Windows 上用 py -3 xxx.py,因为这台机器 python 指向 Store 存根 |
| 打开编辑器页面 | 编辑器地址是 https://.../article,注意 /blogs/create 会跳转到首页 |
| 用绝对路径 | 路径写成 C:/Users/xxx/work/task-01.mjs,反斜杠在 JS 字符串里是转义符 |
| 循环执行 | 每轮写一个新文件 round-01.mjs、round-02.mjs,不要改旧文件——改旧文件会把已经执行过的步骤重放一遍 |
最后一条是我付出过代价的:早期我把"脚本"当成一次性文件反复覆盖,结果某次 Agent 顺着历史把自己重新跑了一遍,重复提交了两条公开内容。从那以后,规则变成"一轮一个新文件,文件名带序号和日期"。
同一类坑还有:脚本运行环境不继承你 shell 里的环境变量。你在终端 export 了一堆东西,Agent 跑起来 process.env 里什么也没有。所以所有输入都直接写进脚本,不要指望环境变量传递。
四、规则三:每一步后面接一个"如果失败,看什么"
新手写的 Skill 是"正常路径说明书",老手写的是"失败路径说明书"。
正常的操作,Agent 靠常识也能摸出来;真正浪费时间的,是它卡住之后胡乱重试。所以每个关键动作后面,最好跟一句失败分支:
1. 打开任务页,等待 3~5 秒(页面数据是异步拉的)。
失败表现:页面显示"请登录"。
→ 不要重试,登录态已失效,转 2。
2. 登录态失效时,把浏览器停在登录页,交给用户手动登录,
不要尝试用 URL 里的 ticket 参数复现登录——那是一次性凭证,
在用户浏览器里已经被消费过,复用必然失败。
3. 登录成功后回到任务页,先确认用户名出现,再继续。
这段里最有价值的是"不要做什么"。Agent 的默认倾向是"再试一次",而很多场景下重试是有害的:重复提交、重复发帖、触发风控、把一次性凭证用废。
我个人经验:一份 Skill 里,否定句的价值大约是肯定句的三倍。
五、规则四:只写"人类不会想到要写"的信息
文档最大的浪费不是写少了,是写多了。凡是维基百科、官方文档、模型已经知道的东西,都不要抄。
值得写进去的,通常只有三类:
1. 平台的反直觉限制
比如某平台的文章标签不支持手动添加、只吃系统自动匹配的结果;某表单的必填项不填时只弹一个没有字段名的提示;某个"同意协议"的勾选框其实是个 span,input.click() 无效,必须派发真正的点击事件。这些内容在任何官方文档里都查不到,但不知道就做不完。
2. 只有踩过才知道的时序
"提交后积分不会立刻到账,通常几分钟后才更新"——这种信息决定了 Agent 是"提交完就报告成功",还是"提交完等一会儿再核对"。
3. 明确的验收标准
"任务做完了"必须有可观测的判据:某个字段变成 1、某个按钮变成禁用、某处出现一串特定文案。没有判据的 Skill,Agent 会在"我觉得差不多了"的时候停下。
六、规则五:把输出定义成接口,而不是一段话
如果 Skill 的输出要进入下游流程,就必须像接口一样定义:
返回:JSON 数组,每项包含
id string 唯一标识
title string 标题,已去除首尾空白
status enum done | pending | failed
失败时:返回 { "error": "...", "at_step": "..." }
定义清楚之后,好处立刻出现:Agent 不需要"感觉一下结果对不对",脚本可以直接判定;出了问题也能定位到步骤,而不是拿到一段"大概是什么地方错了"的自述。
顺手推荐一个小习惯:让 Skill 把中间产物落盘。原始响应存一份、解析后的结构存一份、日志存一份。这跟写代码打日志是一个道理——出事时你只有现场。
七、规则六:先选观察手段,再写动作
这一条是给"要操作界面"的 Skill 的。
同样是点一个按钮,有两条路:
- 语义路:拿页面的可访问性快照,用角色和名称定位元素。稳、可读、页面小改版还能活。
- 视觉路:截图 + 坐标点击。适用于画布、富文本、表格这类没有语义的界面。
我写过的 Skill 里都明确写了优先级:能用语义就不用坐标;一旦用了坐标,必须紧跟一次截图验证。原因是坐标点击是"哑操作",点歪了不会报错,只会静默失效,然后后面的每一步都在错误状态上继续跑。
同样重要的是等什么。固定 sleep(3000) 是最差的写法,因为它既慢又不可靠。更好的写法是等一个可观测条件:等某个元素可见、等 URL 变化、等某个全局变量变成 true。Skill 里要把这些"等待条件"写出来,因为 Agent 不知道你的系统里什么信号代表"加载完成"。
八、规则七:克制——Skill 不是 README,也不是软文
最后一条是纪律问题。Skill 文档是给机器读的执行手册,它应该:
- 用短句和列表,不用长段落铺陈背景;
- 给确定的命令,不给"你可以考虑使用……"这种开放式建议;
- 不写营销语气,不写"业界领先""一站式解决方案";
- 不重复,同一个约束说了两遍就删一遍——重复会让 Agent 误以为那是重点;
- 不超过必要的长度。文档越长,模型越容易在中间段"看漏",这是常识,也是我实测里最明显的一个现象。
一个可操作的判断标准:如果某一段删掉之后,Agent 的操作不会变差,那这段就该删。
九、一个真实的对照
同一件事——「跑完脚本后检查结果」——两种写法:
差版:
运行脚本,然后检查输出是否正确。
好版:
运行 py -3 check.py(工作目录必须是仓库根目录)。
判定标准:
- 退出码 0 且 stdout 最后一行以 "OK" 开头 → 成功,继续下一步
- 退出码 0 但出现 "UNVERIFIED" → 结果存疑,把 stdout 全文贴给用户,不要自行下结论
- 退出码非 0 → 不要重试;先读 logs/last-run.log 的最后 30 行,
按三类分流:网络错误(可重试一次)、权限错误(转人工)、
解析错误(说明数据结构变了,停止)
差版看起来很通顺,但 Agent 拿到它只能靠猜。好版把一个模糊动作拆成了三条规定动作加三条分流规则,写起来多花五分钟,后面少返工半小时。
顺带说一句:好版里那种「停止」「不要自行下结论」的指令非常关键。Agent 在有压力(有任务、有目标)的时候,倾向于把不确定的结果解释成成功。明确告诉它「这里可以停下」,比要求它「尽量完成」有用得多。
十、自检清单
写完之后,我用这 8 条过一遍:
- description 里有没有写"什么时候用"和"什么时候不用"?
- 每个环境相关的细节,是不是具体到了可以照抄的程度?
- 关键步骤后面,有没有跟着失败分支和"不要做什么"?
- 有没有写"验收判据"?Agent 怎么知道自己做完了?
- 输出是不是结构化到你不需要"感觉"就能判断对错?
- 涉及界面的地方,观察手段和等待条件是否明确?
- 有没有为了显得完整而写进去的、其实没人需要的背景?
- 如果换一台机器、换一天让另一个人(或另一个 Agent)照着做,能不能不问你任何问题就跑完?
第 8 条是最狠的:Skill 的验收标准是"零追问可执行"。
十一、写在最后
我很喜欢一句话:文档是给"下一个接手的人"写的,只是那个人现在恰好是 AI。
给 Agent 写文档,本质上是在做一件很古典的工程工作——把隐性知识显性化、把环境约束写死、把失败模式列全。它不需要你更懂模型,只需要你更诚实地面对"我刚才到底是怎么做成的"。
我现在的习惯是:每做完一件"以后还会再做"的事,顺手把 Skill 补一版。补的时候只写今天新踩的坑,不重写全文。几个月下来,那份文档就变成了一件挺值钱的东西——它记录的已经不是怎么做,而是"哪条路走不通"。
这一点,模型换代也带不走。
- 点赞
- 收藏
- 关注作者
评论(0)