当前位置: 首页 > news >正文

OpenClaw技能开发入门:为Qwen3.5-9B定制图片分类插件

OpenClaw技能开发入门:为Qwen3.5-9B定制图片分类插件

1. 为什么需要开发图片分类技能

上周整理手机相册时,我对着3000多张杂乱无章的照片头疼不已——旅行风景、工作截图、宠物照片全都混在一起。手动分类不仅耗时费力,还经常因为主观判断不一致导致重复劳动。这让我萌生了一个想法:能否用OpenClaw+Qwen3.5-9B多模态能力实现自动化图片分类?

经过三天摸索,我成功开发出一个能理解图片内容并按主题自动归档的技能。这个过程中踩过的坑和最终解决方案,正是本文要分享的核心内容。相比通用AI助手,定制化技能的优势在于:

  • 精准适配个人需求:可以按照自己的分类体系(如"工作/生活/宠物")来定义规则
  • 保护隐私数据:所有处理都在本地完成,避免上传照片到第三方服务
  • 持续迭代优化:可以根据实际效果不断调整分类逻辑

2. 开发环境准备

2.1 基础工具链检查

在开始前,请确保已具备以下环境(以macOS为例):

# 检查Node.js版本(需要v18+) node -v # 检查OpenClaw CLI openclaw --version # 安装clawhub脚手架 npm install -g clawhub

如果尚未部署Qwen3.5-9B模型,可以使用星图平台的一键镜像:

# 快速启动模型服务(假设使用平台镜像) docker run -p 5000:5000 qwen3.5-9b-awq-4bit

2.2 模型能力验证

开发前建议先用curl测试模型的多模态能力:

curl -X POST http://localhost:5000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen-vl", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "描述这张图片的主要内容"}, {"type": "image_url", "image_url": {"url": "file:///Users/me/photo.jpg"}} ] } ] }'

正常响应应包含对图片内容的文字描述,这是后续分类的基础。

3. 创建技能脚手架

3.1 初始化项目

使用clawhub创建技能骨架:

clawhub init photo-classifier --template=basic-skill cd photo-classifier

生成的核心文件结构如下:

. ├── manifest.json # 技能元数据 ├── package.json # Node.js依赖 ├── src │ ├── index.js # 主逻辑 │ └── utils.js # 工具函数 └── test # 测试用例

3.2 配置技能元数据

编辑manifest.json定义技能能力:

{ "name": "photo-classifier", "version": "0.1.0", "description": "基于Qwen3.5的智能图片分类器", "entry": "src/index.js", "triggers": { "classifyPhotos": { "description": "对指定目录图片进行分类", "parameters": { "folderPath": { "type": "string", "description": "待分类图片目录路径" } } } }, "dependencies": { "models": ["qwen-vl"] } }

关键配置说明:

  • triggers定义了技能调用入口
  • dependencies声明需要Qwen多模态模型支持
  • parameters定义了用户需要提供的参数

4. 核心逻辑开发

4.1 图片处理模块

src/utils.js中添加图片预处理函数:

const fs = require('fs'); const path = require('path'); async function scanImageFolder(folderPath) { const files = await fs.promises.readdir(folderPath); return files .filter(file => ['.jpg', '.png'].includes(path.extname(file).toLowerCase())) .map(file => path.join(folderPath, file)); } function createCategoryFolders(rootPath, categories) { categories.forEach(cat => { const dir = path.join(rootPath, cat); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } }); }

4.2 模型交互逻辑

src/index.js中实现分类主逻辑:

