wifi万能增强器
105.11M · 2026-04-16
OpenClaw 的 Skills,本质上不是一个「可调用工具」,它更像一套经过约束的运行手册:启动时把技能目录扫描出来,压成一份 <available_skills> 清单塞进 system prompt,模型自己判断要不要选一个 skill,然后再通过 Read 工具去读这个 skill 的 SKILL.md。读完以后,没有任何独立执行器接管,还是在当前这条 session 的 tool-loop 里继续跑。
Claude Code 走的是另一条路。它把 skill 做成了 tool,工具里负责校验、加载、执行,甚至可以放进一个新上下文里跑完,再把结果回传主对话。
这两个实现方向,表面上都叫 skills,工程含义完全不一样。
如果你是做 Agent 平台、企业内 Copilot、代码助手、任务执行器,这个差异不只是架构图上的审美问题。它会直接影响:
很多人一看到 skills,第一反应是:是不是和 memory 一样,先走 embedding 检索,再把相关技能召回进上下文。
不是。
OpenClaw 的 skills 召回机制非常直接,甚至可以说有点「朴素」:扫描目录,生成目录清单,注入提示词,让模型自己选。整条链路分三段:
OpenClaw 反过来做了一件更工程化的事:先把 skill 列表显式给模型,再用 system prompt 约束它怎么选。
这个机制的起点在 src/agents/skills/workspace.ts 的 loadSkillEntries()。
OpenClaw 会从多个 root 目录扫描 SKILL.md,然后合并成最终技能集。这里是有明确的覆盖优先级的:
extra < bundled < managed < agents-personal < agents-project < workspace
它的逻辑是:越靠近当前工作空间、越贴近用户项目的 skill,优先级越高。平台预置的 bundled skill 可以兜底,但项目级 skill 要能覆盖它。否则你做企业落地时会很难受,团队定制流程永远被平台内置逻辑压着打。
从目录结构看,OpenClaw 支持两种 skill 形态:
这样,团队在实际维护 skill 时,有两种典型组织方式:
都支持,落地阻力会小很多。
它对 SKILL.md 做了体积限制,默认超过 256KB 就直接跳过。
SKILL.md 本来就应该是高密度操作指南,不应该演变成一个什么都往里塞的大文档。你一旦允许 skill 文件无限变大,后面一定会有人把 SOP、FAQ、设计文档、事故复盘全扔进去,最后技能选择和加载成本一起爆炸。OpenClaw 在扫描阶段直接卡体积,其实是在替平台维护纪律。
给 skill 增加最小限度的结构化元信息
扫描到 SKILL.md 后,OpenClaw 会读原文并解析 frontmatter。坏掉或者缺失的 frontmatter 会被忽略。
这个决策也很对。
OpenClaw 这里更像是「有就用,没有拉倒」。它承认 markdown 本体才是 skill 的核心,frontmatter 只是辅助控制面。这个姿态很适合 skills 这种增长很快、来源很多的资产类型。
但这里也埋了一个工程 trade-off:frontmatter 被弱约束,意味着后续治理和平台能力扩展会受限。你今天只做 discovery 和 basic gating,这么玩没问题;你明天如果要做 skill 分类、依赖分析、版本兼容、批量审计,元信息松散会让成本陡增。
OpenClaw 当前站在了「先把系统跑起来」的一边,没有走「先把规范做重」的路子。
这意味着它更适合中小规模 skill 生态,或者说更适合个人助手这类工具,而不是一个强治理的企业级 skill marketplace。
扫描出来只是候选集,不等于模型能看到。
OpenClaw 在注入 system prompt 之前会做一轮 gating。这个步骤比很多人想象得重要,因为它决定了模型到底暴露给了哪些能力。
过滤逻辑里有几类条件。
最基础的 enable/disable
如果某个 skill 在配置里被标成 skills.entries..enabled === false,它就会被剔除。
这是最基础的 kill switch。工程上没什么可争议的,必须有。不然你没法快速止血。某个 skill 写坏了、依赖环境挂了、被发现会引导模型做危险操作,没有一键下线能力,平台就不配上线。
对内置技能单独管控
skills.allowBundled 只约束 bundled 来源。
这个细节很有意思。它说明 OpenClaw 把 bundled skills 当成一类特殊资产处理:平台自带,但不默认无条件信任。
为什么这事重要?因为内置 skill 经常是平台演进中最容易「偷偷变多」的那部分。你今天打包 5 个,明天为了演示方便塞到 20 个,后天 prompt 里一大坨 descriptions,模型选 skill 的噪声越来越大。allowlist 的存在,本质上是在给平台预装能力上保险栓。
按运行环境判断 skill 是否可用
OpenClaw 会根据 metadata.requires 去判断 skill 能不能用,条件包括:
这个设计非常工程化。因为 skill 如果涉及真实操作,它一定和环境耦合。比如某个 skill 依赖特定 cli,或者要求某个 API token,或者只能在 Linux 跑。你如果不在注入前做 eligibility,而是让模型先看到 skill,再在执行时失败,用户体验会很差,模型行为也会变形:它会看到一个貌似可用的方案,实际一调就炸。
OpenClaw 选择「先过滤,再暴露」,这是我非常认同的策略。因为对模型来说,看得见就等于潜在可用。你让它看见无效 skill,本质上是在制造认知噪声。
系统内部保留,模型不可见
如果某个 skill 标记了 disable-model-invocation,它不会进入 prompt 的 <available_skills>,但仍然存在于系统内部,可用于管理或校验。
因为技能资产不只有「给模型用」这一种角色。你可能有些 skill 需要:
OpenClaw 没把「存在」和「可被模型调用」绑死,这样 skill registry 才像个平台能力,而不是一个 prompt 拼装器。
很多人说 skills 被召回,其实这句话在 OpenClaw 语境里容易让人误解。
真正被放进上下文里的第一层,不是 SKILL.md 内容,而是 <available_skills> 这个目录清单。它由 buildWorkspaceSkillsPrompt() 生成,注入到 system prompt。
也就是说,模型最先看到的是技能目录,不是技能正文。
这个做法也算是渐进式披露的一种实现。先给模型足够决定是否要读 skill 的最小信息,避免一开始就把所有技能全文灌进去。
OpenClaw 在 system prompt 里有一段明确的 Skills mandatory 规则,大意是:
这三条里,最重要的是后两条。
这是在压制模型的泛化冲动。模型很喜欢「我觉得这个也相关,那个也相关」,然后多读几个,最后把自己卷进上下文泥潭。OpenClaw 用提示词硬性要求「明确匹配一个」才允许进入下一步,这本质上是在给模型加稀疏化约束。
效果未必 100% 可控,但方向是对的。
如果你做过基于 prompt 的 tool orchestration,就会知道一个常见死法:模型在一堆说明里来回跳,读完 A 觉得 B 也有用,再读 B,顺手 C 也看看,最后 token 花了不少,任务还没干。
OpenClaw 这里直接规定 upfront 只能读一个 skill。我个人判断,这不是因为理论上最优,而是因为工程上最稳。
它牺牲了一部分组合式技能能力,换来了几个非常实际的好处:
代价也很明确:如果任务天然需要多个 skill 协同,OpenClaw 当前机制会显得笨。模型要么自己在单个 skill 指导下绕着做,要么根本选不准。
这也是它和 Claude Code 一个很大的分歧。Claude Code 把 skill 视作 tool,更容易天然支持复杂编排;OpenClaw 把 skill 视作可读说明,天然倾向于单次聚焦。
<available_skills> 不是无上限注入的。技能太多时,OpenClaw 会降级成 compact 格式,甚至截断,并提示 skills truncated。
这个点看起来像 prompt 小技巧,其实是很重要的预算治理。
因为技能系统一旦跑起来,数量几乎只会越来越多。最初十几个 skill,description 全量塞进去还行;到几十上百个 skill,再这么搞,system prompt 很快会变成垃圾堆。OpenClaw 至少意识到了这个问题,所以做了两级退化:
这说明它把 prompt 当成有限资源,而不是无限容器。
但实话实说,这个策略只是在「延缓爆炸」,不是根治。skill 数量继续增长以后,靠 compact/truncate 顶不住。因为问题不只是 token 多了,而是模型在目录里做决策的辨识难度会越来越高。description 再压缩,skill 之间的区分度也会变差。
所以我对这块的判断是:OpenClaw 的 catalog 注入机制适合中等规模 skill 集,不适合无限扩张。 如果你团队未来真要做上百个 skill 的企业级平台,迟早要引入更分层的 catalog、分类路由、或者显式 selector,而不是靠一坨 <available_skills> 让模型裸选。
OpenClaw 的第二层加载是按需读取。模型先看到目录清单,选中 skill 以后,才通过 Read 工具去读对应路径的 SKILL.md。
system prompt 里只有规则和技能目录。真正的 SKILL.md 内容,是在模型发起一次 read tool call 后,作为 toolResult 追加进当前消息流。
也就是说,skill 正文进入上下文的方式,和你用工具读一个普通文件没有本质区别。差别只是 system prompt 先规定了什么时候允许这样读。
这个设计的好处非常明确:
坏处也很明确:
从实现角度看,OpenClaw 这里是很克制的。它没有发明一个 Skill Runtime,没有做一套专门的 skill 调度协议,就是借已有的 read 工具完成正文加载。
这让系统保持简单,但也让 skill 更像「读到的一份说明书」,而不是「被激活的执行单元」。
既然 skill 是文件,模型要去读 SKILL.md,安全问题马上就来了:路径能不能逃逸?symbolic link 能不能把 skill 指到 root 外?模型能不能顺着 location 读到不该读的内容?
OpenClaw 这里做了两层保护。
在技能发现阶段,它会对 realpath 做 containment 检查,防止 symlink 把 skill 指到 root 外面。
这是典型的「尽早失败」策略。我一直觉得文件系统相关的安全问题,能在发现阶段拦的,不要拖到执行阶段。因为一旦把异常路径放进 skill registry,后面每个环节都得假设它可能有问题,整个系统会变得很难推理。
扫描时就把越界项挡掉,registry 内部的数据至少是干净的。
模型真正发起读取时,Read 工具还会做 sandbox root 校验,禁止 .. 或绝对路径逃逸 workspace root。
也就是说,即使 discovery 阶段没出问题,真正读取文件时还有一层运行时防线。
文件边界这事,单点防护永远不够。扫描阶段挡的是「注册进来的 skill 本身」,读取阶段挡的是「模型实际提出的路径参数」。二者保护的对象不一样。
工程上要是只做第一层,你会被运行时路径拼接坑;只做第二层,你会把很多脏数据带进 registry,影响可观测性和调试。
OpenClaw 在这块虽然不算复杂,但做法是标准的。
OpenClaw 的 skills 机制,如果只看「枚举目录 -> 注入 prompt -> read 文件」,会有人觉得太朴素。真正值得注意的是,它和 memory 一样,贯彻了一套很明确的渐进式披露思路。
这是上下文预算治理的逻辑。
原则就两条:
在 OpenClaw 里,memory 和 skills 都是这么干的,只是路径不同。
memory_search 先返回短片段,带 path 和 line range,不是全文注入。底层还有 SNIPPET_MAX_CHARS = 700 的硬上限。如果后端预算紧,还会继续裁结果。
之后再通过 memory_get 按 path + from/lines 去拉具体行段。
这个流程是非常标准的 progressive disclosure:先定位,再精读。
skills 这边没有向量召回,而是目录清单。模型先看 <available_skills>,只在明确匹配一个时才读正文,并且 upfront 最多一个。
两条链路表面不同,本质一样:都在防止大块文本无脑灌进上下文。
我为什么说这点值钱?因为很多团队做 Agent 系统时,最大的问题不是模型不会做事,而是上下文管理太粗糙。什么都想喂进去,最后 token 烧得飞快,模型还因为噪声太高做不准。
OpenClaw 至少在架构层面承认了一件事实:上下文是预算,不是仓库。
这件事说起来简单,真正落实到工具语义、提示词规则、底层裁剪,很多系统做不到。
在 OpenClaw 里,skill 读完之后,并没有一个单独的执行环境接管它。没有所谓「Skill Runtime」去解释 SKILL.md,也没有「新上下文执行 skill」这回事。它还是在同一个 activeSession.prompt(...) 的 tool-loop 里继续跑。
链路大概是这样:
关键点:skill 内容只是同一消息流里多了一条 toolResult。
这意味着什么?
意味着 OpenClaw 的 skill 执行,本质上是「模型读了一份流程说明,然后继续在原对话里行动」。它没有新的边界,没有新的记忆隔离,没有新的权限域。真正的隔离,来自工具列表裁剪和文件读写沙箱,不来自上下文切换。
这和 Claude Code 很不一样。
Claude Code 的 skill 流程有几个特征:
从工程抽象上看,Claude Code 的 skill 更像一个「子程序入口」。它有名字、有调用接口、有内部装载逻辑,甚至有上下文隔离能力。
OpenClaw 没有走这条路。它把 skill 设计成「模型可读的文件」,由模型自己决定是否展开,并在原上下文里继续操作。
这两个方向,没有谁天然高级,但适用面不同
如果你要的是:
Claude Code 那种 tool 化 skill 更合适。
如果你要的是:
OpenClaw 这种文件化 skill 更实用。
工程上不看理念,看代价结构。
我猜它的设计动机是:尽量复用现有 agent runtime,而不是为 skills 单独发明一层执行框架。
你看它的做法就知道了:
这是一套很节制的架构思路。好处是:
实现成本低 :不用造新协议,不用加新消息类型,不用多一层 runtime。对一个正在演进中的 agent 系统来说,这非常现实。 Skill 作者认知负担小:本质上写一个 SKILL.md 就行。对于组织内部推广,这是巨大优势。因为真正阻碍 skill 规模化的,从来不是模型能力,而是作者生态能不能起来。 运行链路可观测性还不错:所有事情都发生在同一 session 里。read 了什么、接着调了什么工具、toolResult 长什么样,回放起来相对直观。
但它的代价也有。
代价 1:skill 缺少强执行边界
skill 本身不是 tool,没有独立权限面。你没法像封装一个函数那样,给 skill 绑定专属 schema、专属校验、专属 side effect 边界。最终还是模型在拿到 skill 文本后,自由地调用后续工具。
这就意味着 skill 的约束力主要来自提示词,不来自执行器。
代价 2:组合式编排能力弱
system prompt 里要求 upfront 最多读一个 skill,这对预算控制很好,对复杂任务不友好。多 skill 协同在这个体系里不是一等公民。
代价 3:skill 的结果不可天然封装
Claude Code 那种「在新上下文执行 skill,再返回结果」,天然有个输入输出边界。OpenClaw 这里没有。skill 一旦展开,后续动作直接混进主会话消息流。你很难把它当作一个独立执行单元来治理。
代价 4:对模型的选择质量要求高
因为没有独立 selector,也没有 tool-level dispatcher,skill 能不能选对,主要靠 <available_skills> 的 descriptions 和 system prompt 规则。这对 skill 描述质量要求很高。写得不清楚,模型就选歪。数量一多,问题更明显。
OpenClaw 的思路是「先裁剪能力,再让模型行动」
这一点我很喜欢,因为它比「调用时再临时拦截」更稳。
OpenClaw 的权限控制,不是把所有工具都亮给模型,然后在调用某个危险工具时说不行。它更像是:
skills 这边也一样:
这种「先裁剪,再推理」的方式有个很大的好处:模型认知空间更干净。它不会围着一堆不可用能力打转,也不会生成大量被拒调用的无效动作。
如果你做企业场景,这比事后 deny 好得多。因为用户只会看到 agent 做合理尝试,而不是不停撞墙。
当然,它的代价是灵活性差一点。你没法在非常细粒度的时刻做动态放行,除非重新构建 tool list 或 skill list。但我认为这笔账是划算的。Agent 系统的第一优先级不是灵活,是可控。
觉得比较好的点:
第一,简单。 这个简单不是简陋,是尽量不新增系统概念。skill 就是文件,加载靠 read,执行靠原有 tool-loop。对演进中的 agent 框架来说,这是非常健康的选择。
第二,预算意识强。 <available_skills> 目录注入、最多只读一个 skill、compact/truncated 降级,这些都说明它把 context 当稀缺资源处理。
第三,权限思路对。 先过滤 skill 和 tool,再让模型行动。可见性先于可调用性,这很工程化。
第四,适合知识流程化。 很多团队真正需要的,不是一个会自己发明流程的 agent,而是把组织内已有 SOP 结构化地喂给模型。OpenClaw 这套很适合干这个。
一些局限:
第一,规模扩展性一般。 catalog 注入机制天然不适合 skill 数量无限增长。它适合几十级别,不适合大规模 marketplace。
第二,组合能力弱。 「最多只读一个 skill」对稳态有帮助,对复杂任务编排是限制。
第三,skill 缺少运行时身份。 它不是 tool,没有明确的输入输出边界,也没有独立权限与审计单元。后续做深治理会比较难。
第四,过度依赖模型选择。 一旦 descriptions 写得不好,或者目录过大,skill 选择质量会变成系统上限。
在系统架构选型时,如果有以下的条件,可以优先选择 OpenClaw 的设计逻辑:
有如下的情况时,就不太适用使用这种方案:
这些场景下,我更倾向 Claude Code 那种 tool 化 skill,或者更进一步,直接走 subagent / workflow node / task runtime。
如果只用一句话概括两者区别:
Claude Code 的 skill 更像可调用子程序,OpenClaw 的 skill 更像按需展开的运行手册。
前者强调执行单元,后者强调上下文注入。 前者天然适合隔离和编排,后者天然适合轻量接入和流程沉淀。 前者的复杂度在 runtime,后者的复杂度在 prompt 和内容治理。
OpenClaw 用极其精简的 Prompt 规则和现成的 Read 工具,低成本实现了 Agent Skills 标准。它够用,但也把长文本管理的压力,原封不动地推给了底层大模型的 Context Window。
我个人对 OpenClaw 这套实现是认可的,前提是别把它想象成一个万能技能平台。它解决的是「如何在不重写 agent runtime 的前提下,把结构化流程知识接进模型执行链路」这个问题。这个问题它解得挺干净。
但如果你要的是 Claude Code 那种「新上下文执行 skill、像子程序一样调用、跑完把结果带回来」,你该找的是子会话、subagent、任务编排层,而不是继续往 SKILL.md 上堆规则。
以上。