Files
dingtalk-workspace-cli/docs/tool-search-github-architecture-research.md
T

29 KiB
Raw Blame History

DWS Tool Search:GitHub 源码架构调研

1. 结论先行

GitHub 上没有一个项目可以被 DWS 整体照搬。首先要区分执行模型:Codex/Anthropic/OpenAI 的 deferred search 面向多个外层函数工具,而 DWS 本身就是 Agent 的一个元工具,Catalog 条目是 DWS 子命令。因此 DWS 不需要动态将搜索结果注册成新 Host Tool;可复用的是不同项目已经验证过的检索和契约边界:

  1. 协议形态参考 Anthropic / OpenAI 的 reference → inspect。 DWS 搜索只返回轻量引用,命中后才读完整命令契约;但 Inspect 后仍调用同一 DWS,不动态注册新外层工具。
  2. Codex 证明本地 Tool Search 可以做到 Host 级闭环,但不应照搬其 ranker。 当前 Codex 已有 Rust 本地 BM25、namespace、MCP/Apps 和 deferred Schema 回填;但它是英文管线,没有 DWS 的 Exact Guard、exact_filtered、Catalog 双 hash 与稳定 canonical tie-break。
  3. 检索内核重点参考 Ratel 的本地部分。 最有价值的不是固定 k1/b,而是不可变索引快照、全量重建 BM25 统计和稳定 tie-break;Dense/RRF 仅作为研究对照,不进入当前 DWS 产品链路。
  4. 上下文和状态预算参考 NVIDIA NemoClaw。 query、返回文本、已发现工具数、checkpoint 状态和可见 Schema 都应有确定性上限;同时必须明确“披露不是授权”。
  5. 中文与字段策略必须由 DWS 自己评测。 ToolUniverse 甚至因模板噪声而只索引参数名、不索引参数描述,说明“字段越全越好”不成立。
  6. 删除外部 Provider 故障面。 Ratel 和 Haystack 都会把某些 Dense/子检索器错误向上抛出;DWS 当前不需要为可选增益引入认证、超时、融合和降级协议,因此已删除 Provider/fallback 原型。
  7. 搜索可信不等于执行可信。 GitHub 参考实现基本不处理 DingTalk 权限、确认、幂等、未知受理状态和补偿;这些必须继续由 DWS 的 Inspect、Cobra、Runner 和 recovery 分层承担。

建议目标架构保持:

reviewed CommandRegistry + Cobra + metadata
                    ↓ one-way resolution
             immutable SchemaRegistry snapshot
              ├─ identity resolve / Inspect index
              └─ local lexical index
                        ↓ bounded ToolReference
                    exact Inspect + hash check
                        ↓
                    real Cobra Execute
                        ↓
               Verify / Retry / Compensate

2. 调研方法与证据等级

本报告只使用固定 commit 的仓库源码、测试、ADR 和官方 SDK 类型作为证据。README 只用于导航,不用于证明内部实现。

证据按用途分为四类:

等级 含义 本报告中的项目
协议证据 源码中存在 deferred/reference/namespace 等公开形态 Anthropic SDK、OpenAI Agents SDK
编排证据 源码展示搜索结果如何进入 Agent 下一轮工具列表 LangGraph BigTool、Semantic Kernel、NemoClaw
检索工程证据 源码实现索引、缓存、并发、融合和失败边界 Ratel、ToolUniverse、Haystack
评测证据 代码/论文定义指标和多相关工具评测方法 ToolRet

“仓库有实现”不等于“适合 DWS 生产默认”。本报告同时检查:

  • 是否有固定身份和唯一 Catalog;
  • Search 是否与 Inspect / Execute 分开;
  • 是否有 exact、hard filter 和稳定 tie-break;
  • 索引更新是否原子、可版本化;
  • 一路失败时是整体失败还是可降级;
  • 是否有权限、确认、幂等和恢复语义;
  • 是否有与核心行为直接对应的测试。

3. 源码级横向对照

