
OpenClaw 指南(六):技能系统与 MCP 落地
Skill 不是 Prompt 模板——它是一套完整的 SOP,包括触发条件、工具权限和执行流程。再加上 MCP 把外部能力接入 Agent,从浏览器自动化到数据库查询,一个配置文件搞定。
学到第五篇时,你的 OpenClaw 不仅能正常运行、支持对话,更从一个演示原型蜕变为真正可落地的 Agent 系统。

我们要做什么#

我们要构建一个晨间简报 Agent,它能做到:
- 每个工作日早上 7 点自动运行
- 通过 Playwright MCP Server 抓取 Hacker News 的头条新闻
- 通过封装
gcalcli的 Skill 读取当天的日历安排 - 将上述内容汇总成一段文字,并推送到我的 Telegram
这是一个真实可用的工作流。完成之后,你将拥有一个可复用的系统骨架——只需替换数据源即可适配自己的需求。但在动手之前,我们先厘清即将整合的两个核心机制。
Skills、Tools 与 MCP —— 心智模型#
这三个概念常被混为一谈,但它们在设计上泾渭分明。
| 概念 | 是什么 | 谁编写 | 何时加载 |
|---|---|---|---|
| Tool(工具) | 一个动词:读文件、执行命令、网页搜索等。具有类型化 Schema 和处理函数(handler function)。 | 框架作者或你自己(自定义工具) | 始终加载;模型每轮对话都能看到完整的工具列表 |
| Skill(技能) | 一种知识性名词:一份 Markdown 格式的标准操作流程(SOP),告诉 Agent 如何 完成特定任务。 | 你自己 | 懒加载 —— 仅在触发时才加载 manifest,正文按需载入 |
| MCP Server(MCP 服务端) | 一个外部进程,通过 Model Context Protocol(MCP)暴露 额外 的工具。 | 第三方或你自己 | 网关启动时加载;其工具会与内置工具并列呈现 |
三者的关系很清晰:Skills 使用 Tools,MCP Servers 提供 Tools。例如,一个 Skill 可以写道:“使用 Playwright 工具抓取该页面”——其中 Playwright 工具来自 MCP Server,而 Skill 则指导 Agent 如何组合和调用这些工具。
打个比方:Tools 是 Agent 的双手,Skills 是操作手册,MCP 则是为 Agent 额外配备新双手的机制。
第一步:写一个 Skill#
Skill 存放在 ~/.openclaw/skills/<name>/SKILL.md。我们先写一个用于“总结头条”的 Skill:
| |
创建 ~/.openclaw/skills/summarize-headlines/SKILL.md:
| |
SKILL.md 文件结构解析#
该文件包含两部分:YAML 前置元数据(即 manifest)和 Markdown 正文(即 SOP)。两者缺一不可,且在不同阶段承担不同职责。
Manifest 在网关启动时加载。所有 Skill 的 manifest 都会被注入系统提示词(system prompt),供模型判断应调用哪个 Skill。各字段说明如下:
| 字段 | 是否必需 | 用途 | 示例 |
|---|---|---|---|
name | 是 | 唯一标识符,用于日志记录和跨引用。 | summarize-headlines |
description | 是 | 单行摘要,模型据此判断相关性。 | Summarize a list of headlines... |
trigger | 是 | 自然语言触发条件。请从用户视角撰写,而非实现视角。 | when user asks for a news briefing |
tools_required | 否 | 本 Skill 所需的工具列表。若声明,网关会预先授权。 | [web_search, exec] |
skills_required | 否 | 本 Skill 所依赖的其他 Skill。触发时,其正文会被热加载。 | [today-calendar] |
priority | 否 | 取值为 high、normal 或 low,用于多个 Skill 匹配时的优先级裁决;默认为 normal。 | high |
version | 否 | 语义化版本号(Semver),仅作信息参考,便于协作共享。 | 1.0.0 |
Body 仅在模型触发该 Skill 时加载,即标准操作流程(SOP)——包含具体指令、输出模板、边界情况处理等。你可以把它当作给新员工的入职文档:越具体越好。模糊指令(如 “summarize well”)会导致输出飘忽不定;而明确指令(如 “最多 4 句,首句必须是信号最强的新闻,跳过付费墙内容”)则能保证结果稳定可靠。
如何编写高效的 trigger#
trigger 是整个 Skill 中最关键的一行。太宽泛会误触发,太狭窄则可能完全不触发。以下是一些典型模式:
低效 trigger 示例:
when the user asks about news—— 过于宽泛,会在 “what’s new in the codebase” 等非新闻场景下误触发when summarize-headlines should run—— 循环定义,对模型毫无意义
高效 trigger 示例:
when user asks for a news briefing, headline summary, or daily news digest—— 明确列举具体名词when user asks to take meeting notes or document a meeting—— 动作 + 领域组合
调试 trigger 问题: 如果 Skill 没有按预期触发,请设置环境变量 OPENCLAW_LOG=debug 并发送测试消息。查看 gateway.log 中的 skill_selection 日志条目——它会列出模型评估了哪些 Skill,以及最终选择(或未选择)某 Skill 的原因。
重启网关,确认 Skill 已成功加载:
| |
你也可以直接查看模型实际看到的内容:
| |
第二步:挂载 MCP Server#
MCP(Model Context Protocol)是一种将大语言模型连接到外部工具服务器的标准协议。OpenClaw 本身不原生支持 MCP,而是通过 MCPorter 作为适配层(shim),在 OpenClaw 内部的工具格式与 MCP 协议之间进行双向转换。
安装 MCPorter#
| |
验证安装是否成功:
| |
添加 Playwright 作为 MCP Server#
| |
这条命令告诉 MCPorter:“存在一个名为 playwright 的 MCP Server,启动方式是运行 npx @playwright/mcp@latest。” MCPorter 会自动启动该进程并管理其生命周期。
接着,在 openclaw.json 中配置 OpenClaw 使用 MCPorter:
| |
重启网关。此时,Playwright MCP Server 暴露的浏览器自动化工具即可被 Agent 调用。可用工具包括:
| MCP Tool | 功能说明 | 典型用途 |
|---|---|---|
browser_navigate | 导航至指定 URL | 打开页面以进行爬取 |
browser_snapshot | 获取当前页面的可访问性树 | 读取结构化内容 |
browser_click | 点击指定元素 | 驱动多页流程(如分步表单、分页导航) |
browser_type | 向输入框中键入文本 | 表单填写、搜索框输入 |
browser_evaluate | 在页面上下文中执行任意 JavaScript | 提取 DOM 树未覆盖的数据 |
browser_take_screenshot | 截取当前视口图像 | 可视化验证、调试排查 |
测试 MCP 连接#
在 TUI 中测试一下:
| |
如果 Agent 返回了一个列表,说明链路已通;若失败,常见原因如下:
- MCPorter 未运行:运行
mcporter status,确认playwright显示为running。若为stopped,手动执行mcporter start playwright,并检查日志~/.mcporter/logs/playwright.log排查错误。 - 端口冲突:MCPorter 默认监听
:7890。若该端口被占用,可设置环境变量MCPORTER_PORT=7891,并同步更新openclaw.json中的porter_endpoint。 - Playwright 浏览器未安装:首次运行
npx @playwright/mcp@latest会自动下载 Chromium 等浏览器,耗时约 2–3 分钟、占用约 400MB 磁盘空间。若中途中断,请手动运行npx playwright install chromium补全安装。
添加其他 MCP Server#
该模式适用于任何符合 MCP 规范的服务器。以下是几个常用示例:
| |
添加后,更新 openclaw.json:
| |
每个 MCP Server 注册的工具都会与 OpenClaw 内置工具一同出现在 Agent 的工具列表中,模型对其调用方式完全一致,无需区分来源。
第三步:封装 CLI 工具的 Skill#
并非所有集成都需要 MCP Server。对于简单的 CLI 工具,写一个使用 exec 工具的 Skill 通常更简洁。我用 gcalcli 管理 Google 日历:
| |
~/.openclaw/skills/today-calendar/SKILL.md:
| |
注意,这个 Skill 本质上是一份操作指南(recipe),而非函数。模型是运行时,exec 是动词,Skill 则是将两者绑定在一起的知识载体。
何时使用 exec vs. MCP#
决策非常直接:
| 场景 | 使用 exec | 使用 MCP |
|---|---|---|
| 一次性 CLI 命令 | 是 | 过度设计 |
| 有状态交互(浏览器、数据库) | 否 | 是 |
| 输出结构复杂、类型明确的工具 | 可能 | 首选 |
| 需跨项目复用的工具 | 否 | 是 |
| 快速原型开发 | 是 | 否 |
经验法则:如果交互模式是“执行命令 → 解析 stdout”,就用 exec;如果涉及多轮交互或需要维持持久状态,则应使用 MCP Server。
exec 类 Skill 的安全注意事项#
exec 工具被标记为 dangerous 权限级别,原因就在于此。当 Skill 使用 exec 时,请务必注意:
- 固定命令字面量。在 Skill 正文中硬编码具体命令,不要写成“运行任意所需 shell 命令”。模型一旦有发挥空间,就可能构造出危险指令。
- 在配置中声明
trusted_commands。将该 Skill 实际使用的命令显式加入可信列表,避免每次调用都弹出确认提示:1 2 3 4 5"tools": { "exec": { "trusted_commands": ["gcalcli agenda", "gcalcli list", "git status"] } } - 校验输出内容。如果 Skill 会解析工具输出并将其传回模型,需考虑异常输出的影响——例如,恶意构造的日历事件标题理论上可能注入指令。
第四步:组合 Skill#

