☰
OpenClaw接入Skills实战:让AI助理真正动手干活
2026/10/20 8:24:10 网站建设 项目流程

说实话,第一次把 OpenClaw 跑起来的时候,我心里是有点失望的。它确实能接上大模型 API,能聊天,能记住上下文——可这不就是套了一层壳的聊天机器人吗?直到我花了一个下午,把第一个 Skill 挂进它的技能目录,然后亲眼看着它自动调起脚本、把一堆散乱的日志整理成表格、再按模板生成一份报告,我才反应过来:所谓“贾维斯”,差的根本不是话术,而是那双能干活的“手”。

这篇文章我就从 OpenClaw 接入 Skills 这条线往下讲,不绕弯子。会先讲清楚技能机制到底是怎么回事,再给你一个能直接抄的实操流程,最后把我自己踩过的坑、总结的经验一次性倒出来。适合两类人看:一是刚搭好 OpenClaw 但不知道下一步怎么玩的新手;二是已经装了 Skills 却老觉得“它怎么不按我想的调用”的折腾型玩家。

1. 为什么大模型光会说话,当不了贾维斯

1.1 大模型是大脑,Skills 是手脚

先把这个关系掰开揉碎。大模型这东西,本质上是一个“概率文本生成器”。你问它“今天天气怎么样”,它能给你写出一段像模像样的天气描述,但它不会真的去访问气象接口,也没有办法打开浏览器、读写文件、发 HTTP 请求、操作数据库。它的一切“能力”都停留在生成文本这个层面。

这就好比你让一个只会读书的学霸去帮你搬家。他能在纸上把搬家流程写得明明白白——“先打包、再搬运、最后归置”——但真要扛起箱子,手是无能为力的。OpenClaw 里的 Skills,就是给这个学霸安装了一双手脚。每个 Skill 包含一段可执行的脚本,脚本能真正去调用系统命令、访问网络、处理数据,然后把结果拿回来。

很多人的误解在于:以为把模型换大一点,AI 助理就能自己干活了。但实际上,从“听懂你的需求”到“真正办成事”,中间隔着一条巨大的鸿沟。OpenClaw 恰恰是来填这条沟的框架,而 Skills 是它最核心的执行单元。

1.2 从“听懂”到“办成”,中间发生了什么

那 OpenClaw 是怎么把“大脑”和“手脚”接起来的?这里得提到一项底层机制——函数调用(Function Calling / Tool Use),虽然你平时感知不到它。

整个过程可以拆成四步:

  1. 你向 OpenClaw 发出指令,比如“帮我把 /tmp/download 目录下的 Excel 汇总一下”。
  2. 大模型收到这句话后,并不会直接去扫描目录。它会先在 OpenClaw 提供的技能清单里“找”,看哪个 Skill 的描述和当前任务匹配。
  3. 一旦匹配上,模型会输出一个结构化的调用请求,里面带有技能名称和从你话里抽取的参数。OpenClaw 收到这个请求后,在本地或容器里真正执行对应的脚本。
  4. 脚本把执行结果返回给模型,模型再把它组织成一段自然语言回复给你。

这个循环跑通之后,OpenClaw 就不再是“复读机”了。它像一个真正能办事的助手——眼睛在大模型这里,手在脚本那里,而 OpenClaw 是中间的神经系统。你所有关于“贾维斯”的想象,其实都建立在这条闭环是否顺畅上。

2. 接入 Skills 前,先把这几个概念吃透

2.1 技能清单:大模型读的“招聘启事”

每个 Skill 都必须附带一份描述文件。在 OpenClaw 的不同版本里,它可能叫manifest.yaml、skill.json或SKILL.md,但核心字段大同小异。这里我统一用manifest.yaml来说。

这份文件里最重要的不是脚本代码本身,而是“描述”和“参数说明”。因为大模型根本不看你脚本里写了什么,它只看这段文本:

  • 描述(description):告诉模型“这个技能是干什么的、什么时候该用、什么时候不该用”。
  • 参数(parameters):声明调用这个技能需要哪些输入,比如文件路径、城市名称、日期范围,相当于给脚本定了一个输入接口。
  • 执行方式(command / runtime):指定用什么语言、什么命令去跑脚本。