const axios = require('axios'); const { scanImageFolder, createCategoryFolders } = require('./utils'); const MODEL_API = 'http://localhost:5000/v1/chat/completions'; async function analyzeImage(imagePath) { const response = await axios.post(MODEL_API, { model: "qwen-vl", messages: [{ role: "user", content: [ { type: "text", text: "用不超过3个关键词描述图片内容,格式为: 人物|物体|场景" }, { type: "image_url", image_url: { url: `file://${imagePath}` } } ] }] }); return response.data.choices[0].message.content; } function determineCategory(analysisResult) { const [person, object, scene] = analysisResult.split('|').map(s => s.trim()); // 自定义分类规则 if (person.includes('同事') || object.includes('截图')) return '工作'; if (person.includes('猫') || object.includes('宠物')) return '宠物'; if (scene.includes('海滩') || scene.includes('山')) return '旅行'; return '其他'; }

5. 技能集成与测试

5.1 主函数实现

继续完善src/index.js

module.exports = async function (context) { const { folderPath } = context.parameters; const categories = ['工作', '旅行', '宠物', '其他']; try { createCategoryFolders(folderPath, categories); const imageFiles = await scanImageFolder(folderPath); for (const file of imageFiles) { const analysis = await analyzeImage(file); const category = determineCategory(analysis); const destPath = path.join( path.dirname(file), category, path.basename(file) ); fs.renameSync(file, destPath); context.log(`已分类: ${file} -> ${category}`); } return { success: true, classified: imageFiles.length }; } catch (error) { context.logger.error('分类失败:', error); throw new Error('图片分类处理失败'); } };

5.2 本地测试方法

创建测试脚本test/test.js

const skill = require('../src/index'); (async () => { const mockContext = { parameters: { folderPath: './test-photos' }, log: console.log, logger: { error: console.error } }; await skill(mockContext); })();

放置测试图片到test-photos目录后运行:

node test/test.js

6. 部署与使用

6.1 安装到OpenClaw

在技能目录执行:

clawhub pack clawhub install ./photo-classifier-0.1.0.claw

6.2 通过对话调用

启动OpenClaw后,可以在聊天窗口输入:

帮我分类照片:~/Pictures/未整理

6.3 性能优化建议

在实际使用中发现两个优化点:

  1. 批量处理:修改为每次请求分析多张图片,减少API调用次数
  2. 缓存机制:对已分类图片记录哈希值,避免重复处理

优化后的模型请求示例:

async function analyzeImagesBatch(imagePaths) { const messages = imagePaths.map(path => ({ role: "user", content: [ { type: "text", text: "批量分析:用关键词描述每张图片" }, { type: "image_url", image_url: { url: `file://${path}` } } ] })); // 实际实现需要模型支持批量处理 const response = await axios.post(MODEL_API, { model: "qwen-vl", messages }); return response.data; }

7. 开发心得与注意事项

通过这次开发,我总结了几个关键经验:

模型提示词设计:最初使用"描述这张图片"的简单提示,导致返回结果格式不一致。改为严格指定"关键词1|关键词2|关键词3"格式后,解析成功率显著提升。

错误处理:要特别注意模型可能返回非预期内容的情况。我在determineCategory函数中添加了默认分类和格式校验:

function safeSplit(str) { try { const parts = str.split('|'); return parts.length === 3 ? parts : ['','','']; } catch { return ['','','']; } }

权限问题:在Windows开发时遇到文件操作权限错误,需要通过openclaw.config.json显式声明需要的权限:

{ "permissions": { "filesystem": ["read", "write"] } }

这个技能的开发过程让我深刻体会到,好的AI应用不仅需要强大的模型,更需要细致的工程化设计。现在我的相册终于恢复了整洁,而开发过程中积累的经验,也为后续开发更复杂的OpenClaw技能打下了基础。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

http://www.jsqmd.com/news/589603/

相关文章:

  • OpenClaw跨平台控制:千问3.5-35B-A3B-FP8任务手机端触发方案
  • 从CVE-2025-29927看Next.js中间件递归校验机制的攻防博弈
  • STM32F103C8T6流水灯实战:从寄存器配置到波形分析(C与汇编双版本)
  • LIS(最长上升子序列)超全解析
  • OpenClaw浏览器自动化:Qwen3-32B镜像操控Chrome实战
  • 一文详解如何使用PHP进行正则表达式匹配
  • BCompare不止于代码:手把手教你用它做合同定稿、论文修订的文档对比神器
  • 学术海报自动生成:OpenClaw+Phi-3-vision科研工作流实践
  • 2026年沈阳正规的汽车贴膜实体店有哪些,汽车膜/玻璃膜/汽车贴膜/沈北贴膜/太阳膜/贴车衣,汽车贴膜专业店联系方式 - 品牌推荐师
  • 资源监控方案:OpenClaw+Qwen3-14B的GPU显存预警系统
  • OpenClaw+Phi-3-mini-128k-instruct个人知识库:自动整理收藏网页
  • OpenClaw+Qwen3.5-9B低成本运营:个人自媒体内容自动化生产
  • 从BERT到BERT4Rec:为什么双向建模在推荐系统中如此重要?
  • Wav2Vec 2.0:从海量无标签语音到精准识别的自监督学习之路
  • 2026年主播推荐手机补光灯厂家推荐与选型指南 - 品牌宣传支持者
  • MG811SpaceData:嵌入式端CO₂传感器四维建模与多气体解耦框架
  • 从零开始搭建FPGA开发环境:EP4CE22F17C8+WM8731音频处理实战指南
  • 从智能音箱到医疗设备:RC正弦波振荡器的10个意想不到的应用场景
  • 手把手教你用C语言实现Modbus RTU从站:从代码解析到实战调试(附完整工程)
  • OpenClaw知识管理:Qwen3.5-9B构建个人Wiki与智能问答
  • OpenClaw研究助手:千问3.5-9B驱动的文献综述自动化
  • OpenClaw植物养护仪:Qwen3-14b_int4_awq分析的传感器数据与照料建议
  • 【模电实战】—— 从纹波到稳定:整流滤波电路的工程设计与选型指南
  • Supabase注册与新增用户全解析:5个关键区别及适用场景指南
  • 数据库安全自查清单:你的Redis/MongoDB真的防住注入攻击了吗?
  • 别再死记硬背了!用这10个XSS-Labs关卡,手把手教你理解前端过滤与绕过逻辑
  • PyTorch与torchvision版本兼容性全解析:从安装到升级的避坑指南
  • 大疆照片的‘测绘模式’和‘畸变矫正’到底怎么用?一个案例讲清测绘项目中的元数据配置要点
  • OpenClaw+千问3.5-9B:自动化简历生成与优化
  • 避开ESP32音频开发的坑:新旧i2s驱动混用导致的CONFLICT错误排查与修复