两种扩展机制
OpenCode 提供两种不同的扩展方式,适用于不同场景:
| 特性 | Agent Skills | Custom Tools |
|---|---|---|
| 定义方式 | Markdown 文件 | TypeScript/JavaScript |
| 复杂度 | 简单 | 中等 |
| 适用场景 | 指令模板、工作流 | 外部 API、复杂逻辑 |
| 参数验证 | 无 | Zod Schema |
| 可复用性 | 项目级 | 全局/项目级 |
Agent Skills
什么是 Agent Skills
Agent Skills 是通过 SKILL.md 文件定义的可复用指令模板。它们帮助 AI 理解特定的工作流程和最佳实践。
创建 Skill
在项目根目录创建 .opencode/skills/deploy/SKILL.md:
---
name: deploy
description: 部署应用到生产环境
triggers:
- 部署
- deploy
- 上线
---
# 部署流程
当用户要求部署时,按以下步骤执行:
## 前置检查
1. 确认当前分支是 main
2. 运行测试:`npm test`
3. 检查构建:`npm run build`
## 部署步骤
1. 构建生产版本:`npm run build:prod`
2. 上传到服务器:`rsync -avz dist/ server:/app/`
3. 重启服务:`ssh server 'systemctl restart app'`
4. 验证部署:`curl -f https://app.example.com/health`
## 回滚
如果部署失败,执行回滚:
`ssh server 'cd /app && git checkout HEAD~1 && npm run build && systemctl restart app'`
使用 Skill
> 部署到生产环境
[AI 识别到 deploy skill]
好的,我来帮你部署。首先进行前置检查...
1. ✓ 当前分支:main
2. 运行测试...
✓ 15 tests passed
3. 检查构建...
✓ Build successful
开始部署...
Skill 目录结构
.opencode/
└── skills/
├── deploy/
│ └── SKILL.md
├── code-review/
│ └── SKILL.md
└── database-migration/
└── SKILL.md
Custom Tools
什么是 Custom Tools
Custom Tools 是用 TypeScript/JavaScript 编写的自定义工具函数,可以执行任意逻辑,包括调用外部 API、操作数据库等。
创建 Tool
创建 .opencode/tools/weather.ts:
import { z } from "zod";
export default {
name: "get_weather",
description: "获取指定城市的天气信息",
parameters: z.object({
city: z.string().describe("城市名称"),
unit: z.enum(["celsius", "fahrenheit"]).default("celsius"),
}),
async execute({ city, unit }) {
const response = await fetch(
`https://api.weather.com/v1/${city}?unit=${unit}`
);
const data = await response.json();
return {
temperature: data.temp,
condition: data.condition,
humidity: data.humidity,
};
},
};
Tool 配置
在 config.json 中注册 Tool:
{
"tools": {
"custom": {
"enabled": true,
"paths": [".opencode/tools/*.ts"]
}
}
}
使用 Tool
> 北京今天天气怎么样?
[AI 调用 get_weather tool]
北京今天天气:
- 温度:22°C
- 天气:晴
- 湿度:45%
实战案例
案例一:数据库查询 Tool
import { z } from "zod";
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
export default {
name: "query_database",
description: "执行只读 SQL 查询",
parameters: z.object({
sql: z.string().describe("SQL 查询语句"),
params: z.array(z.any()).optional().describe("查询参数"),
}),
async execute({ sql, params }) {
// 安全检查:只允许 SELECT
if (!sql.trim().toUpperCase().startsWith("SELECT")) {
throw new Error("Only SELECT queries are allowed");
}
const result = await pool.query(sql, params);
return result.rows;
},
};
案例二:Jira 集成 Skill
---
name: jira
description: 与 Jira 交互,管理任务
triggers:
- jira
- 任务
- ticket
---
# Jira 操作
## 创建任务
使用 MCP 的 Jira 工具创建任务:
- 项目:PROJECT
- 类型:Task/Bug/Story
- 优先级:P0-P3
## 查询任务
查询分配给当前用户的任务,按优先级排序。
## 更新状态
更新任务状态前,确认:
1. 前置条件是否满足
2. 是否需要通知相关人员
案例三:调用 Python 脚本
import { z } from "zod";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
export default {
name: "run_python",
description: "运行 Python 脚本",
parameters: z.object({
script: z.string().describe("Python 脚本路径"),
args: z.array(z.string()).optional().describe("脚本参数"),
}),
async execute({ script, args = [] }) {
const { stdout, stderr } = await execAsync(
`python3 ${script} ${args.join(" ")}`
);
if (stderr) throw new Error(stderr);
return stdout;
},
};
权限配置
Tool 权限
{
"permissions": {
"tools": {
"get_weather": "allow",
"query_database": "ask",
"run_python": "deny"
}
}
}
Skill 权限
Skill 中的命令也受权限控制:
{
"permissions": {
"commands": {
"npm test": "allow",
"rsync *": "ask",
"rm *": "deny"
}
}
}
最佳实践
- 单一职责:每个 Tool/Skill 只做一件事
- 明确描述:description 要清晰说明用途
- 参数验证:使用 Zod 严格验证输入
- 错误处理:提供有意义的错误信息
- 安全意识:敏感操作需要权限确认