先说结论:LLM不会选错,但OpenClaw可能选不到你认为最最最最匹配的那一个。从结果上看,仍然是选错了skill,但不是LLM的锅。
这周在clawhub上看到一个有意思的讨论:如果我的OpenClaw本地有1000万个skill,会不会因为上下文过载,导致AI选错skill?
直觉上确实有可能:1000万个skill的description塞进提示词,token数早就爆炸了。
但OpenClaw的实际实现,和你想的不太一样。
核心答案:不会"选错",但会"漏掉"——解决方案并不彻底
先说结论:OpenClaw不会因为上下文过载而"选错"skill,但可能会因为截断而"看不到"某些skill。
更关键的是:OpenClaw的解决方案并不彻底,它假设skill数量不会太多。
这是两个不同的概念:
"选错":AI看到了skill A和skill B,两个都匹配,结果选了不太合适的那个。
"看不到":AI压根没看到skill C,因为它在截断时被丢掉了。虽然从结果上看是选错了,但不是LLM的上下文爆炸而选错。。。
源码解析:Skill加载的完整流程
本文基于 OpenClaw 2026.4.16 版本分析
▪ 1. 没有基于用户问题的筛选
很多人以为OpenClaw会用向量数据库或RAG来检索skill,但实际代码里根本没有这回事。
看 src/agents/skills/workspace.ts 的核心逻辑:
// 1. 加载skill时,从多个来源收集所有skill const skillEntries = loadSkillEntries(workspaceDir, opts); // 2. 前置筛选:过滤掉不符合运行条件的skill const eligible = filterSkillEntries( skillEntries, opts?.config, effectiveSkillFilter, opts?.eligibility, ); // 3. 按字母排序 const promptSkills = compactSkillPaths(resolvedSkills) .slice() .sort((a, b) => a.name.localeCompare(b.name, "en")); // 4. 应用Token限制 const { skillsForPrompt, truncated, compact } = applySkillsPromptLimits({ skills: promptSkills, config: opts?.config, agentId: opts?.agentId, }); // 5. 格式化成XML,塞进提示词 const prompt = formatSkillsForPrompt(skillsForPrompt);
关键发现:
就是前置筛选 → 字母排序 → Token限制 → 全部格式化 → 塞给LLM。
▪ 2. 前置筛选:只过滤运行条件,不匹配用户问题
filterSkillEntries 的核心是 shouldIncludeSkill:
export function shouldIncludeSkill(params: { entry: SkillEntry; config?: OpenClawConfig; eligibility?: SkillEligibilityContext; }): boolean { // 1. 检查skill是否被显式禁用 if (skillConfig?.enabled === false) { return false; } // 2. 检查bundled skill是否在白名单中 if (!isBundledSkillAllowed(entry, allowBundled)) { return false; } // 3. 运行时环境检查(最关键的筛选) return evaluateRuntimeEligibility({ os: entry.metadata?.os, remotePlatforms: eligibility?.remote?.platforms, always: entry.metadata?.always, requires: entry.metadata?.requires, hasBin: hasBinary, hasRemoteBin: eligibility?.remote?.hasBin, hasAnyRemoteBin: eligibility?.remote?.hasAnyBin, hasEnv: (envName) => Boolean( process.env[envName] || skillConfig?.env?.[envName] || (skillConfig?.apiKey && entry.metadata?.primaryEnv === envName), ), isConfigPathTruthy: (configPath) => isConfigPathTruthy(config, configPath), }); }
前置筛选只会过滤这些:
--- metadata: os: - darwin - linux ---
如果你在Windows上运行,标注了 os: [darwin, linux] 的skill会被过滤掉。
--- metadata: requires: bins: - git - gh env: - OPENAI_API_KEY config: - browser.enabled ---
git/gh 命令 → 被过滤OPENAI_API_KEY → 被过滤browser.enabled 为 false → 被过滤{ "skills": { "allowBundled": ["github", "weather"] } }
不在白名单的bundled skill被过滤掉。
{ "agents": { "defaults": { "skills": ["github", "git", "coding-agent"] } } }
只保留白名单中的skill。
▪ 3. 前置筛选后的数量:可能还是很多
关键发现: 前置筛选只过滤"运行条件",不过滤"用户问题相关性"。
假设你有1000万个skill,但:
os: [] 或不设)requires: {})筛选后还是1000万个!
这时候,Token防线会触发:
const DEFAULT_MAX_SKILLS_IN_PROMPT = 150; const byCount = params.skills.slice(0, limits.maxSkillsInPrompt);
只保留前150个(按字母排序)。
const DEFAULT_MAX_SKILLS_PROMPT_CHARS = 18_000; if (!fitsFull(skillsForPrompt)) { // 切换到compact格式(只有name + location) compact = true; }
if (!fitsCompact(skillsForPrompt)) { // 二分搜索找到最大的能塞进去的prefix skillsForPrompt = skillsForPrompt.slice(0, lo); }
▪ 4. 匹配逻辑完全交给LLM
看 src/agents/system-prompt.ts 的指令:
function buildSkillsSection(params: { skillsPrompt?: string; readToolName: string }) { return [ "## Skills (mandatory)", "Before replying: scan entries.", "- If exactly one skill clearly applies: read its SKILL.md...", "- If multiple could apply: choose the most specific one...", "- If none clearly apply: do not read any SKILL.md.", trimmed, ]; }
"scan entries" — 让LLM自己扫描所有skill的description。
不是系统预先筛选出最相关的skill,而是把所有符合运行条件的skill的description都给LLM,让LLM自己选。
为什么说解决方案不彻底?
▪ 问题1:假设skill数量不会太多
OpenClaw的默认配置:
maxSkillsInPrompt: 150maxSkillsPromptChars: 18000这意味着:
这不是智能方案,是暴力方案。
▪ 问题2:没有基于用户问题的筛选
如果用户问"GitHub issue怎么处理":
github-issues50万个description的token是多少?
假设每个description平均100字符:
如果github-issues在前150个(按字母排序):
如果github-issues在第151个:
▪ 问题3:字母排序截断的局限性
const promptSkills = compactSkillPaths(resolvedSkills) .slice() .sort((a, b) => a.name.localeCompare(b.name, "en"));
skill按字母顺序排序,然后截断。
这意味着:
github-issues 会被排在前面(g开头)zzz-helper 会被排在后面(z开头),很可能被截断这不是基于相关性排序,而是基于字母顺序。
▪ 问题4:MCP/Function Call不影响筛选
你可能会问:一个skill可能会用到多个MCP或Function Call,这些不参与筛选吗?
答案是:不参与。
MCP(Model Context Protocol)和Function Call是skill内部使用的工具,是skill运行时需要的资源,不是筛选skill的依据。
OpenClaw的筛选逻辑:
这意味着:
实际场景分析
▪ 场景1:依赖筛选很严格(常见情况)
你是一个后端开发者,安装了1000万个skill:
最终只剩10个skill!
这时候:
这种情况下,OpenClaw的方案是有效的。
▪ 场景2:依赖筛选不严格,但数量限制兜底
你是一个全栈开发者,环境配置很全:
这时候:
这种情况下,OpenClaw的方案是"暴力截断",不是智能筛选。
▪ 场景3:极端情况,全部通过筛选
所有1000万个skill都通过筛选:
这种情况下,OpenClaw的方案完全失效。
实战建议:如何缓解这个问题?
▪ 1. 合理设置metadata(最重要)
❌ 不好:依赖太少
--- name: my-skill description: Do something ---
这个skill会在所有环境通过筛选,增加候选数量。
✅ 好:明确依赖
--- name: github-issues description: Fetch GitHub issues, spawn sub-agents to implement fixes metadata: requires: bins: - git - gh config: - browser.enabled os: - darwin - linux ---
这个skill只在有git/gh命令、浏览器启用、非Windows环境时通过筛选。
▪ 2. 使用skillFilter(最有效)
如果你知道这次任务只需要某个技能集,直接过滤:
{ "agents": { "defaults": { "skills": ["github", "git", "coding-agent"] } } }
这样:
这是最有效的解决方案。
▪ 3. 按环境拆分workspace
如果你的skill数量真的超过300个,考虑按环境拆分:
~/workspace/backend/ # 后端相关skill(100个) ~/workspace/frontend/ # 前端相关skill(100个) ~/workspace/ai/ # AI相关skill(100个)
用不同的agent配置加载不同的workspace:
{ "agents": { "list": [ { "id": "backend-dev", "skills": ["backend/*"], "workspace": "~/workspace/backend" }, { "id": "frontend-dev", "skills": ["frontend/*"], "workspace": "~/workspace/frontend" } ] } }
这是终极方案:不是让一个agent背负所有skill,而是让多个agent各司其职。
▪ 4. 调整limits(慎用)
如果经常遇到截断,可以调大限制:
{ "skills": { "limits": { "maxSkillsInPrompt": 300, "maxSkillsPromptChars": 36000 } } }
但要注意:
源码中的隐藏细节
▪ 1. 路径压缩节省token
// /Users/alice/.bun/.../skills/github/SKILL.md // → ~/.bun/.../skills/github/SKILL.md
每个skill路径节省5-6个token,100个skill就是500-600个token。
▪ 2. 字母顺序排序
.sort((a, b) => a.name.localeCompare(b.name, "en"));
技巧: 重要skill的name用字母表前半部分开头(如a-github),避免被截断。
▪ 3. 截断时的二分搜索
不是简单的slice(0, N),而是二分搜索找到最大的能塞进去的prefix。
结论
OpenClaw的解决方案并不彻底,它假设:
但这在以下情况下会失效:

给你的建议:
最后,给一个终极建议:
如果你的skill数量真的超过300个,需要对skill进行治理:
考虑按环境/用途拆分成多个workspace,用不同的agent配置来加载不同的skill子集。
不是让一个agent背负所有skill,而是让多个agent各司其职。
觉得有用?欢迎点赞、在看、转发!
有任何问题,评论区留言,我会一一回复。
一文讲清:LLM、CoT、Function Calling、MCP、Skills、Agent、Agent OS
别再问LLM、Workflow、Function Call、MCP、Skill、Agent、OpenClaw是什么了,看完这篇秒懂!有配套源码