用 Kanban 流水线自动化博客发布:从选题到上线全链路
我的博客发布是完全自动化的。每天凌晨 3 点有一个 cron 任务扫描前一日的对话记录,提取有价值的选题,自动创建 Kanban 流水线。等我醒来看手机,文章已经躺在微信草稿箱里了。
这套系统是我在 Hermes Agent 上搭建的,用了不到两周迭代稳定下来。它没有用复杂的框架,核心是两样东西:一个 SQLite 里的 Kanban 看板,和几个一百来行的 Python 脚本。
全链路总览
从选题落地到文章上线,中间经过 5 个步骤:
选题触发(cron / 手动 / 飞书)
│
▼
T1: 素材收集 + 选题诊断 ──┐
│ │
▼ │
T2: 撰写文章 + AI 自检+配图 │
│ │
├───────────────────────┤ (T3+T4 并行)
▼ ▼
T3: 安全检查 T4: 封面设计
│ │
└───────┬───────────────┘
▼
T5: 发布(网站 + 微信 + Git)

触发管线的方式有三种:
- cron 自动提取:凌晨 3 点扫描昨天的对话,有选题价值的内容自动建管线
- 手动发标题:用户发一个文章标题,模型直接进 T2 写稿
- 飞书选题表:在飞书多维表格里管理选题池,选一个「未执行」的跑管线
选题从哪里来
选题是流水线的第一站,也是目前唯一需要人工参与的部分。
日活提取(凌晨 3 点):一个 cron 任务 blog-topic-picker 执行 session_search 扫描昨天的对话,用规则判断哪些讨论内容适合写博客。提取到的选题写到飞书多维表格的「公众号选题管理」表中,标签分为 AI、工具、教程、生活、技术五类。带「热点」标签的选题会走热点管线(3 步),其他走博客管线(5 步)。
飞书选题表:一个飞书多维表格(Base),用 feishu-topic-manager.py 脚本管理。六个状态:待评估 → 素材收集中 → 写作中 → 待发布 → 已发布 → 已放弃。选题可以从 cron 自动创建,也可以手动在飞书里加。选择一个「待评估」的选题后,脚本会自动创建 Kanban 流水线,把状态推到对应步骤,并建立依赖链。整个过程不需要打开编辑器。
两条流水线
博客文章和热点报道的内容类型不同,我跑了两种管线结构。
博客管线:T1→T5
T1 素材收集 [blog-topic-picker, dbs-content]
T2 撰写+自检+配图 [ruite-blog, humanizer-zh, dbs-ai-check, image-gen]
T3 安全检查 [blog-topic-picker]
T4 封面设计 [guizang-social-card] ← T3+T4 并行
T5 发布 [ruite-blog, dbs-xhs-title]
T3 和 T4 同时跑,T5 等两者都完成才执行。最初是 4 步流水线(T3=T4 合一),很快发现安全检查经常比封面设计快很多,合在一张卡片里导致安全检查通过了但封面没做完,T4 被不必要地阻塞。拆开并行后,整个管线耗时缩短了约 40%。
create-pipeline.py 负责创建这 5 张卡片并建立依赖链。核心就一个函数:
t1 = create_card("素材收集: 标题", t1_body, skills=[...], workspace="dir:~/repo")
t2 = create_card("撰写文章: 标题", t2_body, skills=[...], parent=t1, ...)
t3 = create_card("安全检查: 标题", t3_body, skills=[...], parent=t2, ...)
t4 = create_card("封面设计: 标题", t4_body, skills=[...], parent=t2, ...)
t5 = create_card("发布: 标题", t5_body, skills=[...], parent=[t3, t4], ...) # 等两者
parent 参数是关键。T2 的 parent=t1 确保 T2 不会在 T1 没完成时被触发。T5 的 parent=[t3, t4] 是两个父任务——只有 T3 和 T4 都完成后,T5 才从 todo 提升到 ready。
热点管线:T1→T3
热点文章是突发事件驱动的,写法不同。不要求 2000 字的技术教程,而是 2000-4000 字的多源分析。所以管线更短:
T1 调研+撰写+核查 [aihot, zhihu-toolkit, ruite-blog, humanizer-zh, dbs-ai-check, image-gen, ...]
T2 封面设计 [guizang-social-card]
T3 发布 [ruite-blog]