Skill 真正强大的能力在这里显现:组合型 Skill 能将多个 Skill 与工具编排成一条完整的多步工作流。
| |
~/.openclaw/skills/morning-briefing/SKILL.md:
| |
晨会 — YYYY-MM-DD#
今日#
[output of today-calendar]
新闻#
[output of summarize-headlines]
| |
skills_required 字段告诉 OpenClaw:当这个 Skill 触发时,要把所依赖的子 Skill 正文预加载进上下文。无需重新获取,也没有额外延迟。这是一个关键优化——否则,Agent 必须逐个触发子 Skill,每次都得付出 manifest 查询的开销。
Skill 组合的内部机制#
当 morning-briefing 触发时,网关会执行以下操作:
- 将
morning-briefing的正文载入提示词; - 发现
skills_required: [today-calendar, summarize-headlines]; - 将这两个子 Skill 的正文一并载入提示词,与父 Skill 并列;
- 此时模型同时拥有全部三个 SOP,可以按序执行各步骤。
Agent 循环照常运行:模型规划工具调用 → 网关执行 → 结果返回。关键区别在于:由于三个 Skill 正文都在提示词中,模型对每个工具的用途和上下文理解更充分。
这与传统代码中的函数组合不同——没有调用栈,也没有显式返回值。模型通读全部三个 SOP,内化其逻辑,再自主生成并执行融合后的完整计划。该机制之所以可行,是因为大语言模型擅长遵循多步指令。
调试组合型 Skill#
最常见的失败现象是:模型跳过某一步骤。比如成功获取了新闻,却遗漏了日历查询(或反之)。这通常是提示词过长、模型丢失上下文所致。
诊断方法:检查逐轮 JSON 日志:
| |
如果日志中包含 browser_navigate 但没有 exec(对应 gcalcli 调用),说明日历步骤被跳过了。修复方案包括:
- 显式编号所有步骤(如上例所示);
- 在 Skill 正文末尾添加核对清单:“发送前请确认:日历内容已包含?新闻摘要已包含?日期是否正确?”
- 为该 Skill 降低
max_turns,防止循环失控。在openclaw.json中配置:1 2 3 4 5"skill_config": { "morning-briefing": { "max_turns": 15 } }
第五步:Cron#
Skill 真正变得有用,是它能在你不在场时自动运行。在 openclaw.json 中配置:
| |
0 7 * * 1-5 表示周一到周五早上 7 点。重启网关,然后用以下命令验证:
| |
首次运行时,请观察网关日志:你会看到 Agent 循环触发、Skill 加载、Playwright 工具调用滚动执行,最终消息推送至你的 Telegram。
Cron 配置参考#
| 字段 | 是否必需 | 类型 | 说明 |
|---|---|---|---|
name | 是 | string | 唯一任务名称,用于日志及 openclaw cron list。 |
schedule | 是 | cron 表达式 | 标准 5 字段 cron 表达式。 |
skill | 是 | string | 触发的 Skill 名称,必须存在于 ~/.openclaw/skills/。 |
channel | 是 | string | 输出发送的目标 channel,必须为已配置的 channel。 |
user_id | 否 | string | 使用哪位用户的 memory / context。默认为 admin 用户。 |
timeout_sec | 否 | integer | 最大执行时长(秒),默认值:120。 |
retry | 否 | integer | 失败时重试次数,默认值:0。 |
env | 否 | object | 该任务运行时传递给工具的额外环境变量。 |
Cron 下的限制与注意事项#
Cron 任务在模拟会话(synthetic session)中运行——没有真实用户参与。这带来两点关键影响:
- 无确认提示:如果 Skill 使用
exec且所执行命令未列入trusted_commands,Cron 任务会因等待永不出现的用户确认而挂起。请务必把所有 Cron 触发的命令加入可信命令列表。 - 无后续交互:如果模型响应中包含提问(例如:“是否包含加密货币新闻?”),无人可作答;消息发布至 channel 后即结束会话。因此,Cron 触发的 Skill 必须自包含——所有决策应由 SOP 明确定义,不可依赖用户实时交互。
调试 Cron 任务的实用技巧:
| |
真实场景下的 Skill 示例#
晨间简报是一个入门级项目。以下是我在实践中常用的另外三种模式,附关键设计考量。
模式 1:Git 周变更日志#
一个从 git 提交记录生成周度变更日志的 Skill:
| |
设计理由:输入明确(git log 输出)、转换清晰(按 prefix 分组)、输出确定(固定路径的 Markdown 文件),无歧义。
模式 2:数据库健康检查#
一个基于 SQLite MCP Server 的周期性健康检查 Skill:
| |
模式 3:PR 审查助手#
一个融合 GitHub MCP 与代码分析能力的 Skill:
| |
故障排查#
这是我上线首月遇到的主要问题及解决方式。
Skill 触发成功,但输出错误#
现象:Skill 正常触发,但 Agent 忽略了 SOP 中约一半的指令。
原因:Skill 正文过长或表述模糊。模型会像人类一样跳读长文本。
解决:正文控制在 500 字以内;用编号步骤替代段落叙述;将输出模板置于末尾(利用 recency bias);若逻辑必须复杂,请拆分为多个子 Skill,并通过 skills_required 显式编排。
MCP Server 在对话中途崩溃#
现象:Agent 执行工作流中途报错 “connection refused”。
原因:MCP Server 进程意外退出。Playwright 尤其容易因页面触发 OOM、弹出无法处理的下载对话框而崩溃。
解决:MCPorter 支持 auto-restart,请确认已启用:
| |
若 60 秒内崩溃次数超过 max_restarts,MCPorter 将放弃重试并记录错误。请检查 ~/.mcporter/logs/playwright.log 定位原因。常见诱因:页面触发无限 JS 循环,或加载超 100MB 的资源。
Cron 任务显示执行成功,但未发送消息#
现象:openclaw cron history 显示任务成功运行,但目标 channel 无任何消息。
原因:通常为 channel 认证失效——OAuth token 过期、钉钉 Webhook URL 轮转、Telegram Bot Token 被撤销等。
解决:查看 gateway.log 中对应 Cron 时间戳,搜索 “channel send failed” 错误。重新认证 channel:openclaw channel test telegram 会发送测试消息并报告所有 auth 异常。
多个 Skill 抢占同一 trigger#
现象:同一用户消息下行为不一致——有时 Skill A 触发,有时 Skill B 触发。
原因:trigger 描述存在重叠。模型会依据细微措辞差异随机选择其一。
解决:确保 trigger 互斥。例如,若同时存在 “meeting notes” 和 “project notes” Skill,切勿对二者都写 when user asks about notes。应改为:
when user asks about meeting notes or documenting a meetingwhen user asks about project notes or project status
你也可强制指定 Skill:
| |
该命令完全绕过 trigger 匹配机制。
你现在拥有了什么#
- 一个长驻运行的 Agent,连接着真实的聊天平台
- 将领域知识与 Agent 循环分离的 Skills
- 一个提供 OpenClaw 原生不具备能力的 MCP Server
- 一个把“我得去问”变成“它自己来”的 Cron 任务
- 一套出问题时帮你定位原因的调试工具
这就是完整闭环。官方文档里的其他案例——第二大脑、内容 pipeline、DevOps 自动化——都是这五步的变体:换些 Skill,换些 MCPs,改几行 Cron 配置而已。
接下来我会做什么#
按投入精力从小到大,三件事:
- 加个反馈循环。回复晨间简报进行纠正(比如“跳过 crypto 头条”)。写个 Skill 把这些纠正记入
~/.openclaw/memory/feedback/morning-briefing.md。第二天早上的简报会读取这些内容。一周之后,简报会悄无声息地适配你的偏好——你完全不用动 SOP。 - 让新闻源可配置。写个 Skill 从
~/openclaw-workspace/sources.yaml读取并遍历。这几乎等于免费得了个“Agent 版 RSS 阅读器”。这份 YAML 文件就是简单的 UI——加一行 URL,第二天的简报就有了。 - 接第二个渠道。同一个 Agent,工作时间也推送到钉钉。Skill 不用改——channel 层是解耦的。你可以同时在两个地方收到同样的简报,也可以根据上下文把不同的 Skill 路由到不同 channel。
QuickStart 到此结束。官方文档其余章节将深入讲解各层实现细节。现在你已掌握整体架构,并清楚如何在各模块之间切换与协作。
如果只记住一件事,请牢记:真正具有长期价值的是那些看似平凡的基础层——Skills、记忆机制(memory)和通信渠道(channels)。Agent 的核心循环逻辑大同小异;让整个系统真正落地可用的,是你构建的 Skill 库和接入的实际渠道。祝好运。