项目 实际拥有的层 已核验实现 不应照搬或误读
Anthropic Python SDK @ 009b035 BM25/Regex 托管搜索的协议类型;普通 tool 也支持 defer defer_loading、tool_search_tool_result、仅含 tool_name 的 tool_reference;官方 client 示例用 substring 自实现搜索 SDK 没有 BM25/Regex 检索代码;“加载完整定义”是服务端行为,本地只有 registry/available-name 簿记;confirmation/idempotency 均未提供
OpenAI Agents SDK @ 5250cb8 deferred function、namespace、hosted MCP 和 Responses 配置/校验 ToolSearchTool;qualified identity、冲突检测、deferred lookup/approval key;文档建议 namespace 少于 10 个函数 execution="client" 不被标准 Runner 自动执行;非 Responses 后端 fail-fast;SDK 不是本地 ranker,也不实现定义注入运行时
OpenAI Codex @ b1373b7 生产 Host 级本地 Tool Search handler使用 Rust BM25;tool projection索引 namespace/name/description/参数并把完整 deferred Schema 写入 tool_search_output;接通 MCP、Apps 和动态 registry Language::English;无 Exact Guard/exact_filtered、Catalog 双 hash、查询级 product/effect/exclude filter 和显式 stable tie-break;该外层 registry 闭环不是 DWS 元工具路径的必需依赖
NVIDIA NemoClaw @ ac6adac 预算完整的渐进披露 middleware progressive_tool_disclosure.py限制 query、输出、state、名称、工具数和单项/总 Schema bytes;拒绝重名;checkpoint reducer 确定性 搜索只是 case-insensitive substring;完整 executor registry 仍在且猜名可执行;专项验证和接线脚本代表工程证据,不等于已核验生产 SLA
LangGraph BigTool @ 0bb7f92 Search → bind selected tools → execute 的 Agent 图 graph.py累积 ID,并在下一轮 bind_tools;Store semantic search 默认每次 2 个 unknown ID 裸字典访问导致 KeyError,坏 ID 又因只增 reducer 持续污染线程;状态无预算、无 Catalog hash/权限/恢复
Semantic Kernel @ c028a0c 框架自动用近期对话做 function vector search ContextualFunctionProvider首次懒向量化,并默认拼最近 2 条消息;FunctionStore 默认只向量化 name + description 标记 SKEXP0130;collection/embedding/unknown name 均 fail-fast;外部 store 同步与生命周期由调用方负责,不存参数 Schema
Ratel @ dcb657f BM25 / Dense / Hybrid 检索内核与缓存 search.rs稳定排序和缓存;dense_cache.rs原子构建;fusion.rs两路深召回 RRF 默认英文 tokenizer/model;Dense/Hybrid 错误会返回 Err,不是自动 BM25 fallback;不拥有 Inspect/Execute 安全
ToolUniverse @ cf5566c 实用 keyword/BM25、Embedding、LLM finder tool_finder_keyword.py做 n-gram BM25 和 exact bonus;tool_finder_embedding.py把工具文本和模型配置纳入 cache key 三套 finder 没有统一 Hybrid;参数描述排除只是实现选择/注释,需由 DWS 消融验证;ASCII tokenizer 不支持中文;index/cache freshness 和稳定 tie-break 不够严格
Haystack @ e7d2643 通用并发多路检索与 RRF MultiRetriever并发执行;_reciprocal_rank_fusion融合异构排名 组件标记 experimental;任一路失败会整体失败;MultiRetriever 未暴露 RRF weight;无显式 doc-id tie-break
ToolRet @ c4181d9 大规模工具检索 benchmark eval.py计算 NDCG、MAP、Recall、Precision、Comprehensiveness 只负责评测,不是服务架构;固定 commit 无 tests,部分 BM25/rerank/ColBERT 路径存在明显代码缺陷,指标思想可借、harness 不可直接复用

4. 七个关键架构发现

4.1 Progressive disclosure 不是授权

NemoClaw 的源码把这一点写得最明确:middleware 只过滤每次发给模型的工具,完整 executor registry 仍然存在;如果模型猜到隐藏工具名,仍可能进入执行器。因此:

  • Search/披露只能减少上下文,不能授予权限;
  • ToolReference.effect/risk 只是已审核元数据,不是执行许可;
  • 用户 ACL、确认、凭据、sandbox 和业务校验必须在执行端再次生效;
  • “搜索结果里没有”也不能作为 deny policy,真正 deny 必须在 Runner/transport 边界执行。

这与 DWS 当前分层一致:搜索只消费 typed Catalog,最终仍调用真实 Cobra leaf。

4.2 Catalog view 和 executor registry 必须同源但不能混为一谈

BigTool 维护 tool_registry,NemoClaw 又专门拒绝同名的不同 owner。原因是:模型看到的 Schema 和 executor 按名字查到的实现如果来自两套去重规则,可能“绑定 A、执行 B”。

DWS 应维持单向发布图:

