当 AI 学会排版:我如何用 3 个开源 Skill 编出一个自动化排版引擎

你将学到:如何将 3 个独立的 AI Skill(md2wechat、baoyu-post-to-wechat、自研编排器)组合成一个端到端的内容发布引擎——从选题研究到博客+公众平台双端同步,中间还定制了 6 套专属视觉风格。

每次写完一篇技术文章,我都要重复三个痛苦步骤:调 Markdown 样式让它适配平台、手动上传图片到 OSS、再在后台粘贴排版。一篇文章光「搬砖」就要 40 分钟。

更糟的是,市面上的工具要么只管渲染(md2wechat),要么只管发布(baoyu-post-to-wechat),没有一个能从「选题 → 写稿 → 渲染 → 博客 → 发布」一条龙跑完。

于是我决定:不造轮子,而是把轮子编成引擎


目录


一、三个轮子,三种哲学

先介绍一下我手头的三个 Skill,它们各自擅长什么、又各自缺什么。

1.1 md2wechat —— 渲染引擎

定位:Markdown → 平台 HTML 的”底层引擎”。

md2wechat 是一个 CLI 工具,核心能力是 inspect → preview → convert 三板斧。

它有 52 个主题43 个高级版式模块:::module 语法),还提供 generate_covergenerate_infographic 封面生成管线。

它的设计哲学是 发现驱动(Discovery-First):不靠文档记忆能力,而是强制让 agent 先跑 themes list --json 拿到最新事实,再选主题。这避免了”文档说有但实际已下架”的尴尬。

它不做的事:不写文章、不调平台接口、不关心你的博客。

1.2 baoyu-post-to-wechat —— 发布引擎

定位:已有文章后,专攻”推上平台”这最后一公里。

宝玉的 Skill 强在工程化:4 种主题 + 13 种色板多账号支持accounts: 配置块)。

还有三种发布通道(服务端接口 / 浏览器自动化 / 远程隧道),以及评论控制、原文链接等细节。

它的哲学是 参数驱动 + 工程化:把主题/颜色/账号/通道做成可配置矩阵,逻辑写在 TypeScript 里并有测试覆盖。

它不做的事:不写文章、不做可读性检查、不关心你的博客。

1.3 我的 wechat-article-generator —— 编排器

定位:端到端总控,把上面两个和「写作 + 博客」绑在一起。

维度编排器md2wechatbaoyu
创作(研究、写稿)内置流程不涉及不涉及
渲染委托 md2wechat自身核心内部处理
发布委托 baoyu不涉及自身核心
Hexo 博客唯一支持不涉及不涉及
可读性 Gate6 项硬阻断inspect readiness
多账号委托 baoyuconfig 命令一等公民
风格系统6 套 Style Pack52 主题4 主题+13色

二、编排架构:不重造,只缝合

核心思路很简单:编排层不实现任何底层能力,只做三件事——调度、质控、降级兜底。

三层技能编排架构

架构分三层:

  1. 编排层(wechat-article-generator):确定”谁来做”,维护全局 Quality Gate
  2. 渲染层(md2wechat):Markdown → 内联样式 HTML,发现主题、版式模块
  3. 发布层(baoyu-post-to-wechat):接口/浏览器/远程三通道推平台

关键规则:编排器绝不重新实现底层 Skill 已有的能力。渲染走 md2wechat,发布走 baoyu,编排器只管”什么时候调谁”和”过了质控才能发”。


三、8 步工作流:从选题到双端发布

8步编排工作流

每一步都有明确的所有者:

Step 1: Intake 接单

识别用户意图:选题/续写/润色?目标读者?输出目标(本地/博客/草稿/直接发布)?多账号时确认用哪个。

Step 2: Research 研究

对外部话题搜索源事实,保留 source URL 到 front matter。不编造数据。

Step 3: Write 写稿

编排器自研。短段落、清晰层级、嵌入图片、元数据。参考 article-templates.mdheadline-examples.md

Step 4: PicGo 图片上传

强制步骤。每张图必须通过 picgo_upload.py 上传 OSS,禁止本地路径进入 Markdown。上传失败则停。

