数据截至 (上游 commit a5ac26f27989)
工具集:Cline 的「手」
本章讲什么: 模型缺的第二样东西是手 —— 把它说的「改这个文件」精确落到真实磁盘上。这章讲 Cline 内置哪些工具、文件编辑为什么用「唯一匹配才替换」、以及 Plan 模式和 Act 模式怎么用一组开关切换工具集。
1. 工具是什么(在 Cline 里)
一个工具就是 { name, description, inputSchema, execute } 四件套,用 createTool(sdk/packages/shared/src/tools/create.ts)造出来。模型看到 description 和 inputSchema 决定调不调、传什么参数;execute 是真正干活的函数。
Cline 的默认工具由一组工厂函数生产,集中在 definitions.ts,由 createDefaultTools(definitions.ts:824)按配置组装。
2. 默认工具清单
| 工具 | 干什么 | 工厂函数 |
|---|---|---|
read_files | 读一个或多个文件(支持行范围分页) | createReadFilesTool |
search_codebase | 正则搜代码库 | createSearchTool |
run_commands | 跑 shell 命令(支持 heredoc 合并) | (definitions.ts 内) |
editor | 改文件:str_replace / 插入行 / 新建 | createEditorTool(executor: createEditorExecutor) |
apply_patch | 用 GPT-5 补丁语法批量改 | (executor: apply-patch.ts) |
fetch_web_content | 抓网页 | (web-fetch.ts) |
skills | 调用预置 skills | — |
ask_question | 向用户提问 | — |
submit_and_exit | 提交最终答案并结束(完成工具) | createSubmitAndExitTool |
spawn_agent | 派生子 agent(见 05 章) | createSpawnAgentTool |
每个工具的 description 都写得很细致 —— 比如 read_files 明确告诉模型「已知多个文件就一次读完,和其它独立调用放同一回合」(definitions.ts:268 附近),这是在 prompt 层鼓励并行工具调用。
3. 文件编辑:为什么是「唯一匹配才替换」
Cline 的主力编辑工具 editor 用的是 str_replace 语义,实现极其保守。看 replaceInFile(sdk/packages/core/src/extensions/tools/executors/editor.ts:125):
// 示意,非源码 —— 提炼自 editor.ts:125-150 replaceInFile
const occurrences = countOccurrences(content, oldStr);
if (occurrences === 0) throw new Error("文本没找到"); // 一个都没匹配 → 报错
if (occurrences > 1) throw new Error("多处匹配"); // 匹配到多处 → 也报错
const updated = content.replace(oldStr, newStr ?? ""); // 恰好一处 → 安全替换
重点看那个 occurrences > 1 的检查。 这是有意为之的安全设计:
- 如果模型给的
old_text在文件里出现多次,Cline 拒绝替换而不是替换第一个。因为「替错地方」是编码 agent 最危险的失败模式之一 —— 默默改错一处,后面全连环崩。 - 它不做模糊匹配(不像有些 agent 会容忍空白差异、做相似度匹配)。要么精确唯一命中,要么报错让模型重新给一段更大、更独特的上下文。
这是「宁可让模型多试一次,也绝不改错地方」的取舍。替换成功后还会生成一个紧凑的行级 diff 返回(createLineDiff,editor.ts:67),让模型看到改动效果。
编辑工具还有两条旁路:insert_line != null 走插入(insertInFile,editor.ts:152),目标文件不存在则直接 createFile(editor.ts:106)。路径安全由 resolveFilePath(editor.ts:37)守:相对路径默认不许逃出 cwd。
4. 第二条编辑路:apply_patch
apply_patch(executors/apply-patch.ts)是另一种风格 —— 接受 GPT-5 的 apply_patch 补丁语法(文件头注释明说),一次可以增/删/改/移动多个文件。它有自己的解析器 PatchParser(apply-patch-parser.ts),还兼容老式 shell 包装写法。
两者的取舍:
editor(str_replace) | apply_patch | |
|---|---|---|
| 粒度 | 单文件、单处替换 | 多文件、多 hunk |
| 匹配 | 精确唯一字符串 | 补丁上下文行 |
| 谁更稳 | 改一两处时最安全 | 大批量重构时更高效 |
| 默认开关 | Act 模式默认开 | 默认关(enableApplyPatch: false) |
5. Plan 模式 vs Act 模式:换一套工具
Cline 有个标志性概念:Plan(只读规划) 和 Act(动手干活) 两种模式。实现不靠复杂状态机,就是换一组工具开关 —— 见 ToolPresets(sdk/packages/core/src/extensions/tools/presets.ts:20)。
关键差异就一行:
| 开关 | plan | act |
|---|---|---|
enableEditor | false | true |
enableReadFiles | true | true |
enableSearch | true | true |
enableBash | true | true |
直觉: Plan 模式 = 把
editor这把「会改文件的刀」收起来。模型还能读、能搜、能跑命令调研,但碰不到写文件,所以它只能输出一份计划。resolveToolPresetName(presets.ts:115附近)根据mode选预设。
预设表里还有 search(纯探索)、minimal、yolo(自动批准、带 submit_and_exit、给可信本地自动化用)几档,都是同一组 boolean 开关的不同组合。
6. 系统提示词怎么配合
工具集要配上系统提示词才好用。默认提示词 DEFAULT_CLINE_SYSTEM_PROMPT(sdk/packages/shared/src/prompt/system.ts:1)里有几条值得注意:
- 反复强调并行工具调用:「识别出下一步所有独立的读/搜/命令/编辑,现在就全部发出,别等一个结果再发下一个」。
- 强制绝对路径、先给计划再动手、改完要验证。
- 末尾约定:没有工具调用的回复就视为「带最终答案的完成」(
system.ts:30)—— 这正好对上 01 章里「toolCalls 为空就收尾」的循环逻辑。
还有一个 YOLO_CLINE_SYSTEM_PROMPT(system.ts:38)给无头/后台模式:它要求模型一直跑工具直到调 submit_and_exit,且「修 bug 后必须跑相关测试套件直到通过」。
7. 巧妙之处
- 编辑的安全性写进了语义:多处匹配直接拒绝(
editor.ts:139),把「改错地方」从可能变成不可能。 - 模式 = 工具子集,不是新代码路径:Plan/Act 只是
ToolPresets里的 boolean 开关,极易理解和扩展(presets.ts:20)。 - 完成靠工具属性:
submit_and_exit带lifecycle.completesRun: true(definitions.ts:765),内核据此收尾,无需特判工具名。
8. 边界与局限
str_replace不做模糊匹配 —— 模型给的old_text必须和磁盘字符级一致且唯一,否则要重试,偶尔会多耗一轮。- 工具是否真的执行,还要过内核的批准层(01 章 §5)和
SessionRuntime的策略过滤(03 章),工具清单里有不代表一定能跑。
9. 代码地图
| 主题 | 文件路径 | 符号名 |
|---|---|---|
| 默认工具工厂 | sdk/packages/core/src/extensions/tools/definitions.ts | createDefaultTools、createReadFilesTool、createSearchTool |
| 完成工具 | sdk/packages/core/src/extensions/tools/definitions.ts | createSubmitAndExitTool(completesRun: true) |
| 精确编辑 | sdk/packages/core/src/extensions/tools/executors/editor.ts | replaceInFile、createEditorExecutor |
| 补丁编辑 | sdk/packages/core/src/extensions/tools/executors/apply-patch.ts | PatchParser |
| 工具预设/模式 | sdk/packages/core/src/extensions/tools/presets.ts | ToolPresets、resolveToolPresetName |
| 系统提示词 | sdk/packages/shared/src/prompt/system.ts | DEFAULT_CLINE_SYSTEM_PROMPT、YOLO_CLINE_SYSTEM_PROMPT |
| createTool 原语 | sdk/packages/shared/src/tools/create.ts | createTool |