Skill Router 正在從「可有可無」變成 Agent 架構裡的交通警察。截至 2026 年 8 月 8 日,資安垂直套件 reverse-skill 在 GitHub Trending 顯示「本週 10,400 stars」;2026 年 8 月 6 日提交的預印本,又把一個持續成長、建圖時有 690 個 Skill 節點的資料庫拿來測試檢索。這是很強的興趣訊號,但不是「每個 Agent 都需要同一套 Router」的證明。
真正的問題很直白:Skill 裝得愈多,目錄愈長;全部載入很貴,只看關鍵字又容易選錯。這篇專為第一次做 Agent 系統的讀者寫,不假設你會資訊檢索。我會先拆清楚 discovery、routing、loading、sequencing,再帶你做一個 BM25+embedding 的 top-k Router,加上低信心澄清、NO_SKILL fallback 與可重跑的評測。
先說結論:Skill Router 的一句話公式
本篇要做的最小可用版本:Skill Router = BM25(抓字面)+ Embedding(抓意思)+ Abstain(不確定就不選)。
- 啟動時只向模型揭露輕量目錄,不把每份
SKILL.md正文都放進 context;宿主仍可預先解析或快取檔案。 - 每次任務先取 top-k 候選,再用信心閘門決定「啟用、澄清、或不選」。
- 選中一個或多個任務 Skills 後,才展開明確 prerequisites,決定執行順序。
- 成敗看 held-out 任務,不看你自己照著 Skill 描述改寫的漂亮測試題。
Skill Router 是什麼?先把四個動作分開
把 Agent 想成剛進大型五金行的新員工。它不需要先背完每把工具的說明書;它需要先看目錄、找到候選、拿出正確工具,若工作要兩把工具,再決定先後。這四步分別是:
- Discovery「盤點目錄」:掃描允許的 Skill 位置,讀取名稱、描述、路徑與相容條件。
- Routing「找候選」:拿目前任務去搜尋目錄,排出最相關的 top-k。
- Loading/Activation「拿說明書」:通過閘門後才把完整
SKILL.md放進模型 context。 - Sequencing「排施工順序」:若任務需要多個 Skills,再依 prerequisites、輸入輸出與先後關係排序。
Agent Skills 官方 client guide 把 progressive disclosure 分成三層:啟動時只向模型揭露名稱與描述,啟用時讀完整指令;指令需要時,才讀 references/assets 或執行 scripts。官方粗估每個目錄項約 50–100 tokens。換句話說,Skill Router 管的是「先找誰」;Loader 管的是「何時把正文拿進來」。
Agent Skills 規格沒有規定 BM25、embedding、top-k、信心門檻或多 Skill dependency graph;本文都是 Router 控制層的自訂實作。