Cobra + reviewed CommandRegistry + metadata
              → one resolved ToolSpec
              → Search view / Inspect view / execution identity

Search 不得重新调用 tools/list 建第二份目录,也不得自己生成 executable identity。候选必须只来自当前 typed Catalog。

4.3 索引一致性比选择哪种 ranker 更基础

Ratel 提供了三个值得直接吸收的规则:

  1. BM25 corpus 变化后完整重建统计,不做会冻结旧 avgdl 的伪增量 upsert;
  2. 先对完整候选做 (score desc, id asc),再截 Top-K,避免 HashSet/浮点同分导致 Top-K 成员漂移;
  3. Dense batch 先完整校验 model fingerprint、维度和数量,再一次提交;全量 rebuild 失败保留旧完整向量。注意增量 replace 会先使旧 ID 向量失效,随后 embedding 失败时 Dense 暂不可用;这不是任意更新都保留 last-good snapshot。

DWS 当前 Catalog 是随二进制发布的不可变快照,Alpha 可以在构造时一次建索引。若未来支持远端热更新,应采用比 Ratel whole-catalog reload 更强的 build-then-swap,并增加 IndexGeneration:

type CatalogVersionRef struct {
    SourceHash  string
    SurfaceHash string
}

type SearchIndexSnapshot struct {
    Catalog CatalogVersionRef
    Lexical LexicalIndex
    BuiltAt time.Time
}

新 snapshot 完整构建和验证成功后再原子替换;Search 与 Inspect 必须看见同一代。

4.4 Hybrid/RRF 调研结论:不进入当前方案

Ratel 的 Hybrid 是 BM25 和 Dense 各自召回到 depth 100,再用 RRF 融合。Haystack 也先并发取回各路列表,再融合。共同结论是:Dense 只能重排 sparse Top-N 时,无法补回 sparse miss,不是真正的 Hybrid。

Ratel 固定 commit 的 k1=.9/b=.4、RRF k=60(0-based rank)与 depth=100 都有源码/注释证据;Haystack 私有函数用 k=61 表达 1-based 论文公式,数学等价,但 MultiRetriever 没暴露 weights,最终排序也没有 doc-id tie-break。它们证明实现方式,不证明 DWS 中文参数最优;DWS 已测到 sparse arm/depth/k 会改变 R@K 和 workflow,必须自行锁 dev/test。

但两者的错误语义都不能照搬:

  • Ratel Semantic/Hybrid 直接返回可捕获的 EmbedderError;
  • Haystack 任一路 retriever 出错会让整个 MultiRetriever 失败。
  • Codex 对空 query/limit=0 返回 RespondToModel,对不支持的 payload 返回 Fatal;它没有可失败 Provider arm,因此也没有“保留本地候选、只标记降级”的对等契约。
  • Gemini CLI 公开文档定义了 discovery command/MCP 注册和 include/exclude,但未定义外部检索失败后返回稳定本地候选的协议;不应在没有对应源码/契约证据时简化成“Gemini 直接报错”。

DWS CLI 的离线约束通过单一本地检索链满足:

local lexical success → bounded ToolReference
runtime Catalog assembly corrupt → fail closed, search unavailable
caller context canceled → return cancellation

历史 Provider/fallback 原型已经删除。Dense/RRF 实验仍说明多路检索应采用独立深召回,而不是只重排 sparse Top-N;但这些研究事实不再构成 DWS v1 的实现要求。若未来独立评测证明必须引入第二路召回,应通过新 RFC 重新证明收益能够覆盖新增故障面。

4.5 必须给 query、引用、状态和 Schema 设预算

NemoClaw 不只限制 Top-K,还限制:

  • model 提供的 query 长度;
  • 单次搜索返回的 UTF-8 bytes;
  • 每项描述长度;
  • checkpoint 中累计工具名数量和 bytes;
  • 单工具 Schema bytes;
  • 一次模型请求可见的 Schema 总 bytes。

固定 commit 的具体常量是:query 256 chars、search output 8 KiB、单线程 discovered tools 64、discovered state 8 KiB、单工具名 120 bytes、单工具 Schema 16 KiB、已发现 Schema 总量 128 KiB、单次 search results 20、单项 description 256 chars。无匹配返回可行动文本;超预算返回解释并按 UTF-8 边界截断;malformed schema fail-closed。这些是可引用的实现常量,不是 DWS 已验证阈值。

