[Vibing Coding][DeepSeek]用大模型自动为博客生成分类与标签

断断续续写了几百篇博客文章了,总是想着怎么样可以更好的整理和总结这些文章。最近借着重构Hexo/NexT的机会,想着可以利用大模型来帮助我为博客自动生成分类和标签。

实现概述

整个流程分为两个阶段:

  • 第一阶段:基于已有博客文章的内容、标题及现有 front-matter(如 categories / tags),利用大模型(DeepSeek自动生成一套结构清晰、语义一致的预定义分类体系(categories.yaml)和标准化标签词表(tag_vocabulary.yaml
  • 第二阶段:使用这套“知识本体”作为约束,为所有文章(包括历史文章和未来新文)重新分配或首次打标,确保整个博客的元数据统一、可维护、可扩展。

这种方式的好处

  1. 避免人工主观偏差:传统手动打标容易因时间、情绪或认知变化导致不一致(比如同一篇 Docker 教程有时打 “容器”,有时打 “DevOps”)。
  2. 结构先行,治理后置:先由 LLM 归纳出合理的分类逻辑(如“教程 > 工具使用”而非“深度学习”),再用于分配,保证体系合理性。
  3. 支持持续演进:当发现新类别/标签时,系统会标记出来供人工审核,形成“AI 提议 + 人审定”的闭环。
  4. 工程化 & 可复现:两阶段解耦,脚本化运行,适合集成到 CI/CD 或写作流程中。
  5. 节省长期维护成本:初期投入一次自动化构建,后续新增文章只需一键打标,无需反复思考“该归到哪”。

具体代码实现

代码位于仓库:zjykzj/zjykzj.github.io

第一阶段:构建博客的“知识本体”

这一阶段由 generate_ontology.py 脚本完成,目标是从混沌中提炼秩序。

功能拆分

  • 任务 A:分析全部文章,归纳出标准化的分类路径(category hierarchy),聚焦文章类型/目的(如“教程 > 工具使用”、“复盘 > 项目总结”),而非技术主题。
  • 任务 B:提取所有具体技术实体(如 PyTorch、Git、2024),合并别名,生成去重的标准标签词表。

功能实现

脚本会遍历 blog/source/_posts 下的所有 Markdown 文件,解析 front-matter 和正文内容。通过精心设计的 Prompt,引导 DeepSeek 模型输出符合要求的 YAML 结构:

  • 分类体系强调“文体”而非“主题”,例如 ["年度总结"]["教程", "工具使用"]
  • 标签体系则聚焦具体技术名词,并自动合并别名(如 dockerDockerDocker Enginestandard_tag: Docker);
  • 为应对长文本,标签生成采用分批处理(默认每批 50 篇);
  • 内置强健容错机制:LLM 调用失败自动重试,YAML 解析失败会构造纠错 prompt 并再次尝试;
  • 所有失败批次会保存 .raw 调试文件,便于人工介入。

功能使用

1
python generate_ontology.py

第二阶段:智能分配分类与标签

在第一阶段成功构建出结构清晰的分类体系(categories.yaml)和标准化标签词表(tag_vocabulary.yaml)后,第二阶段的目标就变得非常明确:将这套“知识本体”落地到每一篇具体文章中。这一步由脚本 assign_categories_tags.py 完成,其核心逻辑是——在预定义的选项集合内,为每篇文章选择最贴切的元数据。

功能拆分

  • 批量处理模式:遍历整个 _posts 目录,自动为所有文章分配分类和标签;
  • 单文件精细模式:支持对特定长文(如年度总结、技术综述)进行全文分析,并放宽输出数量限制;
  • 封闭集约束匹配:LLM 的输出严格限定在第一阶段生成的 YAML 体系内,避免自由发挥导致的不一致;
  • 新项检测与报告:若模型建议了未在预定义体系中的类别或标签,系统会记录并提示人工审核,但不会自动写入;
  • 安全写回机制:仅更新 front-matter 中的 categoriestags 字段,其余内容保持不变。

功能实现

脚本启动时首先加载两个 YAML 文件,解析出所有合法的分类路径(如 ["教程", "工具使用"])和标准标签(如 Docker, Git)。随后,对每篇文章执行以下流程:

  1. 内容提取:读取 Markdown 文件的标题和正文(默认截取前 3000 字符,可通过参数调整);
  2. Prompt 构造:将文章内容与完整的可选分类/标签列表一并输入给 DeepSeek 模型。关键设计在于:显式列出所有合法选项,引导模型做“多选题”而非“填空题”;
  3. 模型调用:使用 DeepSeek Reasoner 模型生成 YAML 格式的响应,包含推荐的 categories(最多 3 项)和 tags(最多 8 项);
  4. 结果解析与校验:检查返回值是否在预定义集合中。若出现新项,将其加入“待审列表”;否则,规范化格式(如将字符串转为嵌套列表);
  5. 写回文件:使用 ruamel.yaml 精确更新 front-matter,保留原有注释和字段顺序。

功能使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 批量处理(默认配置:最多 3 个分类、8 个标签,读取前 3000 字符)
python assign_categories_tags.py ./source/_posts

# 2. 单独处理某篇长文(如年度总结),使用全文并放宽限制
python assign_categories_tags.py \
--single-file ./source/_posts/2024-year-in-review.md \
--max-categories 5 \
--max-tags 15 \
--max-content-chars -1

# 3. 批量处理但略微放宽数量限制(谨慎使用,避免体系污染)
python assign_categories_tags.py ./source/_posts \
--max-categories 4 \
--max-tags 10

# 4. 自定义输入长度(例如只看前 5000 字符)
python assign_categories_tags.py ./source/_posts --max-content-chars 5000

注意:
- 必须设置环境变量 OPENAI_API_KEY 或在代码中配置 DeepSeek API 密钥;
- 预定义体系文件路径可通过 --categories 和 --tags 参数指定。

小结

实际上我最开始想的是完全自动化的调用大模型来为每篇文章生成类别和标签,甚至于完全使用Vibe Coding的方式来实现整个工程。但是生成的工程很难满足自己的需求和预期,我意识到还是需要人工参与在其中,只需要让大模型在某些关键的步骤上面执行,这种搭配可以更好的实现理想的功能。

另外,关于大模型调用的费用完全不用担心,这几天我尝试了上千次针对博客文章的调用,到现在还用不到20元。