Tool 接口
一个 Agent 的 Tool 不是普通函数。普通函数只需要输入和输出,Tool 还要告诉模型:
- 我叫什么。
- 我能做什么。
- 我的参数是什么格式。
- 我是否只读。
- 我是否需要权限。
- 我的结果如何回传给模型。
Claude Code 在 Tool.ts 里定义了一个很大的 Tool 类型。它包含:
nameinputSchemacalldescriptionpromptcheckPermissionsvalidateInputisReadOnlyisConcurrencySafemapToolResultToToolResultBlockParam- UI 渲染相关方法
源码锚点
阅读 Tool.ts 时建议先看 4 个类型:
ToolUseContext:工具执行时能访问的运行环境,包括工具池、MCP、AppState、文件读取缓存、通知、权限上下文等。ToolResult:工具执行结果,允许返回data、额外消息和上下文修改器。Tool:完整工具接口。buildTool():给工具补默认实现的辅助函数。
这个接口之所以大,是因为 Claude Code 的 Tool 不只服务模型,也服务 UI、权限、MCP、遥测、转录搜索和自动安全分类。自研 Agent 早期不需要把这些都放进一个接口。
Tool 的最小本质
如果抛开 Claude Code 的产品细节,一个 Tool 最少需要这样:
ts
export type Tool<Input, Output> = {
name: string
description: string
inputSchema: Schema<Input>
readonly: boolean
execute(input: Input, context: ToolContext): Promise<Output>
toModelResult(output: Output): ToolResultContent
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
这已经覆盖了最重要的事情:
- 模型知道工具存在。
- Agent 能校验参数。
- Agent 能执行工具。
- 执行结果能回到模型。
schema 为什么重要
模型输出工具调用时,参数并不天然可信。schema 的作用是:
- 约束模型输出格式。
- 在工具执行前尽早发现错误。
- 生成 API tool schema。
- 让工具实现代码拿到类型安全的输入。
Claude Code 先用 inputSchema.safeParse 校验,再调用工具自己的 validateInput()。这两层分别解决:
- 参数形状对不对。
- 参数在当前上下文里能不能用。
例如读文件工具的参数可能满足 schema,但路径指向不存在文件,这就需要工具级校验。
结果映射
Tool 的输出不能直接丢给模型。它要被映射成 tool_result:
text
tool.call()
-> ToolResult
-> mapToolResultToToolResultBlockParam()
-> user message with tool_result1
2
3
4
2
3
4
这是 Tool 系统的关键边界:工具内部可以返回结构化对象,但模型看到的是 API 协议要求的 tool_result block。