DWS 当前实现已进一步加入 256 rune / 2 KiB query、8 个 subquery、64 KiB request、8 KiB response、候选和摘要边界;超限返回 typed validation,不静默截断。后续 Host 会话层还应增加:

  • Inspect 的单 leaf bytes 观测与异常保护;
  • Host 累积已发现工具和已 Inspect Schema 的上下文预算。

预算溢出应返回“被截断、请细化 query”的机器可读状态,不能静默截断到一个看似完整的列表。

4.6 显式搜索与自动注入是两种不同编排范式

Anthropic/OpenAI/NemoClaw/BigTool 都让模型显式调用 search/retrieve tool;Semantic Kernel 则在每次模型调用前,默认用最近 2 条消息自动构造 query 并注入候选。二者不是协议细节,而是可观测性和成本取舍:

  • 显式 Search 多一次 Agent step,但 query、Catalog version、候选与失败语义天然进入 transcript,容易审计、复现和恢复;
  • 自动注入减少一次模型 tool call,却会在每轮模型调用前产生隐式检索,必须处理近期工具输出污染、额外延迟、重复检索和“为何出现这个工具”的解释;
  • OpenAI execution="client" 明确要求手工 orchestration,证明本地 Host 不能假设 SDK 会自动完成 Search→Load;
  • Anthropic 本地 substring 示例证明“协议与 ranker 解耦”,不证明 substring 是 DWS 的质量默认。

DWS 的规范选择应是 显式、versioned Search→Inspect。Host 可以为了交互体验基于近期用户消息自动触发同一个 Search API,但必须生成等价 SearchTrace,禁止拼入不可信工具输出,并且不得绕过 exact、hard filter、Catalog hash 或预算。这样自动触发只是 orchestration optimization,不成为第二套检索语义。

4.7 Namespace 适合作为 hint,不适合作为唯一第一层路由

OpenAI 对 namespace 的 identity、冲突校验和“每组尽量少于 10 个函数”建议很有价值;DWS 已有 product/group/canonical,可以直接生成 reviewed namespace view。但当前 1,098 工具 Catalog 中的跨产品任务和 product_mismatch 风险决定了:

  • namespace 可以作为已知产品时的 hard filter,或未知产品时的可解释召回特征;
  • 不应强制“先选唯一 namespace,再只做组内搜索”,否则 router miss 会造成不可恢复的 leaf recall loss;
  • 多动作任务应允许每个 subquery 命中不同 namespace;
  • namespace 描述、route Top-K 和组内函数数必须进入独立消融,不能直接套用厂商 <10 建议。

5. 对 DWS 当前 Spike 的源码审查

当前 internal/cli/tool_search.go 已经具备:

  • 从同一 SchemaRegistry 构建不可变本地索引;
  • Exact Guard;
  • product/effect/exclude/executable hard filter;
  • canonical 稳定 tie-break;
  • source/surface hash;
  • 默认 Top-5 轻量 ToolReference;
  • 多动作 round-robin 合并。

与 GitHub 参考实现对照后发现的差距及当前分支状态如下。

5.1 已删除:Provider 与外部排名

当前公开边界只有 versioned stdin/stdout JSON 和本地排名。external_ranking、ToolSearchCandidateProvider、RRF、provider timeout/bulkhead、_fallback、degraded 与 provider warning codes 均已删除。双 hash 只用于 Search→Inspect 的 Catalog 一致性闭环。

5.2 已修复:Exact 命中但被过滤时终止

旧逻辑只有“exact 且 eligible”才直接返回。当前分支已让 exact identity 在 product/effect/exclude/availability 不满足时返回以下 typed 结果,且候选为空,不再进入 fuzzy:

建议返回:

strategy=exact_filtered
candidates=[]
reason=excluded | product_mismatch | effect_mismatch | unavailable

若需要替代工具,由上层使用新的自然语言 intent 明确发起第二次搜索。

5.3 P0:搜索 hard filter 不是用户 ACL

当前只过滤 Catalog availability、product、effect 和显式 exclude。公开输出必须继续声明:

  • available_in_catalog=true 不等于当前用户有 DingTalk 权限;
  • 不得把搜索结果或 Agent identity 用作授权依据。

5.4 已简化:无外部错误协议

本地检索没有 Provider 错误或降级状态。响应超过 8 KiB 时只按完整 reference 边界截断并设置 truncated=true,不再为这一单一状态维护 warning code 数组。

5.5 部分修复:资源预算与可观测状态

