iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
AI Engineering

[ opencode ] 開源 AI coding agent系列 第 16

16-opencode | Custom tools:擴充 agent 的手腳

  • 分享至 

  • xImage
  •  

! 本篇文章將會介紹 custom tools,用幾十行 TypeScript 幫 AI 打造專屬工具,甚至直接內建 Python :D

TL;DR: https://dev.benben.me/slides/s/ironman-16-custom-tools

本篇目標

讀完這篇你會學到:

  • tool() helper 定義 AI 可呼叫的工具
  • 定義參數(Zod schema)與讀取執行 context
  • 權限控制與命名規則

Skill 給知識,tool 給行動

Day 15 的 skill 是「教 AI 怎麼想」,custom tool 則是「給 AI 新的能做到」。查公司資料庫、呼叫內部 API、跑自訂腳本——這些 bash 湊不出來或湊得很醜的事,寫成一個 tool 之後,AI 像用內建工具一樣自然地呼叫它。

建立第一個 tool

存放位置

  • 專案:.opencode/tools/
  • 全域:~/.config/opencode/tools/

檔名就是工具名database.ts 會註冊一個叫 database 的工具。

最小範例

// .opencode/tools/database.ts
import {tool} from '@opencode-ai/plugin'

export default tool({
  description: 'Query the project database',
  args: {
    query: tool.schema.string().describe('SQL query to execute'),
  },
  async execute(args) {
    // 你的資料庫邏輯
    return `Executed query: ${args.query}`
  },
})

三個成分:

  • description:AI 判斷「何時該用這工具」的依據,跟 skill 的 description 一樣要寫清楚
  • args:參數的 Zod schematool.schema 就是 Zod)。.describe() 會成為參數說明,AI 看著它填參數
  • execute:真正執行的函式,回傳字串(或物件)給 AI

存檔、重啟 opencode,AI 的工具箱就多了一個 database

執行 context

execute 的第二個參數帶著 session 資訊:

async execute(args, context) {
  const { agent, sessionID, directory, worktree } = context
  // ...
}

context.worktree 是 git worktree 根目錄,context.directory 是工作目錄——路徑處理靠這兩個,不要寫死。

進階技巧

一檔多工具

一個檔案 export 多個 tool,會註冊成 檔名_匯出名

// .opencode/tools/math.ts
export const add = tool({
  /* ... */
})
export const multiply = tool({
  /* ... */
})

註冊出 math_addmath_multiply 兩個工具。

覆蓋內建工具

custom tool 跟內建工具撞名時,custom 優先。例如寫一個 bash.ts 擋掉危險指令——所有 bash 呼叫都會繞進你的 wrapper。官方提醒:想「停用」內建工具而不是替換的話,用 permissions 就好,別為了關燈蓋一棟房子。

工具裡跑 Python(或任何語言)

tool 定義是 TypeScript,但定義裡可以呼叫任何語言的腳本

// .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(),
    b: tool.schema.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.$ shell API 叫 Python 跑 add.py。團隊既有腳本資產不用重寫,包一層就能上。

使用 npm 套件

.opencode/package.json 宣告 dependency(例如 shell 轉義庫 shescape),opencode 啟動時自動 bun install,tool 裡直接 import。

權限與安全

Custom tool 就是 tool,Day 11 的 permission 系統一體適用:

{
  "permission": {
    "database": "ask"
  }
}

敏感工具設 ask——AI 每次呼叫前都要你點頭。工具描述裡也建議寫清楚副作用(「會寫入生產資料庫」),AI 會更謹慎地用。

注意!像 database 這種吃整句 SQL 的 tool 要再多想一層:query 是 AI 生成的,prepared statement 擋不了 prompt injection——AI 讀到惡意檔案可能被慫恿下 DROP TABLE。保險做法是讓工具天然做不了壞事:連線用唯讀帳號,或把 execute 限制成只放行 SELECT

Tool vs MCP:什麼時候用哪個?

Custom tool MCP server
形式 一個 TS 檔 獨立 process / 服務
共用範圍 這個專案 / 這台機器 任何支援 MCP 的工具都能連
開發成本 幾十行 包協定、起 server

口訣:自己專案用 → custom tool;跨工具、跨團隊共用 → MCP

常見問題

Q:tool 報錯 AI 看得到嗎?
A:execute 拋出的錯誤會回給 AI,它通常會回報或換個方式重試。回傳「Error: ...」字串也行,總之把失敗資訊講清楚,AI 的自我修正能力會讓你驚訝。

Q:tool 會吃到我的 API key 嗎?
A:需要 key 時用環境變數(process.env),別寫進檔案。搭配 Day 08 的 {env:變數名} 觀念,機密永遠不落地。

Q:修改 tool 之後要重啟嗎?
A:保險做法是重啟 session 讓工具重新註冊。

小結

  • .opencode/tools/*.tstool() + Zod schema,檔名即工具名
  • execute 裡可以跑任何語言的腳本,context.worktree 處理路徑
  • 撞名覆蓋內建、permission 管 ask / deny
  • 專案自用選 tool,跨工具共用選 MCP

寫這篇的當下,opencode 已經悄悄推出 2.0.x 了!,筆者這邊也會先試試水溫,試結束之後再多個幾篇。

明日預告

Day 17:Plugins 與 SDK——事件 hook 加程式化客戶端,把 opencode 變成真正的平台。


有任何疑問但沒有 iT 邦幫忙帳號,或是想匿名提問?
歡迎到 https://dev.benben.me/q/P3C5U6 提問或加油打氣,沒意外的話會在完賽之後一起回答 :D


上一篇
15-opencode | Agent Skills:教 agent 新技能
下一篇
17-opencode | Plugins 與 SDK:程式化擴充
系列文
[ opencode ] 開源 AI coding agent24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言