你细品一下就会发现,这本质上是一份“给大模型看的招聘启事”。模型像一个 HR,根据你描述的内容决定“派哪个员工去办这件事”。如果你描述写得模棱两可,模型就会乱点鸳鸯谱,把查天气的技能拿去算账——这种事我遇到过不止一次,后面会专门展开讲。

2.2 脚本本体:真正干活的执行体

描述文件之下,才是那个真正干活的脚本。OpenClaw 对脚本语言没有强制限制,但社区里主流是 Python,其次是 Node.js,少数简单操作会写 Bash。

选择 Python 的理由很朴素:生态足够全。处理 Excel 有openpyxl,发请求有requests,分析数据有pandas。你不需要让大模型去生成一段复杂 Shell 指令,只需要让它按参数调用你的函数。这也是 Skills 设计里很聪明的一点——把不可控的“模型自由发挥”压缩到最小,把稳定可控的代码固化到脚本里。

2.3 路由与沙箱:OpenClaw 在背后做了什么

OpenClaw 连接模型和脚本,还有两个容易被忽略的环节,一个叫“技能路由”,一个叫“执行沙箱”。

技能路由解决的是“选谁”的问题。当你有十几个 Skills 时,模型不可能把每个脚本都读一遍,它只读每个技能的描述。所以你的描述写得好不好,直接决定了路由准不准。这里有个朴素但有效的原则:描述里写清楚“使用场景”和“边界”,甚至可以直接写“当用户聊到 XXX 话题时不要调用本技能”。

沙箱则解决“安全”问题。官方推荐的做法是把技能脚本放进一个受限环境里执行,比如容器或受限用户目录,这样脚本即使写崩了、删错了文件,也不会拖垮宿主系统。我的习惯是:所有涉及文件写入和网络请求的技能,一律在容器里跑;只读类技能才直接放本机执行。

2.4 我的建议:先装现成的,再自己造轮子

很多人一上来就想写自己的技能,结果卡在调参上大半天。我更推荐先把你需要的现成技能装上——OpenClaw 官方仓库和社区里维护着一批高质量技能,从查天气、读 RSS、操作浏览器到发邮件都有。先跑通整套机制,你才会知道“一次成功的调用”应该是什么手感,然后再动笔写自己的。

3. 实操:给 OpenClaw 装上第一个 Skill,让它学会查天气

3.1 先把环境跑起来

我这里假设你已经装好了 OpenClaw 主程序,并且能正常对话。如果还没装,官方的安装脚本一般就是一路默认:它会在你的用户目录下创建.openclaw文件夹,里面包含配置文件、日志目录和技能目录。

可以打开终端验证一下:

openclaw --version

能看到版本号,说明主程序 OK。然后确定你的技能目录位置,不同版本路径略有差异,最常见的两个是:

~/.openclaw/skills/ ~/.config/openclaw/skills/

用ls看一眼哪个存在就用哪个。找不到就直接创建一个,OpenClaw 启动时也会自动扫描这个目录。

3.2 把技能文件放进正确的位置

假设你要装一个天气查询技能,社区里通常给的是一个压缩包或 git 仓库。结构一般长这样:

weather-skill/ ├── manifest.yaml ├── script.py ├── requirements.txt └── README.md

你要做的事情很简单:把整个文件夹复制到技能目录下,然后保证目录名和manifest.yaml里的name字段一致。我见过不少人栽在目录名不匹配上,导致技能被扫描到但一直加载失败,所以这个细节第一次就要做对。

复制完之后,manifest.yaml的样子大概是这样的:

name: weather_query description: | 根据城市名称查询实时天气和未来三天预报。 当用户询问“天气”、“气温”、“下雨”、“风力”等话题时使用。 如果用户提到“气温历史数据”或“气候统计”,不要使用本技能。 parameters: type: object properties: city: type: string description: "城市名称,例如:北京、上海、广州" days: type: integer description: "预报天数,默认为1,最大为3" default: 1 required: - city runtime: command: "python3 script.py"

注意那段 description。我特意写了“什么时候用”和“什么时候不要用”,这能让模型在路由阶段少犯浑。required字段里只放必填参数,其余给默认值,因为模型从一句话里提取参数的能力虽然不差,但如果你全是必填项,它提取不到就很容易报错。

