代码语言
选择后全站课程跟随

Tools

3,595 字 · 预计阅读 10 分钟

前情提要

  • 在 30 行的循环里,调用工具只有一行:tools[call.name](**call.args)
  • Claude Code 有 50 多个工具,最核心的是这几个:读文件、写文件、改文件、找文件、搜内容、跑命令
  • 第2节的 mini-cc v0.1 只有三个只读工具,还不会动手

第2节的 mini-cc 只会看,不会动手。这一节要让它能写文件、改文件、跑命令。

一旦能动手,问题就来了:模型传错了参数怎么办?它要改一个它根本没读过的文件怎么办?它一口气要读十个文件,一个一个读要等多久?

这一节看 Claude Code 怎么回答这三个问题。主要看 src/Tool.ts(一个工具长什么样)和 src/services/tools/(一次工具调用怎么执行)。


一、一个工具的两半

工具需要模型可读说明和程序可执行实现

所有工具,不管是 Read、Bash,还是 MCP 工具、子代理,都实现同一个接口(src/Tool.ts)。挑主要的字段:

typescript
// src/Tool.ts(节选、简化)
type Tool = {
  name: string                          // 模型用这个名字调用
  prompt(): string                      // 工具说明:写给模型看的
  inputSchema: ZodSchema                // 参数格式:程序用它做校验

  call(input, context): Result          // 真正干活
  validateInput?(input): Result         // 执行前的业务检查
  checkPermissions(input): Decision     // 这次调用要不要问人
  isReadOnly(input): boolean            // 只读吗?
  isConcurrencySafe(input): boolean     // 能和其他工具一起并行吗?
  maxResultSizeChars: number            // 结果超过多长就存到磁盘
}

仔细看,这些字段分成了两半:

写给模型看的 写给程序用的
name、prompt、参数说明 参数校验、业务检查、权限、能不能并行、结果大小

模型只能看到左边那一半。右边那一半,模型不知道、也改不了,全是 Harness 自己的事。

一个工具,一半是给模型的说明书,一半是给程序的护栏。


二、工具说明就是提示词

prompt() 返回的工具说明会原样进入上下文,模型靠它决定怎么用这个工具。所以工具说明本身就是提示词,而且可以写得很长。

最典型的是 Bash 工具(BashTool/prompt.ts)。它的说明里有一整节「Committing changes with git」,规定了提交代码的完整流程。节选几行:

Git Safety Protocol:
- NEVER update the git config
- NEVER run destructive git commands (push --force, reset --hard, ...) unless the user explicitly requests these actions
- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
- NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit
  when explicitly asked, otherwise the user will feel that you are being too proactive

1. 并行运行 git status、git diff、git log
2. 分析改动,起草提交信息
3. 添加文件、用 HEREDOC 提交、提交后再跑一次 git status
4. 如果 pre-commit hook 失败:修好问题,创建一个新的提交(不要 amend)

你平时看到的很多行为,都写在这里:提交之前先并行看一遍 status、diff 和最近的提交记录;提交信息用 HEREDOC 传;失败了不 amend 而是新建提交。

还有一句你可能深有同感:「除非用户明确要求,否则绝不提交」,这条早就写在工具说明里了。 可它依然会偶尔自作主张。因为工具说明也是提示词,提示词只能管「想不想」,管不了「能不能」。这就是第4节要讲的权限系统存在的原因。

工具说明是提示词,它决定模型「想怎么用」这个工具。


三、七道关卡

工具调用要经过权限与执行门槛

30 行的版本里,调用工具只有一行。在 Claude Code 里,一次工具调用要过七道关(src/services/tools/toolExecution.ts):

模型说:我要调用 Edit(file_path=..., old_string=..., new_string=...)
   │
   ├─ ① 参数校验            参数类型不对 → 把错误原样还给模型,让它重试
   ├─ ② 工具自己的检查       比如:这个文件读过之后被人改过了 → 让它重新读
   ├─ ③ PreToolUse Hook     你的脚本可以拦下、放行或者改参数(第9节)
   ├─ ④ 权限判定             deny / ask / allow / 权限模式(第4节)
   ├─ ⑤ 真正执行             tool.call()
   ├─ ⑥ PostToolUse Hook    格式化、检查(第9节)
   └─ ⑦ 结果太大             存到磁盘,只给模型一段预览(第11节)

这一节先讲 ①、② 和 ⑤,剩下几道关在后面各节补上。

每一道关拦下来,都不会让程序崩掉,而是变成一条错误结果交给模型。模型看到错误,下一轮自己调整。

本文是会员内容

全文 3,595 字,已试读约 30%。 开通专业版可阅读全文,并解锁全部课程与后续更新。

开通专业版

支持 7 天无理由退款 · 早鸟期前 500 名自动升级永久卡