最近,我完成了一次 WordPress 历史文章摘要补全。
这次任务最终处理了 42 篇中文历史文章,并同步补全了对应英文文章的摘要。最终结果为:
- 已完成:42/42
- 待处理:0
- 异常状态:0
执行过程中出现过 GLM 请求超时、WordPress REST API 连接中断、Polylang SSH 检查超时,以及 SlyTranslate 返回 HTTP 500 等问题,但都通过状态记录、断点恢复和只读核验机制安全处理,没有重复生成摘要,也没有误改文章关系。
这次实践让我更加确定:批量修改 WordPress 历史内容时,真正重要的并不是“能否调用大模型生成一段文字”,而是能否建立一套可审计、可恢复、可验证,并且不会误伤现有内容的生产流程。
一、为什么要补全历史文章摘要
我的 WordPress 网站已经积累了大量技术文章。
其中一部分早期文章没有填写摘要。中文文章的摘要为空,对应的英文翻译文章摘要通常也是空的。
这会带来几个问题:
- 文章列表页只能临时截取正文作为摘要。
- SEO 插件可能无法直接使用稳定的文章摘要。
- 英文站文章缺少可控的英文简介。
- 后续进行文章推荐、内容聚合和结构化输出时,摘要字段无法直接使用。
- 如果未来继续进行批量内容维护,空摘要会成为长期遗留问题。
最简单的处理方式,是遍历所有空摘要文章,调用大模型生成摘要,然后写入数据库。
但这种方案风险很高。
网站中并不是所有空摘要文章都适合直接修改。有些文章可能没有英文翻译,有些文章的中英文关系可能已经异常,还有些文章可能使用特殊 Gutenberg 区块、Code Block Pro 代码块或其他复杂内容结构。
因此,这次没有直接从“批量写入”开始,而是先进行了完整的只读盘点。
二、先建立固定候选清单
第一阶段只读取生产环境数据,不进行任何写入。
候选文章必须同时满足以下条件:
- 中文文章已经发布;
- 中文摘要为空;
- 使用 Gutenberg 编辑器;
- 正文包含 Code Block Pro 等需要特别保护的结构;
- 存在对应的英文翻译文章;
- 英文文章已经发布;
- 英文摘要为空;
- Polylang 中英文关系正确;
- 中英文文章 ID 明确;
- 文章当前状态、正文和标题可以计算固定哈希。
经过筛选后,得到了一份固定候选清单,共 42 组中英文文章。
另外还有 46 篇已经存在中文摘要的文章。这些文章被明确排除在候选清单之外,后续脚本不会修改它们。
固定候选清单的意义在于:正式执行时不再重新扫描整个 WordPress 数据库,而是只允许处理审计阶段确认过的文章 ID。
即使网站后续新增了文章,或者其他文章状态发生变化,也不会被自动纳入本次批处理。
三、中文摘要与英文摘要采用不同处理方式
这次流程并不是直接让一个模型同时生成中英文摘要。
实际处理分为两个阶段。
1. 使用 GLM 4.7 生成中文摘要
GLM 4.7 只负责根据中文文章标题和正文生成中文摘要。
摘要要求包括:
- 只返回一段纯文本;
- 不使用 Markdown;
- 不使用项目符号;
- 不添加“本文介绍了”之外的额外说明;
- 长度控制在 160~240 个中文字符左右;
- 最低不能少于 80 个字符;
- 最高不能超过 300 个字符;
- 不包含代码、命令或 Gutenberg 区块标记;
- 保持个人技术博客的真实和克制,不使用营销表达。
生成摘要前,脚本会先从正文中移除:
- Gutenberg 区块注释;
- HTML 标签;
- Code Block Pro 代码内容;
- 普通代码块;
- 短代码;
- URL;
- 文件路径;
- 其他不适合作为摘要上下文的结构。
这样可以减少模型将代码、命令或 HTML 片段写入摘要的概率。
2. 使用 SlyTranslate 和 GLM 5.2 更新英文文章
中文摘要写入成功后,不再单独调用 GLM 4.7 生成英文摘要。
脚本会调用现有的 SlyTranslate 覆盖翻译接口,使用 GLM 5.2 重新处理对应的英文文章。
请求采用覆盖模式:
{
"input": {
"post_id": 18150,
"source_language": "zh",
"target_language": "en",
"post_status": "publish",
"overwrite": true,
"translate_title": true,
"model_slug": "glm-5.2"
}
}
这样做有几个好处:
- 继续复用已经调优的 SlyTranslate 翻译管线;
- 保留原有 Gutenberg 区块保护逻辑;
- 保留 Code Block Pro 代码块;
- 保留 HTML、短代码、URL、路径和产品名;
- 直接更新已有英文文章;
- 不创建新的英文文章;
- 不改变文章发布状态;
- 不破坏 Polylang 中英文关联。
四、为什么不能直接批量执行
真正危险的部分并不是模型生成摘要,而是生产环境写入。
一次完整流程至少包含以下操作:
- 读取中文文章。
- 读取英文文章。
- 核对文章状态。
- 核对当前标题与正文哈希。
- 通过 SSH 加载 WordPress。
- 核对 Polylang 语言和双向关联。
- 调用 GLM 4.7。
- 校验生成摘要。
- 备份文章写入前数据。
- 通过 REST API 更新中文摘要。
- 再次读取中文文章确认写入结果。
- 再次核对 Polylang 关系。
- 调用 SlyTranslate 覆盖翻译。
- 读取英文文章确认英文摘要。
- 再次核对文章状态和中英文关系。
- 将执行状态标记为完成。
在这 16 个步骤中的任何一个位置,都可能发生网络超时、接口错误或者服务端断开连接。
如果只是用一个简单的循环执行,失败后很难判断:
- 中文摘要是否已经写入;
- 英文覆盖翻译是否已经执行;
- SlyTranslate 是否已经成功,只是响应没有返回;
- 是否应该重新生成中文摘要;
- 是否应该重新调用覆盖翻译;
- 是否可能对同一文章执行两次写入。
因此,我为每篇候选文章建立了独立的执行状态文件。
五、为每篇文章保存执行状态
每篇中文文章都有一个独立的状态文件,例如:
data/backups/single-candidate/chinese-18150.execution.json
状态文件会记录:
- 中文文章 ID;
- 英文文章 ID;
- 写入前备份路径;
- 任务开始时间;
- 已生成的中文摘要;
- 摘要生成尝试次数;
- 当前执行状态;
- 完成时间;
- 最终英文文章 ID;
- 网络或接口错误信息。
主要状态包括:
prepared
excerpt_rejected
chinese_excerpt_saved
translation_started
translation_failed
completed
这些状态并不只是为了显示进度,而是决定任务失败后应该从哪个位置恢复。
例如:
prepared:还没有写入中文摘要,可以重新调用 GLM;chinese_excerpt_saved:中文摘要已经写入,不能再次生成,只能继续英文覆盖;translation_failed:覆盖翻译明确失败,可以重新调用 SlyTranslate;translation_started:覆盖请求已经发出,但最终结果不确定,必须先只读核验;completed:所有检查通过,后续批次直接跳过。
六、写入前为每篇文章单独备份
每篇文章第一次进入真实执行流程时,都会保存一份写入前备份:
data/backups/single-candidate/chinese-18150.pre-write.json
备份文件权限固定为:
0600
备份内容包括执行前读取到的文章数据和安全检查需要的字段。
状态文件与备份文件都不会保存:
- 智谱 API Key;
- WordPress 登录 Cookie;
- REST API nonce;
- Authorization 请求头;
- 其他认证信息。
即使日志或备份文件被复制,也不会直接暴露生产环境凭证。
七、摘要验证失败时只重试生成阶段
早期测试中,GLM 偶尔会返回带有项目符号或类似 Markdown 的摘要。
例如,模型可能返回:
- 第一项内容
- 第二项内容
这种内容虽然可以阅读,但不符合 WordPress 摘要字段只保存单段纯文本的要求。
因此,脚本对生成结果执行严格校验。
只有出现摘要格式校验错误时,才允许重新调用 GLM,最多尝试 3 次。
被拒绝的结果会单独保存在:
data/backups/single-candidate/rejected/
文件权限同样为 0600。
其他类型的错误,例如 WordPress 状态变化、内容哈希不一致或 Polylang 关系异常,不会触发模型重试,而是直接停止任务。
这样可以避免把真正的安全异常误判为普通模型输出问题。
八、恢复模式不再依赖 GLM API Key
执行过程中曾经出现过一个恢复逻辑问题。
某篇文章已经成功写入中文摘要,但 SlyTranslate 返回 HTTP 500。此时状态为:
translation_failed
正确操作应该是执行:
python3 bin/execute-single-candidate.py \
--post-id 17945 \
--execute \
--resume
恢复流程不需要重新生成中文摘要,因此也不应该使用 GLM 4.7。
但最初的命令行程序会在进入恢复逻辑前直接构造 GLM 客户端,导致即使使用 --resume,仍然要求环境变量:
ZHIPU_API_KEY
后来将 GLM 客户端改为延迟导入和延迟实例化:
- 普通
--execute才构造 GLM 客户端; --execute --resume传入glm=None;- 恢复流程完全不读取智谱 API Key;
- 普通执行缺少 API Key 时仍然拒绝执行。
这项修复完成后,针对性测试和完整测试全部通过,共计 204 项。
九、最危险的状态:translation_started
执行文章 18150 → 18156 时,出现了一个更复杂的边界情况。
流程已经完成:
- GLM 4.7 生成中文摘要;
- 中文摘要写入 WordPress;
- SlyTranslate 覆盖翻译;
- 英文摘要实际已经生成。
但是,在覆盖翻译完成后,程序再次读取英文文章进行最终校验时,连接被服务器断开:
RemoteDisconnected
状态文件停留在:
translation_started
此时不能直接判断覆盖翻译失败。
如果简单地对 translation_started 再次执行 SlyTranslate,有可能重复覆盖已经成功翻译的英文文章。
因此,我先进行了只读检查。
检查结果为:
zh_id: 18150
zh_status: publish
zh_excerpt_length: 154
en_id: 18156
en_status: publish
en_excerpt_length: 459
Polylang 双向关系也完全正确:
{
"zh_language": "zh",
"en_language": "en",
"zh_translations": {
"zh": 18150,
"en": 18156
},
"en_translations": {
"en": 18156,
"zh": 18150
}
}
这说明 SlyTranslate 实际已经成功,只是最终 REST 读取失败。

