ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenClaw Skills开发实战:从零构建AI Agent可复用工作流

OpenClaw Skills开发实战:从零构建AI Agent可复用工作流 说个我自己的经历。第一次跑通 OpenClaw 的时候我挺兴奋的感觉终于有一个 AI Agent 能按我的想法干活了。结果新鲜感还没过就发现一个问题让它总结网页、写写周报都还行可我想让它帮我处理实际工作里的重复事务它要么不会要么答非所问。后来我才搞清楚OpenClaw 的能力边界不是模型本身决定的而是由一组叫 Skills 的扩展单元决定的。你想要 Agent 掌握什么具体能力就得在 Skills 体系里给它配一个对应的技能包。这篇文章就聚焦 Skills 开发这件事把从零开发、部署到不同环境、再到踩坑排错的完整经验写出来。适合所有已经跑通 OpenClaw、但想让 Agent 真正贴合自己工作流的人。1. 先想明白 Skills 在扩展什么Agent 的能力边界从哪来1.1 大模型只是大脑真正干活靠的是手脚在动手开发之前得先把一个问题想清楚Agent 缺的到底是什么如果现在给你一个满血大模型它能写出很漂亮的代码也能给你解释任何概念但当你让它去把这个目录里所有超过 100MB 的文件找出来时它没法直接操作文件系统——因为它没有手。大模型本质上是一个文本进文本出的系统它的世界只有 token。要想让它影响真实世界必须给它工具也就是函数调用function calling。这些工具本质上是一段代码的入口模型负责决定现在该不该用、参数怎么填工具负责真正执行并返回结果。OpenClaw 里的 Skills就是这一思路的工程化封装。一个 Skill 通常是一个独立目录里面既有给模型看的使用说明也有给机器执行的真实逻辑。它解决的问题很具体让 Agent 把一次性对话能力沉淀成可复用、可积累的工作能力。说白了没有 Skills 的 Agent 只是个聊天框有了 Skills 的 Agent 才是一个能上工的劳动力。1.2 OpenClaw 的 Skills 机制和传统插件有什么不同很多人第一次接触 Skills 会把它类比成插件。方向不错但两者其实是两个层面的东西。插件Plugin通常是代码级别的深度集成需要针对宿主程序做扩展开发你要懂 OpenClaw 的内部 API改完要编译、要随主程序发版。Skill 则更像一个带说明书的可执行包模型看到说明书就知道什么时候该调用、怎么传参、返回结果长什么样真正做事的还是下面的脚本脚本可以独立测试也可以换一种语言重写。我在实际使用中的体会用一个表格来对比最直观维度普通提示词插件PluginSkill开发成本低写一段话高要懂框架 API中写说明脚本执行确定性低模型自由发挥高代码控制高脚本控制可迁移性差和对话绑死差和框架绑死好目录即能力适合场景一次性问答深度集成系统可复用工作流所以我的结论是如果你想要的是一次性对话能力写提示词就够了如果你想把某个工作流固化下来让它在任何会话里都可复现那就应该做成 Skill。这中间的分界线我自己的判断标准是这个动作三个月后还要不要用。1.3 一套 Skill 的基本形态一个目录就是一项能力OpenClaw 里常见的做法是每个 Skill 一个目录目录名就是 Skill 名内部结构大致长成这样check-commit-message/ ├── SKILL.md # 写给 Agent 看的能力说明书 ├── scripts/ │ └── check_commit.py # 真正执行逻辑的脚本 ├── assets/ │ └── examples/ # 示例输出、模板等资源 └── requirements.txt # 依赖声明这个结构看起来很朴素但每个文件都有它的职责。SKILL.md 回答这个能力做什么、什么时候用、怎么用scripts 回答具体怎么执行assets 放辅助资源requirements 解决换台机器能不能跑。如果只有 SKILL.md 没有脚本它本质上只是个加了壳的提示词执行结果不可控如果只有脚本没有 SKILL.mdAgent 根本不知道什么时候该调它。两者必须成对出现Skill 才成立。2. 一个 Skill 的目录解剖每个文件各司其职2.1 SKILL.md写给 Agent 看的能力说明书SKILL.md 是整个 Skill 的灵魂它的核心功能是回答三个问题这个能力是做什么的哪些场景下该用具体怎么调用写的时候要记住一个关键点这份文档的读者不是人是模型。模型的阅读方式和程序员完全不一样它靠语义匹配来决定是否调用你写的这个 Skill所以描述的质量直接决定命中率。我以前面提到的检查 git 提交信息规范的 Skill 为例它的元信息部分大概是这样的--- name: check-commit-message description: - 检查 git commit message 是否符合 conventional commits 规范。 当用户准备提交代码、收到提交信息相关报错、或想批量检查历史提交时使用。 不承担代码审查或生成提交信息的职责。 ---description 里不要写这是一个检查工具这种废话而要写用户在什么情况下会遇到什么问题、用它能得到什么结果。模型靠这段描述决定是否调用描述写得越贴近真实用户场景命中率越高。我在后面专门有一节讲这个这里先记住结论。2.2 scripts 目录真正执行逻辑的代码scripts 目录放真正干活的脚本。我见过不少新手把大量逻辑写进 SKILL.md 的提示词里让模型自己看着办。这其实是个陷阱提示词里的步骤模型可以自由发挥稳定性很差脚本里的逻辑是确定的输出是可控的。凡是涉及精确计算、文件读取、命令执行的都应该下沉到脚本里。脚本怎么写有一个原则输入输出越简单越好。我自己的实践是——标准输入接收数据标准输出返回结果退出码表示执行状态。这样无论模型通过哪种方式调用都能拿到一致的协议。语言选型上我的排序是Python Node.js Shell。原因是 Python 处理字符串和结构化数据最方便Node.js 也很强而 Shell 适合做胶水复杂逻辑写起来太痛苦。当然实际还要看运行环境装了哪些运行时这个后面部署部分会详细讲。2.3 资源文件与依赖声明让 Skill 可移植、可维护资源和依赖这一块最容易被忽略但在跨环境迁移时恰恰最关键。一个 Skill 如果依赖第三方包最好在目录下带 requirements.txt 或 package.json如果有模板、示例或者静态资源放在 assets 目录里。做得规范一点还应该在 SKILL.md 里写清楚依赖的安装方式。我的习惯是任何一个 Skill 都保证克隆下来后执行一条安装命令、再执行一条运行命令就能用。这不仅是给别人用方便更是给自己方便。我有一次把 Skill 从一台服务器迁到另一台因为少了 requirements.txt三个脚本挂了两个从那天起我强制自己每个 Skill 必须带依赖声明。一个目录就是一项能力这项能力能不能在别处重建全靠这些容易被忽视的辅助文件撑着。3. 完整开发实录从零做一个 git 提交规范检查 Skill3.1 为什么是git 提交检查需求拆解的方法建议每个新手自己写的第一个 Skill都选一个小而确定的场景。我拿git 提交信息规范检查举例原因有三点一是场景高频写代码的人天天要提交二是判断逻辑清晰规则明确不依赖模糊的大模型理解三是输出简单一眼能看出对错方便验证。需求拆解阶段要做两件事定义输入定义输出。我的输入定义是 commit message 文本或者一个仓库路径输出定义是 JSON 结构包含 passed 布尔值和 problems 数组。这里有一个经验不要把需求定得太大。我最初还想着检查分支命名、关联 Jira 单号、检查作者邮箱结果第一版写得又臭又长。后来砍到只剩 conventional commits 规范检查开发量小Agent 也更容易理解。Skill 的粒度宁小勿大一个 Skill 只解决一个明确问题这是 OpenAI 之外、OpenClaw 生态里同样适用的原则。3.2 写脚本与自测先把确定性的逻辑做扎实脚本部分我用 Python 实现核心逻辑如下#!/usr/bin/env python3 Check git commit message conventions. import sys import json import re # conventional commit: type(scope): subject PATTERN re.compile(r^(feat|fix|docs|style|refactor|test|chore)(\([a-z0-9-]\))?: .) MAX_SUBJECT_LEN 72 def check_commit_subject(subject: str): problems [] if not PATTERN.match(subject): problems.append(提交信息不是 conventional 格式参考type(scope): subject) if len(subject) MAX_SUBJECT_LEN: problems.append(fsubject 超过 {MAX_SUBJECT_LEN} 字符当前 {len(subject)} 字符) if subject.endswith(.): problems.append(subject 末尾不要加英文句号) if subject and subject[0].isupper(): problems.append(subject 建议用小写字母开头) return problems def main(): msg sys.argv[1] if len(sys.argv) 1 else sys.stdin.read().strip() if not msg: print(json.dumps({passed: False, problems: [提交信息为空]}, ensure_asciiFalse)) sys.exit(1) problems check_commit_subject(msg.split(\n)[0]) result {passed: not problems, problems: problems} print(json.dumps(result, ensure_asciiFalse)) sys.exit(0 if result[passed] else 1) if __name__ __main__: main()这段脚本做了三件事读取 commit message用正则匹配格式把问题列表用 JSON 输出退出码表示结果。自测阶段直接命令行验证echo fix login bug | python3 scripts/check_commit.py # 预期passed true echo Fix login bug. | python3 scripts/check_commit.py # 预期passed falseproblems 里有类型格式、大写开头、句号三个问题我建议在联调之前先做一个完整的测试表把各种边界输入都跑一遍空消息、只有 type 没有冒号、超长 subject、带 scope 的 commit……这一步的价值是确定脚本本身的下限。Agent 调用 Skill 时如果脚本对边缘输入处理不好模型还要费劲解读乱码整个体验会非常差。3.3 写 SKILL.md 与联调让 Agent 真正学会什么时候用它脚本能跑只是第一步Skill 的真正难点在 SKILL.md。我给这个 Skill 写描述时前前后后改了三版。第一版写的是检查 commit message 是否规范实际测试时 Agent 死活不主动调用。后来我改成当用户准备提交代码、或抱怨提交信息被拒绝时用这个工具检查原因并给出修改建议效果立刻好很多。SKILL.md 里除了元信息我还写明了调用协议## 输入 - 方式一将 commit message 通过标准输入传给 scripts/check_commit.py - 方式二传入 --repo 参数指向本地仓库脚本自动检查最近一次提交 ## 输出 - 一个 JSON 对象{passed: true/false, problems: [问题列表]} ## 使用步骤 1. 判断用户输入的是提交信息文本还是仓库路径 2. 选择对应参数运行 scripts/check_commit.py 3. 读取 JSON 结果逐条向用户解释需要修改的地方联调阶段最值得做的操作是模拟真实用户场景来测试。比如开一个全新会话对 Agent 说我 commit 被拒了报错说格式不对帮我看看为什么看它会不会主动调用这个 Skill。如果它没调用不要怀疑模型笨第一时间去改 description。模型的选择逻辑比你想象得更依赖描述文本。4. 从本地到服务器Skill 部署与跨环境迁移经验4.1 Skills 目录放哪里目录布局与命名规范OpenClaw 的 Skills 默认有个人目录也有全局目录常见的是~/.openclaw/skills或项目内的skills/目录。不管放哪我建议每个 Skill 一个目录命名用小写字母加连字符目录名就是 Skill 名。比如check-commit-message、fetch-page、summarize-doc这种。一个目录里不要堆多个 Skill否则加载和调试都很难受。加载顺序在日志里能找到我每次新增 Skill 后都会先看一眼启动日志确认它被正常加载进来了再开始测试。这个地方还有一个容易踩的坑目录名和 SKILL.md 里的 name 字段不一致。有些版本会以目录名为准有些以字段为准一旦不一致就会出现日志里加载了但模型始终调不到的诡异问题。我的习惯是让目录名和 name 字段保持完全一致省掉这种排查成本。4.2 Windows WSL 2最容易翻车的一段Windows 上部署 OpenClaw 经常碰到一类报错比如提示无法安全验证 WSL 环境。第一次看到这种话我也懵了以为是什么安全策略问题。排查了一圈才发现这类提示背后大概率是两种现实原因一是系统装了 WSL 但从未初始化默认发行版根本不存在二是 OpenClaw 跑在 Windows 侧但 Skill 脚本要在 WSL 的 Linux 环境执行文件路径、环境变量全对不上。排查顺序也很直接打开 PowerShell先跑wsl --status和wsl -l -v确认有没有可用的发行版、状态是不是 Running然后直接在 WSL 终端里手动执行一遍 Skill 所依赖的命令看看能不能跑通。别上来就怀疑 Agent 配置问题大部分 WSL 相关报错的根子都在系统环境本身。我踩过一个具体的坑在 Windows 上写了一个 Skill脚本里用了 Windows 的绝对路径比如C:\data\input.txt。开发时直接跑没问题换到 OpenClaw 里执行就找不到文件。后来我统一改成脚本只接收相对路径运行时需要的绝对值通过注入的环境变量获取涉及跨系统的脚本在开头做一次路径归一化处理。这样无论在 Windows 还是 Linux 下执行行为都一致。4.3 Linux 服务器与手机终端的差异化部署如果你打算把 Agent 常驻在一台服务器上Skills 的部署其实最简单把目录复制过去、装好依赖、跑一遍自测脚本就能用。这里唯一要当心的是运行时版本服务器上的 Python/Node 版本容易偏老建议在 SKILL.md 里写清楚最低版本要求。我自己的习惯是在 requirements.txt 里锁版本但锁得太死又容易在别的机器上装不上所以都是指定最小版本而不是精确锁死。手机端的情况要复杂一些。Termux 这类终端环境确实能跑 Agent也能装 Skills但两个限制非常现实一是文件系统权限Termux 默认访问共享目录需要额外授权Skill 如果读写外部文件很容易失败二是依赖安装不完全某些 Python 包在 Termux 里没有预编译版本装起来麻烦。所以我的做法是手机端只放只读类、轻量级的 Skill比如查天气、查汇率、解析文本这类涉及重计算或者写文件的一律走服务器。别指望一台手机能扛住 Agent 的完整生产力场景它就是随身助手不是生产主力。5. 真正好用的 Skill 是怎么打磨出来的描述、容错与并发5.1 描述与命名策略Agent 能不能选对 Skill就看这里描述写得好不好直接决定 Agent 能不能在正确的时机调用正确的 Skill。我自己总结的写法是一句话说清楚用户遇到什么场景时会需要它一句话说清它输出什么再补一句它不做什么。前两句话保证模型知道什么时候用后一句话防止模型把它错误地用在不相关场景。举例来说我那个提交检查 Skill 里就写了如果用户只是询问 git 用法不要调用本工具这比只在描述里写正向场景靠谱得多。命名方面建议用动词短语fetch-page、check-commit、summarize-doc。模型在浏览 Skill 索引时动词开头的信息密度最高一眼就能看出这个能力是做什么的。我在测试中发现名称是名词的 Skill 被调用的概率明显更低大概是因为模型在匹配用户意图时动词短语和动作的关联强度天然更高。5.2 容错设计Skill 挂了Agent 得知道发生了什么Agent 调用 Skill 失败是家常便饭问题不在于避免失败而在于失败后的反馈是否有效。我见过太多脚本出错就 print 一行 Traceback 然后退出。模型拿到这堆报错完全不知道下一步怎么办。正确做法是在脚本里捕获主要异常输出结构化错误信息发生了什么、可能原因、建议操作。举个例子如果你的 Skill 依赖 jq 但环境里没装与其让模型看到jq: command not found不如在脚本里自己探测依赖并输出缺少 jq可执行 apt install jq 安装。这样 Agent 在下一次推理时就能直接把解决方案抛给用户而不只是把报错甩给用户看。另一个容错要点是幂等性。同一个 Skill 无论被调用多少次结果都应该一致或可重放不能因为第二次执行就把第一次的状态覆盖了。写临时文件必须用系统临时目录用完即清理涉及写入操作的 Skill 尽量先做条件检查避免重复执行导致的副作用。5.3 并发与资源占用多任务下的隐性风险很多人把 Agent 当成单线程工具来设计一旦面对并发任务就出事。比如多个任务同时调用同一个 Skill而 Skill 内部往固定路径写日志文件两个进程就会互相覆盖再比如脚本里起了个监听端口第二次调用直接报端口占用。应对原则很简单脚本里不要有任何共享的可变状态。所有临时数据用 mktemp 生成独立目录禁止监听端口给脚本设置合理超时避免模型傻等一个卡死的进程。如果确实有需要长期运行的服务把它独立部署成一个 HTTP 服务Skill 脚本只做客户端调用。这样并发问题从根上就避免了Agent 同时跑几个任务也不会有冲突。6. Skill 不生效先走完这条排查链路6.1 从加载到调用逐层确认问题在哪为什么我的 Skill 没被调用是我看到最多的提问类型。根据这些日子的经验九成问题不在脚本本身。我的排查顺序是固定的第一步确认 Skill 被加载了。启动日志里一般会列出加载的 Skills 清单如果清单里根本没有你的目录那问题出在路径配置或命名规范。第二步确认描述能被模型看到。描述太长被截断、或者被其他内容挤掉模型就不知道有这个能力存在。第三步确认模型在同一轮对话里能不能把用户意图和Skill 描述关联起来。你可以开一个全新会话用一句话描述场景看它会不会调如果不会基本可以断定是描述写得不够触发导向。第四步才轮到查脚本手动跑一遍确认退出码、输出格式没问题。这套链路我走了一遍又一遍最后发现大部分问题都出在第二步和第三步。有时候你在 description 里加一句当用户提到某个词时命中率能涨一大截。所以先别急着改代码把描述当成一个投放策略去迭代。6.2 与 Claude Code、Codex 生态的横向对比用过 Claude Code 或 Codex 的朋友会发现它们也都有类似的 Skills 机制基本思路一致给模型一组描述加脚本的能力单元让模型在适当时机自行调用。区别主要在生态绑定、模型中立性和质量把控这三个维度生态绑定程度模型中立性质量把控OpenClaw Skills开源、独立形态朴素高一套 Skills 换模型也能用全靠自行把关Claude Code和官方生态绑得比较紧低围绕主力模型设计官方有审核机制Codex偏仓库拉取脚本中社区维护为主我的判断是如果你在做一个需要长期演化、厂商中立的 Agent 工程项目OpenClaw 的 Skills 值得认真研究如果只是为了在编辑器里快速提升编码效率官方生态的现成能力往往更省事。不是哪个好哪个坏而是目标和场景不同。6.3 权限边界给 Agent 上技能之前先想清楚风险Skills 本质上赋予了 Agent 执行代码的能力这意味着它有多大权限完全取决于你给了它什么。我给自己定了三条硬规矩也在开发指南里分享给大家。第一Skill 只做声明的事。脚本入口做参数白名单校验不接受任何运行时注入的自由文本。第二凡涉及外部副作用比如发消息、改文件、调接口必须支持--dry-run参数先输出预览再由用户确认。Agent 可以先告诉用户我会做这些事确认后才真正执行。第三密钥和敏感信息一律走环境变量注入绝不允许写死在脚本里SKILL.md 里也要提醒模型不要打印密钥内容。这三点做下来Agent 再聪明也不会越权做不该做的事。开发 Skill 这件事本质上是在给 Agent 划定能力边界哪些事它可以自己判断哪些事必须经过预览确认哪些事完全不能碰。想清楚这三条线再动手写代码方向就错不了。
返回列表