主题
第十章 工具系统完整解析(三系统对比)
← 返回目录 | 上一章:上下文工程 | 下一章:自动化与开发者体验 →
前置阅读:工具链与会话模型 和 扩展与权限 从架构角度介绍了 Opencode/OmO 的工具系统轮廓;Claude Code 工具系统 介绍了 Claude Code 的工具设计。本章从实际使用角度做三系统横向对比。
10.1 工具架构概览
三个系统的工具架构反映了截然不同的设计哲学:
| 维度 | Opencode | OmO (扩展 Opencode) | Claude Code |
|---|---|---|---|
| 工具数量 | ~19 内置 | ~40(19 原生 + 22 新增) | 50+ |
| 类型定义 | Vercel AI SDK tool() | 同 OC + 覆写 4 个 | Tool<Input,Output,Progress> 泛型 |
| 注册方式 | 代码内置 + MCP | 代码内置 + 插件注入 + MCP | buildTool(def) 工厂 + MCP |
| 并发模型 | 流水线并行 | 同 OC | partitionToolCalls() 分区并发 |
| 扩展机制 | MCP 协议 | 插件 Hook + MCP | MCP + Plugin SDK |
| 权限控制 | 用户确认 | Agent 级白/黑名单 | 7 模式 + 8 来源 + ML 分类 |
Opencode + OmO:AI SDK + Hook Pipeline
Opencode 使用 Vercel AI SDK 的 tool() 封装所有工具。工具定义包含 description(模型看到的)和 parameters(JSON Schema),通过 execute 回调执行。OmO 在此基础上通过 tool.execute.before / tool.execute.after Hook 形成完整的执行管线。
Claude Code:泛型工具系统
Claude Code 的工具基于 Tool<Input, Output, Progress> 泛型接口(类型定义 792 行),通过 buildTool(def) 工厂创建。工厂提供 7 个可覆盖方法,所有方法都有 fail-closed 默认值——如果你忘了实现某个方法,工具会安全地拒绝执行而非静默通过。
typescript
// Claude Code 的 buildTool 工厂(简化)
buildTool({
name, description, inputSchema,
isEnabled, // 是否在当前上下文中可用
isReadOnly, // 是否只读(影响权限判断)
userFacingName, // 用户看到的名称
prompt, // 模型看到的详细提示
call, // 实际执行逻辑
renderToolResult, // UI 渲染逻辑
})10.2 工具清单与分类
Opencode + OmO 工具全景
来源标记:OC = Opencode 原生、OmO = Oh My OpenAgent 新增、OmO↑OC = OmO 覆写
| 分类 | 工具 | 来源 | 核心功能 |
|---|---|---|---|
| 文件操作 | read, write, edit, apply_patch | OC | 读/写/编辑/补丁 |
hashline_edit | OmO | 基于行哈希的精确编辑 | |
| 搜索 | grep, glob | OmO↑OC | 增强版正则搜索 + 文件匹配 |
ast_grep_search, ast_grep_replace | OmO | AST 感知搜索/替换(25 语言) | |
| Shell | bash | OC | 持久 Shell 会话中执行命令 |
interactive_bash | OmO | tmux 交互(vim、htop 等) | |
| Web | webfetch, websearch, codesearch | OC | URL 获取、语义搜索、代码搜索 |
| 代码智能 | lsp (原版) | OC | 统一 LSP 操作入口 |
lsp_* (6 个) | OmO | 拆分为独立工具(更易调用) | |
| Agent 协作 | task | OmO↑OC | 子任务委派 + 后台执行 |
background_output, background_cancel | OmO | 后台任务管理 | |
call_omo_agent | OmO | 直接调用指定 Agent | |
| 会话 | session_list/read/search/info | OmO | 跨会话历史查询 |
| 任务管理 | todowrite | OC | 当前会话待办列表 |
task_create/list/get/update | OmO | 持久化任务 CRUD | |
| 交互 | question | OC | 向用户提问 |
look_at | OmO | 图片/PDF 信息提取 | |
| Skill/MCP | skill | OmO↑OC | 加载 Skill 指令集 |
skill_mcp | OmO | 调用 Skill 内嵌 MCP | |
| 控制流 | batch, plan_exit, invalid | OC | 并行容器、模式切换、兜底 |
统计:OC 原生 19 个(其中 4 个被 OmO 覆写)+ OmO 新增 22 个 = 最终可用约 40 个工具。
Claude Code 工具全景
Claude Code 有 50+ 个工具,但不是所有工具同时对模型可见——ToolSearch 机制让约 30 个工具在初始时只发送名称和搜索提示,需要时才加载完整定义。
| 分类 | 代表性工具 | 核心功能 |
|---|---|---|
| 文件操作 | FileReadTool, FileWriteTool, FileEditTool | 读/写/编辑 |
| 搜索 | GlobTool, GrepTool | 文件匹配 + 正则搜索 |
| Shell | BashTool(18 文件,最复杂单工具) | 命令执行,输入依赖行为 |
| Agent 协作 | AgentTool | 生成子代理(同步/异步/Fork) |
| 记忆 | MemoryReadTool, MemoryWriteTool | 持久 Memory 读写 |
| MCP | McpTool(动态生成) | 调用 MCP 服务器工具 |
| 任务 | TodoReadTool, TodoWriteTool | 待办列表管理 |
| 交互 | QuestionTool | 向用户提问 |
| 通信 | SendMessageTool | 团队 Agent 间消息传递 |
| Notebook | NotebookReadTool, NotebookEditTool | Jupyter Notebook 操作 |
关键差异:OmO 的 LSP 工具套件(6 个)和 AST grep 工具(2 个)在 Claude Code 中没有对应——Claude Code 依赖 BashTool 调用外部 LSP/搜索命令。反过来,Claude Code 的 Memory 工具和 Notebook 工具在 OmO 中没有对应。
10.3 工具执行管线
Opencode + OmO:Hook Pipeline
每次工具调用都经过完整的 5 阶段管线:
模型输出 tool_use
↓
┌─────────────────────────────────┐
│ 1. AI SDK 解析参数 JSON │
│ → 触发 tool-call 事件 │
├─────────────────────────────────┤
│ 2. tool.execute.before Hook │ ← OmO 前置逻辑
│ - 权限检查 / 参数变换 │
│ - AGENTS.md 注入 │
│ - 写操作防护(先 Read) │
├─────────────────────────────────┤
│ 3. 实际执行 │
│ - 内置工具: execute 回调 │
│ - MCP 工具: tool/call 协议 │
├─────────────────────────────────┤
│ 4. tool.execute.after Hook │ ← OmO 后置逻辑
│ - 输出裁剪 / 附件处理 │
│ - 行哈希增强 │
│ - System Reminder 注入 │
├─────────────────────────────────┤
│ 5. 结果注入 │
│ → tool role 消息进入下一轮 │
└─────────────────────────────────┘流式检测:系统不等模型完全输出后才执行工具——在流式输出过程中,第一个工具调用的参数解析完毕就立即开始执行,实现事实上的流水线并行。
Claude Code:StreamingToolExecutor
Claude Code 的工具执行同样是流式的,但有一个关键增强——StreamingToolExecutor(530 行)。
模型流式输出中...
↓
┌─────────────────────────────────┐
│ StreamingToolExecutor │
│ ├─ partitionToolCalls() │ ← 分区决策
│ │ ├─ 只读工具 → 并发批次 │
│ │ └─ 写入工具 → 串行批次 │
│ ├─ 流式参数收集 │
│ ├─ 参数完整即开始执行 │
│ └─ Bash 错误 → 级联取消同批工具 │
├─────────────────────────────────┤
│ 权限检查 │
│ ├─ 7 种模式匹配 │
│ ├─ 8 种规则来源优先级排序 │
│ └─ ML 分类器自动判断 │
├─────────────────────────────────┤
│ 执行 + 结果收集 │
│ ├─ Progress 回调(实时进度) │
│ └─ renderToolResult(UI 渲染) │
└─────────────────────────────────┘并发安全分区:partitionToolCalls() 将同一批工具调用分为"可并发"和"必须串行"两组。只读操作(grep、glob、read)可以并发执行,写操作(edit、bash)必须串行。这比 OC/OmO 的全并行更安全——防止两个写操作竞争同一文件。
Bash 级联取消:如果 Bash 命令执行失败,同批次的其他工具会被级联取消——这基于"如果构建失败了,后续的 lint 检查也没意义"的判断。
对比
| 维度 | Opencode/OmO | Claude Code |
|---|---|---|
| 流式执行 | 是 | 是 |
| 并发策略 | 全并行(模型决定) | 读写分区(系统决定) |
| 错误级联 | 无 | Bash 失败取消同批 |
| Hook 管线 | before → execute → after | buildTool 内置 7 方法 |
| UI 渲染 | 统一文本输出 | 每工具自定义 renderToolResult |
10.4 工具权限与安全
工具权限是 AI Agent 安全的核心问题——如何在赋予 Agent 充分能力的同时防止误操作。
Opencode:用户确认模型
Opencode 采用简单的"危险操作需用户确认"模型。对于文件写入、Shell 命令等操作,系统可能弹出确认对话框。MCP 工具在首次调用时也会请求用户授权。
OmO:Agent 级工具矩阵
OmO 在 Opencode 的基础上增加了 Agent 级工具限制矩阵:
| Agent | 禁止的工具 |
|---|---|
| Oracle | write, edit, task, call_omo_agent |
| Librarian | write, edit, task, call_omo_agent |
| Explore | write, edit, task, call_omo_agent |
| Multimodal-Looker | 除 read 外的所有工具 |
| Momus | write, edit, task |
这确保只读 Agent 不会意外修改代码,计划审查 Agent 不会自行执行修改。限制通过 agent-tool-restrictions.ts 实现,在 Agent 创建时从可用工具列表中过滤。
Claude Code:7 模式 × 8 来源
Claude Code 拥有三个系统中最精细的权限模型(详见 第十五章):
7 种权限模式(从最宽松到最严格):
- YOLO — 无需确认,全自动
- Auto-edit — 编辑自动放行,Bash 需确认
- Default — 标准确认流程
- Plan — 只读模式
- Deny-all — 全拒绝
- ... 等
8 种规则来源(按优先级排序):
- 命令行参数(
--allowedTools) - 环境变量
- CLAUDE.md 中的规则
- 项目
settings.json - 用户
settings.json - ML 分类器判断
- 工具默认策略(
isReadOnly()) - 全局默认
ML 自动分类器:在 Auto-edit / YOLO 模式下,系统使用一个轻量级 ML 模型对每次工具调用进行风险分类,决定是否需要用户确认。分类依据包括命令内容、工作目录、文件路径等。
决策追踪:每个权限决策都有完整的追踪信息——哪条规则匹配了、优先级如何、最终判断是什么——便于调试和审计。
循环检测:Doom Loop
两个系统都有防止无限工具调用循环的机制:
- Opencode:
processor.ts中的 Doom Loop 检测——同一工具 + 同一参数连续出现 ≥ 3 次时暂停并询问用户 - Claude Code:类似的循环检测,但集成在 query loop 中,作为输出过滤器的一部分
10.5 工具发现与条件加载
不是所有工具都应该同时暴露给模型——工具越多,模型选择正确工具的难度越大,且工具描述占用宝贵的上下文空间。
Opencode + OmO:条件可用性
OC/OmO 通过环境变量和功能开关控制工具可见性:
| 工具 | 条件 |
|---|---|
websearch | 需要 OPENCODE_ENABLE_WEB_SEARCH |
codesearch | 需要 OPENCODE_ENABLE_CODE_SEARCH |
question | 需要客户端支持 ask 能力 |
lsp (原版) | 需要 OPENCODE_ENABLE_LSP_TOOL 实验开关 |
batch | 需要 experimental.batch_tool: true |
plan_exit | 仅 Plan Agent 可见 |
hashline_edit | Hash Line Enhancer Hook 激活时注入 |
OmO 的 Agent 工具矩阵(§10.4)是另一层过滤——不同 Agent 看到不同的工具子集。
Claude Code:ToolSearch 延迟加载
Claude Code 的创新是 ToolSearch——约 30 个工具在初始加载时只发送名称和一行搜索提示(searchHint),不发送完整定义。模型如果判断需要某个工具,先通过搜索发现它,系统再加载完整的描述和参数。
初始加载: FileReadTool ✓ | GrepTool ✓ | BashTool ✓ | ... (核心工具)
NotebookEditTool → [name + hint only]
MemoryWriteTool → [name + hint only]
...约 30 个延迟工具
模型需要时: "I need to edit a notebook..."
→ ToolSearch 匹配 → 加载 NotebookEditTool 完整定义
→ 模型获得完整参数 Schema这个设计在工具数量 50+ 时非常关键——如果全量发送所有工具定义,仅工具 Schema 就可能占用数千 Token,且每次工具列表变化都会导致 Prompt Cache 失效。
对比
| 维度 | OC/OmO | Claude Code |
|---|---|---|
| 过滤粒度 | 工具级(有/无) | 工具级 + Schema 延迟加载 |
| 过滤维度 | 环境变量 + Agent 类型 | 用户类型 + 功能标记 + 搜索 |
| 对模型的影响 | 不可见的工具完全不存在 | 延迟工具有名称但无 Schema |
| 缓存影响 | 不考虑 | 减少 Schema 变更导致的缓存失效 |
10.6 工具调用协议对比
Opencode:Vercel AI SDK
Opencode 通过 Vercel AI SDK 统一不同 Provider 的工具调用协议。支持 Claude 的多 tool_use block、GPT 的 parallel_tool_calls、Gemini 的多 functionCall parts。系统侧不限制单次调用数量。
Claude Code:原生 Anthropic API
Claude Code 直接使用 Anthropic API 的工具调用格式。由于只支持 Claude 模型,不需要跨 Provider 的协议统一层。这让它能利用 Anthropic API 的所有高级特性(如 Prompt Caching 的精确控制、Beta 版功能标记等)。
10.7 小结
三个系统的工具设计反映了不同的成熟度和关注点:
- Opencode 提供了扎实的基础:19 个核心工具 + Vercel AI SDK 集成 + 流式执行 + MCP 扩展。
- OmO 在此基础上做了两件事:拆分(LSP 统一工具拆为 6 个独立工具)和增强(新增 22 个工具覆盖 Agent 协作、会话历史、AST 搜索等领域),同时通过 Hook 管线实现了工具执行的全生命周期控制。
- Claude Code 则展示了大规模工具系统的工程实践:泛型类型系统、延迟加载、读写分区并发、ML 权限分类、Bash 级联取消——每个设计都在解决"50+ 工具"规模下的具体痛点。
一个值得注意的趋势:三个系统都在向"工具不仅是 API 调用"的方向演进——工具承载了权限、安全、UI 渲染、进度追踪等责任,越来越像一个微型的"能力单元"而非简单的函数封装。