為什麼 Skills 愈多,不一定愈強?
第一個成本是 context。按照官方每個目錄項約 50–100 tokens 的估算,100 個 Skills 的輕量目錄就可能佔 5,000–10,000 tokens;這還不是正文。第二個成本是混淆:pdf-ocr、pdf-redactor、pdf-form-fill 都有 PDF,字面很像,真正意圖卻不同。第三個成本是錯誤流程:選到「把畫面模糊」的 Skill,不等於真正移除 PDF 文字層裡的個資。
2026 年 8 月 6 日提交的 《Comparative Approaches to Agent Retrieval over Large Skill Libraries》v1 預印本,把這個痛點量化了。在這一份單一組織、117-query 的評測裡,BM25 hit@5 是 50.4%,hybrid 是 73.5%(95% half-width ±8.0 個百分點),相差 23.1 個百分點;但 hybrid 仍有 26.5% 沒把正確 Skill 放進前五。這支持在該目錄測 hybrid,不證明它在每個 corpus、語言或 embedding 都會勝出。
這裡要讀準數字:690 是建圖當下的 Skill 節點數;主要 retrieval 表格使用 117 題與 875 筆 catalogue entries,論文也註明部分較早測量發生在 639-Skill 快照。研究索引的是名稱與一行描述,不是把 690 份完整正文都拿來搜尋。
先把 Skill metadata 寫成「可檢索的名片」
Agent Skills 規格只要求 name 與 description;compatibility、metadata 是選填,而且自訂 metadata 是 string-to-string map。以下 alphalab/* 欄位是 Router 的延伸約定,不是所有宿主都會自動理解:
---
name: pdf-redactor
description: Remove sensitive text from PDFs before sharing. Use for PDF redaction, PII masking, or sanitizing scanned documents.
compatibility: Requires Python, a readable PDF, and permission to write a new file.
metadata:
alphalab/router-version: "1"
alphalab/aliases: "pdf-redact,pdf-sanitize"
alphalab/intents: "redact PDF,remove PII,sanitize scanned document"
alphalab/input-kinds: "pdf,image,redaction-rules"
alphalab/output-kinds: "redacted-pdf,audit-log"
alphalab/requires: "pdf-ocr when input is scanned"
alphalab/not-for: "ordinary image blur,PDF form filling"
---
- Name 與 aliases 解決精確名稱、縮寫、產品名。
- Intent 與 not-for 說清楚要完成什麼,以及相鄰 Skill 的邊界。
- Inputs 只在 runtime 已有可信結構化事實時做 hard filter;格式或必要輸入未知時先澄清,不能靠含糊 query 猜測。
- Outputs 讓多 Skill 流程知道上一站會交出什麼。
- Prerequisites 與 compatibility 管權限、環境與先後,不要混成搜尋關鍵字。
欄位變多不代表命中率會自動上升;它先讓限制變得可檢查。上面的 alphalab/requires 也只是人類可讀摘要,不能直接排程。Indexer 應把它編譯並驗證成結構化記錄,例如 {"prerequisites":[{"skill_id":"pdf-ocr","when":{"input_kind":"scanned-pdf"}}]};只有 allowlist 內、條件可判定且通過 cycle check 的 ID 才能進 dependency graph。若輸入是否為掃描檔仍不明,先澄清,不要猜。需要陣列、正負例與依賴圖時,可保留標準 SKILL.md,再產生 router-index.jsonl。
實作 Skill Router:BM25+Embedding+RRF
第 1 層:BM25 抓「字面很像」
BM25 像圖書館的精準索引,擅長 .pdf、PostgreSQL、產品名與罕見錯誤碼。原型可用 rank_bm25;它要求已斷詞的 token lists,或由你提供 tokenizer,沒有內建 CJK 前處理。繁中/英文混合資料通常不宜只靠 text.split(),而且 corpus 與 query 必須用同一套斷詞。
第 2 層:Embedding 抓「意思很像」
使用者說「把個資遮掉」,Skill 可能寫的是 redaction,字面沒有重疊。Embedding 會把 query 與 routing card 轉成向量,再用相似度找近鄰。Sentence Transformers 文件對非對稱搜尋建議分別使用 v5+ 的 encode_query 與 encode_document;若模型沒有 query/document prompts 或 route,兩者可能和一般 encode() 產生相同結果。
第 3 層:RRF 合併兩份排名
BM25 分數與 cosine similarity 不在同一把尺上,直接相加很危險。入門版可用 Reciprocal Rank Fusion:只看每個候選在兩份清單的名次,計算 1 / (60 + rank) 後相加。60 是常見起點,不是通用最佳值;depth、top-k 與融合方式都要在開發集調整。
先安裝 v5 系列 API。以下是刻意不可直接部署的 Python-like pseudocode;它會保留 ranking evidence,供下一節的 Gate 使用:
python -m pip install "sentence-transformers>=5,<6" rank-bm25 pyyaml
# Python-like pseudocode;tokenizer、model 初始化與 imports 省略
# 所有門檻只能由 dev set 取得,不能照抄範例數字
# offline:每個 Skill 只建立一張短 routing card
cards = [routing_card(skill) for skill in skills]
bm25 = BM25Okapi([tokenize(card) for card in cards])
doc_vecs = encoder.encode_document(cards, normalize_embeddings=True)
# online:兩路各取 20,再用排名融合
def retrieve(query, top_k=5, depth=20):
bm25_scores = bm25.get_scores(tokenize(query))
lexical = [
i for i in top_indices(bm25_scores, depth)
if isfinite(bm25_scores[i]) and bm25_scores[i] > 0
] # BM25 全為 0 時,這一路不投票
q = encoder.encode_query(query, normalize_embeddings=True)
cosine_scores = doc_vecs @ q
semantic = top_indices(cosine_scores, depth)
fused = defaultdict(float)
for result in (lexical, semantic):
for rank, idx in enumerate(result, start=1):
fused[idx] += 1 / (60 + rank)
ranked = sorted(fused, key=lambda i: (-fused[i], skills[i].id))
evidence = {
"bm25_scores": bm25_scores,
"cosine_scores": cosine_scores,
"lexical_ranked": lexical,
"semantic_ranked": semantic,
"rrf_scores": fused,
}
return [skills[i].id for i in ranked[:top_k]], evidence
candidates, evidence = retrieve(query)
decision = gate(candidates, evidence, DEV_CALIBRATED_THRESHOLDS)
Dense retrieval 即使完全不相關也一定排得出前 20 名,所以 top-k 本身不是「有合適 Skill」的證明;Gate 必須看 dev set 校準過的 evidence。正式環境還要補 CJK tokenizer、權限/相容性 hard filter、向量快取與 digest 失效、錯誤處理,Loader 也要再檢查一次授權與相容性。
近似 Skill 很多、短 metadata 不夠辨識時,再分別測 body-aware first-stage retrieval 與 reranker。約 80K-Skill 的 SkillRouter v5在自己的 benchmark 發現 all-field routing 優於只看 name+description;相對地,690-node v1 只轉述 sibling effort 在 256-word-piece short-context encoder 下加入正文變差,並把方向列為 open question。兩者 corpus、encoder、評測不同,不能直接互比;請在同一份 held-out tasks 上做 metadata-only、field-aware 與 body-aware ablation(一次只改一個設計)。
完整走一次:掃描 PDF 個資該載入哪個 Skill?
以下是機制示意,不是實測 benchmark;假設任務是:「我要把一份掃描 PDF 的個資遮掉,再交給客戶。」目錄裡有 pdf-redactor、pdf-ocr、pdf-form-fill、image-blur。
- Discovery 只把四張 routing cards 揭露給模型,不把四份正文放進 context。
- BM25 抓到 PDF;embedding 把「個資遮掉」連到 redaction。
- RRF 把
pdf-redactor排第一、pdf-ocr排第二。 - Gate 接受
pdf-redactor作為任務 Skill;若前兩名其實是 redactor 與 image-blur 且很接近,就問:「要不可逆移除文字,還是只做視覺模糊?」 - Sequencer 看到 scanned input 與明確 prerequisite,排成
pdf-ocr → pdf-redactor,最後才載入這兩份正文。
這個例子也回答一個常見誤會:retrieval rank 代表「和 query 多相關」,不代表「先執行誰」。先選中一個或多個任務 Skills,再展開已驗證的 prerequisite,兩個問題才不會混在一起。
低信心時怎麼辦?不要把 RRF 分數叫做機率
RRF 的 0.031、cosine 的 0.82 都不是「82% 會選對」。正確做法是拿標註過的開發集,記錄 top-1 分數、top-1/top-2 差距、兩個通道是否都把同一 Skill 排進前幾名,再調三段決策:
- AUTO:證據高、差距夠大,啟用第一名。
- CLARIFY:兩個候選都合理,先問一個最能區分 intent、input 或 output 的問題,再重新 routing;仍不清楚就繼續澄清或回
NO_SKILL。 - NO_SKILL:現有 evidence 不足,或目錄確實沒有對應能力;不載入任何 Skill。只有基礎 Agent 在既有權限與政策下原本就獲准處理時才可繼續,否則澄清或回報「目前沒有受支援流程」。這不是繞過安全檢查的許可。
門檻不能從別人的 cosine 數字抄過來。Embedding 模型、目錄文字與負例密度一換,分數分布就會換。把「有沒有任何合適 Skill」與「第一名是否正確」分成兩個判斷,才能區分真正的 no-match 和需要澄清的 near-tie。
先用 dev set 選門檻,再只在鎖住的 test set 報一次結果。若 Gate 輸出 probability,校準器還要用獨立 calibration data;否則只能稱 confidence score/規則分數。用 risk–coverage curve 同時看 AUTO error 與 coverage,避免靠大量 abstain 做出漂亮 accuracy。Tokenizer、embedding revision、routing cards 或 Skill pool 改變後,都要重新驗證門檻。
怎麼評測 Skill Router?先凍結題目,再看 token
別讓寫 Skill 的人照著 description 出題。官方描述優化指南建議同時準備 should-trigger、should-not-trigger 與共享關鍵詞的 near misses,並把 train/validation 分開。做 Router 時再加 indirect symptom、多語言、multi-skill 與真正沒有對應 Skill 的題目;最後鎖住一批從未參與調參的 test queries。
至少保留兩種 test:query-held-out 測同一 Skill 的新說法;skill-held-out 則把整個 Skill ID 及衍生 queries 排除在調參/訓練之外,測新 Skill 上架後的泛化。Query writer 也要分組切割;功能等價的近似 Skills 應標成多個可接受 gold,否則正確替代品會被誤算成錯誤。

至少分三層記錄。排名層:Hit@1 看第一名是否屬於任一 gold;Hit@5 看前五是否至少出現一個 gold;多 Skill 任務的 Recall@5=前五找回的 required Skills/全部 required Skills,另用 Full-Coverage@5 檢查是否全到齊,MRR 則看第一個 relevant Skill 的倒數名次。閘門層:AUTO coverage=自動啟用題數/全部題數,accepted accuracy=AUTO 中選對的比例,並在真正 no-match 題記 false-activation rate。成本與成品層:記 discovery cards、正文、澄清回合合計的 input tokens(p50/p95)、延遲、正確 Skill 是否啟用與任務是否完成。只有所有 gold 都存在於凍結目錄時,全載入的 retrieval coverage 才是 100%;它仍須用端到端成功率與 context 成本評估。
那篇 690-node 研究的 load-all catalogue 是 46,915 tokens,按需搜尋約 560 tokens,減少 98.8%;這是該系統的序列化與目錄快照,不是所有 Router 都會得到的固定折扣。更值得抄的是實驗方法:相同 candidate budget、非 echo queries、並把檢索失敗和 sequencing/execution 失敗分開記。
這個入門架構先把 Graph 放在 sequencing
690-node 研究還測了 typed graph。它先用同一個 embedding top-k 找鄰居,再讓 LLM 為鄰居加上 requires、precedes、feeds-into 等關係;結果 98.6% 的 typed pairs 本來就落在 embedding 已連到的鄰居中。在相同六個候選預算下,hybrid@1+graph hit@5 是 63.2%,直接取 hybrid@6 是 74.4%。
這不代表 graph 沒用。它只表示:如果 graph 的候選邊先由同一套 embedding top-k 產生,它無法替 entry retrieval 增加 reach。這篇研究沒有驗證 graph sequencing 會勝過重複搜尋;作者明列缺少 skill-to-skill sequence dataset,而且 1,022 組 distinct typed pairs 中有 87 組(8.5%)出現方向矛盾。工程上可先用人工驗證的 prerequisites/dependencies 輔助已選定的任務 Skills,做 topological sort(讓 prerequisite 排在依賴者之前),再用 co-usage 或其他與 embedding 相對獨立的訊號,另做 sequence 與 sufficiency 實驗。
Skill Router 最常踩的 6 個坑
- 把「離線索引正文」和「把所有正文塞進 prompt」混為一談:runtime 仍只載入少數 Skills;offline retriever/reranker 是否讀 body,要用同一測試集做 metadata-only、分欄與 body-aware ablation。
- 只測明講 Skill 名稱的 query:加入改寫、症狀描述、錯字與跨語言。
- 直接加 BM25 與 cosine 原始分數:先用 RRF,或在開發集學習正規化權重。
- 永遠強制 top-1:把
CLARIFY與NO_SKILL當正式輸出。 - 把相似度當執行順序:只有明確 dependency 才能決定 prerequisites。
- 只看 retrieval、不看成品:記錄最後是否真的啟用正確 Skill、任務是否完成、載入多少 tokens。
Skill Router 常見問題 FAQ
1. Skill Router 是另一個 LLM 嗎?
不一定。最小版本就是本機 BM25、embedding 與規則閘門;只有需要精細 rerank 或生成澄清問題時,才可能多用一次模型。
2. 只有 10 個 Skills 也要做嗎?
通常先不用。官方輕量 catalog 加模型判斷常已夠用;當錯選、目錄截斷或 token 成本開始可量測,再加 Router。
3. Top-k 要設 1 還是 5?
先把 5 當候選起點,不是固定答案。Gate 可以選 0 個、1 個或多個 relevant Skills;例如「研究後再發布」可能需要兩個互補能力,而不只是主 Skill 的 prerequisite。只載入判定相關的 Skills,再展開各自的明確 prerequisites;候選 k 與最大載入數要按 Recall、錯選、token 與端到端成功率調整。
4. 只用 embedding 可以嗎?
可以做 baseline,但別先假設它會贏。產品名、錯誤碼與副檔名常讓 BM25 很有價值;hybrid 的意義就是保留兩種訊號。
5. 可以把 cosine 0.8 當自動啟用門檻嗎?
不能直接照抄。門檻要在自己的模型、目錄與 no-match 開發集校準,並一起看 top-1/top-2 margin。
6. Graph Router 比 hybrid retrieval 更進階嗎?
不是同一題。Hybrid 回答「現在最相關的是誰」;dependency graph 更適合回答「選中後還缺誰、先做誰」。
7. 使用者能不能直接指定 Skill?
可以,而且明確指定通常應優先。但 slash command 或 Skill mention 的語法由宿主決定,不是 Agent Skills 規格的一部分;Loader 仍要做權限、相容性與名稱有效性檢查。
8. 怎麼知道 Router 真的變好?
看鎖住的 test set 與端到端任務。同時比較命中率、錯誤啟用、澄清率、tokens、延遲與最後完成率;只展示幾個成功 demo 不夠。
給新手的 7 個重點
- 先分清 discovery、routing、loading、sequencing。
- 先做可讀、可檢查的 routing card,再談複雜模型。
- BM25 抓字面,embedding 抓語意,RRF 合併排名。
- Top-k 是候選,不是一次載入 k 份正文。
- 低信心要能澄清,也要能回傳
NO_SKILL。 - Graph 用明確 prerequisites 排序,不用相似度杜撰依賴。
- 最後以 held-out queries、token 與任務完成率驗收。
📚 延伸閱讀:把 Router 接回完整 Agent 系統
- Resource2Skill 是什麼:先學會怎麼把原始素材整理成可重用 Skill。
- Context Engineering 上下文工程:理解為什麼「只載入需要的內容」會影響 Agent 品質。
- AI Agent Harness 是什麼:把 Router 放回模型、工具、狀態與驗證的整體架構。
- 動手搭最小 Agent Harness:看一次完整 agentic loop 怎麼跑。
- Claude 怎麼省 token:從 context 使用習慣延伸到可操作的節省方法。
- Hermes Agent 是什麼:理解具備 Skill 學習與調度能力的 Agent 如何組成。
- AlphaLab AI 專區:從基礎原理一路讀到 Agent 開發。
- AlphaLab 線上課程:把 Agent 的設計、實作與驗收串成完整學習路徑。
結論:先做一個敢說「不知道」的 Router
Skill Router 的價值,不是讓 Agent 每次都自信選一個答案,而是把「找候選、判斷不確定、按需載入、安排先後」變成可觀察、可測試的控制層。回到開頭的公式:BM25 抓字面,Embedding 抓意思,Abstain 防止硬選。
今天先做 smoke test:挑 20 個真實 Skills,收集 direct、paraphrase、indirect、ambiguous、multi-skill 與 no-match 任務;在看結果前就把 dev 與 locked test 分開。用 dev 調 tokenizer、k 與門檻,只在 test 比 BM25、embedding、hybrid。若總共只有 40 題,請報每格 raw counts 與不確定性,不要把同一批題調完後的百分比當成泛化成績。你需要的不是更多 Skills,而是一個知道何時該拿哪一把工具、也知道何時先別拿的 Agent。



