Files
2026-04-03 13:01:19 +08:00

21 KiB
Raw Permalink Blame History

工具系统详解

本文件说明:详细介绍 Claude Code 的工具系统,包括所有内置工具的功能、输入 schema、权限模型和核心逻辑。

1. 工具系统架构

1.1 工具注册表

所有内置工具在 tools.ts 中注册:

export function getAllBaseTools(): Tools {
  return [
    AgentTool,
    TaskOutputTool,
    BashTool,
    GlobTool,
    GrepTool,
    ExitPlanModeV2Tool,
    FileReadTool,
    FileEditTool,
    FileWriteTool,
    NotebookEditTool,
    WebFetchTool,
    TodoWriteTool,
    WebSearchTool,
    TaskStopTool,
    AskUserQuestionTool,
    SkillTool,
    EnterPlanModeTool,
    // ... 更多工具
  ]
}

1.2 工具调用流程

用户输入/模型决策
      │
      ▼
checkPermissions() ────► 权限检查
      │
      ▼
validateInput() ────► 输入验证
      │
      ▼
call() ───────────► 工具执行
      │
      ▼
renderToolResultMessage() ────► 结果渲染

1.3 工具基类接口

所有工具都实现以下核心方法:

方法 描述
call(args, context, canUseTool, parentMessage) 工具执行入口
description(input, options) 获取工具描述
inputSchema 输入参数 Zod Schema
checkPermissions(input, context) 权限检查
validateInput(input, context) 输入验证
renderToolUseMessage(input, options) 渲染工具调用消息
renderToolResultMessage(content, options) 渲染工具结果

2. BashTool - Shell 命令执行

2.1 功能描述

BashTool 是 Claude Code 最核心的工具之一,负责在用户授权下执行 Shell 命令。

2.2 输入 Schema

const inputSchema = z.object({
  command: z.string().describe('要执行的命令'),
  cwd: z.string().optional().describe('工作目录'),
  timeout: z.number().optional().describe('超时时间(毫秒)'),
})

2.3 权限模型

