Skill Router
当前在此处安装了大约170个技能,它们的质量和范围差异巨大,
其中几个彼此近似重复(三个独立的“让它看起来不通用”设计技能,
两份 impeccable 副本,xlsx 和 xlsx-dsh 并存)。选择错误是
单个代价最高的错误:错误的技能会消耗其整个文档的上下文,
并将答案引向离题,而完全没有技能通常比使用错误的技能更好。
因此:先路由,再工作。这个文件就是路由程序。它很廉价——只需一次文件扫描, 一两次工具调用——并且取代了从技能列表中猜测的过程。 该程序与安装无关:下面的计数、名称和系列描述的是它编写时所针对的目录, 搜索会根据实际找到的目录进行标准化。
1. 在接触任何内容之前先阅读任务
在内心回答以下问题,每个一行。它们决定路由方向,而不是交付物。
- 产出什么? 文件(docx/xlsx/pdf/pptx/png)、运行代码、决策、消息、计划。
- 什么领域? Web 前端、后端、数据、文档、设计、视频/动画、VR、运维。
- 是否已有现有工件? 从零开始 vs. 修改别人的代码——这会将路由从构建技能转变为审核/审查和先理解的技能。
- 谁阅读输出? 投资人、老师、队友、编译器。受众会改变写作技能,而不是技术技能。
如果请求只有一句话的纯粹意图(“给我弄个酷的东西”),那也是一个路由信号: 这意味着还不能选择任何技能,需要先提出问题(第6步)。
2. 快速路径——检查路由表
读取 references/task-types.md(相对于此技能目录)。第一个表将大约
40种常见任务形态映射到一屏内可展示的已验证技能链;
第二个表列出名称难以猜测的窄领域工具(animation-vocabulary、cdn-caching、vercel-connect),
没有人会直接搜索这些名字,所以在断定没有匹配项之前要检查它。
- 找到匹配项 → 带着那个链进入第4步。不要同时再搜索; 表本身就是答案,再次搜索只会浪费令牌。
- 没有匹配,或匹配不完全 → 第3步。
- 表中列出了你没有的技能(不同的安装环境、不同的交互框架、
全新的机器)→ 完全跳过该表,进入第3步。表只是某个安装的映射;
搜索在任何目录上都能工作。用
--doctor验证。
3. 搜索目录
一条命令,不需要模型参与:
# 路径相对于此技能的目录
node scripts/find_skills.mjs "着陆页感觉太模板化" -n 8
node scripts/find_skills.mjs --doctor # 扫描了哪些根目录,找到了什么
它会根据名称和描述(使用 IDF 加权,因此罕见词比 user/code/when 权重更高)
加上一个经过策划的概念层(用于那些与目标技能没有共同词汇的措辞),
对所有已安装技能进行评分。打印出最佳匹配结果及其 SKILL.md 路径,
如果没有任何符合则显示 NO GOOD MATCH。
如何更好地进行查询:
- 使用任务的名词,而不是用户的句子:
spreadsheet charts csv, 而不是“你能把这个变成带图表的东西吗”。 - 运行 2–3 个不同角度,而不是一个长查询——工件角度
(
pitch deck)、领域角度(investor fundraising)、问题角度 (text looks templated)。如果需要,可以将它们合并到一次 bash 调用中。 --explain会逐令牌打印每个结果排名原因——当结果看起来不对时使用它, 而不是去猜测原因。- 每个结果都标记为
[strong]、[likely]或[weak]。[weak]意味着路由器在根据一个偶然出现的词进行猜测——将其视为建议,而不是答案, 并优先使用你自己的判断。如果所有结果都是 weak,脚本会说明。 --all转储完整目录,--name pdf将单个名称解析为路径,--json给出机器可读的输出,-n 20扩展列表(当你想看到更后面的结果时, 对于措辞不佳的查询,正确答案往往是第4个)。- 结果是排名,不是权威。你仍然需要做出选择。
- 脚本位于此技能的
scripts/目录中。如果交互框架暴露了绝对路径, 使用它;否则先cd进入技能目录。 - 它索引所有存在的东西,而不是一个固定的列表:它会扫描跨交互框架的
常见用户级和项目级技能目录(
~/.pi、~/.claude、~/.codex、~/.agents、~/.cursor,加上<cwd>/skills和插件node_modules)。 可以通过SKILL_ROUTER_ROOTS=/a/skills:/b/skills或--root /a/skills指向任何其他地方。在陌生的机器上,先运行--doctor:它会列出每个根目录、 是否存在、贡献了多少技能、重复的名称以及无法解析的SKILL.md文件。 新目录不需要概念或门控——它们只是词汇排名的可选增强; 即使没有任何概念层,搜索仍然会根据名称和描述进行排名。
如果脚本本身不可用,或者搜索两次都没有返回合理结果,
则回退到从系统提示列表中读取 ~/.pi/agent/skills/ 的描述。
不要停滞不前,也不要打开五个 SKILL.md 文件期望其中某一个能行得通。
4. 选择——保持链简短的规则
-
流程优先于实现。 设定如何运行工作的技能(头脑风暴、 编写计划、系统调试、测试驱动开发、写作技能) 在设定输出看起来什么样的技能(设计、docx、nextjs)之前加载。 流程技能通常会告诉你下一步加载哪个实现技能——让它们引导。
-
最多三个技能。 一个是正常的,两个很常见,三个是上限。第四 个意味着你在收集而不是在决定。
-
每个系列只选一个。 永远不要加载同一系列的两个成员——取第一列:
系列 选一个 前端品味 / 反模板 design-taste-frontend,ui-craft,impeccable,frontend-design,craft重复副本 impeccable(agents/)优于impeccable-dsh;xlsx优于xlsx-dsh;kimi/*优于dsh/*,除非dsh的那个明显更具体文档格式 正好匹配文件的那个: docx、pdf、pptx、xlsx动画 animate(Web)、animate-expo(React Native)——不要同时选择后端 backend-patterns、create-a-backend、api-design——最多两个探索 / VR hz-*系列 +metavr-cli;始终以hz-quest-verify-first开始 -
尊重平台门控。
hz-*、portal、metavr-cli需要 Quest/VR 上下文;cloudbase需要 CloudBase;kimi-webbridge/kimi-cu需要真实的浏览器或 桌面 GUI。如果任务没有提到平台名称,即使词语匹配得再好,该技能也不适用。 -
证明或拒绝。 对于每个候选技能,用一个子句说明:为什么选这个。 如果子句是“它提到了同样的词”,那就拒绝它。两个技能可以共享词汇但仍然用于不同的机器。
-
没有技能也是有效的答案。 如果没有任何技能符合标准,用简短的几句话说明, 然后用你自己的判断完成任务。缺少技能不是启动一个半相关技能的理由。
-
仅在任务转向时重新路由。 同一工作流中的新子任务 不会触发新的搜索。领域变更(用户说“实际上,把它做成幻灯片” )则会。
5. 用一行说明路由,然后继续
在执行工作之前,声明一次路由:
使用
design-taste-frontend(反模板化着陆页)→animate用于英雄区。 文案部分没有合适的技能;我自己来写。
这一行的规则:一两个句子,只包含名称和理由。不要写关于技能库存的论文, 不要写“我为这个任务选择了以下技能,因为……”。用户想看到决策, 而不是决策过程。如果路由不寻常或你明知偏离了表格, 那一行中值得增加一个额外的子句。
6. 只询问真正阻碍工作的问题
这是路由真正体现价值的地方:选定的技能会告诉你它需要知道什么, 所以问那些问题——而且只问那些。
在以下情况下提问,而且只在以下情况下提问:
- 任务有两个或更多真正不同的交付物(“一张海报”可能是 PNG 或 幻灯片,并且文件不同),
- 受众或格式未知且无法从上下文中猜测,
- 所选技能自身的指令要求一个用户必须拥有的决策(品牌、 预算、凭证、真实 vs. 模拟数据),
- 某个路由会涉及真金白银或触及生产环境。
不要问:
- 该用哪个技能——这是本技能的工作。问关于结果的问题,让路由从答案中得出,
- 任何请求已经回答过的问题,任何代码库或文件能回答的问题,
- 任何合理的默认值可以覆盖的问题。选择默认值,在声明行中说你选了哪个默认值, 然后继续前进。这个用户更喜欢长时间无人值守的运行,而不是逐轮确认。
形式:一次 ask_user_question 调用,最多3个问题,每个问题2-4个选项,推荐选项放在第一位并标注“(推荐)”,
每个选项用一句简短的话说明它承诺了什么。永远不要在第一个问卷之后紧接着再堆一个;
如果一个答案引发了新问题,优先选择一个合理的默认值而不是再来一次往返。
如果你加载的技能有自己的探索或提问阶段(大多数设计和规划技能都有), 则运行那个阶段,而不是自己发明问题。连续两轮提问会被认为是拖延。
7. 加载并执行
-
使用
read工具完整读取搜索返回路径的SKILL.md。 草草阅读的技能会产生草率的输出。 -
解析任何
references/、scripts/、assets/路径时,相对于该技能的目录—— 搜索输出会打印文件路径,因此父目录就是技能根目录。 -
按脚本原样运行。如果某个脚本需要一个它没有文档说明的参数, 直接说明,而不是用你自己的实现来代替。
-
技能在冲突时获胜。 一旦加载,它的指令会覆盖本文件关于如何执行工作的意见, 并且覆盖通用的最佳实践。这个文件只负责选择它。
-
如果加载的技能以“先问用户”或“先计划再写代码”开头, 那就去做——路由到一个流程技能然后跳过它的流程, 比完全不路由更糟糕。
-
如果在工作中途发现技能选择错误,直接说明并重新路由(第4步)。 悄悄绕过错误的技能是失败的模式。
-
记录修正,以便同一错误不会再次发生:
node scripts/find_skills.mjs --learn "<出错的措辞>" <正确的技能> node scripts/find_skills.mjs --wrong "<出错的措辞>" <错误的技能>每当用户拒绝某个路由、加载的技能被证明是错误工具、 或者你不得不手动路由因为搜索遗漏了,就这样做。 学习到的修正会在未来类似的查询中超越词汇得分, 并且它们会随安装环境一起移动——这是路由器在其从未见过的环境中变得更好的方式。
8. 结束
在最后用一行说明:使用了哪些技能,以及工件放在哪里。然后停止—— 不要总结技能内容,不要主动解释路由过程。
维护——在不破坏路由器的情况下更改它
路由器是经过评分的,而不是靠感觉。scripts/eval_routing.mjs 包含80个
真实查询,每个查询都附带一组真正可接受的技能答案,
以及十几个门控案例(一个通用的 React 查询绝不能浮现出一个 Quest 技能)。
在任何更改前后运行它:
node scripts/eval_routing.mjs
# 得分: 80/80 (100.0%) 门控泄露: 0
node ... --verbose # 逐案例排名
node ... quest # 仅匹配案例
node scripts/smoke_portable.mjs # 外部目录 + 学习 + 600技能规模
smoke_portable.mjs 是可移植性测试:它在本路由器从未见过的领域(Kubernetes、Rust、Salesforce、Terraform…)中虚构了16个技能,检查排名、释义鲁棒性、可移植门控、学习、重复名称、空目录、含空格的路径、SKILL_ROUTER_ROOTS 以及600技能的规模运行。如果你更改了评分,两个测试套件都必须保持绿色——eval 套件在已知目录上守护质量,smoke 套件在未知目录上守护行为。
任何能提高分数的更改都是进步;任何降低分数的更改都是回归,无论代码看起来多整洁。期望技能未安装的案例会被跳过,而不是失败,因此套件可以在任何机器上运行。
当真实任务路由错误时,在最便宜、最能解释问题的层面修复它:
- 同一概念用词不当 → 在
find_skills.mjs中添加一个经过策划的CONCEPTS规则 (when正则 →boost分数,可选的unless否决和demote)。这一层用于那些与技能没有共同词汇的意图: “模糊想法,没有规格” →brainstorming。 一次性问题? 不要为此使用这一层——改为记录它(--learn)。CONCEPTS是 用于通用行为;记忆则用于“这个措辞,这个技能”。 - 重复出现的任务形态 → 在
references/task-types.md中添加一行。 查询时无需额外成本,快速路径完全跳过搜索。 - 某个技能总是输给噪声邻居 → 将其添加到
DEMOTE,或者给噪声技能 添加一个demote概念(例如,单独的dashboard不能胜过ui-craft与ui-craft-dense-dashboard)。 - 平台技能泄露到通用查询中 → 扩展
GATES,添加必须存在才能激活的关键词。 - 用户纠正过的路由 →
--learn/--wrong,然后继续。偶尔检查--memory:如果同一技能对于同一种措辞反复被纠正, 将模式提升到CONCEPTS中,并--forget那些条目。
首先将失败的查询添加到 CASES 中,看着它失败,然后再修复。不要在没有记录下的查询上调整评分——
那样路由器最终会在你的例子上表现良好,而在用户的实际问题上表现糟糕。
危险信号——你在合理化,停下来
| 想法 | 现实 |
|---|---|
| “这个很简单,不需要路由” | 快速路由,快速实现。快速路径 |
…
[truncated for translation]