OpenCode 学习笔记 02:核心工具 - AI 如何操作代码
Phase 2 完整实现:read, write, edit, bash, grep, glob
January 19, 2026·4 min read·Yimin
#AI#Agent#OpenCode#TypeScript#Tool
AI Agent 的能力 = 工具的能力。工具越强,Agent 越强。
本篇目标
实现 6 个核心工具,让 Agent 能真正操作代码:
| 工具 | 功能 | 核心问题 |
|---|---|---|
read | 读取文件 | Phase 1 已实现 |
write | 写入文件 | 创建/覆盖文件 |
edit | 局部编辑 | 模糊匹配如何工作? |
bash | 执行命令 | 如何处理危险命令? |
grep | 搜索内容 | 搜索工具如何配合? |
glob | 查找文件 | 文件定位 |
一、edit 工具 - 模糊匹配的艺术
1.1 为什么需要模糊匹配?
LLM 生成的代码经常有细微差异:
LLM 想替换: 实际文件:
" const x = 1" " const x = 1" ← 缩进不同
"function foo()" "function foo() " ← 尾部空格
如果只用精确匹配,很多替换会失败。
1.2 OpenCode 的 9 种匹配策略
OpenCode 的 edit.ts 有 9 种 Replacer,按优先级尝试:
| # | 策略 | 说明 |
|---|---|---|
| 1 | SimpleReplacer | 精确匹配 |
| 2 | LineTrimmedReplacer | 每行 trim 后匹配 |
| 3 | BlockAnchorReplacer | 首尾行锚定 + 中间模糊 |
| 4 | WhitespaceNormalizedReplacer | 所有空白标准化 |
| 5 | IndentationFlexibleReplacer | 缩进灵活匹配 |
| 6 | EscapeNormalizedReplacer | 转义字符处理 |
| 7 | TrimmedBoundaryReplacer | 边界修剪 |
| 8 | ContextAwareReplacer | 上下文感知 |
| 9 | MultiOccurrenceReplacer | 多次出现处理 |
1.3 核心算法:Levenshtein 距离
OpenCode 使用 Levenshtein 距离(编辑距离)计算相似度:
"hello" → "hallo" 距离 = 1(改1个字符)
"hello" → "helo" 距离 = 1(删1个字符)
"hello" → "helloo" 距离 = 1(加1个字符)
相似度计算:
similarity = 1 - (levenshtein距离 / 最大长度)
当相似度 > 阈值时,认为匹配成功。
1.4 BlockAnchorReplacer 详解
这是最聪明的策略,用于处理中间内容变化的情况:
要替换的代码:
┌─────────────────────┐
│ function foo() { │ ← 首行锚点
│ // old code │
│ return 1; │
│ } │ ← 尾行锚点
└─────────────────────┘
实际文件中:
┌─────────────────────┐
│ function foo() { │ ← 首行匹配 ✓
│ // different code │ ← 中间模糊匹配
│ return 2; │
│ } │ ← 尾行匹配 ✓
└─────────────────────┘
流程:
- 找到首行完全匹配的位置
- 向下搜索尾行匹配
- 计算中间内容的相似度
- 相似度 > 阈值则替换
1.5 tiny-agent 简化实现
我们实现 4 种核心策略:
1. 精确匹配
2. 行 trim 匹配
3. 缩进灵活匹配
4. 首尾锚点匹配
覆盖 80% 的场景。
二、搜索工具如何配合找代码?
2.1 四种搜索工具的分工
| 工具 | 用途 | 速度 | 精度 |
|---|---|---|---|
glob | 按文件名找文件 | 最快 | 文件级 |
grep | 按内容找位置 | 快 | 行级 |
codesearch | 语义搜索代码 | 慢 | 概念级 |
| LSP | 精确符号跳转 | 快 | 符号级 |
2.2 搜索场景示例
场景:找到 UserService 的所有使用
Step 1: glob "*.ts" → 找到所有 TypeScript 文件
Step 2: grep "UserService" → 找到引用位置
Step 3: read 相关文件 → 查看上下文
场景:理解某个 API 如何工作
Step 1: codesearch "React useState hook" → 找到文档和示例
Step 2: grep "useState" path:src/ → 找到项目中的使用
Step 3: read 具体文件 → 学习用法
2.3 grep 使用示例
# 找函数定义
grep "function fetchUser"
# 找所有 import
grep "import.*from"
# 找 TODO 注释
grep "TODO|FIXME"
三、OpenCode 的高级功能(未实现)
以下是 OpenCode 的功能介绍,tiny-agent 暂未实现。
3.1 Exa API - 为 AI 设计的搜索
Exa 是专为 AI 设计的搜索引擎 API,和 Google 的区别:
| 传统搜索 (Google) | Exa |
|---|---|
| 返回 10 个链接 | 直接返回文本内容 |
| 需要再去爬网页 | 直接可用 |
| 为人类设计 | 为 AI 设计 |
OpenCode 用 Exa 实现两个工具:
| 工具 | 用途 | 示例 |
|---|---|---|
| websearch | 通用网络搜索 | "2024年最好的笔记本" |
| codesearch | 代码/文档搜索 | "Next.js App Router 用法" |
3.2 LSP - 语言服务器协议
LSP(Language Server Protocol)是微软发明的协议,IDE 通过它获得智能功能:
┌─────────┐ ┌──────────────────┐
│ 编辑器 │ ←LSP协议→ │ 语言服务器 │
│ (Cursor) │ │ (ts-server/gopls)│
└─────────┘ └──────────────────┘
| LSP 功能 | 用途 |
|---|---|
| 诊断 | 检查语法错误 |
| 跳转定义 | 精确定位符号 |
| 查找引用 | 找所有使用位置 |
| 自动补全 | 代码补全建议 |
OpenCode 怎么用?
写入文件后自动检查错误,如果有语法问题就让 AI 修复:
写入代码 → LSP 检查 → 发现错误 → AI 自动修复
3.3 为什么我们不实现?
| 功能 | 复杂度 | 需要 |
|---|---|---|
| websearch | 低 | Exa API Key ($) |
| codesearch | 低 | Exa API Key ($) |
| LSP | 高 | 启动语言服务器进程、实现协议通信 |
LSP 复杂的原因:OpenCode 的 lsp/ 目录有 ~1000 行代码专门处理。
这些是生产级功能,理解核心概念后可以自行添加。
四、bash 工具 - 如何处理危险命令?
4.1 OpenCode 的命令解析
OpenCode 使用 Tree-sitter 解析 bash 命令:
git commit -m "fix" && rm -rf ./temp
解析为:
[
{ "command": "git", "args": ["commit", "-m", "fix"] },
{ "command": "rm", "args": ["-rf", "./temp"] }
]
4.2 权限分级
| 命令类型 | 权限级别 | 示例 |
|---|---|---|
| 只读命令 | 自动允许 | ls, cat, git status |
| 项目内写 | 提示确认 | rm ./temp, git commit |
| 项目外操作 | 严格确认 | rm /tmp/xxx |
| 危险命令 | 拒绝执行 | rm -rf / |
4.3 tiny-agent 简化实现
我们使用简单的模式匹配:
const dangerousPatterns = [
/rm\s+-rf\s+\/(?!\w)/, // rm -rf /
/mkfs/, // 格式化磁盘
/dd\s+if=.*of=\/dev/, // 直接写设备
]
生产环境需要更完善的权限系统。
五、工具组合:完整的代码修改流程
用户: "修复 fetchUser 函数的空指针问题"
Step 1: grep "fetchUser" → 找到定义位置
结果: src/api/user.ts:23
Step 2: read src/api/user.ts → 查看代码
发现: 没有 null 检查
Step 3: edit src/api/user.ts → 添加 null 检查
oldString: "return data.user"
newString: "return data?.user ?? null"
Step 4: bash "npm test" → 验证修复
结果: All tests passed ✓
六、总结
工具清单
| 工具 | 核心能力 | 文件 |
|---|---|---|
read | 读取文件 | tool/read.ts |
write | 创建/覆盖文件 | tool/write.ts |
edit | 模糊匹配局部编辑 | tool/edit.ts |
bash | 执行命令 | tool/bash.ts |
grep | 正则搜索 | tool/grep.ts |
glob | 文件查找 | tool/glob.ts |
关键理解
-
模糊匹配很重要
- LLM 输出不精确,需要容错
- OpenCode 有 9 种匹配策略
- Levenshtein 距离计算相似度
-
搜索工具各有分工
- glob: 文件级定位
- grep: 行级定位
- codesearch: 语义级搜索
- LSP: 符号级跳转
-
外部信息获取
- websearch: Exa API 网络搜索
- codesearch: 代码文档搜索
- webfetch: 直接获取网页
-
安全很重要
- Tree-sitter 解析命令
- 分级权限控制
- 危险命令拦截
代码仓库
完整代码:external/tiny-agent/
cd external/tiny-agent
make dev
You: 把 add 函数的返回类型改成 number
AI: [read] 查看文件
[edit] 修改代码(缩进灵活匹配)
✅ 编辑成功