---
id: local-llm-summary
title: 用本地模型给旧文章补摘要和标签
date: 2025-10-08
updated: 2025-10-09
category: 折腾
tags: 本地模型, 自动化
minutes: 13
---

写了三年博客，早期那些文章没有摘要、没有标签，列表页上只有标题。手工补三十篇太烦，我用本地模型跑了一遍。

## 流水线

```
posts/*.md
   │  1. 读 frontmatter，跳过已有 summary 的
   ▼
[拼接提示词] ──► 本地模型（Ollama / llama.cpp）
   │  2. 要求输出严格 JSON
   ▼
校验 JSON ──► 写回 frontmatter
   │  3. 失败重试一次，两次失败就跳过并记日志
   ▼
生成报告：成功 N 篇 / 跳过 M 篇 / 失败 K 篇
```

关键是**要求模型输出 JSON**，而不是"给我一段摘要"。自然语言输出没法可靠地写回文件。

## 提示词

```
你是技术文档编辑。阅读下面的文章，输出严格的 JSON，不要任何解释文字：

{
  "summary": "60-90 字的中文摘要，说明这篇解决了什么问题，不要用'本文介绍了'开头",
  "tags": ["3-5 个标签，每个 2-6 个字，优先用文章里出现的技术名词"]
}

文章标题：{title}
正文：
{body}
```

三个细节决定成败：

- **字数写死**（60–90 字）。不写范围它会给你 20 字或者 300 字。
- **禁掉套话**。"本文介绍了"这类开头百分之百会出现，明确禁掉才有信息量。
- **标签要求"文章里出现过的"**。否则模型会编出文章里根本没提的技术。

## 校验

拿到 JSON 之后我做了四道检查，任何一道不过就跳过：

```
1. json.loads 能解析
2. summary 长度在 40–140 之间
3. tags 是 3–5 个字符串，长度 2–6
4. summary 里不包含原文前 20 个字（防它偷懒直接抄第一段）
```

第四条最有用。模型很容易把首段原样搬过来当摘要，那种摘要在列表页上毫无意义。

## 结果

30 篇里成功 26 篇，跳过 3 篇（原文本身没有 frontmatter，是更早期的手写 HTML），失败 1 篇（模型返回被截断）。

人工过一遍大概花了 20 分钟，改了 4 篇的摘要措辞。这个比例可以接受——**机器负责补齐结构，人负责把关措辞**。

## 值得自动化吗

如果只有 5 篇，不值得。写脚本 + 调提示词的时间比手工写完还长。

但这件事的真正价值不在这一次：脚本留在仓库里，以后每写一篇新文章，跑一下就能生成候选摘要和标签，你只判断"行不行"，不用"从零想"。这个边际成本才是划算的地方。

:::坑
本地小模型（7B 以下）在"严格输出 JSON"这件事上不稳，尤其输入长的时候会截断。要么换大一点的模型，要么把正文先截到 4000 字以内——技术文章的摘要用不到全文。
:::
