返回

Claude Code 源码分析 3:Tools 工具系统设计解析

深入分析 Claude Code 的 Tools 工具系统,这是 AI 与外部世界交互的桥梁。包括 30+ 工具的实现、工具调用流程、权限控制、以及 Agent 子代理工具的设计。

本章概述

系列目录:Claude Code 源码分析系列索引

Tools 工具系统是 Claude Code 的核心,它让 AI 能够安全地与文件系统、终端、网络和其他服务交互。本章将深入分析工具系统的设计理念、实现机制和最佳实践。

你将学到

  • ✅ Tools 系统的架构设计
  • ✅ 30+ 内置工具的分类与功能
  • ✅ AgentTool 子代理系统
  • ✅ 工具权限控制机制
  • ✅ 工具结果处理流程

工具系统概览

flowchart TB
    subgraph ToolSystem["Tools 系统"]
        A[tools.ts] --> B[30+ 工具实现]
        B --> C1[文件操作]
        B --> C2[代码搜索]
        B --> C3[终端执行]
        B --> C4[网络请求]
        B --> C5[子代理]
        B --> C6[MCP]
    end
    
    subgraph Flow["调用流程"]
        D[AI 请求工具] --> E[权限检查]
        E --> F[工具执行]
        F --> G[结果处理]
        G --> H[返回 AI]
    end
    
    subgraph Permission["权限系统"]
        I[规则匹配] --> J[用户确认]
        J --> K[自动允许]
    end
    
    B --> D
    E --> I

核心文件结构

src/
├── tools.ts                    # 工具注册中心
├── Tool.ts                     # 工具基类与类型定义
├── tools/
│   ├── AgentTool/             # 子代理工具
│   │   ├── AgentTool.tsx
│   │   ├── runAgent.ts
│   │   └── built-in/          # 内置代理类型
│   ├── BashTool/              # 终端执行
│   │   ├── BashTool.tsx
│   │   ├── bashPermissions.ts
│   │   └── bashSecurity.ts
│   ├── FileEditTool/          # 文件编辑
│   ├── FileReadTool/          # 文件读取
│   ├── FileWriteTool/         # 文件写入
│   ├── GlobTool/              # 文件匹配
│   ├── GrepTool/              # 内容搜索
│   ├── SkillTool/             # 技能调用
│   ├── WebFetchTool/          # 网页抓取
│   ├── WebSearchTool/         # 网络搜索
│   ├── LSP-related/           # LSP 工具
│   └── MCP-related/           # MCP 工具
└── utils/
    └── permissions/            # 权限控制

工具类型定义

核心类型(Tool.ts)

// Tool.ts - 工具基础定义
export type Tool = {
  name: string
  description: string
  inputSchema: ToolInputJSONSchema
  execute: (input: unknown) => Promise<unknown>
}

// 工具定义构建器
export function buildTool<TInput, TResult>(
  def: ToolDef<TInput, TResult>
): Tool {
  return {
    name: def.name,
    description: def.description,
    inputSchema: def.inputSchema,
    execute: def.execute,
  }
}

工具定义接口

// Tool.ts - 工具定义接口
export type ToolDef<TInput, TResult> = {
  name: string
  description: string
  inputSchema: ToolInputJSONSchema
  execute: (input: TInput, context: ToolUseContext) => Promise<TResult>
  // 可选:权限检查
  canUse?: CanUseToolFn
  // 可选:结果渲染
  renderResult?: (result: TResult) => React.ReactNode
  // 可选:进度回调
  onProgress?: (progress: ToolProgressData) => void
}

工具分类

Claude Code 内置 30+ 工具,可分为以下几类:

1. 文件操作类

工具 功能 安全级别
FileReadTool 读取文件内容
FileWriteTool 写入文件
FileEditTool 编辑文件(查找替换)
GlobTool 文件模式匹配

2. 代码搜索类

工具 功能 安全级别
GrepTool 内容搜索(ripgrep)
LSPTool 语言服务器协议

3. 终端执行类

工具 功能 安全级别
BashTool 执行 shell 命令

4. 网络请求类

工具 功能 安全级别
WebFetchTool 抓取网页
WebSearchTool 网络搜索

5. 子代理类

工具 功能 安全级别
AgentTool 启动子代理
TeamCreateTool 创建团队
TeamDeleteTool 删除团队
SendMessageTool 发送消息给子代理

6. MCP 类

工具 功能 安全级别
MCPTool MCP 服务器调用
ListMcpResourcesTool 列出 MCP 资源
ReadMcpResourceTool 读取 MCP 资源

7. 任务管理类

工具 功能 安全级别
TaskOutputTool 获取任务输出
TodoWriteTool 写入 Todo 列表

8. 计划模式类

工具 功能 安全级别
EnterPlanModeTool 进入计划模式
ExitPlanModeTool 退出计划模式

9. 工作区类

工具 功能 安全级别
EnterWorktreeTool 进入工作树
ExitWorktreeTool 退出工作树

AgentTool 子代理系统

