Skip to main content

工具系统:定义、注册、调度、执行

工具是 Agent 与外部世界交互的"手"。Claude Code 的工具系统设计精巧,覆盖了从定义到权限到执行的完整生命周期。

Tool 接口​

所有工具共享统一的 Tool<Input, Output> 接口,定义在 src/Tool.ts:

type Tool<Input, Output, P = unknown> = {
// 基本信息
name: string
description?: string

// 输入验证
inputSchema: z.ZodType<Input> // Zod schema(运行时验证)
inputJSONSchema?: ToolInputJSONSchema // JSON Schema(供 MCP 使用)

// 核心执行
call(
input: Input,
context: ToolUseContext,
canUseTool: CanUseToolFn,
parentMessage: AssistantMessage,
onProgress?: (data: ToolProgressData) => void,
): Promise<ToolResult<Output>>

// 权限检查
checkPermissions(
input: Input,
context: ToolPermissionContext,
workingDir: string,
): Promise<PermissionResult>

// 输入验证(在 Zod 之后的语义验证)
validateInput?(input: Input): ValidationResult

// 结果映射(将 Output 转为 API 格式)
mapToolResultToToolResultBlockParam(
result: ToolResult<Output>,
context: ToolUseContext,
): ToolResultBlockParam

// UI 渲染
renderToolUseMessage?(input: Input, output: Output): React.ReactNode
renderToolResultMessage?(result: ToolResult<Output>): React.ReactNode

// 元信息
isConcurrencySafe?: boolean // 是否可并发执行
isReadOnly?: () => boolean // 是否只读
isMcp?: boolean // 是否来自 MCP
isEnabled?: (context: ToolUseContext) => boolean // 动态启用/禁用
maxResultSizeChars?: number // 结果最大字符数
}

ToolResult<T> 结构​

type ToolResult<T> = {
data: T // 工具输出数据
newMessages?: Message[] // 附加消息(如错误提示)
contextModifier?: (ctx: ToolUseContext) => ToolUseContext // 上下文修改
mcpMeta?: { ... } // MCP 元信息
}

buildTool() 工厂函数​

每个工具通过 buildTool() 构建,它合并 TOOL_DEFAULTS 提供安全的默认值:

const TOOL_DEFAULTS = {
checkPermissions: () => ({ result: 'allow' }), // 默认允许
isConcurrencySafe: false, // 默认不可并发
isReadOnly: () => false, // 默认非只读
// ...
}

export function buildTool<I, O>(def: ToolDef<I, O>): Tool<I, O> {
return { ...TOOL_DEFAULTS, ...def };
}

工具实现示例​

以 GlobTool 为例:

// src/tools/GlobTool/GlobTool.ts
export const GlobTool = buildTool({
name: 'Glob',
inputSchema: z.object({
pattern: z.string(),
path: z.string().optional(),
}),
isConcurrencySafe: true,
isReadOnly: () => true,

async call(input, context) {
const results = await glob(input.pattern, input.path);
return { data: results };
},

mapToolResultToToolResultBlockParam(result) {
return { type: 'tool_result', content: JSON.stringify(result.data) };
},
});

ToolUseContext 运行时上下文​

ToolUseContext 是传递给每个工具调用的丰富上下文对象:

type ToolUseContext = {
options: {
commands: Command[] // 可用命令列表
tools: Tools // 可用工具列表
mainLoopModel: string // 当前模型
mcpClients: MCPServerConnection[] // MCP 连接
thinkingConfig: ThinkingConfig // 思考配置
// ...
}
abortController: AbortController // 取消控制
readFileState: FileStateCache // 文件状态缓存
getAppState(): AppState // 应用状态
setAppState(f): void // 更新应用状态
messages: Message[] // 当前消息列表
// ...
}

工具注册​

getAllBaseTools()​

src/tools.ts 中的 getAllBaseTools() 返回所有内置工具的完整列表:

export function getAllBaseTools(): Tools {
return [
AgentTool,
BashTool,
FileEditTool,
FileReadTool,
FileWriteTool,
GlobTool,
GrepTool,
NotebookEditTool,
WebFetchTool,
WebSearchTool,
SkillTool,
TodoWriteTool,
// ... 以及条件加载的工具
...(SleepTool ? [SleepTool] : []),
...(cronTools),
// ...
];
}

Feature-gated 工具​

许多工具通过 bun:bundle 的 feature() 或环境变量条件加载,在编译期消除死代码:

const SleepTool = feature('PROACTIVE') || feature('KAIROS')
? require('./tools/SleepTool/SleepTool.js').SleepTool
: null;

getTools() 过滤​

getTools(permissionContext) 在 getAllBaseTools() 基础上过滤:

  1. 应用 deny 规则
  2. 移除 REPL-only 工具(在非交互模式下)
  3. 检查 isEnabled() 动态条件
  4. 应用 "simple" 模式限制