3.3 验证技能是否被识别

装好之后,重启 OpenClaw(或执行热加载命令),然后查看技能列表:

openclaw skills list

如果列表里出现了weather_query,说明扫描没问题。接下来做一个最简单的直连测试——有些版本支持直接手动指定技能名来跑:

openclaw skills run weather_query '{"city": "上海", "days": 2}'

这里手动传入 JSON 参数,是为了跳过模型路由这一步,直接验证脚本本身通不通。如果脚本有 bug,你会在这里看到完整报错;如果脚本正常,返回的就是结构化 JSON 或纯文本。这一步很关键:先确认“手是好的”,再放心交给“大脑”去指挥。

3.4 回到对话框体验完整闭环

脚本验证通过后,回到 OpenClaw 的正常对话界面,发给它一句:

帮我看看上海明天需要带伞吗?

正常情况下,你会看到 OpenClaw 先调用了weather_query技能(日志里会打出来),然后返回一段自然语言回复,比如“上海明天有小雨,出门建议带伞”。这短短几十秒,就是一次完整的“模型理解→技能路由→脚本执行→结果回填”闭环。

跑通这一个技能之后,整套机制你就摸到门道了。剩下的就是批量安装、按需定制,甚至自己动手写新技能。

4. 从零写一个专属技能:自动周报生成器

4.1 动手前先设计输入和输出

装别人的技能只是热身,真正有意思的是按自己工作流写技能。我用一个最实用的例子来讲:自动周报生成器。

这个技能的诉求很典型:系统里散落着各种操作日志和任务记录,每周要人工汇总成一份周报,格式固定,内容还经常忘。如果能把“收集数据→整理格式→生成文档”固化成技能,让模型只负责理解“我要哪一周的报告”,那会省下大量重复劳动。

先设计清楚输入输出:

  • 输入:起始日期、结束日期、项目代号(可选)。
  • 输出:一份 Markdown 格式的周报文件,保存到指定目录,同时把内容发给指定的 Webhook 地址。

输入越简单越好,因为大模型从自然语言里提取参数的可靠性并不是 100%。日期范围、项目代号这种结构化信息够用,再复杂的需求就不适合做成单个技能了。

4.2 把 manifest 里的“话”说清楚

接下来写描述文件。这是最容易敷衍、也最容易出事的地方。我的写法如下:

name: weekly_report_generator description: | 根据日期范围生成项目周报。支持按项目代号筛选。 当用户说“生成周报”、“写一下本周总结”、“汇总上周工作”时使用。 如果用户只是普通聊天、没有要求生成正式文档,不要调用本技能。 parameters: type: object properties: start_date: type: string description: "起始日期,格式 YYYY-MM-DD" end_date: type: string description: "结束日期,格式 YYYY-MM-DD,默认与开始日期同年同周" project_code: type: string description: "项目代号,例如 PROJ-01,可选,默认汇总所有项目" required: - start_date runtime: command: "python3 generate_report.py"

这里我想强调两点经验。第一,description 里“不做什么”比“做什么”更能减少误调用。模型是概率决策,你给它划了边界,它跑偏的概率会明显下降。第二,参数描述里要写清楚格式,比如YYYY-MM-DD,因为模型如果把日期格式传错,脚本再健壮也白搭。

4.3 写执行脚本,注意 stdout 的规矩

脚本本身不复杂,核心逻辑是从一个本地记录文件里读取活动条目,按日期范围过滤,再按项目分组生成 Markdown。