当前分支已增加 query 256 scalars/2 KiB、最多 8 个 subquery、summary 256 scalars、response 8 KiB,以及 truncated/abstained。仍缺少 Host 侧累计 discovered/schema bytes:

  • query/subquery/response bytes 上限;
  • truncated、abstained;
  • 仅在 trace 中记录原始分数,Agent-visible score 明确标为 ordering-only,或直接只返回 rank。

5.6 已修复:词法实现可替换

当前分支已把词法边界抽成 Go LexicalRetriever,并实现 fielded BM25 control 与 fielded TF-IDF cosine shadow;两者共享 tokenizer、hard-filter-before-score、zero-score abstain 和 canonical stable tie-break。默认仍锁 BM25,只有独立 qrels 门禁通过后才能切换。

5.7 P1:评测投影与 Go 发布投影尚未完全对齐

当前 Python proxy 为降低同源泄漏而排除了 use_when;Go 默认也已翻转为不索引 use_when,但 Python 仍没有完整覆盖 Go 的 alias、参数描述、interface description、类型和字段权重。现有 TF-IDF/BM25 R@K 因此仍不能直接代表 Go 发布配置。

必须把以下内容组成显式 ProjectionVersion:

  • 字段集合和字段权重;
  • 是否包含 use_when、参数描述和类型;
  • tokenizer/normalization 版本;
  • zero-score、filter 和 stable tie-break 规则。

Go 与 Python 对同一 Catalog/query/config 的 exact、eligible 集合和 Top-K 应逐 case golden parity;最终算法结论只能来自独立 qrels 上的生产投影。

5.8 已修复:BM25 浮点累加的跨进程不确定性

Spike 原先直接遍历 queryFrequency map[string]int 累加 BM25 分数。Go map 迭代顺序跨进程不稳定,浮点加法又不满足结合律,近似同分候选可能因 ulp 级差异绕过 canonical tie-break。现已改为每请求只排序一次 query term,再让所有 field/document 按固定顺序计分;测试会启动 3 个独立子进程,对完整 JSON response 做逐字节比较。

这项修复关闭了当前本地词法排名的已知不确定性。外部 Provider 已不在方案范围内。

6. 推荐的稳定接口

规范 DTO 只保留一套,以 RFC 5.6 纯本地传输与排名边界、5.7 ToolReference 和 5.8 Inspect 为准。跨进程只允许依赖 tool-search.v1 JSON。dws schema search --request-json - 和双 hash Inspect 已在当前分支实现,DWS Skill/Agent 可以直接调用该链路;不依赖 Host 实现动态 Schema 注入。

跨进程稳定链路是:

tool-search.v1 request
  → tool-search.v1 response {CatalogVersionRef, bounded ToolReference[]}
  → schema-inspect.v1 request {canonical, expected source/surface hash}
  → schema-inspect.v1 response {same CatalogVersionRef, ToolSpec}

接口约束:

  • Search 只返回引用,不返回完整参数 Schema;
  • Inspect 必须按 canonical exact 解析,并校验同一 Catalog hash;
  • Execute 不接受检索 score,只接受 Inspect 得到的 typed contract;
  • Catalog/本地索引损坏必须 fail closed;
  • 用户权限和 destructive confirmation 不能由 Search 决定。

7. 可信执行与安全恢复:GitHub 实现没有替 DWS 解决的部分

开源项目主要优化“模型看到哪些工具”和“如何排序”,没有证明 DingTalk 写操作能安全恢复。规范 InvocationContractV1、hash canonicalization、跨进程 evidence 和数据治理以 RFC 6.1 Invocation Contract 为准;本报告不再定义第二套简化 DTO。

执行与恢复规则:

  1. 执行前再验证。 Inspect hash、当前登录身份、权限、参数约束、confirmation 和 real Cobra leaf 必须同时有效。
  2. 错误分类不等于未执行。 timeout/connection reset 可能发生在服务端已受理之后;未知受理状态的非幂等写禁止自动重放。
  3. 幂等必须有真实后端能力。 Catalog 标注 idempotent 不能凭空制造服务端幂等;只有后端接受且回显 idempotency key 时才自动重试写。
  4. 先 Verify 再 Retry。 创建/发送后优先用 receipt、资源 ID 或查询接口验证;确认未发生才重试。
  5. Compensate 必须逐工具 reviewed。 只有有明确反向操作、资源 ID、权限和确认契约时才能补偿;否则转人工。
  6. 恢复使用原始 Catalog contract。 若版本已经变化,旧 Invocation 只能按审计/验证处理,不能静默套用新 Schema 重放。

8. 推荐实施顺序

