Appearance
Tool 太多时怎么暴露:Metadata、Dynamic Exposure 与 Discovery
前置:让模型稳定调用 Tool:Schema、Examples 与 Registry
核心问题:当系统有几百个 Tool 时,怎样让模型只看到当前真正需要的能力,而不把整个 catalog 塞爆 Context?
github.search code@v2 与 jira.search issue@v1 可分别路由到不同 adapter,并在 Run Manifest 记录实际版本。分析阶段只暴露 read/search;进入批准后的修改阶段才加入 patch/write tools。
Namespace / Version / Metadata
Namespace 防止跨系统工具重名并支持治理;Version 关联 schema 行为;Metadata 可承载风险、成本、来源、tags。它们也是动态 discovery 和 audit 的基础。
Dynamic Tool Exposure
Dynamic Exposure 解决的是:系统有很多 Tool,但当前一次模型调用只应该看到很小一部分。
典型过滤顺序可以是:
text
all catalog
→ tenant/user permission
→ task/domain relevance
→ risk/policy
→ capability search/rank
→ expose full schema for top candidates例如公司有 800 个内部 Tool,当前只是代码阅读任务,就没必要把支付、HR、生产发布 Tool 的 schema 一起放进 Context。这样既省 token,也减少模型误选高风险能力的机会。
最终执行时仍要再次 Registry lookup + authorization;“没暴露给模型”不是强安全边界。
🔍 源码对照:Tool metadata 能提示风险,但不执行权限
精确定位
- 文件:
source/node-agent-coordinator/routed-mcp-bridge.ts - Symbol:
isReadOnly()→tools/list branch - 深入索引:Code Atlas:03-tool-runtime
ts
async function listProjectedTools() {
const discovered = await deps.listTools()
tools = new Map(discovered.map(t => [t.name, t]))
return [...tools.values()].map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
annotations: projectRiskHints(tool),
}))
}对照理解
tools/list不只是把远端 JSON 原样转发:它先形成内部Map<name, Tool>,再投影成模型/协议可见的 definition。- Discovery 和 Execution 因而由稳定的 tool identity 连接;后续
tools/call必须命中刚才发现的 definition。 readOnlyHint / destructiveHint / idempotentHint是 metadata/hint,不是权限执行器。
源码说明
bridge 在 tools/list 时为 Tool 附加 read-only/destructive/idempotent/open-world hints;另一边,prompt assembly 又拥有 connector manifests、MCP discovery status 等输入。这提供了一个很好的交叉案例:Tool Discovery 决定“系统拥有什么能力”,Dynamic Exposure 决定“当前 Turn 向模型展示哪些能力”,两者不能合成一个巨型静态 tool list。
工程边界
案例中 read-only 判断包含基于名称/description 的启发式分类,这种方法不能当安全策略;真正权限必须来自可信 metadata / policy。
Shadow Harness 对照
- 把 capability metadata 存在 Registry/Policy 层,而不是只写进 description。
- ContextBuilder 只暴露本轮被选中的 ToolSpec,并记录 exposure reason。
验证
构造 10/100/1000 tools,比较全量 exposure 与 metadata-filtered exposure 的 token cost、选择准确率和错误调用率。
Tool Discovery at Scale
Tool Discovery at Scale 是在大规模 Tool Catalog 中先检索候选 capability,再按需加载少量 schema 的发现机制。它解决的是“如何从数百或数千工具中找到候选”,而不是直接决定最终授权。
Discovery 自身需要 ranking/eval,不能靠名称 substring 随意匹配。
大规模 Tool Catalog 通常是两阶段选择
第一阶段只检索轻量 metadata:
text
name / namespace
short capability description
risk class
tags
version
required permission得到少量候选后,第二阶段才加载完整 schema/examples 进入模型 Context。这样 Tool search 本身的成本不会随着每个 Tool schema 一起线性增长。
text
1000 tools catalog
→ metadata retrieval top 20
→ policy filter top 8
→ expose 8 full schemas
→ model selects action
→ executor re-authorizesDiscovery ranking 只回答“可能相关”,不回答“允许执行”。最后一道 authorization 必须发生在 Executor 边界。
Version/Metadata 也是可复现性的一部分
同名 github.search@v1 与 @v2 可能 schema 或语义不同。RunManifest 应记录实际 exposed catalog/version;否则历史失败 Run 只能知道模型“调用了 github.search”,却无法重现当时看到的定义。
Tool discovery 的 Eval 也应单独看 recall:正确 Tool 是否进入候选集。如果正确 Tool 在 discovery 阶段就被过滤掉,后面的模型再聪明也选不到。
关联源码
自测
- 系统有 300 个 Tool,但当前任务只需要文件搜索。怎样利用 metadata/capability 把候选缩小,而不一次塞完整 catalog?
- 动态暴露漏掉了一个必要 Tool,与暴露太多无关 Tool,分别会造成什么不同的模型行为?