内置工具分析
概览
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 的内置工具可以学到:
- 功能单一:每个工具只做一件事
- 描述清晰:description 说明使用场景
- 安全分级:只读工具自动执行,写入工具需确认
- 错误友好:返回有意义的错误信息
- 预览支持:写入操作显示预览
小结
- gemini-cli 内置约 10 个核心工具
- 分为文件操作、搜索、执行、网络四类
- 设计原则:单一职责、安全分级、错误友好
下一步
了解了内置工具,接下来学习如何创建自定义工具:自定义工具 →