Step 5: Render 渲染

委托 md2wechat。先跑 themes list --json 发现可用主题,再 inspect → preview → convert。也可以用自研的 render_style_pack.py 直接从 Style Pack 渲染。

Step 6: Gate 质量门

编排器核心。6 项透明指标,任何一项不过即阻断:

#指标含义
1cover_or_poster_remote封面图必须是 OSS URL
2in_article_images_remote≥2 张正文图,全部 OSS
3visual_rhythm_per_600chars每 600 字至少一个视觉打断(引用/列表/代码/图片)
4html_inline_style_only禁止 <style>、class、<head><body>、JS
5html_color_hierarchy≥4 种颜色或有内联标题色
6html_image_alt_or_caption每张图有 alt 或说明文字

Step 7: Blog 博客发布

编排器自研。Markdown 落到 source/_posts/<category>/,跑 npm run build 验证编译。

Step 8: 内容平台草稿

委托 baoyu。服务端接口优先,网络受限则走远程隧道,最后备选浏览器自动化模式。默认只存草稿,不主动发布


四、6 套专属风格系统

我研究了 2025-2026 年主流内容平台视觉风格(极简日系、杂志感编辑部、卡片化、满底色冲击、莫兰迪、手账、暗黑赛博、渐变流体、Bento Grid、中式编辑)。

结合自己的内容类型,定制了 6 套 Style Pack:

6套专属风格系统

Pack名称适合内容调性关键词md2wechat 备选
A灰阶玻璃 Mono Glass随笔/产品发布墨色+玻璃质感+零干扰ink-minimal
B报刊编辑部 Editorial深度评论/技术史米黄底+衬线+朱红序号nyt-classic
C光感卡片 Card Modern工具评测/教程/清单蓝色+数字徽章+圆角卡片sspai-red
D暗夜终端 Cyber LocalAI/Agent/源码深色容器+霓虹紫青github-readme
E莫兰迪生活 Muted Life周记/阅读/慢思考奶油底+灰豆沙mint-fresh
F冲击标题 Bold Block热点/大新闻/立场墨红满底色+金色bold-red

每套 Pack 是一个完整的内联 CSS 视觉系统:H1/H2/H3/段落/引用/代码/分隔线/图片/CTA/页脚全覆盖。

输出 100% 内联样式 HTML,直接粘贴进平台编辑器零适配。

双端联动

平台端render_style_pack.py 直接渲染出 HTML。

博客端:通过 Hexo AnZhiyu 主题的 body[data-style-pack="X"] CSS 作用域,同一篇文章在博客上自动应用对应 Pack 的博客版样式。设置方式:

1
2
3
4
# 文章 front matter
meta:
- name: style-pack
content: C # 用 Pack C 卡片风格

五、三大设计原则

在编排过程中,我提炼了三条”不写进代码就一定会忘”的原则:

原则一:Discovery-First 发现优先

规则:选择 md2wechat 的主题、版式模块时,必须先跑 md2wechat themes list --json 获取最新可用列表,再从中挑选。不能从记忆或文档中猜测

为什么:md2wechat 的 52 个主题会随版本更新增删。如果硬编码 --theme github-readme,升级后可能 404。发现驱动让编排器始终与底层引擎的能力保持同步。

原则二:Inspect-Gate 硬阻断

规则:执行 md2wechat inspect <article.md> 后,必须读取 data.readiness.targets.draft。如果为 false,列出 blockers 并停止——绝不能静默降级

为什么:有一次我在 inspect 报了 cover_missing 的情况下继续走了 draft 路径,结果后台显示封面为空。从此之后,gate 不过即停,不允许”看起来 OK 但其实不能发”。

原则三:Idempotent 幂等重跑

规则:每次运行写入 state.json(记录 markdown SHA256、已上传图片 hash、thumb_media_iddraft_media_id),重跑时复用已有结果。

为什么:调试时经常中断重跑。没有幂等性时,每次重跑都重新上传图片、重新创建草稿,导致素材库堆积重复资源。