AgentTool 是 Claude Code 最强大的工具之一,它允许启动并行工作的子代理。

AgentTool 架构

flowchart TB
    subgraph AgentTool["AgentTool"]
        A[接收任务] --> B[创建代理]
        B --> C{执行模式}
        C -->|同步| D[等待完成]
        C -->|异步| E[后台运行]
        C -->|fork| F[隔离执行]
    end
    
    subgraph Lifecycle["生命周期"]
        G[初始化] --> H[执行]
        H --> I{完成?}
        I -->|是| J[返回结果]
        I -->|否| H
        H --> K[错误] --> L[错误处理]
    end
    
    B --> G

AgentTool 输入定义

// AgentTool.tsx:82-101
const baseInputSchema = lazySchema(() => z.object({
  description: z.string().describe('A short (3-5 word) description of the task'),
  prompt: z.string().describe('The task for the agent to perform'),
  subagent_type: z.string().optional().describe('The type of specialized agent to use'),
  model: z.enum(['sonnet', 'opus', 'haiku']).optional().describe('Optional model override'),
  run_in_background: z.boolean().optional().describe('Set to true to run this agent in the background')
}));

const fullInputSchema = lazySchema(() => {
  const multiAgentInputSchema = z.object({
    name: z.string().optional().describe('Name for the spawned agent'),
    team_name: z.string().optional().describe('Team name for spawning'),
    mode: permissionModeSchema().optional().describe('Permission mode for spawned teammate')
  });
  return baseInputSchema().merge(multiAgentInputSchema).extend({
    isolation: z.enum(['worktree']).optional().describe('Isolation mode'),
    cwd: z.string().optional().describe('Absolute path to run the agent in')
  });
});

内置代理类型

// AgentTool/built-in/generalPurposeAgent.ts
export const GENERAL_PURPOSE_AGENT = {
  name: 'general-purpose',
  description: 'General purpose agent for researching complex questions, searching for code, and executing multi-step tasks',
  tools: ['*'],  // 可以使用所有工具
  model: 'sonnet'
};

子代理执行流程

// AgentTool/runAgent.ts - 简化示意
export async function runAgent(params: RunAgentParams) {
  // 1. 创建代理上下文
  const agentContext = await createAgentContext(params);
  
  // 2. 加载工具集
  const tools = assembleToolPool(params.agentType);
  
  // 3. 构建系统提示词
  const systemPrompt = buildEffectiveSystemPrompt(params);
  
  // 4. 执行对话循环
  while (!isComplete) {
    const response = await callClaudeAPI({
      messages,
      tools,
      systemPrompt
    });
    
    // 处理工具调用
    for (const toolCall of response.tool_calls) {
      const result = await executeTool(toolCall);
      messages.push(toolResultToMessage(result));
    }
  }
  
  // 5. 返回结果
  return finalizeResult(messages);
}

BashTool 安全机制

BashTool 是最危险的工具之一,Claude Code 实现了多层安全机制。

命令分类

// BashTool/BashTool.tsx:60-81
// 搜索命令(可折叠显示)
const BASH_SEARCH_COMMANDS = new Set([
  'find', 'grep', 'rg', 'ag', 'ack', 'locate', 'which', 'whereis'
]);

// 读取命令(可折叠显示)
const BASH_READ_COMMANDS = new Set([
  'cat', 'head', 'tail', 'less', 'more',
  'wc', 'stat', 'file', 'strings',
  'jq', 'awk', 'cut', 'sort', 'uniq', 'tr'
]);

// 目录列表命令
const BASH_LIST_COMMANDS = new Set(['ls', 'tree', 'du']);

// 静默命令(成功时无输出)
const BASH_SILENT_COMMANDS = new Set([
  'mv', 'cp', 'rm', 'mkdir', 'rmdir', 
  'chmod', 'chown', 'touch', 'ln'
]);

权限检查流程

// BashTool/bashPermissions.ts - 简化示意
export function bashToolHasPermission(
  command: string,
  permissionContext: PermissionContext
): PermissionResult {
  // 1. 解析命令
  const parsed = parseCommand(command);
  
  // 2. 检查危险命令
  if (isDangerousCommand(parsed)) {
    return { allowed: false, reason: 'Dangerous command' };
  }
  
  // 3. 检查权限规则
  for (const rule of permissionContext.rules) {
    if (matchesRule(parsed, rule)) {
      return rule.allowed 
        ? { allowed: true }
        : { allowed: false, reason: rule.reason };
    }
  }
  
  // 4. 默认拒绝
  return { allowed: false, reason: 'No matching rule' };
}

破坏性命令警告

// BashTool/destructiveCommandWarning.ts
export function getDestructiveCommandWarning(command: string): string | null {
  if (command.includes('rm -rf') || command.includes('rm -fr')) {
    return '⚠️ This command will recursively delete files';
  }
  if (command.includes('> /dev/null')) {
    return '⚠️ Output will be discarded';
  }
  // ... 其他危险模式
  return null;
}

工具注册与发现

工具注册

