logo
0
1
WeChat Login

如何构建你自己的 Skill 工作流

本文档不描述任何具体业务流程,只讲「方法论」:把一套重复发生、涉及多工具协作的人工流程,如何拆解、封装、编排成一份 AI 可稳定复用的 Skill。

一份好的 Skill,本质是把你脑子里的「工作流」显式化,并让 AI 能以最少的询问最少的状态维护最少的错误把它跑完。


零、前置条件:先把流程想清楚,再谈 Skill

在动手写任何一份 Skill 之前,你必须接受一个核心认知:

Skill 不是"让 AI 变聪明"的魔法,而是把你脑子里本来就清晰的流程,写下来让 AI 照着跑。 如果流程本身是模糊的、靠经验拍脑袋的、每次做法都不一样的——那不是 AI 能解决的问题,而是你自己还没想明白。

AI 惧怕模糊

AI 在执行指令时有一个很明显的特征:

  • 指令越清晰、边界越明确、路径越唯一,AI 的执行准确率越接近 100%。
  • 指令越模糊、判断点越多、分支越隐式,AI 的准确率会以指数级下降——不是线性下降,是指数级。

模糊指令的典型长相:

  • 「差不多就行」「一般这么做」「视情况而定」
  • 「你看着办」「应该不会有问题」「先试试看」
  • 关键变量不说从哪来、多个步骤之间的衔接靠默契
  • 失败了怎么办没人说、成功的标志是什么也没人定义

这些在人类工程师看来"大家都懂"的话,对 AI 来说都是灾难级的不确定性。AI 会在这些模糊点上开始猜测,而每一次猜测都是一次出错的机会。

可 Skill 化的流程,必然满足:清晰、可预测、有迹可循

一条合格的流程,哪怕完全不用 AI、全部交给人来做,也应该能满足:

  1. 清晰:每一步的输入、输出、成功标志都能用一句话讲清楚。
  2. 可预测:相同输入走相同路径,产生相同结果。
  3. 有迹可循:换一个新人,按文档能跑通,不需要依赖某个"老司机"的个人经验。
  4. 可脚本化:每一步至少在理论上能写成 shell / Python 的一行命令;如果某步必须"人看着办",那这一步就是流程的断点,要么显式化,要么移出 Skill 范围。

一个简单的自测方法:假设你明天离职,让一个新入职的同事只看你写的文档就能把这个流程完整跑一遍——如果能,这流程才值得 Skill 化;如果不能,先把文档补齐,再谈自动化。

在做之前,问自己三个问题

在你打开编辑器准备写 SKILL.md 的第一行之前,先拿一张纸,老老实实回答清楚下面三个问题:

  1. 这个流程要干什么?(目标——一句话讲清楚交付物)
  2. 这个流程怎么做?(路径——能列出 N 个不重不漏的步骤)
  3. 这个流程解决什么问题?(价值——不做它会有什么代价、做了能省多少时间)

如果第 1 题答不上:你还没想清楚要做什么,不要写。 如果第 2 题答不出清晰的步骤:先人工跑几次把路径摸出来,不要写。 如果第 3 题答不上:可能这件事根本不值得 Skill 化,不要写。

顺序是:先流程化 → 再脚本化 → 最后 AI 化

一个很常见的误区是:跳过前两步,直接让 AI 来救场

正确的演进顺序应该是:

[人工操作]            ——原始状态,完全靠经验
    ↓  显式化
[文档化的 SOP]        ——换个人能看懂、能跑
    ↓  自动化
[脚本化的 SOP]        ——关键步骤有命令封装,不用记忆细节
    ↓  智能化
[AI 可执行的 Skill]   ——AI 串联脚本、推断参数、处理异常

每一层都是上一层的加速器,而不是替代品。 如果你跳过中间两步,直接从「模糊的人工操作」跨到「让 AI 来搞定」,那 AI 拿到的就是一堆前后矛盾的模糊指令,准确度必然大幅下降。

一句话总结AI 不是在"帮你想",AI 是在"帮你跑"。想清楚是你的事,跑得快才是 AI 的事。


一、什么样的流程适合封装成 Skill