Slice A:搜索内核契约

  • exact_filtered 和 query/response/subquery 预算已完成;
  • Go LexicalRetriever、BM25 control 和 TF-IDF shadow 已完成;
  • 公开 transport 已提前实现,但默认启用仍遵循 Slice C/D 门禁。

Slice B:索引门禁

  • TF-IDF、BM25 共享 tokenizer/filters/tie-break;
  • 固定 ProjectionVersion 和 Go/Python parity;
  • 已实现 Search 的薄 CLI 包装和严格 stdin JSON;
  • 已同步 schema leaf/exclusion;skills 和 release command-surface 门禁仍需复核;
  • 已增加 expected source/surface hash 校验并在 compact Inspect 回传双 hash;
  • 不新增顶层 dws discover。

Future Slice E:Invocation 与 recovery(后续独立 RFC,当前不实现)

  • 在 internal/executor.Invocation 传播 versioned Contract,并由 runtimeRunner 在 transport 前验证;
  • 建立 receipt/postcondition;
  • unknown write 禁止自动重放;
  • journal 原子状态迁移、锁、幂等 finalize 和数据保留门禁;
  • 为第一批写工具逐个审核 compensation。

9. 必须新增的测试

边界 验收测试
Catalog 同源 Search/Inspect/Execute canonical 全量 round-trip;source/surface hash 一致
Exact canonical、primary CLI、unique alias、NFKC、空格;exact filtered 不返回 sibling
Determinism 不同进程/hash seed 下 Top-K 成员和顺序一致
Budget query、subquery 数、单 reference、总 response、Inspect Schema 超限
Security hidden/disclosed 状态不改变 Runner ACL/confirmation;猜工具名仍被执行层拒绝
Index lifecycle 新 snapshot 构建失败保留旧 snapshot;版本切换原子化
Future Recovery(独立 RFC) read、幂等写、非幂等写、unknown acceptance、verify-success、manual handoff

10. 最终选型

DWS 不选择某一个 GitHub 项目作为基础框架,而是组合经过源码验证的模式:

能力 采用的模式 DWS 的增强
Deferred disclosure 协议 Anthropic/OpenAI 的 defer → reference → load 形态 DWS 不动态注册新外层工具;reference 通过双 hash Inspect 映射回同一 DWS 命令空间
Agent 编排 BigTool/Codex 的显式 Search → load/bind → execute DWS 元工具内的 versioned Search → Inspect → CLI Execute;校验 unknown/stale ID,权限仍在执行层
自动触发(可选) Semantic Kernel 的 recent-context retrieval Skill 已能完成规范链路;Host adapter 只作为减少一次模型决策的可选 optimization,必须复用同一 Search API/Trace
Namespace OpenAI 的 qualified identity / namespace 作为 reviewed hint 或已知产品 filter;未知、复合任务保留 global/multi-namespace recall
索引生命周期 Ratel 的完整 BM25 统计、原子 Dense batch/rebuild Catalog generation 绑定、build-then-swap;不照搬英文 tokenizer/model 或固定 k1/b/depth
多路召回与融合 Ratel/Haystack 的研究对照 当前否决,不进入 DWS v1;稳定 (score desc, canonical asc) 仅用于本地词法排名
预算/状态 NemoClaw 的 query/output/state/Schema 多层预算 用 DWS 实测冻结阈值,并覆盖 ToolReference、Inspect 与 Host 累积上下文
字段经验 ToolUniverse 的按通道字段选择、exact bonus、完整 cache key 做中文/中英混合字段消融;参数描述保持 shadow,不复用 ASCII tokenizer 与弱 freshness
评测定义 ToolRet 的 graded qrels 与 Comprehensiveness 使用 DWS 自有、带测试且锁数据版本的 harness;加入 Forbidden、Identity、Workflow、Agent/recovery 指标

最终仍是:

唯一 typed Catalog
  → identity resolve
      ├─ exact → eligibility → exact / exact_filtered(终止)
      └─ not found → Hard Filter
  → 可替换本地轻量召回
  → 确定性排序与预算
  → ToolReference
  → schema-inspect.v1 hash check
  ── 当前 Tool Search RFC 边界 ──
  ⇢ Future RFC: Cobra Execute → reviewed Verify / Retry / Compensate

这套架构的收益不是单纯提高 R@5,而是同时缩小模型上下文、保持 CLI 离线可用、让搜索结果可追溯,并把误重试写操作的风险隔离在明确的执行/恢复契约之外。