# dsh-capability-aware v3 · 调研蒸馏与修正依据 > 2026-10-05 · web-intel medium 档(12+ 源,2 子代理 + 主代理定向核验) > 纪律:research-discipline v1.1(D7 锚定派单:agnes 联网调研带锚、sensenova 读锚提取、主代理终裁)。 > 每条结论附出处;「未核验」项无行动建议。 ## 1. MCP 官方规范 → 插件设计印证与修正 | 蒸馏点 | 官方出处 | 落进插件的决策 | |---|---|---| | Registry 元数据标准字段 `name/title/description/version/packages/remotes`(server.json) | [registry/about](https://modelcontextprotocol.io/registry/about)、[server.schema.json](https://raw.githubusercontent.com/modelcontextprotocol/registry/main/docs/reference/server-json/draft/server.schema.json) | 本机 `mcp_connector.json` 的 `name/transport/command/url` ↔ server.json 的 `name/packages/remotes` 同构;探针按此映射 | | Registry **无推送**,聚合器「低频定期拉取(~每小时)」 | [registry/about](https://modelcontextprotocol.io/registry/about) 原文 "pull new metadata on a regular but infrequent basis" | 插件侧用「fingerprint diff + 日级巡检」即与官方同口径,无需自建推送 | | 协议层工具变更通知:2025-06-18 `tools.listChanged` capability;2026-07-28 改 `subscriptions/listen` | [2025-06-18/tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)、[2026-07-28/changelog](https://modelcontextprotocol.io/specification/2026-07-28/changelog) | 传输层通知归 DSH 连接器;插件层用 `tool_catalog` 快照 diff 兜底(双层防御) | | `tools/list` 结果带 `ttlMs` 缓存提示(SEP-2549) | [2026-07-28/tools](https://modelcontextprotocol.io/specification/2026-07-28/server/tools) | 支持扫描间隔设为日级而非小时级 | | 2026-07-28 无状态化:`server/discover` RPC 替代 initialize 握手 | [2026-07-28/server/discover](https://modelcontextprotocol.io/specification/2026-07-28/server/discover) | 未来 DSH 若升级无状态 MCP,探针只需换数据源,条目 schema 不变 | | 「tool search / deferred tools」专有机制 | 白名单域内**未检索到**官方定义 | 未核验,不做依据(D2) | ## 2. 检索方案 → BM25-lite 路线的实证与边界 - **keyword(BM25) 对描述型工具名/description 简单有效;embedding 在 <500 条 + 零依赖约束下复杂度不划算**(v2 决策,MCP Client Best Practices 与 Reddit 140 工具实战同结论;本机 237 条同规模)。 - v3 实测补充(本机真实清单回归发现的三类 keyword 检索固有缺陷与正解): 1. **词表鸿沟**:「查A股行情」↔ 触发词「股票」——bigram 切不出桥接词。正解 = **人工别名层**(`cap.mjs alias` 灌 `manual.aliases`,匹配时触发面并入 + 别名整词覆盖强加分),而非堆权重。这正是 MCP 官方「model-controlled discovery」留给客户端策展的空间。 2. **长描述刷分**:automation 条目 500 字 prompt 里泛词 bigram 靠词数累积压过特异触发词(实测 34 vs 9)。正解 = **desc 命中每条目封顶 3 token**。 3. **边界字假命中**:单字「调」桥接到「调用方式」。正解 = **单字 CJK 禁 contains 桥接**,只允许触发词全等。 4. **事实型 vs 能力型**:env/hardware/software 是参考事实,任务意图命中时应让位于能力型条目(×0.85)。 - 参考面:Claude Skills「description 即触发器」惯例(本机 54 技能「触发词:」段实测),v2 已落 `extractTriggers`。 ## 3. 环境能力建模 → SBOM 与 CMDB 的口径借鉴 - 软件清单走 **卸载注册表三视图**(HKLM/HKLM WOW6432Node/HKCU)并过滤 `SystemComponent` 与 KB 更新噪声——与 SBOM 工具(WinGet list / BrReturning 注册表枚举)同源口径;dev 工具链单独走 `where + --version`(注册表不覆盖 CLI 工具)。 - 硬件用 **WMI 单次采集**(Win32_Processor/VideoController/LogicalDisk/OperatingSystem),GPU **排除虚拟显示适配器**(本机实测 Todesk/OrayIdd/MuMu 三张虚拟卡 vs 一张实体卡——不排除会把远程桌面虚拟卡当 GPU 能力登记,误导算力判断)。 - 事实型条目 `invoke.kind='manual'` + 描述标「物理事实条目」——与 CMDB「属性 vs 能力」分层一致:插件登记事实,决策(如「要不要上云」)留给人(AGENTS.md 铁律 1)。 ## 4. 定期巡检 → 官方「低频拉取」+ 本机双系统边界的合并口径 - MCP Registry 官方拉取频率「infrequent(~hourly)」→ 能力清单日级巡检足够(fingerprint 含 mtime/版本/内容 hash,日粒度变更不漏)。 - 本机两套定时系统边界(官方 `schedule_create` 投递回原会话 vs 第三方 `automation_create` 每次新 Session)——巡检用的是后者(已有 `automation_8fa49ea2` 每日 06:30),v3 扩覆盖新探针。 - 巡检纪律沿用 v2 定案:**只汇报不自动修复**(事实归 AI,决策归人)。 ## 5. v3 修正清单(全部溯源) | # | 修正 | 溯源 | |---|---|---| | 1 | MCP 探针路径 `mcp_connections.json` → **`mcp_connector.json`**(v1 凭猜测写的路径从未命中) | 本机 2026-10-05 全文取证(378KB 真实文件) | | 2 | MCP 条目增强:`tool_catalog` 工具快照进 triggers/描述/example | 官方 tools/list 语义 + 本机表结构 | | 3 | MCP 中文触发面:市场目录 `catalog.remote.connectors` 的 summary/tags 并入 | 本机取证(AKShare「股票/基金/宏观」) | | 4 | 新增 hardware/software 探针(解析函数与采集分离,解析层可测) | §3 口径 | | 5 | 检索四修正(别名层/desc 封顶/边界字守卫/事实型降权)+ tokens 允许单字符拉丁词 | §2 真实回归 | | 6 | `ambiguous` 返回补 `top` 字段(API 一致性) | T3 实测 undefined 崩溃 | | 7 | IDF 每次现算、语料含 aliases(弃用过期落盘快照) | alias 灌入后 IDF 过期踩坑 | | 8 | trigger 词表策展:ffmpeg 去「字幕」留「转码」类 | 「抓字幕」误配 ffmpeg 实测 | --- # v5 / v0.6.0 · 六缺陷修复溯源(2026-10-07) > **取证方法**(可复用):宿主会话日志 `~/.dsh/sessions///session.v4.jsonl.zstd` > (zstd 压缩 JSONL,python `zstandard` 解压)。记录类型 `tool/call`(`data.name` + `data.arguments`)、 > `tool/result`(callId 在 `data.message.toolCallId`——**不是** `data.toolCallId`)。 > 同一逻辑会话因 fork/continuity 会散在多个 session 文件,须按 `(time, arguments)` 去重。 > **子串计数不可信**:`capability-aware` 36h 内出现 12479 次,绝大部分来自 AGENTS.md 注入块与系统提示词。 ## 6. 真实调用统计(36h / 78 个 session 文件) | 指标 | 数值 | |---|---| | `capability_query` 工具真实调用 | 14 次原始 / **5 次去重后**(agent 自主发起,非用户点名) | | `cap.mjs` CLI 调用 | 154 次,但**几乎全在开发/验证会话**(自测,非日常使用) | | 质量判定 | **3 好 / 2 差** | **两次真实失败(本次修复的直接动因)**: - ❌「发送文件到微信」→ 真答案 `wechat-send-file` 因 `negative:true` 被压掉,返回 `软件: 微信`(93.17) 等——**答非所问**(问「怎么发文件」答「装没装微信」)。 - ❌「文生图」→ 本机确无本地生图能力,但返回 `软件: Visual Studio 生成工具 2022`(38.87, conf=1) 等**完全无关**候选; `cap.mjs guide` 对同一 query 正确返回 `kind:"missing"`,但 agent 调的是 `query` 不是 `guide` → **缺失分支不可达**。 ## 7. 六缺陷与修法(全部由上述取证驱动) | # | 缺陷 | 实测证据 | 修法 | 回归测试 | |---|---|---|---|---| | 1 | 人工数据被扫描抹平 | 灌 AKShare 别名 → `applyScan` 后读回 `[]`;灌回后排名 **12 → 1**;全清单 563 条带人工数据者 **0** | `mergeManual()` 逐字段非空者胜(`registry.js`) | T15 / T16 | | 2 | 受限技能被当废弃 | `wechat-send-file` 精确点名返回 `no_match`;29 条 `disabled=true` 全被合并进 `negative`;其 SKILL.md 实为 `disable-model-invocation`(**权限标志**:仅用户点名可用,正文含「发送前先跑 --dry-run」「不得顺手多发」) | 拆两档语义:`disabled` 可检索/点名可用/带告警;`negative` 才强降权 | T17 | | 3 | 缺失伪装成有候选 | 「文生图」tokens=`[文生,生图,文,图]` → 6 条**并列 12.61**(明细均 `desc⊃文+5.42 desc⊃图+7.19`)纯噪声地板 | desc 禁单字;`queryStrength()` 判据 `aliasHit \|\| (exact && nonDesc>=0.2) \|\| cov>=0.4`,**附加提示不参与排序** | T18 / T22 | | 4 | agent 走退化路径 | `tool.js:48` 漏传 idf:查A股**全候选并列 16**;CLI 同 query 为 `akshare_backtest(36.37)`。「抓B站」工具路径 `visual-studio(15)` vs CLI `64.14` | `match()` 缺省 idf 自愈 + `tool.js` 显式传参 | T19 | | A | 同名条目互相覆盖 | 18 组同名(`bili-daily` 顶层 disabled=true vs web-intel 子技能 disabled=false;`skill-creator` 3 条)→ `(type,name)` 键致 diff 失真 | `entryKey()` 带 `source` | T20 | | B | 路由器覆盖词压过专精技能 | `visual-studio` triggers 含 `字幕`(30 条上限),靠全等 6w 得 64.14 压过 `bili-daily`/`web-intel`(60.37);单字 `b` 单独贡献 **+43.47** | 父子竞争让位(父 ×0.7)+ 单字拉丁 w=0.5 | T21 | ## 8. 数据层:预置别名(`lib/seed.js`) 判据标定结论:**分数阈值无法区分真假命中**——反例「发送文件到微信」里噪声榜首 `软件: 微信`(42.79) **高于**真答案 `wechat-send-file`(26.02)。故改用「命中质量」而非分数。 预置别名覆盖三处已取证缺口(**随插件分发,首次扫描即注入、跨扫描存活**,新装机器无需手工策展): | 条目 | 预置别名 | 取证 | |---|---|---| | `AKShare` (mcp) | A股 / 沪深 / 股市 / 行情数据 / 股票行情 / 历史行情 / 股票数据 / 财经数据 | rank 12 → 1 | | `wechat-send-file` (skill) | 发我微信 / 发送文件到微信 / 发到微信 / 发文件到微信 / 传到手机 / 发到我手机 | `anyStrong` false → true;rank1;s=177.71 | | `imagegen-frontend-web` (skill) | 文生图 / 图像生成 / 生图 / AI画图 / 提示词生图 / 图片生成 | 中文查询到不了英文技能名 | > ⚠ `imagegen-frontend-web` 是**图像提示词方向**技能(由宿主图像工具执行),**不是**本地扩散模型引擎。 > 别名只解决「可检索性」,边界由条目自身 description/bounds 承担——不夸大为「本机可本地生图」。 ## 9. 设计取舍(明确记录,避免后人误改) - **`queryStrength` 只提示、不排序**:宁可多一句提示,也不把真有能力的查询误判为缺失。最坏是多提示,不丢候选。 - **`disabled` 不降权**:权限标志不是质量信号。受限技能该被搜到,由 agent 读告警后决定是否请用户确认。 - **预置别名是并集**:用户 `cap.mjs alias` 加的永不被覆盖;seed 只增不减,幂等。 - **`npm test` 在本机须指文件**:`node --test test/` 目录形态报 `MODULE_NOT_FOUND`。