assembleToolPool() 合并 MCP 工具​

export function assembleToolPool(builtInTools, mcpTools) {
// 内置工具优先(名称冲突时内置工具胜出)
// MCP 工具以 mcp__serverName__toolName 命名
return [...builtInTools, ...filteredMcpTools];
}

内置工具清单​

文件操作​

工具说明并发安全
FileReadTool读取文件(支持图片、PDF、notebook)是
FileWriteTool创建/覆盖文件否
FileEditTool部分修改文件(字符串替换)否
NotebookEditToolJupyter notebook 编辑否
GlobTool文件名模式匹配是
GrepTool基于 ripgrep 的内容搜索是

Shell 执行​

工具说明
BashToolShell 命令执行(带沙箱选项)
PowerShellToolPowerShell 执行(Windows)

网络​

工具说明
WebFetchTool获取 URL 内容
WebSearchTool网络搜索

Agent 与任务​

工具说明
AgentTool子 Agent 生成(嵌套 query 循环)
TaskCreateTool创建后台任务
TaskGetTool / TaskListTool查询任务
TaskUpdateTool / TaskStopTool管理任务
TaskOutputTool获取任务输出
SendMessageTool向其他 Agent 发消息
TeamCreateTool / TeamDeleteTool创建/删除 Teammate

其他​

工具说明
SkillTool执行技能
MCPTool调用 MCP 服务器工具
LSPToolLanguage Server 操作
TodoWriteTool任务清单管理
EnterPlanModeTool / ExitPlanModeTool计划模式切换
ConfigTool运行时配置修改
BriefTool切换简洁输出模式
ToolSearchTool延迟工具发现

工具调度流水线​

toolOrchestration.ts — 编排层​

// src/services/tools/toolOrchestration.ts
export async function* runTools(toolUseBlocks, context, canUseTool) {
// 1. 分区:并发安全 vs 串行
const batches = partitionToolCalls(toolUseBlocks);

for (const batch of batches) {
if (batch.concurrent) {
// 并发执行(上限 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY)
const results = await Promise.all(
batch.tools.map(t => runToolUse(t, context, canUseTool))
);
} else {
// 串行执行
for (const tool of batch.tools) {
yield* runToolUse(tool, context, canUseTool);
}
}
}
}

partitionToolCalls 将工具调用分为:

  • 并发安全批次(isConcurrencySafe: true):如 FileRead、Glob、Grep
  • 串行批次(isConcurrencySafe: false):如 FileWrite、BashTool

toolExecution.ts — 执行层​

单个工具的执行流程:

StreamingToolExecutor — 流式执行器​

当特性开关 tengu_streaming_tool_execution2 开启时,工具在 LLM 流式响应的同时就开始执行:

// 工具参数在流式传输中逐步完成
// 一旦工具的输入完整,立即开始执行
class StreamingToolExecutor {
addTool(toolUse: ToolUseBlock) {
if (tool.isConcurrencySafe) {
// 立即并发启动
this.runConcurrently(toolUse);
} else {
// 排队等待前面的工具完成
this.queueForSerial(toolUse);
}
}

getCompletedResults(): MessageUpdate[] { ... }
}

工具结果处理​

大结果存盘​

当工具结果超过 maxResultSizeChars 阈值时,processToolResultBlock 将完整结果写入磁盘,在消息中只保留预览 + 文件路径:

// src/utils/toolResultStorage.ts
// 超过阈值的结果保存到:session/tool-results/<id>.txt
// 消息中替换为:[PERSISTED_OUTPUT_TAG] 预览 + 路径

结果预算​

applyToolResultBudget 在每轮迭代开始时,对历史工具结果施加 token 预算,确保不超出上下文窗口。

关键源文件​

文件职责
src/Tool.tsTool 接口、ToolUseContext、buildTool()
src/tools.ts工具注册表:getAllBaseTools()、getTools()、assembleToolPool()
src/services/tools/toolOrchestration.ts工具编排:partitionToolCalls、runTools
src/services/tools/toolExecution.ts工具执行:runToolUse、checkPermissionsAndCallTool
src/services/tools/StreamingToolExecutor.ts流式并发执行器
src/services/tools/toolHooks.ts工具前/后置钩子
src/utils/toolResultStorage.ts大结果存盘与预算管理
src/constants/tools.ts工具常量(子 Agent 禁用列表等)

下一步​

前往 05-permission-security.md 了解工具执行前的权限检查机制。

动手实验​

本章有对应的 Python 实验,通过编码复现上述概念:

实验 04 — 工具系统

涵盖内容:Tool 协议、Pydantic 验证、注册表、批量执行

cd experiments && python -m exp_04_tool_system.main --mock