十、为 translation_started 增加只读收敛
为了解决这个问题,恢复逻辑再次进行了调整。
现在遇到 translation_started 时,不会立即重新调用 SlyTranslate,而是先执行只读收敛检查。
检查内容包括:
- 中文文章 ID 与固定清单一致;
- 英文文章 ID 与固定清单一致;
- 中英文文章仍为预期发布状态;
- 中文标题和正文没有变化;
- 已写入的中文摘要与状态文件一致;
- 英文标题和正文非空;
- 英文摘要是否已经生成;
- 中文文章语言为
zh; - 英文文章语言为
en; - 中文到英文的 Polylang 关系正确;
- 英文到中文的反向 Polylang 关系正确。
如果全部核验通过,并且英文摘要已经非空:
- 不再次调用 SlyTranslate;
- 直接将状态写为
completed; - 写入
completed_at; - 写入
translated_post_id。
只有英文摘要仍为空时,才允许重新调用覆盖翻译接口。
如果文章 ID、发布状态、内容哈希或 Polylang 关系出现异常,则拒绝恢复,不调用 SlyTranslate,也不写入 WordPress。
这项修复完成后,完整测试数量增加到 208 项,全部通过。
十一、批量执行时出现的真实故障
最终批处理并不是一次完全无错误的执行。
在剩余文章的批处理中,主要出现了三类临时故障。
1. GLM 请求超时
文章 18488 → 18513 和 18534 → 18610 第一次生成摘要时,GLM 请求出现:
TimeoutError: The read operation timed out
此时状态仍为:
prepared
说明:
- 中文摘要尚未生成;
- WordPress 尚未写入;
- SlyTranslate 尚未调用。
批处理等待 10 秒后,根据最新状态重新执行普通模式,第二次均成功完成。
2. 最终 REST 读取连接中断
文章 18726 → 18746 已经执行覆盖翻译,但最终读取英文文章时出现:
RemoteDisconnected
状态变为:
translation_started
批处理等待 10 秒后自动切换到 --resume。
新的只读收敛逻辑确认英文摘要已经存在,因此没有重复调用 SlyTranslate,直接将任务标记为完成。
3. SlyTranslate 返回 HTTP 500
文章 18815 → 18825 在覆盖翻译阶段返回:
HTTP request failed with status 500
状态变为:
translation_failed
批处理等待 10 秒后执行恢复模式,再次调用覆盖翻译,第二次成功完成。
这些故障说明,批量任务不能把“命令退出非零”简单理解为“整篇文章什么都没做”。
必须根据持久化状态决定下一步操作。


