Skip to content

内置工具分析

概览

gemini-cli 内置了一系列工具,覆盖文件操作、代码搜索、命令执行等场景。

源码位置packages/core/src/tools/

工具分类

文件操作类

工具功能确认
read_file读取文件内容
write_file创建/覆盖文件
edit_file编辑文件部分内容
ls列出目录内容

搜索类

工具功能确认
grep文本内容搜索
glob文件名模式匹配

执行类

工具功能确认
shell执行 shell 命令视命令而定

网络类

工具功能确认
web_fetch获取网页内容
web_search搜索引擎查询

关键工具解析

read_file

读取文件是最基础的工具。

typescript
// packages/core/src/tools/read-file.ts (简化)
export const readFileTool: ServerTool = {
  name: 'read_file',

  schema: {
    name: 'read_file',
    description: `读取文件内容。
- 支持文本文件和代码文件
- 可以指定读取范围(offset, limit)
- 自动处理大文件截断`,
    parameters: {
      type: 'object',
      properties: {
        file_path: { type: 'string' },
        offset: { type: 'number', description: '起始行号' },
        limit: { type: 'number', description: '读取行数' }
      },
      required: ['file_path']
    }
  },

  async execute({ file_path, offset, limit }) {
    const content = await fs.readFile(file_path, 'utf-8')
    const lines = content.split('\n')

    // 处理分页
    const start = offset || 0
    const end = limit ? start + limit : lines.length
    const result = lines.slice(start, end).join('\n')

    return { content: result }
  }
}

设计要点

  • 支持分页读取大文件
  • 自动处理编码
  • 返回行号方便定位

edit_file

编辑文件是 Agent 最常用的写入操作。

typescript
// 简化的 edit_file 实现
export const editFileTool: ServerTool = {
  name: 'edit_file',

  schema: {
    name: 'edit_file',
    description: `编辑文件的部分内容。
- 使用 old_text 定位要替换的内容
- old_text 必须精确匹配(包括空格和换行)
- 比 write_file 更精确,不会误改其他部分`,
    parameters: {
      type: 'object',
      properties: {
        file_path: { type: 'string' },
        old_text: { type: 'string', description: '要替换的原文本' },
        new_text: { type: 'string', description: '新文本' }
      },
      required: ['file_path', 'old_text', 'new_text']
    }
  },

  async execute({ file_path, old_text, new_text }) {
    const content = await fs.readFile(file_path, 'utf-8')

    if (!content.includes(old_text)) {
      return { error: '未找到要替换的文本,请检查 old_text 是否精确匹配' }
    }

    const newContent = content.replace(old_text, new_text)
    await fs.writeFile(file_path, newContent)

    return { content: '文件已更新' }
  },

  async shouldConfirmExecute({ file_path, old_text, new_text }) {
    return {
      title: '编辑文件',
      description: file_path,
      diff: generateDiff(old_text, new_text) // 显示差异
    }
  }
}

设计要点

  • 基于文本匹配而非行号(更稳定)
  • 要求精确匹配(避免误改)
  • 显示 diff 预览

shell

执行命令是最强大也最危险的工具。

typescript
// 简化的 shell 实现
export const shellTool: ServerTool = {
  name: 'shell',

  schema: {
    name: 'shell',
    description: `执行 shell 命令。
适用于:
- 运行构建命令(npm run build)
- 执行测试(npm test)
- Git 操作(git status)
- 安装依赖(npm install)`,
    parameters: {
      type: 'object',
      properties: {
        command: { type: 'string' },
        cwd: { type: 'string' },
        timeout: { type: 'number', description: '超时时间(毫秒)' }
      },
      required: ['command']
    }
  },

  async execute({ command, cwd, timeout = 120000 }) {
    try {
      const { stdout, stderr } = await execAsync(command, {
        cwd,
        timeout,
        maxBuffer: 10 * 1024 * 1024 // 10MB
      })

      return {
        content: stdout || stderr || '(命令执行完成,无输出)'
      }
    } catch (error) {
      return {
        error: `命令失败 (exit ${error.code}): ${error.stderr || error.message}`
      }
    }
  },

  async shouldConfirmExecute({ command }) {
    // 安全的只读命令
    const safePatterns = [
      /^ls(\s|$)/,
      /^cat\s/,
      /^head\s/,
      /^tail\s/,
      /^pwd$/,
      /^echo\s/,
      /^git\s+(status|log|diff|branch)/,
      /^npm\s+(ls|list|outdated)/
    ]

    if (safePatterns.some(p => p.test(command))) {
      return false
    }

    // 其他命令需要确认
    return {
      title: '执行命令',
      description: command,
      risk: command.includes('rm ') ? 'high' : 'medium'
    }
  }
}

设计要点

  • 安全命令自动执行
  • 危险命令需要确认
  • 超时和输出限制

grep

代码搜索工具。

typescript
export const grepTool: ServerTool = {
  name: 'grep',

  schema: {
    name: 'grep',
    description: `搜索文件内容。
- 支持正则表达式
- 可限制文件类型
- 返回匹配行和上下文`,
    parameters: {
      type: 'object',
      properties: {
        pattern: { type: 'string', description: '搜索模式(正则)' },
        path: { type: 'string', description: '搜索路径' },
        include: { type: 'string', description: '文件名模式,如 *.ts' },
        context: { type: 'number', description: '显示上下文行数' }
      },
      required: ['pattern']
    }
  },

  async execute({ pattern, path = '.', include, context = 2 }) {
    // 使用 ripgrep 或内置搜索
    const args = [
      '--line-number',
      `--context=${context}`,
      include ? `--glob=${include}` : '',
      pattern,
      path
    ].filter(Boolean)

    const result = await execAsync(`rg ${args.join(' ')}`)
    return { content: result.stdout }
  }
}

工具协作示例

LLM 经常组合使用多个工具:

用户: 找到所有 TODO 注释并列出来

Agent:
1. [grep] 搜索 "TODO" 模式
2. 返回搜索结果

---

用户: 把 src/index.ts 中的 console.log 都删掉

Agent:
1. [read_file] 读取 src/index.ts
2. [edit_file] 删除 console.log 语句
3. [read_file] 确认修改结果

工具设计总结

从 gemini-cli 的内置工具可以学到:

  1. 功能单一:每个工具只做一件事
  2. 描述清晰:description 说明使用场景
  3. 安全分级:只读工具自动执行,写入工具需确认
  4. 错误友好:返回有意义的错误信息
  5. 预览支持:写入操作显示预览

小结

  • gemini-cli 内置约 10 个核心工具
  • 分为文件操作、搜索、执行、网络四类
  • 设计原则:单一职责、安全分级、错误友好

下一步

了解了内置工具,接下来学习如何创建自定义工具:自定义工具 →

通过实际源码学习 AI Agent 开发