mcpField
S
skill-retrieval

skill-retrieval

github.com/moonlight-lupinAgent 工作流113167 次安装1 天前更新
代码仓库

关于 skill-retrieval

面向 Hermes Agent 的技能检索插件,通过 BM25 按每轮用户消息挑选相关技能描述。它将系统提示词中的完整描述列表压缩为名称索引,再注入少量匹配项,以减少提示词开销。

主要功能

  1. 01按 BM25 排序技能描述
  2. 02压缩系统提示词中的技能列表
  3. 03逐轮注入相关技能描述
  4. 04缓存索引并检测技能变更
  5. 05支持中文、日文和韩文检索

适用场景

  1. 01在大量技能中查找当前任务相关项
  2. 02减少每轮请求中的技能提示词占用
  3. 03让中文查询匹配非英语技能内容

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/moonlight-lupin/agent-skills --skill skill-retrieval

安装后在 Claude Code 中输入/skill-retrieval确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

__init__.py
LICENSE
plugin.yaml
README.md
requirements-dev.txt
requirements.txt
scripts/
__init__.py
bm25_retriever.py
jev_rerank.py
rerank_ab_report.py
tests/
conftest.py
test_bm25_retriever.py
test_cjk_tokenization.py
test_index_cache.py
test_inject_k_split.py
test_issue14_should_show_arity.py
test_issue8_round2.py
test_issue8_round3.py
test_jev_environ.py
test_jev_provider.py
test_jev_rerank.py
test_midscan_fallback.py
test_module_identity.py
test_profile_home_switch.py
test_public_surfaces.py
test_refactor_contract.py
test_regressions.py
test_rerank_hook_wire.py
test_round3_fixes.py
test_round4_fixes.py

详细介绍

技能检索

这是一个 Hermes Agent 插件。它不是 Claude Code 插件,无法在 Claude Code 中加载——该运行时没有 pre_llm_call 事件,没有 Python register() 入口点,并且读取的是 .claude-plugin/plugin.json,而不是 plugin.yaml。需要 Hermes Agent >=0.21.1(在 plugin.yaml 中设置 requires_hermes)。

基于 BM25 的渐进式披露,适用于 Hermes Agent 技能。该插件不会将每项技能的描述全部塞入系统提示词(约 11.5K 个令牌),而是保留一个精简的纯名称索引,并在每轮对话中仅注入最相关的前 K 项描述。

功能

分两个阶段进行渐进式披露:

  1. 阶段 1 — 精简系统提示词(llm_request 中间件): 重写发出请求中的 <available_skills> 块,仅列出技能名称(移除描述)。所有技能仍可按名称检索(约 2K 个令牌,而非约 11.5K)。Hermes 构建的系统提示词不会被修改,因此不会影响提示词缓存。

  2. 阶段 2 — 每轮 BM25 检索(pre_llm_call 钩子):对用户消息进行分词,使用 BM25 Okapi 对启用的技能描述排序,并将前 K 个匹配项(约 300 个令牌)作为上下文注入到用户消息之后。

架构

Each turn (llm_request middleware)
    │
    ▼
Phase 1: rewrite <available_skills> → names only (~2K tokens, request only)

Each turn (pre_llm_call)
    │
    ▼
Phase 2: BM25Index.retrieve(user_message, top_k)
    └── inject "## Retrieved Skills ..." into user message (~300 tokens)

