Appearance
什么才是好 Tool:Contract、Granularity 与 Naming
前置:Model / Runtime Boundary;Structured Interaction / Schema Validation
核心问题:一个能力应该怎样切成 Tool,才能既让模型容易选对,又让 Runtime 能验证输入、副作用和权限?
send email 的 schema 可限制 recipient/body,但 Runtime 还需做 recipient policy、approval 和 idempotency。manage everything(action, payload) 太粗;为每个数据库字段做一个 tool 又太细。search issues / get issue / update issue 通常更自然。
Mental Model
text
Model ToolCall → Registry lookup → schema/domain validation → permission → executor → result policy → ObservationTool definition 决定模型看到的 capability,ToolExecutor 决定系统实际发生的 I/O。两者中间必须存在 validation/policy,而不是模型一调用就直接执行。
Tool 是确定性系统与非确定性模型之间的 Contract
Tool 粒度决定模型要做多少 orchestration:粗工具减少调用但不透明,细工具可组合但增加 selection/plan 负担。优先让每个 Tool 有清晰、可验证的职责。
Tool contract 定义模型能请求什么、程序如何验证和执行、失败怎样表达。模型只产生调用意图,权限和副作用仍由确定性 Runtime 控制。
🔍 源码对照:协议 Tool 只是内部能力的投影
完整源码与通用分析见 06-03 Tool Metadata / Dynamic Discovery。这里不重复代码;这里关注 contract boundary:协议发现结果只能投影成内部 ToolSpec,MCP / Provider 的协议类型不应泄漏进 Runtime Tool Contract。
源码说明
routed-mcp-bridge.ts 把内部 Tool 视为包含 name / providerIdentifier / toolName / description / inputSchema 的能力记录,再投影给外部协议。它提醒我们 Tool Contract 至少要同时服务两端:模型需要清晰的语义和 schema,Runtime 需要稳定 identity 与 provider binding。只设计一个“可调用 Python 函数”不足以覆盖这两个角色。
工程边界
该 bridge 的字段名和 provider 组织方式是产品实现;Shadow Harness 不需要复制 providerIdentifier,但必须有能够唯一解析执行目标的内部 identity。
Shadow Harness 对照
- 区分 model-visible
ToolSpec与 runtime-onlyToolBinding。 - Tool rename/version upgrade 不应让历史 execution record 失去解析能力。
验证
注册两个显示名相同但 provider/version 不同的 Tool,验证模型侧名称策略与 Runtime 侧唯一 identity 不冲突。
Tool Granularity
Tool 粒度决定“多少 orchestration 交给模型,多少封装在确定性代码里”。
例如:
text
粗粒度:deploy_service(service, version)
细粒度:build_image → push_image → update_manifest → rollout → verify粗粒度调用少、业务语义清楚,也更容易把事务/权限封装在 Tool 内;但内部过程对 Agent 不透明。细粒度更灵活、可组合,却增加 planning、tool selection 和中间失败面。
因此不要机械地“一个 HTTP API = 一个 Tool”。更合适的边界通常是:一个 Tool 完成一个可描述、可授权、可验证的用户意图。
Tool Naming / Description
Tool 名称和描述不是文档装饰,而是模型选择 capability 时看到的接口。
例如同时存在:
text
search_files(query)
search_symbols(query)如果描述都只写“搜索代码”,模型很难知道什么时候该按文本找文件、什么时候该按 symbol 找定义。好的 description 应说明 能做什么、什么时候用、关键限制是什么;只有参数含义仍容易误解时再加正反例。
所以 Tool 可用性不仅取决于 executor 是否正确,也取决于模型能否在相近能力中稳定选对。
最小实现 / 数据结构
python
class ToolExecutor:
async def execute(self, call, ctx):
tool = self.registry.require(call.name)
args = tool.validate(call.arguments)
self.policy.authorize(ctx, tool, args)
return await self.runner.run(tool, args, deadline=ctx.deadline)在 Shadow Harness 中怎么落地
ToolDefinition/Registry/Executor/ResultPolicy 分层;Local、MCP、Shell、Agent-as-Tool 统一到内部 Tool contract。
关联源码
自测
- 一个
do_everything(task)Tool 把搜索、修改、部署都包在一起。为什么它对模型选择、权限和副作用审计都不友好? - 设计
read_file与apply_patch时,哪些 contract 信息必须让 Runtime 知道,不能只靠自然语言 Tool 描述?