本文基于 OpenClaw 官方 Github 源码 进行分析,所有分析均有源码引用,确保100%准确。
OpenClaw 对 skills 的处理不是“全量塞给模型”,而是一个分层漏斗:
- 多来源发现(workspace / managed / bundled / extra / plugin 等)
- 来源内限流(默认每次加载上限 200)
- 资格过滤(enabled、allowlist、OS/bin/env/config 条件)
- 优先级合并覆盖(同名 skill 后者覆盖前者)
- 模型挂载预算(默认最多 150 个 + 30k chars)
- 动态刷新(文件监听 + snapshot version)
一句话:先把“能用的”筛出来,再把“该给模型看的”压到预算内。
如果 workspace/skills 下有几百个目录,直接全塞进上下文会出 3 个问题:
- Token 爆炸(成本高、上下文拥堵)
- 模型决策噪音变大(“技能过载”)
- 文件扫描成本高(启动/首轮响应慢)
- 核心加载:
src/agents/skills/workspace.ts - 可用性判定:
src/agents/skills/config.ts - 监听与版本:
src/agents/skills/refresh.ts - 会话更新挂钩:
src/auto-reply/reply/session-updates.ts - 运行时挂载:
src/agents/pi-embedded-runner/run/attempt.ts - 系统提示拼装:
src/agents/system-prompt.ts - 插件技能来源:
src/agents/skills/plugin-skills.ts
OpenClaw 的 skill 来源包括:
- 内置:bundled skills
- 托管:
CONFIG_DIR/skills - 工作区:
/skills - 个人 agents:
~/.agents/skills - 项目 agents:
/.agents/skills - 扩展目录:
skills.load.extraDirs - 插件声明目录:plugin manifest 中声明的 skills 路径
合并顺序(低 -> 高):
extra < bundled < managed < agents-personal < agents-project < workspace
即:workspace 同名 skill 最终优先级最高。
这让“项目本地覆写公共 skill”成为可能,非常实用。
1)来源扫描限流(第一层)
在 workspace.ts 中默认限制:
maxCandidatesPerRoot = 300maxSkillsLoadedPerSource = 200maxSkillFileBytes = 256KB
这意味着它不会无限递归地扫目录,也不会吃下超大 SKILL.md。
2)可用性过滤(第二层)
即使被发现,也未必进入候选:
-
skills.entries.-> 直接排除.enabled === false - bundled allowlist 不通过 -> 排除
- metadata 条件不满足(OS/bin/env/config)-> 排除
- 可结合远程节点能力(如 remote macOS)判定
3)模型挂载预算(第三层)
进入 system prompt 前再次压缩:
-
maxSkillsInPrompt = 150(数量上限) -
maxSkillsPromptChars = 30_000(字符预算)
- 能不能用(依赖/配置/平台)
- 是否允许(enabled/allowlist/filter)
- 能不能塞进预算(数量 + 字符)
所以“合适”指的是运行时可用且预算友好,不是“语义最像”。
时序图(首轮,通常无 snapshot)
User Message -> initSessionState -> ensureSkillSnapshot
-> ensureSkillsWatcher -> buildWorkspaceSkillSnapshot -> loadSkillEntries(多来源) -> shouldIncludeSkill(资格过滤) -> applySkillsPromptLimits(150 + 30k预算) -> session.skillsSnapshot = { prompt, skills, version }
-> runEmbeddedAttempt
-> resolveSkillsPromptForRun(snapshot优先) -> buildEmbeddedSystemPrompt(skillsPrompt挂载) -> LLM 执行
时序图(后续轮次,动态刷新)
SKILL.md add/change/unlink
-> watcher(chokidar) -> bumpSkillsSnapshotVersion(workspace)
Next Message -> ensureSkillSnapshot
-> version变了 => 重建snapshot -> version没变 => 复用snapshot
-> runEmbeddedAttempt(直接复用snapshot.prompt)
很多人以为“没用到就即时丢弃”。实际上不是单点,而是多阶段:
- 扫描阶段:目录过大、文件过大、无
SKILL.md被丢弃 - 资格阶段:不满足 metadata / config 条件被丢弃
- 挂载阶段:超过
maxSkillsInPrompt或maxSkillsPromptChars被丢弃 - 调用阶段:
disable-model-invocation的 skill 不进入模型技能块
所以它更像分层减压系统,不是“模型先看全量再自己忽略”。
如果你已经进入“技能很多”的阶段,建议按这个顺序调:
- 先按业务域拆目录,减少单 root 混杂度
- 调
skills.limits.maxSkillsLoadedPerSource(慎增) - 调
skills.limits.maxSkillsInPrompt(通常 80~150 区间更稳) - 维持
maxSkillsPromptChars的预算意识,避免 system prompt 过重 - 用
skillFilter(agent/channel 级)做软隔离:让不同入口只看相关技能 - 对“不能被模型直接触发”的技能加
disable-model-invocation - skills 不是越多越好,越多越会加重模型认知负担,skills 是需要精简的
- 误区1:skills 目录里有,就一定进上下文
-> 错,至少要过资格过滤 + prompt 预算。 - 误区2:同名 skill 会并存
-> 错,会按优先级覆盖,最终 Map 只留一个。 - 误区3:改了 SKILL.md 必须重启
-> 错,有 watcher + version,下一轮可刷新。 - 误区4:包含语义检索层(比如 Top-K 策略)
-> 错,没有语义检索和全文检索层,这点比较反常识。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/266266.html