// tools.ts - 工具注册中心
export function getTools() {
  return [
    AgentTool,
    BashTool,
    FileEditTool,
    FileReadTool,
    FileWriteTool,
    GlobTool,
    GrepTool,
    NotebookEditTool,
    TaskOutputTool,
    TodoWriteTool,
    WebFetchTool,
    WebSearchTool,
    // ... 其他工具
  ].filter((tool): tool is NonNullable<typeof tool> => tool != null);
}

动态工具集

// 根据场景组装工具集
export function assembleToolPool(agentType: string): Tool[] {
  const baseTools = [
    BashTool,
    FileReadTool,
    GlobTool,
    GrepTool,
  ];
  
  switch (agentType) {
    case 'explore':
      return [...baseTools, FileWriteTool, SkillTool];
    case 'plan':
      return [...baseTools, TodoWriteTool];
    case 'execute':
      return [...baseTools, FileEditTool, FileWriteTool];
    default:
      return baseTools;
  }
}

工具结果处理

结果类型

// Tool.ts - 工具结果类型
export type ToolResult = 
  | { type: 'success'; data: unknown }
  | { type: 'error'; error: string }
  | { type: 'permission_denied'; reason: string }
  | { type: 'pending'; message: string };

结果存储

// utils/toolResultStorage.ts
export function generatePreview(result: unknown, maxSize: number): string {
  const content = JSON.stringify(result, null, 2);
  if (content.length <= maxSize) {
    return content;
  }
  return content.slice(0, maxSize) + '\n... (truncated)';
}

export async function buildLargeToolResultMessage(
  result: unknown,
  toolName: string
): Promise<string> {
  const resultPath = getToolResultPath(toolName);
  await writeFile(resultPath, JSON.stringify(result));
  return `Result saved to: ${resultPath}`;
}

MCP 工具集成

MCP 工具架构

flowchart TB
    subgraph ClaudeCode["Claude Code"]
        A[MCPTool] --> B[MCP Client]
    end
    
    subgraph MCP["MCP Protocol"]
        B --> C[Tools]
        B --> D[Resources]
        B --> E[Prompts]
    end
    
    subgraph Servers["MCP Servers"]
        F[File System]
        G[GitHub]
        H[Database]
        I[Custom]
    end
    
    C --> F
    C --> G
    C --> H
    C --> I

MCP 工具调用

// tools/MCPTool/MCPTool.ts
export async function callMCPTool(
  serverName: string,
  toolName: string,
  args: Record<string, unknown>
): Promise<ToolResult> {
  // 1. 获取 MCP 客户端
  const client = await getMCPClient(serverName);
  
  // 2. 调用工具
  const result = await client.callTool(toolName, args);
  
  // 3. 转换结果格式
  return {
    type: 'success',
    data: mcpResultToToolResult(result)
  };
}

最佳实践

1. 工具设计原则

// ✅ 好的工具设计
const goodTool = buildTool({
  name: 'read_file',
  description: 'Read the contents of a file at the specified path',
  inputSchema: {
    type: 'object',
    properties: {
      file_path: {
        type: 'string',
        description: 'The absolute path to the file'
      }
    },
    required: ['file_path']
  },
  async execute({ file_path }) {
    // 安全检查
    if (!isPathAllowed(file_path)) {
      throw new PermissionError('Path not allowed');
    }
    return await readFile(file_path);
  }
});

2. 权限控制

// ✅ 细粒度权限控制
const secureTool = buildTool({
  name: 'edit_file',
  // ...
  canUse: (context, input) => {
    // 检查路径权限
    if (!context.allowedPaths.includes(input.file_path)) {
      return {
        allowed: false,
        reason: 'File path not in allowed list'
      };
    }
    return { allowed: true };
  }
});

3. 错误处理

// ✅ 详细的错误信息
async function executeTool(input) {
  try {
    return await doSomething(input);
  } catch (error) {
    if (error instanceof FileNotFoundError) {
      return {
        type: 'error',
        error: `File not found: ${error.path}`
      };
    }
    if (error instanceof PermissionError) {
      return {
        type: 'permission_denied',
        reason: error.message
      };
    }
    throw error; // 未知错误,向上传播
  }
}

小结

本章深入分析了 Claude Code 的工具系统:

核心概念

概念 说明 应用场景
ToolDef 工具定义接口 定义工具行为
AgentTool 子代理工具 并行任务处理
BashTool 终端工具 系统命令执行
MCPTool MCP 集成 外部服务调用
权限控制 安全检查 危险操作防护

架构优势

  1. 类型安全 - TypeScript 确保工具和输入的类型正确
  2. 可扩展 - 易于添加新工具
  3. 安全 - 多层权限控制机制
  4. 模块化 - 工具独立,可组合使用

学习收获

  • 🔧 工具设计模式 - 如何设计 AI 可用的工具
  • 🛡️ 安全实践 - 危险操作的多层防护
  • 🚀 子代理系统 - 并行任务处理架构
  • 🔌 MCP 集成 - 标准化的外部服务接入

系列导航

参考资源