同时满足下列多数条件的流程,收益最大:

  1. 重复性高:一周内你会做 3 次以上。
  2. 链路长:需要串联 3 个以上工具/命令/系统。
  3. 上下文强耦合:每一步都依赖上一步产出的信息(ID、Token、路径、容器名 ...)。
  4. 有稳定的 Happy Path:90% 的场景能走同一条主线。
  5. 可观测:每一步都能看到结果,失败可以定位到具体步骤。

反例(不适合):一次性任务、需要大量人工判断、没有稳定工具入口的流程。


二、设计原则(最重要)

在开始写 Skill 之前,先把下面 6 条原则想清楚。这比任何格式模板都重要。

原则 1:AI 推断优先,能不问就不问

不要让 AI 在流程开头问一堆「请告诉我 xxx」。凡是能从对话上下文工作区路径已有配置文件里推断出的信息,都让 AI 自己推断。

举例:你要 AI「调试某个服务的某个接口」,服务名在你自然语言里已经说了,工作区路径 AI 也能看到,这些都不该作为参数询问

落实方式:在 SKILL.md 的开头列一张「信息来源表」,明确告诉 AI 每个关键变量从哪里来、以及什么条件下需要主动获取。

| 信息 | 来源 | 何时主动获取 |
|---|---|---|
| 变量A | 用户自然语言 | 永不主动问 |
| 变量B | 工作区路径 | 永不主动问 |
| 变量C | 本地配置文件 | 文件不存在或字段为空时,执行 <发现命令> |

原则 2:持久化只留一层,且最小化

多层状态(session 缓存 + 磁盘缓存 + 环境变量 + .env ...)是 Skill 腐烂的根源。

规则

  • 整个 Skill 只允许一个持久化位置(例如 $HOME/.<your-skill>/env)。
  • 该文件只存必要的、不可推断的、且不敏感到需要密钥管理的变量。
  • 文件权限设置严格(如 chmod 600)。
  • 提供一个 reset 子命令用于彻底清空。

反模式:把任何「可以当场 docker ps 查出来」「可以当场从 git 推断出来」的值写进缓存。每次查永远比维护缓存更稳

原则 3:懒加载,而不是强制顺序

不要设计「必须先跑 A,再跑 B,再跑 C」的死板流程,那样 AI 和人都会出错。

正确做法:每个子命令自己检查并补齐它需要的前置依赖。

子命令 X 执行时:
  if 需要变量 V 且 V 不存在:
      自动执行获取 V 的逻辑
  if 凭证过期(如 HTTP 401):
      自动刷新一次后重试
  执行真正的业务逻辑

这让 AI 能直接「说干就干」,不需要在脑子里维护一张依赖顺序表。

原则 4:给 AI 一个统一入口

把你能封装的所有「细碎命令」,都收敛到一个脚本的若干子命令下。

<entry> discover        # 发现环境
<entry> login           # 登录
<entry> ensure-xxx      # 懒加载式准备某资源
<entry> call <...>      # 核心业务调用
<entry> env             # 导出可被 eval 的环境变量
<entry> env-reset       # 重置

为什么要封装?

把零散命令整合成统一入口,带来的收益是叠加的,不是线性的:

  1. 降低 AI 的认知负担:AI 需要记忆的"命令形状"从 N 个变成 1 个。AI 出错主要来自"选错工具"和"参数拼错",统一入口直接消灭了前者。
  2. 消除隐式知识:原本散落在工程师脑子里的「这里要加 header、那里要 base64、再那里要转义」全部沉淀到代码里。下次换个人/换个 AI 也能跑。
  3. 错误处理可以复用:鉴权失败、网络抖动、JSON 解析失败……这些边界情况在统一入口里只写一次,所有子命令共享。散装命令每条都要自己处理,覆盖不全就是坑。
  4. 实现可以替换,接口不变:今天底层用 curl,明天换 SDK,后天接内部 RPC,SKILL.md 和 AI 的使用姿势都不用改。这是长期维护性最大的来源。
  5. 天然形成统一日志 / 观测点:同一个入口输出同一种格式的 log / exit code,排查问题时不用在十个工具的输出格式之间跳来跳去。
  6. 把"串联"的复杂度下沉:原本 AI 需要在对话里做"先 A 再 B 如果失败就 C",现在这套编排写进脚本,AI 只需要调一个子命令。

