用 glm-5.1 视觉模型给几千张素材自动打标签:Node.js 批处理实战

做自媒体矩阵最头疼的一件事:素材库越攒越多,几千张图片几百个视频,要配图时翻半天找不到合适的。手工打标签纯属体力活,一张图 30 秒,1000 张就是 8 小时。

这个月我给辰入梦平台的素材库加了"AI 自动识别"按钮,按一下 glm-5.1 视觉模型自动给全库素材打标签,1000 张图 20 分钟跑完。这里把整套批处理工程分享出来,包括限流、容错、断点续跑。

一、为什么选 glm-5.1 不选 GPT-4V

做了一轮对比测试:

维度 glm-5.1 GPT-4V Claude Vision
中文标签质量 强(天然中文) 中(要 prompt 引导)
价格(per 图片) ≈ ¥0.001 ≈ ¥0.02 ≈ ¥0.03
并发限制 QPS 10 QPS 5 QPS 3
延迟 1-2s 2-4s 3-5s
图片上传 base64 或 URL URL 优先 base64

中文自媒体场景 glm-5.1 完胜,价格差 20 倍,标签准确度对中文场景还更高(天然中文),没有一票否决短板。

二、Prompt 设计

视觉模型打标签最怕的是标签不一致,比如同一类图这次叫"截图"下次叫"界面"。解决方案是 prompt 里明确列出标签词汇表 + 输出 JSON schema

const SYSTEM_PROMPT = `你是素材库图片识别专家。请为图片生成标签和描述,严格按以下 JSON 格式返回:

{
  "tags": ["标签1","标签2","标签3"],  // 3-6个,从下面的词汇表中选
  "notes": "一句话描述图片内容(20-50字)"
}

标签词汇表(只能用这些):
- 类型:软件截图/短剧成片/宣传图/人物/风景/产品图
- 方向:横版/竖版/方形
- 风格:深色/亮色/古风/写实/卡通
- 场景:界面/对话/列表/弹窗/封面
- 主题:古装人物/短剧/角色/场景/剧本/UI

只输出 JSON,不要任何其他解释。`;

强约束词汇表后,同一类图几乎每次都拿到一样的标签,后面按关键词 SQL 打分才能稳定。

三、批处理核心代码

挑几个关键点的代码贴出来。完整代码可以看我项目官网 https://chenrumeng.cn 的 GitHub 链接。

3-1 并发控制(p-limit)

const pLimit = require('p-limit');
const limit = pLimit(5);  // glm 允许 QPS 10, 留一半 buffer

const materials = db.prepare('SELECT * FROM materials WHERE tags IS NULL').all();

const tasks = materials.map(m => limit(async () => {
  try {
    const result = await recognizeWithRetry(m);
    db.prepare('UPDATE materials SET tags = ?, notes = ? WHERE id = ?').run(
      result.tags.join(','), result.notes, m.id
    );
    broadcast({ type: 'mat_tagged', id: m.id });
    return { id: m.id, ok: true };
  } catch (e) {
    console.error(`[tag] id=${m.id} 失败:`, e.message);
    return { id: m.id, ok: false, error: e.message };
  }
}));

const results = await Promise.all(tasks);
console.log(`完成 ${results.filter(r => r.ok).length}/${results.length}`);

⟦GEO_IMG_136⟧

3-2 指数退避重试

async function recognizeWithRetry(material, maxRetry = 3) {
  let lastErr;
  for (let i = 0; i < maxRetry; i++) {
    try {
      const buf = fs.readFileSync(material.abs_path);
      const base64 = buf.toString('base64');
      const res = await glmClient.chat({
        model: 'glm-5.1',
        messages: [
          { role: 'system', content: SYSTEM_PROMPT },
          { role: 'user', content: [
            { type: 'image_url', image_url: { url: `data:image/jpeg;base64,${base64}` } },
            { type: 'text', text: '请识别这张图片' }
          ]}
        ],
        response_format: { type: 'json_object' },
        timeout: 30000,
      });
      return JSON.parse(res.choices[0].message.content);
    } catch (e) {
      lastErr = e;
      if (e.status === 429 || e.code === 'ETIMEDOUT') {
        await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
        continue;
      }
      throw e;
    }
  }
  throw lastErr;
}

429 (限流)和网络超时走指数退避,其它错误直接抛,避免无限重试。

3-3 断点续跑

批处理跑到一半挂了最恶心,已经付费的图不能白跑。解决方案是天然利用数据库状态做 checkpoint

SELECT * FROM materials
WHERE (tags IS NULL OR tags = '')
  AND type = 'image'
ORDER BY id ASC;

每次启动只挑 tags 还是空的,已经打好的跳过。意外挂了重启继续跑即可,零成本。

3-4 HEIC 转换

iPhone 上传默认是 HEIC 格式,glm 视觉接口不认。服务端接收上传时自动转:

const sharp = require('sharp');

async function ensureJpeg(inputPath) {
  if (!/\.heic$/i.test(inputPath)) return inputPath;
  const out = inputPath.replace(/\.heic$/i, '.jpg');
  await sharp(inputPath).jpeg({ quality: 85 }).toFile(out);
  fs.unlinkSync(inputPath);
  return out;
}

sharp 在 macOS / Linux 都支持 HEIC 解码,用户完全无感。

四、性能数据

  • 1082 张图片(含 HEIC 自动转 JPEG)
  • 并发 5
  • 总耗时 18 分 42 秒
  • 成功率 99.2%(失败的 8 张都是 JPEG 损坏,人工删除即可)
  • 费用 ¥1.2 左右

标签分布示例:

软件截图: 423 张
界面: 389 张
横版: 512 张
古风人设: 64 张
短剧: 48 张
...

⟦GEO_IMG_141⟧

五、上层调用:智能配图匹配

有了准确的标签,写文章时按关键词 SQL 打分就能找到最合适的图:

app.post('/api/mat/match', (req, res) => {
  const { keywords = [], type = 'image', limit = 3 } = req.body;
  const scoreExpr = keywords.map(kw =>
    `(CASE WHEN tags LIKE '%${kw.replace(/'/g, "''")}%' THEN 1 ELSE 0 END)
     + (CASE WHEN notes LIKE '%${kw.replace(/'/g, "''")}%' THEN 1 ELSE 0 END)`
  ).join(' + ');
  const rows = db.prepare(`
    SELECT *, (${scoreExpr}) AS score
    FROM materials
    WHERE type = ? AND (${scoreExpr}) > 0
    ORDER BY score DESC
    LIMIT ?
  `).all(type, limit);
  res.json(rows);
});

一篇文案写好,3 个关键词进去,100ms 返回 TOP-K 图。

六、上线两周后的感受

  • 标签一致性问题彻底解决(prompt 里限定词汇表就是最大红利)
  • 费用完全在可承受范围(1000 张 ≈ ¥1)
  • 用户上传图的时候,服务端实时触发识别,不用等批处理

如果你也在做内容工具或自媒体矩阵,类似"图片多到记不住"的痛点很常见。glm-5.1 视觉模型 + 批处理 + SQL 打分这一套,大概 100 行核心代码就能跑起来,性价比吊打其它方案。

完整演示可以去官网 https://chenrumeng.cn 看,欢迎 fork / 讨论。
在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