#!/usr/bin/env python3 import argparse import json import urllib.request from datetime import datetime def load_records(path="records.jsonl"): records = [] with open(path, "r", encoding="utf-8") as f: for line in f: try: records.append(json.loads(line)) except json.JSONDecodeError: continue return records def filter_by_date(records, start, end): start_dt = datetime.strptime(start, "%Y-%m-%d") end_dt = datetime.strptime(end, "%Y-%m-%d") result = [] for r in records: r_dt = datetime.strptime(r["date"], "%Y-%m-%d") if start_dt <= r_dt <= end_dt: result.append(r) return result def build_markdown(records, project_code=None): if project_code: records = [r for r in records if r.get("project") == project_code] lines = ["## 周报", ""] for r in sorted(records, key=lambda x: x["date"]): lines.append(f"- {r['date']}({r.get('project', 'N/A')}):{r['content']}") return "\n".join(lines) def send_to_webhook(url, content): data = json.dumps({"text": content}).encode("utf-8") req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"}) with urllib.request.urlopen(req, timeout=10) as resp: return resp.status if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--start-date", required=True) parser.add_argument("--end-date", required=True) parser.add_argument("--project-code", default=None) parser.add_argument("--output", default="weekly_report.md") parser.add_argument("--webhook", default=None) args = parser.parse_args() recs = load_records() filtered = filter_by_date(recs, args.start_date, args.end_date) md = build_markdown(filtered, args.project_code) with open(args.output, "w", encoding="utf-8") as f: f.write(md) if args.webhook: status = send_to_webhook(args.webhook, md) print(json.dumps({"status": status, "file": args.output}, ensure_ascii=False)) else: print(json.dumps({"file": args.output}, ensure_ascii=False))

写脚本时有一个铁律:stdout 只输出给模型看的结果,日志只进 stderr。因为 OpenClaw 会把脚本的标准输出回传到大模型,如果脚本里写满了print("正在处理...")这类调试日志,模型就会被噪音干扰,甚至把日志当成结果回复给你。真正需要诊断时,去看日志文件即可。

4.4 调试技巧:先手动喂参数,再进对话

新技能上线前,我强烈建议先绕过模型,手动执行一次:

python3 generate_report.py --start-date 2025-06-02 --end-date 2025-06-06

确认文件生成、输出 JSON 正常后,再回到 OpenClaw 里让模型来调用。这样可以隔离问题:脚本出错还是模型乱路由,一测便知。另一个技巧是给脚本加--timeout之类的参数(如果有长任务),因为 OpenClaw 默认对技能执行有时间上限,我在下一章会专门说这个坑。

5. 我这几个月踩过的坑,整理成清单给你

5.1 技能描述写得太泛,模型把天气技能调去算账

我第一次写技能时,description 只写了一句话:“查询天气信息”。结果有一天我让它“算一下这个月项目预算的结余”,它居然给我调了天气接口。我把日志翻开,发现模型认为“预算结余”也是“查询信息”,于是命中了我那个描述极宽泛的技能。

解决方法是把描述改成带边界条件的版本,明确写“仅当涉及天气、气温、雨雪时才使用;涉及财务、预算、账目时绝不使用”。模型虽然不懂天气和财务的区别,但描述里的否定句能显著降低误命中概率。这个经验适用于所有技能,别嫌啰嗦。

5.2 脚本依赖装不进沙箱,卡了整整一晚上

有一次写处理 PDF 的技能,脚本里用到pypdf,在沙箱环境执行时直接报ModuleNotFoundError。原因是沙箱里根本不会自动安装requirements.txt里的依赖,需要你手动构建镜像或预先安装。

我当时用了最土但最有效的办法:进入沙箱环境,手动跑一遍pip install -r requirements.txt,确认安装成功后再把依赖固化进镜像。后来学乖了,凡是新技能首跑,第一件事就是把依赖问题解决掉,而不是急着调业务逻辑。这也提醒我:技能的“最小可运行环境”必须自己负责,OpenClaw 不会帮你装依赖。

5.3 路径写死导致的“一键迁移失败”

早期我写技能时经常图省事,在脚本里直接写/home/myuser/records.jsonl。结果技能目录从一台机器复制到另一台时,路径彻底失效,所有调用秒挂。排查半天,最后发现就是路径问题。

现在我的做法是:所有路径一律用相对当前脚本目录的方式,或者读环境变量。比如:

import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) records_path = os.path.join(BASE_DIR, "records.jsonl")

这样技能文件夹拷到哪都能跑。官方仓库里那些高质量技能基本都是这个写法,这是个能省掉大量无谓时间的规范。

5.4 超时与重试:不是所有任务都能秒回

OpenClaw 对技能执行一般有个超时限制,默认值不长,具体看你装的版本。我第一次跑一个批量抓取任务,脚本要跑两分钟,结果在 30 秒左右被强制掐断。当时我以为是脚本卡死,反复调试,浪费了一个晚上。

