使用OpenCode体验Agent Skills 使用 OpenCode 体验 Agent Skills
一、背景
近期OpenCode挺火的,但是听说用这个来连Claude或者别的什么大模型服务商会被封号,特别是使用了【OAuth订阅】方式连接的要特别小心。
很多人喜欢用开源软件,但是这种开源的免费使用,必然跟商业厂家产生冲突。而且自从【界面相同但代码不同就不算抄袭】这种恶心的“潜”规则面世之后,大家都喜欢这么玩。
不过我们也许应该连一下【国内的大模型厂商】试试。
这次张小白选择在Windows环境尝试。
二、安装OpenCode 二、安装 OpenCode
先看一下node.js的是否安装,进入PowerShell环境:
node -v
npm -v

执行安装:
npm install -g opencode-ai@latest

检查是否安装成功:
opencode --version

三、试用OpenCode 三、试用 OpenCode
打开opencode: 打开 opencode:
opencode

1、配置大模型厂商(硅基流动)
关于硅基流动的使用,可以参考张小白以前写的文章:
使用 connect命令,选择一个LLM厂商:
/connect

往下选找到硅基流动(SilconFlow):

输入API密钥:(到 https://cloud.siliconflow.cn/me/account/ak 获得)
输入 API 密钥:(到 https:// cloud.siliconflow.cn/me/account/ak 获得)

回车后选择模型:

这里选择一个免费的模型:Qwen/Qwen3-8B

简单问两句:

大模型接入OK,看来可以尝试Agent Skills了。
看看B站的培训视频:
https://www.bilibili.com/video/BV1GXzaByEEo/
2、Agent Skills下载 2、Agent Skills 下载
先来回顾一下skills的概念:
Claude Skills 是 Anthropic 的 Claude AI 的一项功能,它允许用户创建包含指令、参考文件和脚本的自定义技能包,以教导 Claude 执行特定任务、保持一致性和可靠性。
打开 一个疑似韩国人做的skills广场:

点击sign in

选择Github 选择 Github

授权登录:

点击上面的search:
输入skill-creator 输入技能创建器

选择Anthropic的skill,毕竟属于原装。点击打开:

下载、解压,复制到opencode的skill目录下。
Windows:C:\Users\<你的用户名>\.config\opencode\skills\<skill-name>\SKILL.md
Windows: C:\Users\<你的用户名>\.config\opencode\skills\<skill-name>\SKILL.md

3、创建skill尝试
重新打开opencode
输入:
帮我创建一个可以准确获取当前系统时间的 Skill,描述使用中文,脚本使用Node.js

看样子opencode找到了这个skill-creator的skill,开始跑了。。。
不过跑着跑着就报错了,看来免费的有流量限制。
那就换个【低收费】的试试:

重新 /connect

切换到 deepseek V3.2

帮我创建一个可以准确获取当前系统时间的 Skill,描述使用中文,脚本使用Node.js

可以看到,它分了4步做,创建skill目录结构、编写md文件,创建示例文件,验证和打包。

中间还会报错,但是它好像会自己纠错。只不过纠错会花double token。。。



创建示例文件:



打包验证:


全程花钱如下:

4、检查skill生成结果
在opencode执行的当前目录下生成了一个system-time的目录:

分别看看各个文件长什么样:
SKILL.md






assets/example_asset.txt 资产/example_asset.txt
# Example Asset File
This placeholder represents where asset files would be stored.
Replace with actual asset files (templates, images, fonts, etc.) or delete if not needed.
Asset files are NOT intended to be loaded into context, but rather used within
the output Claude produces.
Example asset files from other skills:
- Brand guidelines: logo.png, slides_template.pptx
- Frontend builder: hello-world/ directory with HTML/React boilerplate
- Typography: custom-font.ttf, font-family.woff2
- Data: sample_data.csv, test_dataset.json
## Common Asset Types
- Templates: .pptx, .docx, boilerplate directories
- Images: .png, .jpg, .svg, .gif
- Fonts: .ttf, .otf, .woff, .woff2
- Boilerplate code: Project directories, starter files
- Icons: .ico, .svg
- Data files: .csv, .json, .xml, .yaml
Note: This is a text placeholder. Actual assets can be any file type.
references/api_reference.md
参考文献/api_reference.md

scripts/example.py
剧本/example.py
#!/usr/bin/env python3
"""
Example helper script for system-time
This is a placeholder script that can be executed directly.
Replace with actual implementation or delete if not needed.
Example real scripts from other skills:
- pdf/scripts/fill_fillable_fields.py - Fills PDF form fields
- pdf/scripts/convert_pdf_to_images.py - Converts PDF pages to images
"""
def main():
print("This is an example script for system-time")
# TODO: Add actual script logic here
# This could be data processing, file conversion, API calls, etc.
if __name__ == "__main__":
main()
scripts/advanced-time.js 剧本/advanced-time.js
#!/usr/bin/env node
/**
* 系统时间获取工具 - 高级版本
* 提供时区转换、时间差计算等功能
*/
function formatDateTime(date, includeMilliseconds = false) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
let formatted = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
if (includeMilliseconds) {
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
formatted += `.${milliseconds}`;
}
return formatted;
}
function getTimeInTimezone(date, timezoneOffset) {
const utcTime = date.getTime() + (date.getTimezoneOffset() * 60000);
return new Date(utcTime + (timezoneOffset * 3600000));
}
function calculateTimeDifference(startTime, endTime) {
const diffMs = Math.abs(endTime - startTime);
const diffSeconds = Math.floor(diffMs / 1000);
const diffMinutes = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
return {
milliseconds: diffMs,
seconds: diffSeconds,
minutes: diffMinutes,
hours: diffHours,
days: diffDays
};
}
function main() {
const now = new Date();
console.log('=== 高级时间功能 ===');
console.log('1. 当前时间信息:');
console.log(` 本地时间: ${now}`);
console.log(` 时间戳: ${now.getTime()} 毫秒`);
console.log();
console.log('2. 时区转换:');
const beijingTime = getTimeInTimezone(now, 8); // GMT+8
const newYorkTime = getTimeInTimezone(now, -5); // GMT-5
const londonTime = getTimeInTimezone(now, 0); // GMT
console.log(` 北京时间: ${formatDateTime(beijingTime)}`);
console.log(` 纽约时间: ${formatDateTime(newYorkTime)}`);
console.log(` 伦敦时间: ${formatDateTime(londonTime)}`);
console.log();
console.log('3. 时间差计算示例:');
const oneHourAgo = new Date(now.getTime() - 3600000);
const diff = calculateTimeDifference(oneHourAgo, now);
console.log(` 与一小时前的时间差:`);
console.log(` 毫秒: ${diff.milliseconds}`);
console.log(` 分钟: ${diff.minutes}`);
console.log(` 小时: ${diff.hours}`);
console.log();
console.log('4. 当前日期组件:');
console.log(` 年: ${now.getFullYear()}`);
console.log(` 月: ${now.getMonth() + 1}`);
console.log(` 日: ${now.getDate()}`);
console.log(` 星期: ${['日', '一', '二', '三', '四', '五', '六'][now.getDay()]}`);
console.log(` 时: ${now.getHours()}`);
console.log(` 分: ${now.getMinutes()}`);
console.log(` 秒: ${now.getSeconds()}`);
console.log(` 毫秒: ${now.getMilliseconds()}`);
console.log('====================');
}
if (require.main === module) {
main();
}
// 导出函数供外部使用
module.exports = {
formatDateTime,
getTimeInTimezone,
calculateTimeDifference,
getCurrentTimeInfo: () => {
const now = new Date();
return {
date: now,
iso: now.toISOString(),
locale: now.toLocaleString(),
timestamp: now.getTime(),
timezone: now.toString().match(/\((.*)\)/)?.[1] || '未知',
components: {
year: now.getFullYear(),
month: now.getMonth() + 1,
day: now.getDate(),
weekday: now.getDay(),
hours: now.getHours(),
minutes: now.getMinutes(),
seconds: now.getSeconds(),
milliseconds: now.getMilliseconds()
}
};
}
};
scripts/get-time.js 脚本/get-time.js
#!/usr/bin/env node
/**
* 系统时间获取工具 - 基本版本
* 获取并显示当前系统时间
*/
function formatDateTime(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
}
function main() {
const now = new Date();
console.log('=== 系统时间信息 ===');
console.log(`完整时间: ${now}`);
console.log(`ISO格式: ${now.toISOString()}`);
console.log(`本地时间: ${now.toLocaleString()}`);
console.log(`格式化: ${formatDateTime(now)}`);
console.log(`时区: ${now.toString().match(/\((.*)\)/)?.[1] || '未知'}`);
console.log(`时间戳(毫秒): ${now.getTime()}`);
console.log(`时间戳(秒): ${Math.floor(now.getTime() / 1000)}`);
console.log('====================');
}
if (require.main === module) {
main();
}
// 导出函数供外部使用
module.exports = {
getTime: () => new Date(),
formatDateTime,
getTimeInSeconds: () => Math.floor(Date.now() / 1000),
getTimeInMilliseconds: () => Date.now()
};
scripts/performance-timer.js
剧本/performance-timer.js
#!/usr/bin/env node
/**
* 性能测量工具
* 用于测量代码执行时间的工具类
*/
class PerformanceTimer {
constructor() {
this.startTime = 0;
this.endTime = 0;
this.markers = new Map();
}
start() {
this.startTime = Date.now();
this.endTime = 0;
this.markers.clear();
return this;
}
mark(name) {
if (this.markers.has(name)) {
console.warn(`标记 "${name}" 已存在,将覆盖`);
}
this.markers.set(name, Date.now());
return this;
}
stop() {
this.endTime = Date.now();
return this.endTime - this.startTime;
}
getElapsed(fromStart = true) {
const current = Date.now();
if (fromStart && this.startTime === 0) {
throw new Error('计时器尚未启动');
}
return fromStart
? current - this.startTime
: (this.endTime === 0 ? 0 : this.endTime - this.startTime);
}
getMarkerTime(markerName) {
if (!this.markers.has(markerName)) {
throw new Error(`标记 "${markerName}" 不存在`);
}
const markerTime = this.markers.get(markerName);
return markerTime - this.startTime;
}
getMarkerDifference(marker1, marker2) {
const time1 = this.markers.get(marker1);
const time2 = this.markers.get(marker2);
if (!time1 || !time2) {
throw new Error(`标记 "${marker1}" 或 "${marker2}" 不存在`);
}
return Math.abs(time2 - time1);
}
formatTime(ms) {
if (ms < 1000) {
return `${ms} 毫秒`;
} else if (ms < 60000) {
const seconds = (ms / 1000).toFixed(2);
return `${seconds} 秒`;
} else {
const minutes = (ms / 60000).toFixed(2);
return `${minutes} 分钟`;
}
}
printSummary() {
if (this.endTime === 0 && this.startTime === 0) {
console.log('计时器未启动');
return;
}
const totalTime = this.getElapsed(false);
const currentElapsed = this.getElapsed();
console.log('=== 性能计时器总结 ===');
console.log(`总执行时间: ${this.formatTime(totalTime)}`);
console.log(`当前耗时: ${this.formatTime(currentElapsed)}`);
if (this.markers.size > 0) {
console.log('\n标记点时间:');
const markersArray = Array.from(this.markers.entries());
markersArray.forEach(([name, time], index) => {
const elapsed = time - this.startTime;
console.log(` ${index + 1}. ${name}: ${this.formatTime(elapsed)}`);
});
}
console.log('=====================');
return this;
}
}
// 使用示例函数
function exampleUsage() {
console.log('=== 性能计时器使用示例 ===\n');
// 示例1:基本用法
console.log('1. 基本计时器使用:');
const timer1 = new PerformanceTimer();
timer1.start();
// 模拟一些操作
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
const elapsed = timer1.stop();
console.log(` 计算结果: ${sum}`);
console.log(` 执行耗时: ${timer1.formatTime(elapsed)}`);
console.log();
// 示例2:标记点功能
console.log('2. 标记点功能:');
const timer2 = new PerformanceTimer();
timer2.start();
setTimeout(() => {
timer2.mark('异步操作开始');
setTimeout(() => {
timer2.mark('异步操作结束');
// 模拟一些同步操作
const array = new Array(10000).fill(0).map((_, i) => i);
timer2.mark('数组创建完成');
const filtered = array.filter(x => x % 2 === 0);
timer2.mark('数组过滤完成');
timer2.stop().printSummary();
console.log(`\n特定标记点之间的时间差:`);
const diff = timer2.getMarkerDifference('异步操作开始', '异步操作结束');
console.log(` 异步操作: ${timer2.formatTime(diff)}`);
}, 100);
}, 50);
setTimeout(() => {
console.log('\n3. 嵌套计时器:');
const parentTimer = new PerformanceTimer();
const childTimer = new PerformanceTimer();
parentTimer.start();
// 外层操作
childTimer.start();
let outerSum = 0;
for (let i = 0; i < 100000; i++) {
outerSum += Math.random();
}
const outerTime = childTimer.stop();
parentTimer.mark('外层循环完成');
// 内层操作
childTimer.start();
let innerSum = 0;
for (let i = 0; i < 1000000; i++) {
innerSum += Math.random();
}
const innerTime = childTimer.stop();
parentTimer.mark('内层循环完成');
parentTimer.stop().printSummary();
console.log(`\n 外层循环: ${parentTimer.formatTime(outerTime)}`);
console.log(` 内层循环: ${parentTimer.formatTime(innerTime)}`);
}, 300);
setTimeout(() => {
console.log('\n=== 示例结束 ===');
process.exit(0);
}, 400);
}
function main() {
if (process.argv.includes('--example')) {
exampleUsage();
} else if (process.argv.includes('--quick')) {
const timer = new PerformanceTimer();
timer.start();
// 快速测试
let result = 0;
for (let i = 0; i < 1000000; i++) {
result += i;
}
const elapsed = timer.stop();
console.log(`快速测试结果: ${result}`);
console.log(`执行时间: ${timer.formatTime(elapsed)}`);
} else {
console.log('性能计时器工具');
console.log('用法:');
console.log(' node performance-timer.js --example 显示使用示例');
console.log(' node performance-timer.js --quick 快速性能测试');
console.log('\n类定义已加载,可在代码中使用:');
console.log(' const timer = new PerformanceTimer();');
console.log(' timer.start();');
console.log(' // 你的代码');
console.log(' const elapsed = timer.stop();');
}
}
if (require.main === module) {
main();
}
module.exports = PerformanceTimer;
确实生成了多个代码。
5、调用刚刚生成的skill
获取当前系统时间

看样子是调到了刚生成的system-time这个skill了。
虽然已经通关,但是感觉挺费token的。听群友说,选择一个code能力好的大模型会更好一些。
(1 封私信) 使用OpenCode体验Agent Skills - 知乎
一、Windows OpenCode的尝试
前情回顾:
1、升级Ollama
张小白在笔记本电脑Windows环境部署了若干Ollama模型:

今天想部署下deepseek-v3.2。
但是这个模型,居然找不到32b以下的版本,而只有一个cloud版本:

按命令执行:
ollama run deepseek-v3.2:cloud

发现本地Ollama的程序版本需要升级。
于是去官网 Download Ollama on macOS 下载最新版安装盘升级


包有1.18G,耐心等待下载完毕。
执行安装:


2、部署deepseek-v3.2 (cloud版)
重新执行:
ollama run deepseek-v3.2:cloud

ollama list

3、在OpenCode中配置Ollama
虽然在Ollama模型清单中,但是其实是在访问云端的模型。(所以没有size)
既然这样,那么OpenCode能不能直接使用Ollama的模型呢?
我们试试。
打开cmd,切换到D:\
opencode

/connect

点击Ollama官网

登录后点击右上角图标,下拉菜单选择Settings

Add API Key

Generate API Key

返回OpenCode,复制粘贴这个Key。

回车确认
可以看到好多模型:



还是先选deepseek -v3.2的吧!

试试AI对话:

4、创建新Skill尝试
帮我创建一个可以准确获取 黄金价格的Skill。


选择2
在这里的体验跟上次使用硅基流动的DeepSeek V3.2版本有点区别。因为它居然在交互式问问题,而不是自动化的执行。


又停下来了。
我得问问它做完了吗。
你做完了吗?




张小白想参考“快速开始”操作,按照上面的方法操作一下试试:


npm start

好像不行,看来代码还是有语法错误的。
那么让OpenCode执行skill试试呢。
执行准确获取 黄金价格的Skill。


它在执行的过程中好像会自动修复代码。。。是一个好的AI程序员。。


好像执行得不太好。
一个主要的原因是LLM要执行的一些命令在Windows上跑不起来。比如bash之类的明明是Linux的命令。
看来这个Ollama Cloud的DeepSeek V3.2的服务确实跟 硅基流动的DeepSeek V3.2区别挺大的。感觉要做不下去了。
要不,换到WSL环境下再试试。
二、WSL Ubuntu 22.04 OpenCode+Ollama Cloud尝试
1、安装OpenCode
npm -v

node -v

打开

npm i -g opencode-ai

opencode

2、在OpenCode配置Ollama cloud LLM
/connect

仍然选择Ollama Cloud

输入API Key:

在模型列表中继续选择 deepSeek-v3.2(如果不行的话,考虑切换到kimi2.5)

对话尝试:

3、安装skill-creator技能
将上次的skill-creator 的skill复制到 ~/.config/opencode/skill目录下并解压:

4、创建新skill尝试
帮我创建一个可以准确获取 黄金价格的Skill,描述使用中文,脚本使用Node.js


在执行skill的过程中,系统会提示权限,点击Allow Always就可以了。
不过任务还是会中止。
你做完了吗?



比如说,又卡在这里了。
做完了吗?


看样子是做完了。
这个skill做完了吗?做完了就测试一下


获取实时的黄金价格


好像这个功能是模拟的。。。不是真实的实时金价。
在前面执行的过程中,出现了以下问题:

说明Ollama Cloud也有免费的调用次数限制。可能是因为这个原因,skill的代码并没有完全写好。
也许也只有花钱才能做完这个skill。

比如花20美金买Pro版,或者花100美金买Max版。



浙公网安备 33010602011771号