opencode的7个基础工具——read、write、edit、multiedit、glob、grep、bash

做 AI 编程助手(或类似工具)的核心,就是怎么让 AI 正确地读写文件、执行命令。本质上,LLM 是个"脑子里有很多知识但手很短"的存在——它能推理,但没法直接摸到你的代码。于是需要一套工具,让它能够安全、可控地操作文件系统。

OpenCode(以及其他同类工具如 Claude Code、Cursor)把这套工具抽象成了 7 个核心 API。下面逐一拆解。


1. read — 统一的文件/目录读取入口

它是干什么的

一个字:只读。AI 想看代码,先走这个入口。

设计思想

一个工具同时处理文件和目录,通过检测文件类型来自动决定怎么展示。

文件读取方面:

  • 支持分页,offset 和 limit 参数让 AI 可以"翻页"读大文件
  • 自动给每行加上行号,方便 AI 定位(比如报错说"第 42 行有问题")
  • 超长的行会自动截断,避免把整个终端撑爆

目录读取方面:

  • 返回目录结构,树状展开
  • 自动识别符号链接(快捷方式),不会当成普通文件处理

特殊格式(图片、PDF):

  • 直接作为附件返回,用 Base64 编码,AI 看到的就是图片本身而不是乱码
  • 二进制文件(非文本)通过采样检测,不尝试强行解码

一个有意思的细节:读取文件后会"假装碰了一下"文件(touch),这样会触发 LSP(Language Server Protocol)预加载——相当于提前告诉IDE"这个文件你该关注了",下次分析代码能更快。

核心原则

只读操作,不修改任何内容


2. write — 覆盖式写入 + 自动 diff 生成

它是干什么的

写入文件内容,全量覆盖。

设计思想

这个工具的设计非常谨慎,强调"先确认再执行,写入后验证"。

幂等性 + diff 确认:写入前,工具会对比旧内容和新内容,生成一个 unified diff(就是你在 git diff 里看到的那种格式),展示给用户看"哪里变了"。这样用户能明确知道 AI 想干什么,然后才授权执行。

写入后诊断:写完之后,立刻触发 LSP 诊断,返回当前文件的错误和警告。如果写入把代码写坏了,能马上知道。

事件通知:写入完成后发布一个 File.Edited 事件,其他模块(比如缓存管理器、依赖分析器)收到通知后可以同步更新状态。

核心原则

先确认再执行,写入后验证


3. edit — 智能替换 + 多策略兜底

它是干什么的

基于字符串匹配做局部替换——这是最常用的编辑工具。

设计思想

edit 的核心是 replace(oldString, newString):找到旧的字符串,替换成新的。

但问题是:AI 给出的 oldString 可能和真实代码有细微差别(比如多了几个空格、缩进不一样)。如果直接匹配不上就失败,用户体验会非常差。

所以这里设计了一整套 Replacer 策略,按顺序尝试:

  1. SimpleReplacer:精确匹配,一模一样才替换
  2. LineTrimmedReplacer:忽略行首尾空格后匹配
  3. BlockAnchorReplacer:用首尾行做锚点,中间部分相似度匹配
  4. WhitespaceNormalizedReplacer:把多个空格/ tab 归一化成一种再匹配
  5. IndentationFlexibleReplacer:缩进灵活匹配(允许不同深度的缩进)
  6. EscapeNormalizedReplacer:处理转义字符(比如 \n 和真正换行的差异)
  7. TrimmedBoundaryReplacer:裁剪边界后匹配
  8. ContextAwareReplacer:参考上下文判断是否匹配

简单说:如果精确匹配失败了,不要立刻放弃,换个策略再试试。这样能大幅提高 edit 的成功率。

另外还会自动检测原文件的换行符风格(\n 还是 \r\n),保持原样不动。

核心原则

精确替换,智能兜底,保留原格式


4. multiedit — 批量顺序编辑

它是干什么的

一次确认,执行多次 edit。

设计思想

内部其实就是循环调用 edit,但有一个关键约束:按顺序执行。每次 edit 都基于前一次 edit 之后的结果来继续。这样保证了多次修改之间不会互相干扰。

返回的结果只展示最后一次 edit 的输出和元数据。

核心原则

化零为整,一次确认多次修改


5. glob — 基于 Ripgrep 的模式匹配

它是干什么的

用 glob 模式(如 **/*.ts)搜索文件路径。

设计思想

很多新手实现 glob 可能直接用 fs.glob,但 opencode 选择用 Ripgrep 来做底层遍历。Ripgrep 是 Rust 写的高性能搜索工具,比 Node.js 的 glob 模块快得多。

额外做了几件事:

  • 时间排序:搜索结果按修改时间倒序,最新的文件排在前面。AI 通常更需要关注新代码。
  • 数量限制:默认最多返回 100 个结果,防止一次搜出几千个文件把上下文撑爆。
  • 权限控制:搜索前请求 glob 权限,明确告知 AI 会访问哪些路径。

核心原则

高性能、结果可预期、限制输出


6. grep — 内容搜索 + 结果结构化

它是干什么的

在文件内容中搜索正则表达式。

设计思想

底层也是调用 Ripgrep(rg 命令),解析输出为结构化格式:filePath|lineNum|content。

同样按文件修改时间倒序排列。有意思的是容错处理:如果遇到 broken symlink(损坏的快捷方式),会忽略它继续搜;只有在前两层(文件读取和内容解析)都出问题时才真正失败。

核心原则

精准搜索,结构化输出


7. bash — 命令执行 + 静态分析 + 权限请求

它是干什么的

执行 shell 命令,比如 npm install、git commit、python run.py。

设计思想

这是最危险的工具——也是最需要谨慎设计的。

静态分析在先:执行命令前,先用 tree-sitter(一个代码解析库)解析命令文本,提取出会涉及哪些路径。比如 cd src && rm -rf *.log,能识别出涉及 src 目录。

权限预请求:把命令转换成权限模式(如 npm install → npm *),在执行前向用户请求 bash 权限和 external_directory 权限。明确告诉用户:我要执行这个命令,它会访问这些路径,你同意吗?

流式输出:命令的 stdout 和 stderr 实时流式返回,AI 能看到执行过程,有问题随时调整策略。

⚠️ 注意:bash 无法处理交互式输入(比如要求输入密码的 sudo 命令、vim 编辑器等),这类场景需要特殊处理。

核心原则

分析先行,权限明确,安全执行


总结对比

工具 操作方式 核心特点
read 只读 统一入口,自动处理多种格式
write 覆盖 全量替换,diff 确认
edit 替换 多策略兜底,保留格式
multiedit 批量替换 复用 edit,顺序执行
glob 搜索 模式匹配,时间排序
grep 搜索 正则匹配,结构化结果
bash 执行 命令分析,权限预请求

这套工具设计的精髓在于:给 AI 足够的操作能力,同时用幂等性、diff 确认、权限预请求等机制把风险降到最低。没有哪家公司的 AI 编程工具是靠单一绝招成功的——都是在这些细节上慢慢打磨,让 AI 的手变得越来越稳定。

评论区已延迟加载滑到评论区附近时会自动加载,也可以现在手动打开。