十二、最终批处理如何决定执行模式
最终批处理不会固定对每篇文章执行同一条命令,而是先读取状态文件。
状态与执行方式的对应关系如下:
none
prepared
excerpt_rejected
使用普通执行:
python3 bin/execute-single-candidate.py \
--post-id <ID> \
--execute
以下状态:
chinese_excerpt_saved
translation_started
translation_failed
使用恢复执行:
python3 bin/execute-single-candidate.py \
--post-id <ID> \
--execute \
--resume
如果状态已经是:
completed
则直接跳过。
每篇文章最多尝试 3 次。
两次尝试之间等待 10 秒,并根据最新状态重新选择执行模式。
无法识别的状态不会被自动处理,而是立即停止整个批次。
整个批处理运行在子 Shell 中,即使任务失败,也不会关闭当前终端窗口。
十三、最终执行结果
最后一次批处理开始时,剩余 26 篇文章。
大多数文章第一次执行即成功。
其中:
- 两篇文章遇到 GLM 超时,第二次普通执行成功;
- 一篇文章在最终 REST 校验时断线,通过
translation_started只读收敛成功; - 一篇文章遇到 SlyTranslate HTTP 500,通过
translation_failed恢复成功。
最终汇总结果为:
已完成:42/42
待处理:0
异常状态:0