一句话:统一入口 = 把流程的复杂度从"AI 对话层"下沉到"代码层"。代码是稳定的,对话是概率的。

怎么封装?—— 四步法

第一步:把所有人工操作列出来

把你在这个流程里会用到的所有命令,不分大小全部列出来。比如:

curl -X POST https://<host>/oauth/login ...
curl -X GET  https://<host>/api/v1/xxx -H "Cookie: ..." -H "Accept: ..."
docker exec -it <ctr> sh -c "..."
<cli-tool> resource list --format json | jq '.items[].id'
cat ~/.something/token
openssl rand -hex 16
...

第二步:按"领域"而不是"工具"分组

不要按「curl / docker / cli」分组——那是工具视角。要按「这个命令解决什么问题」分组——这是业务视角。

【发现类】:找出运行环境信息(host / client_id / user_id)
【鉴权类】:登录、拿 token、刷 cookie
【业务类】:调用具体接口、查询具体资源
【环境类】:导出环境变量、重置状态

第三步:每个分组收敛成一个子命令

每个子命令应该:

  • 名字是动词discover / login / call / ensure-token / reset,而不是名词。
  • 参数极少:能从配置文件 / 环境里读的,绝不作为参数。
  • 输出稳定:要么 exit 0 且输出可解析;要么 exit 非 0 且 stderr 说清楚错在哪。
  • 幂等:多次执行结果一致(尤其是 ensure-* 系列)。

第四步:子命令之间用"懒加载"串联,而不是"硬编码顺序"

错误做法:

# 要求用户必须按这个顺序跑,错一步全盘皆输
<entry> discover
<entry> login
<entry> ensure-token
<entry> call /api/xxx

正确做法:每个子命令自己检查依赖,缺啥补啥:

def cmd_call(path):
    ensure_host()      # 没发现过?自己 discover
    ensure_cookie()    # 没 cookie?自己 login
    resp = http_get(path)
    if resp.status == 401:
        refresh_cookie()   # 过期了?刷新一次再来
        resp = http_get(path)
    return resp

这样 AI 只要知道「我要调某个接口」,直接 <entry> call /xxx 就行,前置步骤不用它操心

封装前 vs 封装后(对比示例)

假设原本要调一个需要登录态的接口,散装命令是这样的:

# ❌ 封装前:AI 要管 5 件事,每件都可能出错
HOST=$(curl -s -I http://localhost/oauth/login | grep -i location | sed ...)
COOKIE=$(curl -s -X POST "https://$HOST/oauth/login" -d '...' -c - | grep SESSION | awk '...')
if [ -z "$COOKIE" ]; then echo "login failed"; exit 1; fi
RESP=$(curl -s "https://$HOST/api/v1/xxx" -H "Cookie: $COOKIE" -H "Accept: application/json")
echo "$RESP" | jq .

问题:

  • AI 要记住每一步的参数和 flag
  • 任何一步网络抖一下就要从头来
  • Cookie 过期没有重试机制
  • 换个 host、换个鉴权协议,整段都要重写

封装后:

# ✅ 封装后:AI 只要一行
<entry> call /api/v1/xxx

AI 看到的 SKILL.md 里只需要写:

调接口:<entry> call <path> [METHOD] [body],会自动处理登录、401 刷新、Accept 头。

信息量从 5 个命令 × 若干参数,压缩到了 1 个命令 + 1 行说明。这就是封装带来的确定性红利。

什么该封装、什么不该封装

该封装不该封装
多步、有状态、鉴权相关的操作单条、无状态、纯查询的命令(如 lspwd
涉及 JSON 解析、错误重试的逻辑标准工具已经做得很好的操作(如 git status
跨工具串联(curl + jq + docker)只调一次且未来不会再调的一次性命令
业务概念("创建一个测试环境")物理动作("执行 docker run")—— 后者应是封装内部实现

判断标准:如果一个操作需要 AI 「想一下怎么组合」,那就该封装;如果 AI 一条命令就能搞定,不需要封装。

封装的终极目标

让 SKILL.md 里出现的每一条命令,都是"业务语言"而不是"工具语言"。

  • 业务语言:<entry> call /api/v1/xxx./ops.sh start <service><entry> ensure-token
  • 工具语言:curl -X POST ... -H ... -d ...docker exec -it ... sh -c '...'jq '.items[].id'

AI 读 SKILL.md 的时候,看到的应该是一串串语义清晰的动作,而不是一堆 flag 的排列组合。

原则 5:语言选型按「谁更稳」

  • 网络调用、状态机、JSON 解析、鉴权 → 用 Python / Go,标准库优先,不引入第三方依赖
  • 容器操作、进程管理、文件挂载 → 用 Bash,它天生擅长,且在任何机器上都有。
  • 不要在 Bash 里写复杂 JSON 处理逻辑,也不要在 Python 里调一堆 subprocess 去做容器操作。

原则 6:每一步「有日志可查,有办法停下来」

Skill 最怕「跑到一半不知道发生了什么」。每一步都要保证:

  • 有观测点:日志文件路径固定、命令成功/失败 exit code 明确。
  • 有收尾:提供一个幂等的 stop / cleanup 命令,执行后回到干净状态。
  • 可迭代小循环:定义清晰的「改代码 → 重启 → 重试」三步循环,越短越好。

三、Skill 的目录骨架(推荐)

your-skill/
├── README.md              # 给人看:这个 Skill 是什么、怎么用、FAQ
├── SKILL.md               # 给 AI 看:完整 SOP(这是 Skill 的"主文件")
└── scripts/
    ├── <entry>.py         # 统一入口(推荐 Python,标准库)
    ├── <ops>.sh           # 系统级操作(容器/进程/文件)
    └── 00-ensure-<dep>.sh # 前置依赖自动安装

README.md vs SKILL.md 的分工

文件读者内容侧重
README.md人类开发者「它能干什么、我为什么要用它、快速上手」
SKILL.mdAI「在什么情况下触发、完整的 Step 1~N、每一步用哪个命令、边界条件、速查表」

二者有少量重复是正常的,但不要互相复制粘贴——写给人和写给 AI 的结构不同


四、SKILL.md 的推荐骨架

下面是一个与业务无关的通用骨架。你的 SKILL.md 照着填就行。

Front Matter(告诉 AI 什么时候加载这个 Skill)

---
name: your-skill
description: 一句话说明「做什么」+「什么场景触发」。AI 靠这段文字决定是否加载,写得越精准命中率越高。
---

写好 description 的要点:动词 + 领域 + 触发条件。避免「这是一个工具」这类空话。

关键约定

在所有步骤之前,集中声明贯穿全文的约定:

  • Skill 根目录变量名(不要硬编码绝对路径)。
  • 哪些变量 AI 该自己推断。
  • 统一入口命令的路径。
  • 持久化文件位置与权限。
  • 懒加载的整体策略。

子命令速查

一张表把所有子命令列完,AI 不用翻详细步骤也能大致找到需要的命令。

Step 1 ~ Step N:主流程

每一步都按下面的结构写:

  1. 目标:这一步要达成什么。
  2. 何时可跳过:避免每次都全量执行。
  3. 命令块:直接可执行,带必要注释。
  4. 决策树(如果分支多):用简单的 ASCII 树画出来比文字描述清晰 10 倍。

迭代小循环

显式写出「改代码 → 重启 → 重试」之类的最短循环,让 AI 在多轮对话里能稳定复用。

收尾步骤

强制要求 AI 在任务结束时执行清理命令。否则你会留下一堆"测试残留"。

速查表(两张)

  • 行为速查:哪些变量何时获取、何时刷新。让 AI 理解懒加载的全貌。
  • 常见坑速查:现象 → 一行解决方案。这是 Skill 稳定性的"安全网"。

五、脚本层面的几条硬规矩

5.1 统一入口脚本的必备子命令

任何 Skill 的统一入口,至少应该提供:

类别子命令用途
发现discover探测环境、填充持久化变量
鉴权login / token-ensure懒加载式获取/刷新凭证
核心动作call / run / do实际业务调用,失败自动重试一次
环境注入env打印 export 语句,供 eval "$(... env)"
重置env-reset一键回到初始状态

5.2 错误处理的统一模式

  • 网络/鉴权类错误:捕获一次 → 刷新凭证 → 重试一次 → 仍失败才报错退出。
  • 环境类错误(缺依赖、缺容器):明确告诉用户「缺什么、怎么装」,给出下一条命令。
  • 不要在脚本里静默失败。exit code 0 永远意味着"真的成功了"。

5.3 容器/进程脚本的幂等性

  • start 若容器已在运行:要么复用,要么先清理再启动,不要报错停住。
  • stop 若容器不存在:正常退出,不要报错。
  • restart = stop + start,不要写成两个独立的子命令组合。

5.4 日志落地到宿主机固定路径

如果你的流程会在容器里启动服务,不要依赖 docker logs——它只抓 PID 1 的输出,容器内用 exec 启动的进程日志进不去。

规范做法:

  • 统一重定向到宿主机路径,如 $CODE_ROOT/.<skill>-output-<ctx>.log
  • 在 SKILL.md 里把这个路径显式写出来,让 AI 知道去哪里 tail
  • 提供「清空日志」的一行命令,避免迭代时老日志干扰判断。

六、常见反模式(避坑清单)

反模式为什么不行正确做法
SKILL.md 里写「请先执行 A,再 B,再 C」AI 很容易跳步或搞错顺序让每个子命令懒加载自己的依赖
关键变量从多个地方读取状态不一致时难排查单一持久化文件 + 单一加载函数
在 Bash 里解析复杂 JSON脆弱、难调试换 Python 标准库 json
把 Token 写进代码仓安全事故只写入 $HOME/.xxx/env,权限 600
每次让用户确认一堆参数AI 体验差,用户还不如自己点鼠标AI 从上下文推断,只在真歧义时才问
缓存「当场查很快」的值(如容器名)容易过时每次 docker ps 现查
没有 cleanup 子命令测试资源越积越多提供幂等的 stop / env-reset
description 写成「这是一个 xx 工具」AI 加载不准description 包含动词 + 场景 + 触发词

七、给 Skill 上线前的自检清单

  • description 里是否包含触发关键词(用户会自然说的话)?
  • AI 是否能只凭自然语言描述就推断出所有必要变量?
  • 所有子命令是否都是懒加载的,可以任意顺序调用?
  • 是否存在唯一的持久化文件,且提供 reset?
  • 失败路径是否都有明确的下一条命令
  • 是否有迭代小循环的说明?
  • 是否有收尾清理步骤,且幂等?
  • README 和 SKILL.md 是否分别面向人和 AI 撰写?
  • 是否有「常见坑速查表」作为最后的安全网?
  • Skill 跑完后,宿主机上是否不残留任何临时资源

八、从 0 到 1 的建议顺序

如果你打算从头构建一份 Skill,推荐按这个顺序:

  1. 先手动跑 3 遍,每一步命令都记下来,不要急着写脚本。
  2. 识别出真正不可推断的变量(通常只有 2~5 个),其他全部让 AI / 脚本自动获取。
  3. 统一入口脚本,先实现 discover 和核心 call,其他子命令逐步加。
  4. SKILL.md 骨架(Front Matter + 关键约定 + Step 框架),然后回到 1 再手动跑一次——这次照着 SKILL.md 跑。
  5. 在第 4 步你会发现一堆「啊这里 AI 会不知道」「这里我又得问一次」的坑,把它们逐个消掉。
  6. 加两张速查表(行为速查 + 常见坑速查)。
  7. 让一个没接触过这个流程的同事(或干净 session 的 AI)照着 SKILL.md 跑一遍,观察卡点。
  8. 迭代 2~3 轮后冻结,之后只做维护。

九、总结

一份好的 Skill,核心不是「文档写得多详细」,而是:

让 AI 能像一个熟练的工程师一样,以最少的提问、最少的错误、最短的路径,跑完你最擅长的那套流程。

做到这一点,只需要坚持三件事:单一入口、懒加载、最小持久化。其他所有细节都是从这三条原则自然长出来的。

About

No description, topics, or website provided.