后来查文档才明白,超时时间是可以调的。但我也反思了一个更根本的问题:动辄几分钟的长任务不适合做成同步技能。更好的方案是脚本后台异步执行,先把任务标记为“已提交”,再提供一个查询接口,让技能返回任务 ID,用户过一会儿再查结果。这套模式对付长任务非常管用,我现在所有批量处理技能都按这个思路写。

5.5 两个技能抢同一个外部服务

再后来我装了自动化操作浏览器的技能,又装了一个自动填表的技能。两个技能都依赖同一个后台服务,结果同时被触发时互相抢资源,页面状态被搞乱。

这个问题的根子是技能职责边界不清。我的做法是在 manifest 里明确拆分使用场景,让其中一个技能只管“打开/抓取”,另一个只管“填写/提交”,并在描述里互相标注“本技能不做 XXX,请交给 YYY 技能”。OpenClaw 本身不限制技能之间的边界,但设计者必须自己划清。职责清晰的技能库,比技能数量多但互相打架的库好用十倍。

6. 进阶玩法:让多个 Skills 学会分工协作

6.1 先查日历,再订会议:技能编排的雏形

OpenClaw 真正迷人的地方在于,技能可以被“编排”起来。比如我想让助理自动安排一场会议,它不需要一个大而全的“会议技能”,而是拆成两个小技能:一个查日历空闲时间,一个创建会议邀请。模型会先调用查询技能拿到空闲时段,再把这个结果作为参数传给创建会议技能。

这种“小技能拼装”的模式,比一个大脚本硬扛全部逻辑稳健得多。每个脚本职责单一,单独调试、单独升级都不影响其他部分。很多“智能体工作流”的玩法,底层都是这种简单哲学。

6.2 用命名规范和优先级管理技能库

技能一多,管理就变成大问题。我会给技能命名定一套规则:领域-动作-对象。比如calendar_query_slots、mail_send_report、browser_fetch_page。这样技能列表一眼扫过去就知道谁负责什么,不会出现两个语义相似的技能互相干扰。

另外,如果几个技能都能处理同类请求,可以在描述里加上“优先级”暗示。比如你同时有“快速搜索”和“深度分析”两个技能,就在前者的描述里写“当用户需要快速直接答案时优先使用本技能”,后者写“当用户需要详尽分析报告时使用本技能”。模型读到这类语义,路由会更符合预期。

6.3 给外部接口留好“安全阀”

技能一旦涉及发邮件、转账、删文件这些有副作用的操作,我强烈建议做两道安全措施:

  • API Key、Token 一律放环境变量,不要写死在脚本里。技能目录可能在多台机器间复制,密钥一旦泄漏就是连锁事故。
  • 危险操作加确认环节。可以设计成技能先返回一个“待确认摘要”,让模型向你复述“即将向 XXX 发送邮件,主题为 YYY”,得到你确认后再真正执行。这个模式表面上多了一步,但对交易类、发送类操作来说,是值得的保险。

6.4 版本管理与回滚:技能坏了别慌

最后一个经验是给技能目录上 Git 管理。每改动一个技能脚本就提交一次,写清 commit message。某次改坏了,直接git revert就回到上一个能用的版本。这套操作不复杂,但能救命——尤其是你同时维护十几个技能、又喜欢频繁微调描述词的时候。有一次我为了优化路由,改了某个技能的 description,结果这个技能连续三天没被触发过,回滚后立刻恢复正常。从那以后,我再也没有裸改过技能文件。

回到开头那个问题:OpenClaw 到底离“贾维斯”有多远?我的答案是,技术上差的很少,真正差的是你往它的技能库里塞了多少“真本事”。每接入一个 Skill,它就长出一只新的手;每写清楚一段描述,它就更懂你一分。从第一个天气技能跑通,到给自己定制周报生成器,再到设计出一套能互相协作的技能矩阵——这个过程不复杂,但需要一点点耐心,和把“让 AI 真正干活”这件事当真的态度。如果你也想让你那个只会聊天的助理动起来,我建议就从今天装一个最小的技能开始。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询