Skip to content

工具系统:Agent 的双手

如果把 Agent Loop 比作 Agent 的心跳,那工具系统就是它的双手。没有手,Agent 只能说话;有了手,Agent 才能动手。

工具系统是 Agent 的双手

Agent 都有哪些手:内置工具一览

以 Claude Code 为例,我们可以看到一个 Coding Agent 需要哪些工具。按职责,它们可以分为几大类:

文件操作:读取文件、写入文件、编辑文件、编辑 Jupyter 笔记本——这是 Agent 读写代码和配置的基础能力。

系统操作:执行 Shell 命令、按文件名模式搜索、按文件内容搜索——这是 Agent 与操作系统交互的通道。

代理与任务管理:创建子代理、创建/查询/更新/停止任务——这是 Agent 把大任务拆解、委派、追踪的能力。

网络:网页搜索、网页内容抓取——这是 Agent 访问互联网信息的能力。

调度与监控:创建/删除定时任务、监控进程事件——这是 Agent 按计划执行和持续观察的能力。

技能与扩展:执行自定义技能、对接 MCP 协议——这是 Agent 通过插件机制无限扩展的能力。

工具是怎么定义的

以 Claude Code 为例,在 Agent 内部,一个完整的工具定义包括:

要素作用说明
名称唯一标识符模型用它来调用工具,比如 BashFileRead
描述功能说明告诉模型这个工具是干什么的、什么场景该用它
参数 Schema输入结构定义工具接受的参数——名称、类型、是否必填,相当于一份"调用说明书"
是否启用 ⚡环境判断实时检查当前环境是否允许使用。比如网络搜索工具在断网环境下自动不可用;MCP 工具在对应服务器离线时自动禁用
是否只读安全标记只读取信息还是会产生修改
是否破坏性安全标记操作是否不可逆(比如删除文件)
是否并发安全安全标记多个子代理同时使用是否安全
权限检查 ⚡访问控制每次调用时实时验证。检查用户的权限配置、当前运行模式等,决定放行还是拦截
是否延迟加载性能优化初始时是否加载,等需要时再发现

⚡ 标记为动态要素——每次使用时实时计算,同一个工具在不同环境、不同时刻结果可能不同。其余要素为静态,工具注册时就已确定。

工具过滤管线:谁能上场

不是所有工具在任何时候都能用。工具过滤管线是一个多层筛选机制,决策主体分别是系统、用户、工具自身,确保模型只接触到当前环境允许的工具。

工具过滤管线

决策者做什么
模式过滤系统根据运行模式决定基础工具集。比如简单模式(--bare)只保留执行命令、读文件、编辑文件
规则过滤用户移除被用户配置拒绝的工具。比如配置"禁止网络搜索",对应工具直接剔除
状态检查工具每个工具判断自身当前是否可用。比如,网络搜索工具会检查搜索服务是否配置且可用;语言服务工具会检查语言服务器是否已连接

任何一层独立拦截即可移除工具。

Fail-Closed:贯穿管线的设计哲学

Claude Code 设计了偏向保守的安全策略,来提升系统可靠性,主要体现在:

  • 并发安全默认 false。 工具的"是否并发安全"标记注册时就确定了,默认 false,工具必须显式声明安全才能享受并发优化。

  • 拒绝优先于允许。 同时存在 allow 和 deny 规则时,deny 总是优先。

  • 安全检查不可绕过。 即使开启"绕过权限"模式,修改 .git/config.claude/settings.json 等核心文件仍会被拦截。

这种设计的背后是 Fail-Closed 安全哲学——来源于电磁门锁:断电时门锁关闭(fail-closed),而不是打开(fail-open)。核心理念:无法确定安全时,默认拒绝。

但还有一个问题:即使经过过滤,把所有工具描述都塞进提示词,既浪费 token,也让模型难以准确选择,这就有了 TooSearch 按需加载这个设计。

ToolSearch:按需加载

如果把所有工具的定义都塞进每次对话的初始提示里,会有两个问题:一是浪费 token——工具描述占用的空间很大;二是模型在太多工具中反而难以准确选择。延迟加载不仅是性能优化,也是一种"最小暴露"的安全策略——模型看不到的工具,就不会被误调用或滥用。

ToolSearch 是 Claude Code 解决这个问题的方案:延迟加载,或者叫按需加载

ToolSearch 按需加载机制

系统把工具分为两类:

  • 立即可用工具:核心工具(执行命令、读写文件、子代理等)在对话开始时就加载,模型可以直接调用

  • 延迟工具:使用频率较低的工具以及所有 MCP 工具,在初始时不加载,交给一个叫 ToolSearch 的特殊工具来管理(内置工具需要显式标记才会延迟,而 MCP 工具默认全部延迟,除非明确要求立即加载)

ToolSearch 本身是一个立即可用的工具。 当模型意识到需要某个尚未加载的功能时(比如"我需要搜索网络"),它会调用 ToolSearch,传入关键词。

搜索有三种路径,按优先级依次尝试:

精确匹配。 如果查询恰好等于某个延迟工具的名称(不区分大小写),直接返回,不做任何评分。这是最快的路径。

MCP 前缀匹配。 如果查询以 mcp__ 开头(比如 mcp__slack),直接匹配所有以该前缀开头的 MCP 工具。因为前缀本身已经很明确,不需要评分。

关键词搜索。 前两条路都没命中时,走模糊搜索。系统把查询拆成多个词,分"必需词"和"可选词"——必需词(用 + 前缀标记)必须出现在工具的名称或描述中,不满足的直接淘汰;可选词用来在候选工具中计算匹配分数。

评分考虑三个维度,权重从高到低:

匹配维度内置工具MCP 工具说明
工具名精确匹配+10+12查询词与工具名完全一致
工具名部分匹配+5+6查询词出现在工具名的某个片段中
搜索提示匹配+4+4工具开发者手动标注的关键词短语
描述匹配+2+2查询词出现在工具描述中

MCP 工具在每个维度上都比内置工具权重略高(+1~+2),因为 MCP 工具通常代表外部服务集成(比如 Slack、GitHub),搜索意图更明确,匹配应该优先。

最终按总分降序排列,分数为零的不返回,最多返回 5 个结果。

以查询 +playwright click 为例,候选工具包括 mcp__playwright__browser_clickmcp__playwright__browser_navigate 等。playwright 带有 + 前缀,是必需词;click 是可选词。评分流程如下:

  1. 候选筛选:必需词 playwright 必须出现在工具名或描述中,不满足的直接淘汰
  2. 逐词评分:对每个候选工具,用所有词(必需词 + 可选词)分别匹配各维度,累加得分
    • mcp__playwright__browser_clickplaywright 精确匹配工具名片段 → +12,click 精确匹配工具名片段 → +12,总分 24
    • mcp__playwright__browser_navigateplaywright 精确匹配 → +12,click 未命中 → +0,总分 12
  3. 排序返回:按总分降序排列,browser_click(24) > browser_navigate(12)

工具经过了过滤筛选和按需加载,终于出现在模型面前。但模型真正发起一次工具调用时,还有最后一道防线——权限管线。那正是下一节的内容。