ARTICLE · 1129333
OpenClaw 的 Skill,究竟是谁在加载?
山之上下 · OpenClaw 工程手记 02
OpenClaw 会先把匹配的 Skill 目录信息(名称、描述、路径)注入上下文,模型据此判断要不要用。
选中后,模型再通过 read 按需读取 SKILL.md 正文,获取具体执行步骤;不是发现文件就自动全文加载。
因此,描述负责让 Skill 被选中,正文负责指导实际执行。
之前做多 Agent 的时候,我们由 Master 识别意图,再把任务路由给具体的 SubAgent。
换成 OpenClaw 加 Skills,需要先弄清楚:这次的选择是谁做的?系统发现一个文件,就会自动把它塞给模型,还是要等模型自己去读?
不妨换个生活里的例子。假设我已经准备好一个整理照片的 Skill,也接入了只读的照片扫描工具,然后提出:
按拍摄日期和活动名,给这批照片出一份改名方案。先别改原文件。
Skill 正文里写着怎样识别日期、处理重名、展示结果。但在模型读到这些步骤之前,它凭什么知道该用这一份说明?
同样是 Markdown,进入上下文的方式不一样
先看工作区文件。AGENTS.md、SOUL.md、IDENTITY.md、USER.md 等约定文件,可以在模型调用前由系统注入。源码里面的方法buildProjectContextSection() 会把准备好的文件内容组织成 Project Context,不是先让模型挨个调用读取工具。
Skill 走的是另一条路径:先给符合条件的能力目录,通常包含名称、描述和位置;正文需要时再读取。
把照片例子的第一次输入,按用途简化一下:
调用前 · 教学示意
系统提示词(节选)
运行规则、Skill 选择与读取规则
工作区约定:
AGENTS.md:操作文件前先出方案
SOUL.md:直接回答,少寒暄
IDENTITY.md:本地工作助手
USER.md:按“原名 / 建议名”展示
Skill 目录:
名称:photo-organize
描述:按日期、活动名整理照片命名
位置:/workspace/skills/photo-organize/SKILL.md
工具定义:read、已接入的照片扫描工具
会话消息:给这批照片出改名方案,先别改文件
工具定义和会话消息是另外的输入组成,不能只拿一段系统提示词当作全部上下文。此时,模型知道存在照片整理能力,但还没读到具体步骤,也没有扫描结果。
更关注的,是目录前面那几句提示词
system-prompt-skills.ts 中的 buildSkillsSection(),不只拼接目录,还会生成选择规则。它指导模型寻找匹配的工作流,再通过可用的读取入口取得具体说明。
其中两句原文是:
系统提示词 · 源码节选
Several: most specific. No relevant skill: read none.
Up-front max one. Never invent paths.
有多个候选时选最具体的,没有相关能力就不读;起步阶段最多先读一个,不编造路径。“起步”这个限定很重要,它不是说整个任务只能用一个 Skill。
这个说明更在意描述和正文的分工。
假如目录只写“专业的文件管理能力”,模型很难据此区分照片命名、文件备份和文档归档。正文里的照片处理步骤再详细,也要先有机会被读到。
“什么时候该用我”,不能只藏在“选中我之后才读得到”的正文里。
同样,整理照片是专用流程,“修改文件前先出方案”却是我希望跨任务生效的工作约定。我会把后者提前放进工作区规则,而不是期待每个 Skill 都重复提醒。当然,文字约定仍然不能代替执行层的权限限制。
一个容易漏看的条件:模型真的有办法读吗?
继续往调用方看,system-prompt.ts 里还有一个判断:canAccessSkills。
在普通内置运行时、未开启 Code Mode 的路径下,如果模型没有可见的 read,可用能力中也没有 skills_read,这一处就不会构建 Skills 区块。
仓库里的测试还覆盖了一个更细的情况:候选能力中声明了 read,但本轮模型只看得到 tool_search,测试仍要求 Skills 目录不出现在提示词里。
这里核对的是代码分支和仓库测试断言,不是我跑出的一条线上故障。
这个条件很有用:文件存在、配置里有能力,不代表本轮模型已经拿到了使用它的入口。
如果问题出在这里,继续润色 SKILL.md 没有抓住原因。还没读到的文字,写得更强硬也帮不上忙。
CLI 后端、Code Mode 等有不同入口,不能把“没有 read 就一定没有 Skills”推广到所有运行方式。
读到了,才轮到具体步骤发挥作用
回到照片整理。假设模型选中 photo-organize,请求读取对应文件,运行时会把读到的内容作为工具结果交回后续调用。它不会因此自动变成一段新的系统提示词。
这时,模型才拿到“先扫描日期、检查重名、生成对照表”等做法。随后调用扫描工具,等真实文件信息回来,再整理方案。
所以这条路径是:先看到能力入口,再读操作说明,最后结合工具结果做事。 每一步都可能没有按预期发生,不能只盯着最终答案。
以后排查一个 Skill 为什么没用上,我会先看三处:
目录里有没有它? 没有,先检查加载条件、配置和读取入口;启用 skills_search 的路径,还要检查搜索记录。
有没有发起读取? 有目录却没读取,再检查描述是否能区分任务、选择指令是否合适。
读回来以后做了什么? 到这一步,才重点检查操作步骤、工具返回和执行偏差。
/context detail 可以辅助查看本轮渲染的 Skill 条目、工作区内容和工具定义;是否真正读过正文,还要结合工具调用记录判断。
对我来说,理解加载顺序之后,最直接的改变是知道该把话写在哪里,也知道出问题时先查哪里。
Skill 不必把所有话都提前说完。但它需要先让模型知道,这个任务为什么值得打开它。
山之上下 · AI 工程