返回 AI编程

7、OpenCode自定义工具完整指南

OpenCode 自定义工具完整指南

第一步:什么是自定义工具

自定义工具是用户创建的函数,AI 可以在对话过程中调用这些工具。

核心特点:

  • 与内置工具(read、write、bash)配合使用
  • 用 TypeScript/JavaScript 定义
  • 可调用任何语言的脚本
  • 灵活的参数和返回值处理

与 MCP 的对比:
| 特性 | 自定义工具 | MCP 服务器 |
|------|-----------|-----------|
| 安全性 | 本地执行,更安全 | 需要网络通信 |
| 复杂性 | 简单直接 | 配置较复杂 |
| 控制粒度 | 完全控制代码 | 依赖第三方服务 |
| 上下文占用 | 较小 | 可能很大 |


第二步:工具存放位置

项目本地

.opencode/tools/

全局配置

~/.config/opencode/tools/

第三步:创建单个工具

使用 tool() helper 创建工具:

import { tool } from "@opencode-ai/plugin"

export default tool({
  description: "Query the database",
  args: {
    query: tool.schema.string().describe("SQL query to execute")
  },
  async execute(args) {
    // 你的数据库逻辑
    return `Executed query: ${args.query}`
  }
})

关键点

  • 文件名 = 工具名
  • description 描述工具用途
  • args 定义参数(使用 Zod schema)

第四步:创建多工具文件

单个 TypeScript 文件可导出多个工具:

import { tool } from "@opencode-ai/plugin"

export const add = tool({
  description: "Add two numbers",
  args: {
    a: tool.schema.number().describe("First number"),
    b: tool.schema.number().describe("Second number")
  },
  async execute(args) {
    return args.a + args.b
  }
})

export const multiply = tool({
  description: "Multiply two numbers",
  args: {
    a: tool.schema.number().describe("First number"),
    b: tool.schema.number().describe("Second number")
  },
  async execute(args) {
    return args.a * args.b
  }
})

工具命名规则

  • 导出名 = 工具名的一部分
  • 完整工具名:<filename>_<exportname>
  • 示例:math_addmath_multiply

第五步:参数类型定义

使用 tool.schema(基于 Zod)定义参数:

args: {
  name: tool.schema.string().describe("User name"),
  age: tool.schema.number().describe("User age"),
  active: tool.schema.boolean().describe("Is active"),
  tags: tool.schema.array(tool.schema.string()).describe("Tags"),
  config: tool.schema.object({
    key: tool.schema.string()
  }).describe("Config object")
}

支持的类型

  • string、number、boolean
  • array、object
  • enum、optional

第六步:集成任意语言脚本

工具定义可以用 TypeScript,实际执行任意语言脚本:

1. 创建 Python 脚本 .opencode/tools/add.py

import sys
a = int(sys.argv[1])
b = int(sys.argv[2])
print(a + b)

2. 创建工具定义 .opencode/tools/python-add.ts

import { tool } from "@opencode-ai/plugin"
import path from "path"

export default tool({
  description: "Add two numbers using Python",
  args: {
    a: tool.schema.number().describe("First number"),
    b: tool.schema.number().describe("Second number")
  },
  async execute(args, context) {
    const script = path.join(context.worktree, ".opencode/tools/add.py")
    const result = await Bun.$`python3 ${script} ${args.a} ${args.b}`.text()
    return result.trim()
  }
})

支持的运行方式

  • Bun.$ 命令执行
  • child_process 模块
  • 直接调用系统命令

第七步:访问会话上下文

工具可以接收会话上下文信息:

export default tool({
  description: "Get project information",
  args: {},
  async execute(args, context) {
    const { agent, sessionID, messageID, directory, worktree } = context
    return `Agent: ${agent}, Session: ${sessionID}`
  }
})

上下文属性
| 属性 | 描述 |
|------|------|
| agent | 当前使用的代理名称 |
| sessionID | 会话唯一标识 |
| messageID | 消息唯一标识 |
| directory | 会话工作目录 |
| worktree | Git worktree 根目录 |


第八步:使用工具

在对话中直接调用:

Use the database tool to query users
Calculate 5 + 3 using python-add

AI 会自动识别并调用相应工具。


第九步:工具管理配置

通过权限控制工具行为:

{
  "permission": {
    "database": "allow",
    "python-add": "ask",
    "bash": "deny"
  }
}

权限选项

  • allow:允许执行
  • deny:拒绝执行
  • ask:每次询问

通配符配置

{
  "permission": {
    "math_*": "allow"
  }
}

第十步:实用示例

示例1:文件搜索工具

import { tool } from "@opencode-ai/plugin"
import { glob } from "glob"

export default tool({
  description: "Search for files matching pattern",
  args: {
    pattern: tool.schema.string().describe("Glob pattern")
  },
  async execute(args) {
    const files = await glob(args.pattern)
    return files.join("\n")
  }
})

示例2:API 调用工具

import { tool } from "@opencode-ai/plugin"

export default tool({
  description: "Call external API",
  args: {
    url: tool.schema.string().describe("API URL"),
    method: tool.schema.string().describe("HTTP method")
  },
  async execute(args) {
    const response = await fetch(args.url, { method: args.method })
    return await response.json()
  }
})

示例3:代码分析工具

import { tool } from "@opencode-ai/plugin"
import fs from "fs"

export default tool({
  description: "Analyze code complexity",
  args: {
    file: tool.schema.string().describe("File path")
  },
  async execute(args) {
    const content = fs.readFileSync(args.file, "utf-8")
    const lines = content.split("\n").length
    const functions = content.match(/function\s+\w+/g) || []
    return `Lines: ${lines}, Functions: ${functions.length}`
  }
})

常见问题

问题1:工具不被识别

  1. 确认文件在正确目录
  2. 检查文件名和导出名
  3. 重启 OpenCode

问题2:参数验证失败

  1. 检查 Zod schema 定义
  2. 确认参数类型匹配
  3. 查看错误信息调整

问题3:脚本执行失败

  1. 确认脚本有执行权限
  2. 检查路径是否正确
  3. 验证依赖已安装

问题4:上下文访问错误

  1. 确认使用了正确的上下文属性
  2. 检查异步操作是否正确 await
  3. 查看 OpenCode 日志

最佳实践

  1. 工具命名:使用清晰、描述性的名称
  2. 参数设计:必填参数放在前面
  3. 错误处理:返回有意义的错误信息
  4. 文档完善:为每个工具写清晰的 description
  5. 安全性:避免执行未验证的用户输入
  6. 性能:长时间操作考虑异步处理

快速参考

# 工具目录结构
.opencode/tools/
├── database.ts      # 工具:database
├── math.ts          # 工具:math_add, math_multiply
├── python-add.ts    # 工具:python-add
└── api.ts           # 工具:api

# 调用示例
Use database tool to query users
Add 5 and 3 using python-add

与其他扩展方式的对比

| 方式 | 适用场景 | 复杂度 | 安全性 |
|------|---------|--------|--------|
| 自定义工具 | 本地操作、简单集成 | 低 | 高 |
| MCP 服务器 | 外部服务集成 | 中 | 中 |
| 插件 | 深度定制 | 高 | 高 |
| 命令 | 简单任务 | 低 | 高 |

推荐选择

  • 简单任务 → 自定义工具
  • 外部 API → MCP 服务器
  • 深度定制 → 插件