BM25 索引会在首轮对话时,按需基于独立技能(~/.hermes/skills)和插件附带的技能(~/.hermes/plugins/*/skills)构建,然后按 Hermes 主目录、工具能力快照、会话平台和解析后的禁用技能集缓存(这些输入与 Hermes 为其自身技能提示词缓存建立索引的输入相同)。当 Hermes 清除其技能提示词缓存时(通过 skill_manage 创建、修补或删除技能,通过 hub 安装,或切换技能开关),或者磁盘上的轻量清单发生变化时(技能根目录和类别目录的修改时间、顶层 SKILL.md 文件、config.yaml),缓存会在无需重启的情况下重建。 检索使用纯标准库实现的倒排索引(词项 → 预计算的 BM25 权重列表);对于约 200 项技能,检索耗时不到 1 毫秒。

令牌节省

阶段令牌(约)
之前(系统提示词中包含完整技能列表)~11.5K
之后 — 仅含名称的系统提示词~2.0K
之后 — 每轮注入的前 K 项描述~0.3K
每轮净值~2.3K(节省约 9K)

在包含约 300 项技能的 Hermes 安装环境中测得;节省量会随技能数量增加而增长。

安装

将此目录复制或符号链接到 Hermes 插件文件夹中:

# From this repo
ln -s "$(pwd)/plugins/skill-retrieval" ~/.hermes/plugins/skill-retrieval

# Or copy
cp -r plugins/skill-retrieval ~/.hermes/plugins/skill-retrieval

用户插件默认不启用:Hermes 会发现该目录,但在启用之前不会加载(这会将 skill-retrieval 添加到 ~/.hermes/config.yaml 中的 plugins.enabled):

hermes plugins enable skill-retrieval

重启 Agent 会话以运行 register()——它会注册 llm_request 中间件和 pre_llm_call 钩子。

依赖项(如果缺少,请安装到 Hermes Python 环境中):

pip install pyyaml

配置

设置默认值设置方法
TOP_K6环境变量 SKILL_RETRIEVAL_TOP_K
INJECT_KTOP_K环境变量 SKILL_RETRIEVAL_INJECT_K;注入多少个检索候选项。候选池大于注入集(例如 TOP_K=12、INJECT_K=6)时,Jev 重排可以筛选候选项,而不仅仅是重新排序。超过 TOP_K 的值会被限制为 TOP_K。
系统提示词精简启用设置 SKILL_RETRIEVAL_COMPACT=0,可禁用精简,同时保留 BM25 检索注入
BM25 k11.5scripts/bm25_retriever.py 中的常量
BM25 b0.75scripts/bm25_retriever.py 中的常量
Jev 重排关闭设置 SKILL_RETRIEVAL_RERANK=jev 启用;密钥位于 TYPESAFE_API_KEY 中(兼容旧版 TYPESAFE_KEY),从 os.environ 读取
重排提供商typesafeSKILL_RETRIEVAL_RERANK_PROVIDER=openrouter 使用 https://openrouter.ai/api/v1/systemone 和 OPENROUTER_API_KEY
重排日志路径$HERMES_HOME/data/jev-trial/rerank_ab_log.jsonl(超过 5 MB 后轮换)环境变量 SKILL_RETRIEVAL_RERANK_LOG
export SKILL_RETRIEVAL_TOP_K=8
export SKILL_RETRIEVAL_INJECT_K=6
export SKILL_RETRIEVAL_COMPACT=0
export SKILL_RETRIEVAL_RERANK=jev
Jev 重排(可选,默认关闭)

当 SKILL_RETRIEVAL_RERANK=jev 时,BM25 的前 N 个候选项会由 Jev system-one 判断模型重排(POST https://api.typesafe.ai/v1/systemone, 模型 jev-latest)。行为如下:

  • 失败时宽松处理 — 超时时间为 3.0 s,不重试;发生任何错误时,请求会记录警告,并保留 BM25 的原始顺序。检索不会因 Jev 而阻塞。
  • 仅通过环境变量配置 — 所有设置均来自 os.environ(绝不读取文件):TYPESAFE_API_KEY(也接受旧版 TYPESAFE_KEY),或使用 SKILL_RETRIEVAL_RERANK_PROVIDER=openrouter 时的 OPENROUTER_API_KEY(相同约定,通过 OpenRouter 提供服务)。Hermes 会在启动时将当前配置文件的 .env 加载到 environ,因此绝不会读取其他配置文件。
  • A/B 日志 — 每次查询都会将时间戳、会话 ID、200 字符的查询摘录、两种排序、概率、令牌数和延迟记录到上述日志路径;日志超过 5 MB 时会轮转;scripts/rerank_ab_report.py 可在本地汇总日志。
  • 出站上限 — 每次调用最多发送 RERANK_CANDIDATES(默认值为 12)条描述,即使调用方的候选列表更长;其余条目保留在末尾,顺序遵循 BM25,且不会离开本机。

验证是否正常工作

在完整的 Hermes 运行环境之外,Phase 1 会静默地不执行任何操作;BM25 索引也可能静默为空。重启后,请检查 Hermes 日志。

正常启动 — 查找以下日志行:

  • BM25 index built: N docs …
  • Skill retrieval plugin registered (top_k=…, compact=true)

运行降级 — 以下警告表示功能未正常工作:

  • Cannot locate prompt_builder — compaction skipped(Phase 1 失败;匿名会话仍会运行 Phase 2,但具名会话因未记录能力快照而会跳过注入)
  • No active skills found for BM25 index(索引为空 — 未注入任何检索结果)

工作原理

  • 分词器 — 将文本转换为小写、去除标点并按空格拆分。含有 CJK 文字的词元会拆分为二元组(针对 CJK 文字连续片段;长度为 3 个或更多字符的片段会替换为其二元组):CJK 统一表意文字(包括扩展 A 和 B)、日文假名(全角和半角)以及韩文音节 — 因此,中文、日文和韩文查询可以匹配非英文语料文本,而像 用python写 这样的混合词元也会保留 python 词项。
  • 语料 — 每个技能会转换为 "name: description",并附上其 frontmatter 中的 triggers: 列表和 metadata.hermes.tags(如果存在);如果 SKILL.md 正文含有 CJK 文字,则还会附上正文前约 3000 个字符中的 CJK 连续片段(以空格连接,总长度上限为 200 个字符)。将正文纳入语料后,CJK 查询便可匹配技能内容,而不只是(通常为英文的)描述。触发短语、标签和 CJK 连续片段会参与检索评分,但只有描述会注入提示词。跳过 ~/.hermes/config.yaml 中已禁用的技能。
  • 索引 — BM25 Okapi TF 饱和度 + Lucene IDF log(1 + (N-df+0.5)/(df+0.5))(始终为正,因此小型语料和常见词项仍会获得评分),以倒排索引形式存储:dict[str, list[tuple[int, float]]],将每个词项映射到一个倒排列表,其中包含(文档索引,预计算的 BM25 权重)。
  • 检索 — 对索引中出现的每个唯一查询词元,遍历其倒排列表并累加评分;按评分降序排序(仅保留评分 > 0 的结果)。

性能

  • 首次使用时构建索引并缓存(在仅配备 CPU 的虚拟机上,200 个技能约需 8 ms)。之后每轮只检查技能根目录、其一级子目录和 config.yaml,以验证缓存。零技能安装也会缓存空结果(仅发出一条警告,不会重新扫描)。
  • 检索耗时不到 1 ms(200 个技能的平均耗时约为 0.03 ms)。倒排索引只访问与查询词共享词项的文档,不会扫描整个语料库。
  • 无编译依赖。插件仅使用 Python 标准库(以及用于解析配置和 frontmatter 的 pyyaml)。这样可省去 154 MB 的 numpy/scipy 安装和约 573 ms 的导入耗时,这对需要生成子进程的路径(例如 Claude Code 的 UserPromptSubmit 变体)很重要。
  • Hook 出错时会返回 None(不注入),因此 Agent 可以继续工作。

依赖项

  • pyyaml

限制

  • BM25 是词法检索,而非语义检索。即使意图匹配,与技能描述共享词项较少的改述查询也可能排名靠后。
  • 注入块中会截断超过 200 个字符的描述;如需查看完整技能正文,请使用 skill_view(name)。
  • 压缩使用 Hermes 只读的 agent.prompt_builder 辅助函数;如果无法导入,则会跳过阶段 1,并回退到独立加载器进行检索。
  • 只有在此进程中构建了系统提示词后,才会为具名会话注入内容(构建时会记录该会话的工具能力)。重启后恢复但未重新构建的会话不会获得注入内容,以免冒险注入 Hermes 对其隐藏的技能。
  • 在 Hermes 外部(例如通过编辑器)对嵌套的 SKILL.md(category/skill/SKILL.md)仅修改内容,不会改变任何目录的修改时间,因此只有在 Hermes 清除技能提示词缓存或 Agent 重启后才会获取该修改。通过 skill_manage 进行的编辑,以及新增或移除技能、修改配置,都会在下一轮获取。
  • 阶段 1 依赖 Hermes 内部组件(agent.prompt_builder),Hermes 升级后可能会失效。
  • BM25 的 top-1 精确率不稳定:最佳匹配技能往往不在第 1 位,不过通常会排在前几个结果中。排名完全取决于你自己的语料库及其描述措辞,因此不建议将 TOP_K 设为低于约 5。
  • 压缩会使用从 agent.prompt_builder 和 agent.skill_utils 导入的只读函数重写请求中的 <available_skills> 块(README 中披露了全部 10 个函数);如果这些函数的签名发生变化,扫描过程中的任何异常都会触发回退,改用独立加载器,因此语料库绝不会在无提示的情况下变为空。
  • 标准库索引使用 float64 进行计算(之前的 scipy 版本使用 float32)。得分相同的技能,其排序可能与之前不同。这不会造成问题——这些分数确实相同(相差约 1e-6)——但这与 scipy 版本的行为确有差异。

评论

支持 Markdown