设计工具面时,我关注的不是“这个动作能否用
bash完成”,而是 Harness 是否需要对它实施独立策略。只要动作需要审批、权限、审计、渲染或并行调度,就应当具有结构化的专用工具合同。
这条判断讨论的是“向模型暴露什么工具”。至于工具在本机、远端服务还是沙箱中执行,是另一个独立问题。把两者混在一起,容易得到“远程执行就更安全”或“专用工具就不需要沙箱”之类的错误结论。
工具合同决定 Harness 能看见什么
模型每轮收到工具名称、描述和参数结构,然后返回一个工具调用。真正执行、授权和记录这个调用的是 Harness。
如果只提供 bash,Harness 看到的通常是不透明字符串:
{"cmd": "rm /tmp/report.pdf"}系统若要在删除前请求确认,就必须识别所有等价写法,包括 find -delete、脚本调用、重定向覆盖等。这个集合无法可靠穷举,漏判时也不会报错。
专用工具把动作提升为稳定合同:
{"tool": "delete_file", "path": "/tmp/report.pdf"}此时 Harness 不需要推测命令语义,可以直接按工具名称和结构化参数执行审批、路径校验和审计。专用工具的主要价值不是让模型更容易理解,而是让系统获得一个可靠的控制点。
四类需求值得建立专用工具
我会在以下情况把动作从通用执行器中拆出来:
| 需求 | 专用合同提供的能力 |
|---|---|
| 安全边界 | 对发送、删除、外部写入等不可逆动作设置审批和权限 |
| 一致性校验 | 编辑前检查文件版本,避免覆盖并发修改 |
| 交互渲染 | 把提问、确认或表单呈现为明确的用户界面 |
| 执行调度 | 标记只读与可并行动作,控制超时、取消和重试 |
这些需求有一个共同点:策略必须在执行前后稳定生效,不能依赖模型是否记得 Prompt 中的约定。
反过来,如果 Harness 不需要区别处理某个动作,新增专用工具只会增加参数维护、上下文占用和选择负担。工具数量越多,模型需要区分的相似合同也越多。
通用执行器会扩大真实权限
工具边界只与模型能够调用的完整工具集合一样严格。即使 delete_file 配置了审批,只要同时保留不受限制的 bash,模型仍可以通过命令完成同一动作。
这不一定是主动绕过。模型可能只是认为命令更直接,但结果相同:专用工具上的控制策略失去完整性。
因此只能在两种取舍中明确选择:
- 白名单工具面:只暴露已建模动作,控制力强,但未覆盖任务会被阻断;
- 通用执行器加统一门禁:保留动作覆盖面,同时把目录、网络、身份和高风险命令限制放在执行边界。
远端沙箱解决的是“副作用发生在哪里、能接触哪些资源”,专用工具解决的是“Harness 能否识别并控制这个动作”。两者应当组合,而不是相互替代。
我的选择:先通用,再按控制需求拆分
原型阶段我会从少量文件工具和受限执行器开始,避免在需求尚未稳定时提前设计大量合同。某个动作一旦需要审批、结构化渲染、独立审计或并行调度,就把它提升为专用工具,并同步检查通用执行器是否仍能旁路该策略。
MCP 只改变工具定义和调用协议的来源,并不改变这条判断。来自 MCP 的外部写入工具仍然需要权限和审批;工具由谁提供,不能成为放宽控制边界的理由。
这套选择的代价是工具面会随控制需求演化,而不是一次设计完成。但它避免了两个极端:既不会把所有能力压进无法治理的命令字符串,也不会维护大量没有独立策略价值的工具。
下一篇讨论状态边界:checkpoint 为什么是一条链,而不是一个存档。