[Vibe Coding][DeepSeek]用大模型自动为博客生成分类与标签V3
V2 的四阶段流水线运行了几个月,分类体系依旧达不到理想状态:LLM 生成的中性命名缺少个人味道,类别粒度也和博客定位对不齐。V3 把 LLM 的职责从「生成体系」收缩到「从固定词表选标签」,类别分配改成零 API 的机械规则,用 taxonomy.json 固化 21 个类别和 239 个标签。本文记录这次推倒重来的完整过程:两级层级设计、四轮迁移 424 篇文章和踩到的几个坑。
- [Vibe Coding][Github Actions/Pages][Hexo/NexT]从零构建博客网站
- [Vibe Coding][Gitea Actions/Nginx][Hexo/NexT]从零构建博客网站2
[Vibe Coding][DeepSeek]用大模型自动为博客生成分类与标签[Vibe Coding][DeepSeek]用大模型自动为博客生成分类与标签V2- [Vibe Coding][DeepSeek]用大模型自动为博客生成分类与标签V3
为什么还要重写
V2 的四阶段流水线(stage1_extract_meta.py 到 stage4)从 2025 年底运行了几个月。体系能用,但几个问题越来越明显:
- 分类由 LLM 半自动归纳,命名和粒度不受控制,实际导航效果一般
- 每篇新文章理论上要走一遍完整流水线,日常维护成本不低
.ontology/缓存和四个 stage 的边界只存在于脚本里,体系演进没有单一入口- LLM 生成的命名太中性,缺少个人博客的味道:同样一套分类换个博客也能用,体现不出这个博客的技术定位
2026 年 9 月决定推倒重来。这次的思路和 V2 相反:体系完全由人工设计,LLM 只负责最机械的一步——从固定词表里选标签。
固定词表与机械分配
新方案的核心是 blog-taxonomy/taxonomy.json,唯一的体系事实源:
1 | { |
两个配套脚本:
assign_post.py:新文章日常工具。类别按文章所在文件夹机械映射中文名(有parent时输出两级),零 API 成本;标签先尝试把现有标签映射到词表,能映射出 3 个以上就直接采用,不够才调用 LLM 从词表选题refresh_taxonomy.py:年度体检。扫描文件夹和标签使用率,输出缺失文件夹、低频标签和 LLM 新词候选,结果写taxonomy.review.json,绝不自动修改词表
1 | # 处理指定文章(--dry-run 只预览不写回) |
词表平时冻结。新文章只进词表选标签,年度体检后人工确认才动词表。这条规则保证体系不会被单篇文章悄悄改变。
两级层级与文件夹对应
类别支持两级路径,靠 parent 字段表达:
- 有
parent的类别写入categories: [父级, 子级] - 父级是虚拟类(
folder: null),不允许直挂文章
最终体系是 15 个顶级类,其中 5 个两级父类:
| 父类 | 子类 |
|---|---|
| 计算机视觉 | 图像分类 46 / 图像检索 27 / 目标检测 29 / 视觉基础 14 / 视觉理解 10 / 视频理解与压缩 10 |
| 深度学习 | 优化与调度 10 / 训练技巧 14 / 正则化与初始化 6 / 卷积与实现 11 / CNN 理解与可视化 6 |
| 机器学习 | 分类器 14 / 神经网络 7 / 无监督与降维 2 / 泛化与正则化 2 |
| 模型压缩 | 知识蒸馏 7 / 模型剪枝 7 |
| Z-归档 | Jenkins 24 / OKR 7 |
文件夹名与类别名一一对应:cv-image-classification、dl-optimization、ml-classifiers。文件夹就是类别的英文直译,assign_post.py 的类别映射因此完全机械,不依赖任何语义理解。
四轮人工重构记录
迁移分四轮完成,每轮先分析再动手,全部脚本化重写 front-matter:
| 轮次 | 动作 | 范围 |
|---|---|---|
| 第一轮 | 类别更名(部署→工程实践、Agent→LLM 应用、目标分类→图像分类),Jenkins/OKR 归档到 Z-归档 | 109 篇 |
| 第二轮 | 计算机视觉收拢 6 个子类,模型压缩两级化,vision 拆成视觉基础/视觉理解 | 139 篇 |
| 第三轮 | 深度学习拆 5 子类、机器学习拆 4 子类,12 篇检测内容归位目标检测 | 84 篇 |
| 第四轮 | 论文汇总帖补录 3 篇论文,修复 6 篇综述帖的失效分类链接 | 7 篇 |
几个决策依据:
- 拆类门槛 15~20 篇:独立子类至少这个体量,边界再清晰也不拆
- 语义平行:同级类别不能是父子概念,「计算机视觉」和「图像分类」并列就是反例
- 术语以 CV 惯例为准:整图分类任务用「图像分类」,标签用
Image Classification
每轮迁移前先备份(.backup_taxonomy2/3/4),改写脚本对每篇文章断言旧值匹配才替换,保证没有误伤。
几个工程细节
分类页排序。NexT 分类页调用 list_categories(),默认按类别名排序,中文按 Unicode 码点比较。想让归档垫底,拼音 z 前缀没用(字母码点小于汉字),全角 Z(U+FF3A)的码点大于所有常用汉字,所以父类名是「Z-归档」。
改名不破坏 URL。hexo-abbrlink 源码里 abbrlink 由 title 计算(crc32),已有值且 force: false 时不会重算。文件夹随便改名、文章随便移动,只要不动 title 和 abbrlink,URL 完全稳定。顺带发现 _config.yml 里 abbrlink 的注释写错了:注释说基于文件名和创建时间,实际源码是 crc32.str(data.title)。
DeepSeek 调用。base_url 是 https://api.deepseek.com(没有 /v1),模型 deepseek-v4-pro。推理模型做机械任务要加 extra_body={"thinking": {"type": "disabled"}},否则可能返回空回复。
分类页 URL 变化。类别改名后旧分类页直接 404(比如 /categories/目标分类/),没有做重定向。分类页是次要入口,不值得为此维护 alias 插件。
小结
三次迭代,LLM 的职责一直在收缩:
- V1:LLM 端到端生成体系
- V2:人工定骨架,LLM 做分配
- V3:人工定体系,LLM 只从词表选标签
这个方向是对的。分类体系是作者意图的表达:博客定位、命名习惯、粒度偏好,这些决策不该外包给 LLM;标签选择才是语义识别问题,LLM 的价值恰好在这里。这次重构四轮迁移全站 424 篇文章,机械规则零 API 成本;对比 V1 时期上千次调用花不到 20 元,V3 把日常成本降到了接近零。
当然,这套方案成立的前提是词表本身设计得足够好。词表不好,机械规则只是把错误固化得更快,这正是 refresh_taxonomy.py 年度体检存在的意义。