这也证明了本次流程不仅能在理想网络环境下运行,也能应对实际生产环境中常见的临时失败。
十四、这次实现中最重要的几个原则
回顾整个过程,我认为以下原则比具体使用哪个模型更重要。
1. 先审计,再写入
不要让批处理脚本自行决定要修改哪些生产文章。
先生成固定候选清单,再只允许处理清单中的文章。
2. 一篇文章一个状态文件
不要只在终端显示进度。
状态必须持久化,程序重启后仍然能够判断上次停在哪一步。
3. 写入前必须备份
每篇文章在第一次写入前,都保存独立备份。
备份权限应限制为当前用户可读写。
4. 恢复不能等于重复执行
恢复流程必须根据状态决定:
- 是否重新调用模型;
- 是否重新写中文摘要;
- 是否重新调用覆盖翻译;
- 是否只需完成最终核验。
5. 请求失败不代表操作失败
POST 请求超时或者连接断开时,服务端可能已经完成操作。
尤其是在调用耗时较长的翻译接口时,必须先只读核验生产结果,再决定是否重试。
6. 双向验证 Polylang 关系
只确认中文文章指向英文文章还不够。
还要确认英文文章反向指向正确的中文文章。
7. 不要为了批量速度取消安全检查
这次只有 42 篇文章,逐篇执行会增加一些时间。
但相对于修复中英文文章关系、恢复错误摘要或处理重复翻译,这点时间成本完全可以接受。
十五、当前阶段的结论
这次摘要补全不是一个简单的 AI 文本生成任务,而是一次小型的 WordPress 内容迁移和生产数据修复。
GLM 4.7 负责生成中文摘要,SlyTranslate 和 GLM 5.2 负责更新英文翻译,但真正让流程可以安全落地的,是外围的工程控制:
- 固定候选清单;
- 内容哈希;
- 写入前备份;
- REST API 写入;
- Polylang 双向检查;
- 状态持久化;
- 失败分类;
- 安全恢复;
- 只读收敛;
- 自动重试;
- 完整测试。
最终,42 组中英文文章全部完成,已有摘要文章没有被纳入修改范围,中英文文章 ID、发布状态和 Polylang 关系均保持不变。
至此,这次 WordPress 历史文章摘要补全可以正式告一段落。
更重要的是,这套流程已经不再是一次性的临时脚本。
它已经具备了继续扩展到其他历史内容维护任务的基础,例如:
- 补全更多类型文章的摘要;
- 检查中英文摘要一致性;
- 审计历史文章 Meta Description;
- 批量检查 Polylang 关联;
- 对已有摘要进行只读质量评估;
- 为其他 WordPress 内容字段建立可恢复的 AI 更新流程。
对于生产环境中的 AI 自动化,我现在更倾向于一个明确的判断:
模型输出质量固然重要,但真正决定方案能否长期运行的,是模型之外的安全边界、状态管理和恢复能力。
需要长期技术维护或远程问题排查?
我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。
如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:
- ✅ PHP / Laravel / Yii2 老项目无人维护
- ✅ Go / Gin 后端接口需要排查或优化
- ✅ WordPress 网站访问慢、报错或插件冲突
- ✅ Nginx / MySQL / Redis / Linux 服务器异常
- ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
- ✅ 需要长期远程技术支持或兼职维护
更多介绍请查看:关于我 & 合作
微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

发表回复