把低频 Skill 变成可检索冷存储,让 Agent 按需找回能力,省上下文也更稳。
原文链接 :AI小老六
导语
Agent 的能力越来越像一个小型操作系统:它能读文件、调接口、写代码、查日历,也能按团队经验执行一套固定流程。Skill 就是把这些经验沉淀下来的常见方式。
问题也随之出现。Skill 少的时候,把所有 Skill 的名字和描述塞进上下文,模型大概率还能挑对。Skill 一多,这套办法开始变形:上下文预算被占掉,description 被截断,语义相近的 Skill 互相干扰,低频 Skill 明明一个月才用一次,却每天都在消耗常驻 token。
更麻烦的是,很多团队在写 Skill 时天然倾向于"多拆一点"。一个 OpenAPI 一个 Skill,一个业务流程一个 Skill,一个文档模板一个 Skill。短期看很灵活,长期看就会把 Agent 的路由入口堆成一片噪声。
我最近在想的不是"再训练一个更准的 Skill 分类器",而是另一个问题:Skill 能不能像知识库一样被 Agent 主动检索?常用能力保持在手边,长尾能力先放进冷存储;需要时,Agent 自己搜索、检查证据、确认选择,再把对应 Skill 拉回来执行。
这其实就是 Agentic Search 在 Skill 管理里的一个变体。
Skill listing 的真实成本:不是 token 数字那么简单
图:高频 Skill 留在工作台,长尾能力进入可检索冷存储
Skill 的一个核心设计是渐进式加载。默认只把 metadata 放进上下文,真正的操作步骤、示例、脚本和参考资料等到触发后再读。这比把完整插件说明常驻上下文要合理得多。
但 metadata 也不是免费的。
常见 Skill 文件大概长这样:
text
skills/
lark-doc/
SKILL.md # metadata + body
references/
scripts/
lark-mail/
SKILL.md
code-review/
SKILL.md
SKILL.md 通常分成两层:
- frontmatter / metadata:name、description、tags、适用场景,默认参与路由。
- body:完整流程、注意事项、命令示例、错误处理,命中后再读。
这套结构在几十个 Skill 时很好用。到了几百个甚至几千个 Skill,麻烦开始出现。
第一,宿主通常会给 Skill listing 设置固定预算。预算超了怎么办?只能截断 description,甚至只保留 name。一个本来写得很清楚的"飞书文档读取、更新、图片插入与权限处理",被截成"飞书文档读...",路由质量自然会掉。
第二,Skill 数量越多,语义相似项越多。lark-doc、lark-wiki、lark-drive、lark-sheets 都和"飞书文件"有关;stock-analysis、china-stock-analysis、us-stock-analysis 都和股票有关。模型看到一堆短描述时,很容易被表面词拉走。
第三,常驻 listing 会让低频 Skill 持续占预算。一个一年用三次的 Skill,只要 enabled,就和每天都会用的 Skill 站在同一个上下文入口里。这对个人环境还能忍,对团队级 Skill 目录就不太现实了。
所以,Skill 管理的核心矛盾不是"怎么把所有 Skill 介绍得更短",而是:哪些 Skill 应该常驻?哪些 Skill 应该退出上下文,但仍然能被找回?
被动 Top-K 路由为什么不够
一个自然反应是做检索。把 Skill 的 name、description、body 建索引;用户请求来了,embedding 召回 Top-K,再交给 reranker 或 LLM 选一个。
这条路当然能做,而且很多场景有效。但它有两个工程代价。
先说模型依赖。embedding、reranker、向量库、索引刷新、版本兼容,这些东西对平台团队不是大问题,对本地 Agent 用户和小团队就是额外负担。Skill 本来是为了降低使用门槛,最后又引入一套检索基础设施,味道有点不对。
再说交互形态。传统 Top-K 本质上是一次性函数调用:用户 query 进去,候选列表出来,Agent 只能消费结果。如果第一轮 query 抽错了词,或者候选里两个 Skill 很接近,Agent 很难像人一样"换个词再搜一下""打开两个候选看看证据""不确定就不要选"。
这就是被动检索的限制。它把 Agent 放在消费者位置,而不是搜索过程的操作者。
Agentic Search 的关键变化:让模型控制检索过程
Agentic Search 不神秘。它只是把搜索从"一次返回答案"改成"多步收集证据"。
一个更适合 Agent 的检索接口,至少要允许它做四件事:
- 从当前任务里抽关键词,而不是原样拿用户句子去搜。
- 看见候选为什么被召回,包括命中的字段、片段、分数和是否截断。
- 对少量候选做进一步检查,但不要一下子把全文全倒出来。
- 在证据足够时选择,在证据不足时停止或继续搜索。
这和近两年 Agentic RAG、Direct Corpus Interaction、grep-style harness 的讨论是一条线:检索器不再只是黑盒排序器,而是 Agent 可以操作的外部环境。
放到 Skill 管理里,思路会变成这样:
图:Agent 在 enabled Skill 与 metadata corpus 之间按证据路由
这里有一个边界很重要:select 之前,只看 metadata,不读被禁用 Skill 的 body。
这不是洁癖,而是上下文控制。搜索阶段如果每个候选都打开完整说明,Skill router 很快会退化成另一个上下文黑洞。metadata 足够时就选;metadata 不够时,最多检查少量候选;仍然不够,就承认低置信,而不是硬选一个看起来顺眼的。
禁用不是删除:低频 Skill 应该进入冷存储
Skill 管理里最容易被误解的是 disable。
很多人听到禁用,会以为能力消失了。更合理的理解是:禁用只是让它退出常驻 listing。文件还在,metadata 还在,路径还在,使用记录也可以继续记录。它只是从"每天站在上下文门口"变成"需要时可以被查到"。
这有点像内存和磁盘的关系。高频、基础、系统级 Skill 留在内存里;长尾 Skill 放到磁盘上。Agent 不应该每次启动都把整块磁盘读进上下文,它应该有一套索引和读取协议。
一个可维护的 Skill 冷存储,至少需要这些东西:
| 组件 | 作用 | 需要避免的问题 |
|---|---|---|
| metadata corpus | 保存 disabled Skill 的可检索字段,例如 name、description、aliases、tags、tools、domains、intents、examples | description 太短、字段缺失、同质 Skill 没有区分度 |
| stable ref | 用稳定引用指向候选,而不是直接把本地路径暴露给模型 | 路径泄露、路径变化、候选不可复现 |
| inspect 接口 | 允许 Agent 对少量候选查看更多 metadata | 一次性输出过多,重新制造上下文压力 |
| select 记录 | 把"为什么选它"写成可审计事件 | 路由不可追踪,后续无法优化 |
| restore 机制 | 能把 disabled Skill 恢复为 enabled | 禁用变成破坏性操作 |
这样处理后,Skill 数量增长带来的压力就不再线性压到上下文里。上下文里常驻的是少量高频 Skill,加一个 router 入口;长尾 Skill 通过 metadata corpus 被按需找回。
三个 primitive:search、inspect、select
图:Agent 通过 search、inspect、select 逐步收集路由证据
我更倾向于把 Skill 路由拆成三个小工具,而不是做一个"一步到位"的 routeSkill(query)。
corpus search:低成本召回
search 接收 Agent 抽出来的关键词,返回一组候选。这里最好区分 must terms 和 probe terms。
比如用户说"读取飞书 docx 并提取第一章",must terms 可以是 lark、docx,probe terms 可以是 document、fetch、extract。search 返回的不是最终答案,而是候选证据:ref、score、matched terms、description snippets、totalMatches、returned、truncated。
truncated 这个字段很有用。它告诉 Agent:当前 query 太宽了,候选被截断了,需要换词或加约束。没有这个信号,模型会误以为返回列表就是全部世界。
corpus inspect:只检查少量候选
inspect 用来处理"几个候选都像"的情况。它可以返回更完整的 metadata,例如 aliases、tags、tools、domains、intents、examples,但仍然不读 body。
这一步的重点是有界。不要让 Agent 一口气 inspect 50 个候选。通常 2-5 个就够了。Skill 路由不是信息检索比赛,它只是要帮当前任务找到一个能执行的能力入口。
corpus select:把选择变成记录
select 是闭环动作。Agent 必须给出 ref/id、原始 query、confidence 和 reason。CLI 再把 ref 解析成真实 disabled Skill,记录一次 routed use,最后返回 selected.skillMdPath。
这样做有两个好处。
第一,模型不能直接拿搜索结果里的路径乱读。第二,所有选择都有审计记录。以后你想知道哪些 disabled Skill 其实经常被找回,哪些从来没有被选中过,就有数据可看。
一个典型调用流程可以设计成这样:
bash
agentic-skill-router skills corpus search \
--all "lark" \
--any "docx" \
--any "document" \
--any "extract" \
--limit 30 \
--json
agentic-skill-router skills corpus inspect corpus-xxx corpus-yyy --json
agentic-skill-router skills corpus select "corpus-xxx" \
--query "读取飞书 docx 并输出第一章" \
--confidence high \
--reason "metadata covers Lark docx fetching and document content extraction" \
--json
这个接口不炫,但边界清楚。Agent 负责判断,CLI 负责索引、分页、ref、JSON schema、缓存和选择记录。
Bash 直接搜文件,为什么不适合作为默认产品边界
如果只看研究验证,直接让 Agent 用 shell 搜本地 Skill 目录很诱人。find、grep、sed、awk 足够强,模型也能临场组合很多策略。中小规模目录里,这种 DCI 风格的做法甚至会非常准。
但它不适合当默认产品形态。
原因不是 bash 不强,而是太自由。今天模型写 grep -R,明天写 find | xargs,后天又加 head -20。路径里有空格怎么办?文件太多触发 ARG_MAX 怎么办?候选被 head 截掉怎么办?输出太长撑爆上下文怎么办?这些问题最后都会落到 prompt 里,prompt 越写越像一段脆弱的 shell 教程。
Tool-wrapped 的优势就在这里。把容易犯错的部分收到 CLI:路径枚举、缓存、索引、分页、截断提示、候选引用、schema 校验。Agent 还在做主动搜索,但它不必每次临场写一段不稳定的 pipeline。
换句话说,bash 适合调试 failure case,适合做研究对照;默认路径最好还是稳定 primitive。
Metadata-first 的边界:领域词会欺骗路由
只看 metadata 也有上限。
最典型的失败来自"业务领域词"和"底层执行工具"打架。用户说"分析 supply shock 的经济影响并生成表格",metadata-only router 可能被 economics、shock analysis、timeseries 这些领域词吸走。但真正要完成任务,可能需要的是 spreadsheet / Excel Skill,因为交付物是读取表格、写公式、生成文件。
这类 query 不能简单按语义最相近来选。要加一条 tie-break:当任务明确要求操作 xlsx、csv、单元格、公式、透视表或表格产物时,底层 substrate Skill 的优先级应该高于领域分析 Skill。除非领域 Skill 明确声明自己也能完成文件读写和表格输出。
所以,metadata-first 更像第一层过滤,不是最终真理。候选接近时,可以引入 body-on-tie:只读取少量候选的 body,确认谁真的具备执行能力。这个动作必须少量、低频、可记录,否则又会回到全文倒灌的问题。
从理论到一个可用实现:我找到的 agentic-skill-router
前面讲的是设计原则。按这些原则找实现时,我看到一个比较贴近这套思路的项目:agentic-skill-router。
它的定位不是再做一个推荐系统,而是把低频 Skill 从常驻 listing 里移出去,同时保留可检索 metadata。Agent 没有明显命中 enabled Skill 时,再通过 router Skill 进入 search / inspect / select 工作流。
项目地址:
- GitHub:https://github.com/legendtkl/agentic-skill-router
- Web 页面:https://legendtkl.github.io/agentic-skill-router/
我觉得它有几个设计点值得单独看。
第一,disable 的实现很轻。它通过重命名 SKILL.md 为 SKILL.md.agentic-skill-router-disabled 之类的方式让 Skill 退出宿主扫描,但文件本身仍然可恢复。这符合"禁用不是删除"的思路。
第二,检索阶段坚持 metadata-only。router 在 select 前不读取 disabled Skill body,只暴露可路由字段和候选证据。这个边界能避免路由过程自己变成上下文膨胀源。
第三,候选使用 stable corpus ref。Agent 看到的是 corpus-... 这类引用,而不是本地绝对路径。最终必须通过 select 才能拿到 selected.skillMdPath。这让路径暴露、幻觉路径、绕过审计的问题少很多。
第四,select 会记录 routed use。这个细节很工程化:路由不是一次性行为,它会反过来影响后续管理。一个长期被找回的 disabled Skill,可能应该重新 enabled;一个从不被选中的 Skill,可能 metadata 写得不好,也可能确实该清理。
基本安装和初始化很直接:
bash
npm install -g agentic-skill-router
agentic-skill-router init
如果需要指定宿主和作用域,可以显式写:
bash
agentic-skill-router init codex project
agentic-skill-router init codex global
agentic-skill-router init claude-code project
agentic-skill-router init claude-code global
日常管理大概是这些动作:
bash
agentic-skill-router list
agentic-skill-router suggest --json
agentic-skill-router disable <skill-id> --yes
agentic-skill-router enable <skill-id>
agentic-skill-router status
如果在 Codex 或 Claude Code 里用,也可以通过对应宿主的 Skill 触发方式调用。这里不把它当成主角,更准确地说,它是 Agentic Skill Routing 这套设计的一个可运行样本:低频能力冷存储、metadata corpus、Agent 主动检索、选择后再读取 body。
更长期的形态:本地 router 加服务化 registry
本地 Skill 管理能解决一部分问题,但它不该承担全部治理职责。
Skill 一旦在团队内扩散,新的问题会冒出来:哪个版本最新?哪个版本废弃了?谁发布的?有没有签名?有没有组织推荐版本?当前宿主是否兼容?本地目录扫描很难回答这些问题。
更合理的分工可能是:
图:本地 Skill Router 与远端 Registry 的分工
本地继续负责低延迟、隐私、缓存和最终执行。服务端负责目录、版本、信任、策略和反馈闭环。
这个 registry 不需要把所有 Skill body 都服务化,也不应该替 Agent 做最终选择。它更像一个控制平面:告诉本地 router 有哪些 Skill、哪个版本可信、哪些已经 deprecated、哪些适合当前组织、包的 digest 是什么、发布者是谁。
一个完整流程可以是:开发者发布 Skill,registry 校验 schema、metadata、权限声明和签名;组织把它标成 recommended、experimental、deprecated 或 blocked;本地 router 同步 metadata 和 lockfile;Agent 请求到来时先查本地 enabled Skill,未命中再查 cache / registry;选中后才按需拉取或 materialize 对应 Skill。
这比"每台机器各装各的 Skill,然后靠目录扫描自我管理"可靠得多。
收束
Skill 规模化之后,真正难的不是写更多 Skill,而是让 Agent 在正确的时间看见正确的 Skill。
把所有 Skill 常驻上下文,简单但不耐扩展。把路由完全交给一次性 Top-K,省事但会削弱 Agent 的主动判断。更稳的方向是 Agentic Skill Routing:高频 Skill 常驻,长尾 Skill 进入 metadata corpus;Agent 通过 search、inspect、select 多步找回能力,证据不足就继续查或停止,不强行命中。
这套方法的价值不在于某个 ranker 分数多高,而在于边界清楚:metadata 先行、候选有界、选择可审计、body 按需读取、禁用可恢复。等 Skill 再往团队级、组织级扩张,本地 router 还可以自然接上服务化 registry,把发现、版本和信任治理从个人机器里搬出来。
Agent 的上下文窗口不应该变成 Skill 目录的垃圾桶。它更像工作台,只放当前要用的工具。其他工具可以在仓库里,但得有一套靠谱的查找和取用办法。
推荐阅读
平台智能化到了分水岭:为什么配置代码化才是 AI Coding 的下一代接口
业务 Agent 搭建指南:别急着重造 Agent,用知识、工具与评测跑通闭环