权限检查规则

  1. 检查命令是否匹配 alwaysAllowRules
  2. 检查命令是否匹配 alwaysDenyRules
  3. 检查命令是否属于危险命令(如 rm -rf
  4. 用户确认后执行

危险命令警告

  • rm -rf 类删除命令
  • 格式化命令(如 mkfs
  • 覆盖系统文件

2.4 核心逻辑

async call({ command, cwd, timeout }, context) {
  // 1. 展开路径
  const fullCommand = expandPath(command)

  // 2. 权限检查
  const decision = await checkBashPermission(fullCommand, context)

  // 3. 决定是否使用沙箱
  const shouldSandbox = await shouldUseSandbox(fullCommand)

  // 4. 执行命令
  if (shouldSandbox) {
    return executeInSandbox(fullCommand, cwd, timeout)
  } else {
    return executeDirect(fullCommand, cwd, timeout)
  }

  // 5. 追踪文件变更
  if (result.modifiedFiles) {
    for (const file of result.modifiedFiles) {
      updateFileHistory(file, 'modified')
    }
  }
}

2.5 沙箱执行

Claude Code 支持使用沙箱执行危险命令:

async function shouldUseSandbox(command: string): Promise<boolean> {
  // 检测命令是否危险
  const isDangerous = detectDangerousCommand(command)

  // 检查用户是否设置了沙箱偏好
  const sandboxPreference = getSandboxPreference()

  return isDangerous || sandboxPreference === 'always'
}

3. FileReadTool - 文件读取

3.1 功能描述

FileReadTool 用于读取文件内容,支持多种文件类型:

  • 纯文本文件
  • 图片文件PNG, JPG, GIF, WebP
  • PDF 文档
  • Jupyter Notebooks

3.2 输入 Schema

const inputSchema = z.object({
  file_path: z.string().describe('要读取的文件绝对路径'),
  offset: z.number().int().nonnegative().optional().describe('起始行号'),
  limit: z.number().int().positive().optional().describe('读取行数'),
  pages: z.string().optional().describe('PDF 页码范围(如 "1-5"'),
})

3.3 权限模型

  • 检查文件路径是否在允许目录下
  • 检查是否匹配 deny rules
  • 检查是否为会话相关文件(特殊处理)

3.4 核心逻辑

async call({ file_path, offset = 1, limit, pages }, context) {
  const ext = path.extname(file_path).toLowerCase()

  // 根据文件类型处理
  if (ext === '.ipynb') {
    return readNotebook(file_path)
  } else if (IMAGE_EXTENSIONS.has(ext)) {
    return readImage(file_path)
  } else if (ext === '.pdf') {
    return readPDF(file_path, pages)
  } else {
    return readTextFile(file_path, offset, limit)
  }
}

3.5 特殊处理

Deduplication去重

  • 如果文件未修改且读取范围相同,返回 file_unchanged stub
  • 避免重复发送相同内容浪费 Token

内存新鲜度提示

function memoryFileFreshnessNote(mtimeMs: number): string {
  const age = Date.now() - mtimeMs
  if (age < 60000) return '(updated seconds ago)'
  if (age < 3600000) return `(updated ${Math.floor(age/60000)}m ago)`
  // ...
}

4. FileWriteTool - 文件写入

4.1 功能描述

FileWriteTool 用于创建或覆盖文件内容。

4.2 输入 Schema

const inputSchema = z.object({
  file_path: z.string().describe('文件路径'),
  content: z.string().describe('文件内容'),
})

4.3 权限模型

  • 写入权限检查
  • 目录创建权限
  • 危险路径保护(如 /etc/System

4.4 核心逻辑

async call({ file_path, content }, context) {
  // 1. 验证路径
  const fullPath = expandPath(file_path)

  // 2. 安全检查
  if (isDangerousPath(fullPath)) {
    throw new Error('Cannot write to protected path')
  }

  // 3. 确保目录存在
  const dir = path.dirname(fullPath)
  await ensureDirExists(dir)

  // 4. 写入文件
  await writeFile(fullPath, content)

  // 5. 更新文件状态缓存
  context.readFileState.set(fullPath, {
    content,
    timestamp: Date.now(),
  })

  return { success: true, path: fullPath }
}

5. FileEditTool - 文件编辑

5.1 功能描述

FileEditTool 支持两种编辑模式:

  1. Search/Replace 模式:通过 old_string 和 new_string 进行替换
  2. Edit 模式:直接编辑文件内容

5.2 输入 Schema

const inputSchema = z.object({
  file_path: z.string().describe('文件路径'),
  old_string: z.string().optional().describe('要替换的文本(精确匹配)'),
  new_string: z.string().optional().describe('替换后的文本'),
  // 或者使用 partial_diff
  partial_diff: z.object({
    replacements: z.array(z.object({
      old_string: z.string(),
      new_string: z.string(),
    }))
  }).optional()
})

5.3 权限模型

  • 需要有效的 old_string防止意外覆盖
  • 不能用于删除整个文件
  • 禁止编辑二进制文件

5.4 核心逻辑

async call({ file_path, old_string, new_string, partial_diff }, context) {
  // 1. 读取当前文件内容
  const content = await readFile(file_path)

  // 2. 执行替换
  let newContent: string

  if (partial_diff) {
    // 批量替换
    newContent = content
    for (const { old_string, new_string } of partial_diff.replacements) {
      newContent = applyReplacement(newContent, old_string, new_string)
    }
  } else {
    // 单次替换
    newContent = applyReplacement(content, old_string, new_string)
  }

  // 3. 验证 old_string 存在且唯一
  const occurrences = countOccurrences(content, old_string)
  if (occurrences === 0) {
    throw new Error('old_string not found in file')
  }
  if (occurrences > 1) {
    throw new Error('old_string appears multiple times, be more specific')
  }

  // 4. 写入文件
  await writeFile(file_path, newContent)

  // 5. 更新缓存
  context.readFileState.set(file_path, {
    content: newContent,
    timestamp: Date.now(),
  })
}

6. GlobTool - 文件模式匹配

6.1 功能描述

使用 glob 模式查找文件。

6.2 输入 Schema

const inputSchema = z.object({
  pattern: z.string().describe('Glob 模式(如 "**/*.ts"'),
  cwd: z.string().optional().describe('搜索根目录'),
})

6.3 核心逻辑

async call({ pattern, cwd }, context) {
  // 使用 ripgrep 的 glob 功能实现高性能搜索
  const results = await execFile('rg', [
    '--files-with-matches',
    '--glob', pattern,
    cwd || process.cwd()
  ])

  return {
    files: results.split('\n').filter(Boolean)
  }
}

7. GrepTool - 代码搜索

7.1 功能描述

在代码库中搜索匹配文本。

7.2 输入 Schema

const inputSchema = z.object({
  pattern: z.string().describe('搜索模式(支持正则)'),
  cwd: z.string().optional().describe('搜索目录'),
  context: z.number().optional().describe('上下文行数'),
  file_pattern: z.string().optional().describe('文件过滤模式'),
})

7.3 核心逻辑

async call({ pattern, cwd, context = 3, file_pattern }, context) {
  const args = [
    '--json',
    '-C', context.toString(),
    pattern,
  ]

  if (file_pattern) {
    args.push('--glob', file_pattern)
  }

  args.push(cwd || '.')

  const results = await execFile('rg', args)

  // 解析 JSON 输出
  const matches = JSON.parse(results)

  return {
    matches: matches.map(parseMatch),
    count: matches.length
  }
}

8. WebFetchTool - 网页获取

8.1 功能描述

获取网页内容。

8.2 输入 Schema

const inputSchema = z.object({
  url: z.string().url().describe('网页 URL'),
})

8.3 权限模型

预批准域名列表

  • anthropic.com
  • claude.ai
  • github.com
  • 主要新闻和文档站点

8.4 核心逻辑

async call({ url }, context) {
  // 1. URL 安全检查
  if (!isPreapprovedUrl(url)) {
    const decision = await context.requestPrompt('web_fetch', url)
    if (!decision.approved) {
      throw new Error('URL not approved')
    }
  }

  // 2. 获取网页
  const response = await fetch(url)

  // 3. 解析 HTML
  const text = await extractText(response)

  // 4. 清理和格式化
  return {
    content: cleanHtml(text),
    title: extractTitle(response),
    url,
  }
}

9. WebSearchTool - 网络搜索

9.1 功能描述

执行网络搜索。

9.2 输入 Schema

const inputSchema = z.object({
  query: z.string().describe('搜索查询'),
})

9.3 核心逻辑

async call({ query }, context) {
  // 使用搜索引擎 API
  const results = await searchEngine.query(query)

  return {
    results: results.map(r => ({
      title: r.title,
      url: r.url,
      snippet: r.snippet,
    })),
    total: results.length,
  }
}

10. AgentTool - 子 Agent

10.1 功能描述

AgentTool 允许 Claude 创建和管理子 Agent 来并行执行任务。

10.2 输入 Schema

const inputSchema = z.object({
  agent: z.enum(['general', 'plan', 'explore', ...]).describe('Agent 类型'),
  prompt: z.string().describe('给 Agent 的指令'),
  agentId: z.string().optional().describe('现有 Agent ID用于恢复'),
  maxTurns: z.number().optional().describe('最大轮次'),
})

10.3 Agent 类型

类型 描述
general 通用任务执行
plan 计划制定
explore 代码探索
verification 验证检查

10.4 核心逻辑

async call({ agent, prompt, maxTurns }, context) {
  // 1. 创建或恢复 Agent
  const agentId = await createSubAgent({
    type: agent,
    prompt,
    maxTurns,
  })

  // 2. 执行 Agent
  const result = await runAgent(agentId, context)

  // 3. 返回结果
  return {
    output: result.output,
    agentId,
    turns: result.turns,
  }
}

11. SkillTool - 技能执行

11.1 功能描述

SkillTool 用于执行用户定义的技能Skills这些技能以 Markdown 文件形式保存在本地目录中。

11.2 输入 Schema

const inputSchema = z.object({
  name: z.string().describe('技能名称'),
  args: z.string().optional().describe('传递给技能的参数'),
})

11.3 技能定义格式

技能目录结构:

~/.claude/skills/my-skill/
  └── skill.md

skill.md 格式:

---
name: my-skill
description: 这个技能做什么
---

# My Skill

这个技能用于执行特定任务...

## 使用方法

执行时会运行以下脚本...

11.4 核心逻辑

async call({ name, args }, context) {
  // 1. 查找技能定义
  const skill = await findSkill(name)

  if (!skill) {
    throw new Error(`Skill not found: ${name}`)
  }

  // 2. 解析技能定义
  const { prompt, script } = parseSkillDefinition(skill)

  // 3. 执行脚本
  const output = await executeScript(script, { args })

  return {
    output,
    skillName: name,
  }
}

12. MCPTool - Model Context Protocol

12.1 功能描述

MCPTool 是 MCPModel Context Protocol协议的工具包装器允许调用 MCP 服务器提供的工具。

12.2 输入 Schema

const inputSchema = z.object({
  server: z.string().describe('MCP 服务器名称'),
  tool: z.string().describe('工具名称'),
  arguments: z.record(z.string(), z.unknown()).optional().describe('工具参数'),
})

12.3 核心逻辑

async call({ server, tool, arguments }, context) {
  // 1. 获取 MCP 客户端
  const client = context.mcpClients.find(c => c.name === server)

  if (!client) {
    throw new Error(`MCP server not found: ${server}`)
  }

  // 2. 发送工具调用请求
  const result = await client.callTool(tool, arguments)

  // 3. 返回结果
  return result
}

13. LSPTool - 语言服务器协议

13.1 功能描述

LSPTool 提供对 Language Server Protocol 的访问,用于代码导航、诊断等。

13.2 核心功能

  • 跳转到定义 (Go to Definition)
  • 查找引用 (Find References)
  • 代码补全 (Completions)
  • 诊断信息 (Diagnostics)

14. NotebookEditTool - Jupyter Notebook 编辑

14.1 功能描述

NotebookEditTool 专门用于编辑 Jupyter Notebook 文件。

14.2 输入 Schema

const inputSchema = z.object({
  file_path: z.string().describe('Notebook 文件路径'),
  cell_id: z.string().optional().describe('要编辑的单元格 ID'),
  new_source: z.string().optional().describe('新单元格内容'),
  action: z.enum(['insert', 'delete', 'move']).optional().describe('操作类型'),
})

15. Task 系列工具

15.1 概述

Task 系列工具提供完整的任务管理功能:

工具 描述
TaskCreateTool 创建新任务
TaskGetTool 获取任务详情
TaskUpdateTool 更新任务状态
TaskListTool 列出任务
TaskStopTool 停止任务
TaskOutputTool 获取任务输出

15.2 TaskCreateTool 输入 Schema

const inputSchema = z.object({
  description: z.string().describe('任务描述'),
  status: z.enum(['pending', 'in_progress', 'completed']).optional(),
  priority: z.enum(['low', 'medium', 'high']).optional(),
})

15.3 任务状态流转

pending ──► in_progress ──► completed
    │              │
    └──────► failed

16. SendMessageTool - 团队消息

16.1 功能描述

SendMessageTool 用于向团队成员发送消息。

16.2 输入 Schema

const inputSchema = z.object({
  recipient: z.string().describe('收件人标识'),
  message: z.string().describe('消息内容'),
})

17. TeamCreateTool - 创建团队

17.1 功能描述

TeamCreateTool 创建一个 Agent 团队,团队成员可以协作完成任务。

17.2 输入 Schema

const inputSchema = z.object({
  name: z.string().describe('团队名称'),
  members: z.array(z.object({
    name: z.string(),
    role: z.enum(['coordinator', 'worker', 'reviewer']),
    agentType: z.string().optional(),
  })).describe('团队成员'),
})

17.3 团队角色

角色 描述
coordinator 协调者,负责分配任务
worker 执行者,负责完成任务
reviewer 审核者,负责检查结果

18. EnterPlanModeTool / ExitPlanModeTool

18.1 功能描述

计划模式允许 Claude 在执行前先制定计划,用户确认后再执行。

18.2 输入 Schema

// EnterPlanModeTool
const inputSchema = z.object({
  prompt: z.string().optional().describe('计划提示'),
})

// ExitPlanModeTool
// 无需参数

19. EnterWorktreeTool / ExitWorktreeTool

19.1 功能描述

用于创建和切换 Git Worktree便于在多个分支上同时工作。

19.2 输入 Schema

// EnterWorktreeTool
const inputSchema = z.object({
  branch: z.string().describe('分支名'),
  path: z.string().optional().describe('Worktree 路径'),
})

// ExitWorktreeTool
const inputSchema = z.object({
  path: z.string().optional().describe('要删除的 Worktree 路径'),
})

20. ToolSearchTool - 工具搜索

20.1 功能描述

ToolSearchTool 允许模型在运行时搜索可用工具,当工具过多时会延迟加载。

20.2 输入 Schema

const inputSchema = z.object({
  query: z.string().describe('搜索查询'),
})

20.3 延迟加载机制

// 当工具数量超过阈值时启用延迟加载
const TOOL_SEARCH_THRESHOLD = 50

if (totalTools > TOOL_SEARCH_THRESHOLD) {
  // 工具标记为 shouldDefer: true
  // 首次调用时需要通过 ToolSearchTool 激活
}

21. CronCreateTool - 定时任务

21.1 功能描述

CronCreateTool 创建定时执行的任务。

21.2 输入 Schema

const inputSchema = z.object({
  schedule: z.string().describe('Cron 表达式'),
  command: z.string().describe('要执行的命令'),
  name: z.string().optional().describe('任务名称'),
})

22. RemoteTriggerTool - 远程触发

22.1 功能描述

RemoteTriggerTool 允许从远程触发任务执行。

22.2 输入 Schema

const inputSchema = z.object({
  trigger_id: z.string().describe('触发器 ID'),
  payload: z.record(z.string(), z.unknown()).optional().describe('传递的数据'),
})

23. SleepTool - 延迟执行

23.1 功能描述

SleepTool 用于在任务执行中引入延迟。

23.2 输入 Schema

const inputSchema = z.object({
  duration: z.number().describe('延迟时间(秒)'),
})

24. SyntheticOutputTool - 结构化输出

24.1 功能描述

SyntheticOutputTool 用于提供符合 JSON Schema 的结构化输出。

24.2 输入 Schema

const inputSchema = z.object({
  schema: z.record(z.string(), z.unknown()).describe('JSON Schema'),
  data: z.record(z.string(), z.unknown()).describe('输出数据'),
})

24.3 验证机制

async call({ schema, data }, context) {
  // 使用 Zod 验证数据
  const validator = z.object(schema)
  const result = validator.safeParse(data)

  if (!result.success) {
    throw new Error(`Invalid output: ${result.error.message}`)
  }

  return { validated: result.data }
}

25. 工具权限系统总结

25.1 权限模式

模式 描述 行为
default 默认模式 询问危险操作
auto 自动模式 基于规则自动决定
bypass 绕过模式 允许所有操作
plan 计划模式 强制计划模式

25.2 权限检查流程

1. validateInput() - 验证输入有效性
       │
       ▼
2. checkPermissions() - 检查权限规则
       │
       ├──► alwaysAllow → 返回允许
       │
       ├──► alwaysDeny → 返回拒绝
       │
       └──► 需要询问 → 等待用户确认

25.3 权限规则匹配

// 权限规则支持通配符模式
const rules = {
  'Bash(rm *)': 'deny',      // 拒绝所有 rm 命令
  'Bash(git *)': 'allow',    // 允许所有 git 命令
  'Read(/home/user/src/*)': 'allow',  // 允许读取特定目录
}

26. 工具渲染系统

26.1 渲染方法

方法 用途
renderToolUseMessage 渲染工具调用消息
renderToolUseTag 渲染工具标签(如超时标记)
renderToolUseProgressMessage 渲染进度消息
renderToolResultMessage 渲染工具结果
renderToolUseErrorMessage 渲染错误消息
renderToolUseRejectedMessage 渲染拒绝消息

26.2 渲染选项

interface RenderOptions {
  style?: 'condensed' | 'full'
  theme?: ThemeName
  verbose?: boolean
  isTranscriptMode?: boolean
  terminalSize?: { columns: number; rows: number }
}

27. 总结

Claude Code 的工具系统设计遵循以下原则:

  1. 一致性:所有工具实现统一的 Tool 接口
  2. 安全性:细粒度的权限控制和验证
  3. 可扩展性:支持 MCP、插件、技能等多种扩展机制
  4. 用户控制:用户可精确控制每个工具的使用权限
  5. 高性能:支持流式执行、缓存、去重等优化