六、踩坑与收获

坑 1:平台 HTML 兼容性是”伪命题”

平台编辑器会吃掉 <style> 块、class 选择器、<head>/<body> 标签、自定义字体声明、JS、SVG——几乎所有”正常”网页的写法都不行。

结论:所有视觉必须靠内联 style 属性 + 颜色块 + 边框 + 字号字重做层级,不能靠 CSS 选择器或效果。Style Pack 的每一条 CSS 规则都要”摊平”到每个元素上。

坑 2:视觉节奏检查的 false positive

初版的 visual_rhythm_per_600chars^ 正则锚点检测视觉打断,但在去除空格后的文本窗口中 ^ 永远不匹配,导致每篇文章都报”没有视觉打断”。

修复:重写为 visual_break_positions() ——在原始 Markdown 中定位所有打断点(H2+、引用、列表、代码块、图片、分隔线),映射到压缩坐标后再检查每个 600 字窗口。

坑 3:浏览器打开渲染结果乱码

render_style_pack.py 输出的 HTML 是裸 <section> 片段(没有 <html>/<head>/<meta charset>),直接用浏览器打开会默认 Latin-1 编码,中文全乱码。

修复:输出文件时包裹完整的 HTML 壳(含 <meta charset="utf-8">),粘贴到编辑器时只用 <section> 内部内容。

收获:编排 > 重造

最核心的认知转变是:不要自研已经有人做好的事

md2wechat 有 52 个主题 + 43 个版式模块,baoyu 有三通道发布 + 多账号 + 远程隧道,这些我自己写要几周。而编排器只需要 400 行 Python 就把它们的最佳能力串起来了。


七、内容安全风控

这一节是实战踩出来的经验。在向内容平台提交草稿时,我遇到了 45166 invalid content 错误——文章被平台审核系统拦截,但没有任何具体原因提示。

7.1 触发审核的常见词

以下词汇在技术文章中很常见,但在平台审核中可能触发风控:

敏感词安全替换说明
微信公众号内容平台 / 公众平台品牌词直接出现容易触发
公众号平台 / 编辑后台同上
API接口 / 服务端接口技术术语但审核敏感
SSH / SOCKS5远程隧道 / 安全通道网络穿透相关
IP 白名单网络访问控制安全相关
access_token凭证 / 令牌认证相关
Chrome CDP浏览器自动化自动化相关
Secret / 密钥配置项 / 凭证密钥类

7.2 风控检查步骤

我在编排器的 Quality Gate 中增加了一步内容安全预检,在提交草稿之前自动扫描:

  1. 扫描 Markdown 和渲染后 HTML 中的敏感词列表
  2. 命中时输出警告和替换建议
  3. 自动替换或人工确认后才能继续

7.3 给编排器开发者的建议

  • 写稿时就注意措辞:不要等到提交时才发现被拦截,改起来很痛苦
  • 双版本策略:博客版可以用完整技术术语,平台版需要安全替换
  • 审核错误码 45166:这是”内容不合规”的通用错误,平台不会告诉你具体哪里有问题,只能自己排查
  • 重试策略:替换后重试,每次只改一处,逐步定位触发词

八、开源地址与后续计划

  • md2wechatgithub.com/geekjourneyx/md2wechat-skill
  • baoyu-post-to-wechatgithub.com/anthropics/claude-code(Skill 生态)
  • 编排器 + 6 套 Style Pack:随本博客仓库开源

后续计划

  1. Style Pack 可视化选配器:在博客端做一个交互式预览页面,选 Pack → 实时预览效果
  2. 更多 Pack:基于读者反馈增加中式编辑(红黑宋体)、手账 Sketchnote 等
  3. 测试覆盖:给 render_style_pack.pyvalidate_article_experience.py 补自动化测试
  4. 内容安全预检:在 Quality Gate 中集成敏感词扫描,提交前自动替换或告警

如果你也想让 AI 帮你自动排版,核心就一句话:别造轮子,编引擎。找到好的渲染和发布工具,然后专注做好编排和质控——这才是你自己的差异化价值。