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

张开发
2026/4/5 3:06:59 15 分钟阅读

分享文章

OpenClaw技能开发入门:为Qwen3.5-9B定制图片分类插件
OpenClaw技能开发入门为Qwen3.5-9B定制图片分类插件1. 为什么需要开发图片分类技能上周整理手机相册时我对着3000多张杂乱无章的照片头疼不已——旅行风景、工作截图、宠物照片全都混在一起。手动分类不仅耗时费力还经常因为主观判断不一致导致重复劳动。这让我萌生了一个想法能否用OpenClawQwen3.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-4bit2.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 --templatebasic-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.jsmodule.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.jsconst 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.js6. 部署与使用6.1 安装到OpenClaw在技能目录执行clawhub pack clawhub install ./photo-classifier-0.1.0.claw6.2 通过对话调用启动OpenClaw后可以在聊天窗口输入帮我分类照片~/Pictures/未整理6.3 性能优化建议在实际使用中发现两个优化点批量处理修改为每次请求分析多张图片减少API调用次数缓存机制对已分类图片记录哈希值避免重复处理优化后的模型请求示例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星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

更多文章