T1 是合并版——调研、写作、质量自检、事实核查由同一个 worker 完成。因为这三步共享同一套素材上下文,拆成多张卡片意味着每个 worker 都要重新搜索和阅读素材,得不偿失。反而封面设计保持独立(方便单独重跑封面),发布步骤纯机械(脚本可自动化,无需推理)。
T3 的依赖写法有个经典教训:必须是 parent=[t1, t2],不能是 parent=t1。如果只依赖 T1,dispatcher 会在 T1 完成后立刻派发 T3,此时封面可能还没生成。结果就是发布步骤用网站默认 logo 做封面,而非专门设计的封面图。这个 bug 在实际运行中出现过,修复后加了一行注释强调。
五步详解
T1:素材收集 + 选题诊断
T1 做的不是简单的资料粘贴。worker 会先调用 session_search 从对话中提取完整上下文,然后整理操作步骤、命令、配置、踩坑点。同时用 dbs-content 做五维选题诊断:
- 文字洁癖:检查表达是否啰嗦
- 封面标题:选题是否自带爆款潜力
- 表达效率:信息密度够不够
- 认知落差:读者能不能学到新东西
- AI 辅助:哪些部分可以用工具提效
诊断结果写入素材文档顶部,供 T2 写稿时参考。
T2:撰写 + AI 自检 + 配图
最重的步骤。worker 先读素材文档,按标准结构写作(背景→是什么→怎么用→踩坑→总结),然后做三件事:
-
humanizer-zh:检查 24 种 AI 写作模式。AI 高频词、三段式结构、破折号过度、填充短语、通用积极结论——这些特征在产生时就要避免,而不是写完再修改。
-
dbs-ai-check:扫描 22 种 AI 写作特征。强信号(🔴)直接修改,中弱信号记录到素材文档供参考。
-
配图生成:从文章中提炼「认知锚点」,为每个锚点生成一张英文 prompt 给图像生成模型。默认用阿里云 qwen-image-2.0-pro(1280×720 16:9),备选商汤日日新。prompt 不含任何文字,negative_prompt 统一排除
text, words, letters, numbers, title, watermark, signature——AI 生图带乱码文字是常见问题。
配图生成后会用 vision_analyze 检查质量,确认无文字乱码、内容相关、比例正确。
T3:安全检查
敏感信息扫描。正则匹配 token、secret、password、key、ghp_、sk-、Bearer、私有 IP 段。发现即替换或删除。
这一步机械,但必不可少。写过一篇教程,里面有 Redis 配置示例用了 requirepass,发布前检查发现暴露了测试环境的密码。
T4:封面设计
用 guizang-social-card 生成封面。HTML 单文件 + Playwright 截图:2100×900(21:9 主封)+ 1080×1080(1:1 方封)。
风格选择:技术教程用瑞士风格(IKB Blue 底色 + Inter 字体 + 网格装饰线),热点文章用 Editorial 风格。AI 生成的纯图封面作为降级方案。
几个踩坑点:
- Node.js v26 兼容问题:Ubuntu 26.04 上 puppeteer 的
page.goto第二次调用会报Navigating frame was detached。降级方案是用 Python PIL 纯代码生成封面——无浏览器依赖,渲染极快,但排版灵活性有限。 - 渲染缓存清理:Playwright 截图后遗留的 chromium 二进制(~655MB)和 node_modules(~30MB)会被
git add -A误追踪,也可能阻塞 wrangler deploy。发布前必须清理。 - 封面不允许引用正文插图:T4 生成的封面不能复用 T2 的正文配图。封面是独立的视觉设计。如果 T4 失败,降级使用默认网站 logo,而不是拿正文插图裁剪。
T5:发布
纯机械步骤,四个子任务串行:
Pelican 构建(~15s)
→ Cloudflare Pages 部署(~13s,已上传文件跳过)
→ 微信草稿箱推送(~5s,含正文图片自动上传)
→ Git 提交推送(~3s)
→ 飞书状态更新(已发布)
Pelican 构建:项目从 articles/ 和 digests/ 读 Markdown 源文件,生成静态 HTML 到 site/。用了自定义主题(base、index、article、tag、tags 模板)和自定义插件处理 YAML frontmatter。热点文章和 AI 日报标记 type: hotspot / type: digest,首页模板过滤不展示,但存档在站点。
Cloudflare Pages:wrangler pages deploy 做增量上传,已经上传过的文件跳过(日志可见 “168 files already uploaded, 1 new”)。覆盖瓶颈不是上传速度(~2s),是 wrangler CLI 的固定开销(~11s)。
微信草稿箱:大坑最多的一步。Markdown → 微信格式 HTML 用 md2wechat.py 转换,支持三个主题。过程中需要:
- 正文图片自动上传为微信素材库的永久 URL(mmbiz 格式)
- 在 HTML 阶段替换
<img src>(不能在 markdown 阶段替换,因为 mmbiz URL 中的下划线会被 md2wechat 解析为斜体<em>) - 一次推送是新建草稿(
draft/add),再次推送自动更新(draft/update) - frontmatter 自动剥离,
wechat_media_id写入 frontmatter 供下次更新使用
Git 提交:每次推送前注入 GitHub token 认证,推送后恢复原始 URL——Git 认证在 cron 和 kanban worker 里经常丢失。
通知和监控
每步完成后都通过 ntfy 推送通知:
curl -s -o /dev/null \
-H "Title: T2 ✅ 撰写文章完成" \
-H "Tags: white_check_mark" \
-d "文章标题" \
https://ntfy.sh/统一话题
可以实时追踪管线进行到哪一步了。如果哪步卡住,看通知就能知道——比如封面设计完成的通知没收到,就知道 T2 还在写。ntfy 的话题还能用 webhook 路由做事件驱动触发。
踩坑集
跑了两周,记录几个有代表性的坑:
Kanban worker 的写操作可能丢失。 patch 工具返回成功但修改没落盘——发生在 worker 上下文压缩时。修正数据后必须立即用 read_file 回读确认。这个回读模式在金额/百分比修改、敏感信息替换、文件名更改后都要执行。
依赖链写错。 T5 的 parent 如果只写 parent=t3 忘了 T4,dispatcher 在 T3 完成后就触发发布,此时封面可能还没生成。封面不对但步骤通过了,直到在网站上看到默认 logo 才发现。上面提到的 parent=[t1, t2] 教训就是同一个根源。
Node.js v26 与 puppeteer 的冲突。 第二次调用 page.goto 会报错。这是操作系统升级带来的兼容问题,最终用 PIL 纯代码方案兜底。
Git 认证在 cron 中丢失。 kanban worker 和 cron 任务没有交互式终端,每次 push 前必须手动注入 token 到 remote URL。后来写进 T5 的 body 作为固定步骤。
封面渲染的 655MB 残留。 chromium 浏览器二进制被 Playwright 下载后留在 covers/{slug}/ 下。如果清理不及时,git add -A 会试图提交 655MB 的二进制文件,wrangler deploy 也会被它拖慢。解决方案:T4 完成后立即删除渲染缓存,T5 开始前再次检查。
Profile 名写错导致任务永远停在 ready。 创建卡片时如果在 --assignee 传了一个不存在的 profile 名,dispatcher 不会报错——它只是不派发。卡片创建了,状态永远是 ready,没人来领。创建前跑一遍 hermes profile list 确认 profile 名是对的。
整个系统的技术栈
工具/平台 用途
───────────── ──────────────────────────
Hermes Kanban 任务调度 + 状态管理
Pelican 静态博客生成引擎
Cloudflare Pages 网站托管(免费计划)
微信公众号 API 草稿箱推送 + 素材上传
GitHub 源码 + 构建产物存档
飞书多维表格 选题管理(状态跟踪)
ntfy.sh 进度通知
guizang-social-card 封面图生成
qwen-image-pro 正文配图(阿里云百炼)
humanizer-zh 中文 AI 特征检测
dbs-ai-check AI 写作检测
整个系统只有一台 Linux 机器运行,没有外部 CI。Hermes Gateway 作为常驻进程管理 cron 和 kanban dispatcher,所有脚本放在博客仓库的 scripts/ 下。
写在最后
从最初手动写博客→手动部署→手动推送微信,到现在的全自动化流水线,核心变化不是写了多少代码,而是理解了任务编排的本质:把一个大任务拆成独立的小任务,每个小任务只关心一件事,通过持久化队列保证进度不丢失。
我现在的写作流程已经变成这样:
- 写代码/解决问题的时候,和 Hermes 对话
- 凌晨 3 点,cron 自动提取有价值的对话成为选题
- 醒来确认一下选题方向,或者直接收到文章推送通知
- 去公众号后台预览→发布
整个过程唯一需要人工的,是选题决策和最终预览发布。中间的 5 个步骤不用我管。
不需要复杂的框架。几个脚本 + 一个 SQLite 看板,足够搭建属于你自己的写作流水线。
文中提到的脚本和工具链(开源或可自建):
- Hermes Agent Kanban:
hermes kanban create / list / show create-pipeline.py/create-pipeline-hotspot.py:流水线创建器feishu-topic-manager.py:飞书选题管理publish-website.sh:一键部署网站publish-wechat.py:微信草稿箱推送md2wechat.py:Markdown → 微信格式 HTMLguizang-social-card:封面图生成humanizer-zh:中文 AI 特征检测