用 Markdown 生成符合中文排版规范的正式 Word 文档:typeset 工具详解
把 Markdown 转成 Word,pandoc 是一条常见路径。但 pandoc x.md -o x.docx 出来的文档,给英文博客用没问题,换成中文合同、协议、服务确认单、方案书或正式函件,就处处不对了。纸型、字体、行距、页眉页脚、表格跨页、标题孤行、签章区散落——每一样都要重新调,而且有些问题只有打开 Word 才看得到。
typeset 这个工具解决的就是这个问题。它把 Markdown 生成排版规范的中文 .docx,同时附带一套检查机制,帮你发现版面问题。
安装与依赖
typeset 本身是一个 Agent Skill,但也提供了独立的命令行工具。安装之前,先装好底层依赖:
brew install pandoc poppler
brew install --cask libreoffice
-
pandoc:核心转换引擎,负责 Markdown → docx。 -
poppler: verify.py渲染检查时用于处理 PDF。 -
LibreOffice:用于无头模式( --headless)把 docx 转 PDF,再逐页渲染成 JPG 供人工检查。
克隆仓库到对应目录即可使用。按 Agent Skills 开放标准,Codex CLI 读取 ~/.agents/skills/,Claude Code 读取 ~/.claude/skills/。装一份、两处都能用:
git clone https://github.com/cerul-ai/typeset.git ~/.agents/skills/typeset
ln -s ../../.agents/skills/typeset ~/.claude/skills/typeset
之后在 Claude Code 或 Codex 里说“帮我把这份合同做成 Word”,就会自动调用。
直接当命令行工具用也行,核心脚本就两个:
-
scripts/build.py:Markdown →.docx -
scripts/verify.py:结构 lint + 渲染检查
排版参数差异
pandoc 默认的 docx 输出和中文正式文书需要的差距,不只是“字体对不对”这么简单。
| 项目 | pandoc 默认 | 中文正式文书需要 |
|---|---|---|
| 纸型 | Letter | A4 |
| 标题 | #0F4761 青蓝色、不加粗 |
纯黑色、加粗、黑体 |
| 西文字体 | Aptos | Times New Roman |
| 中文字体 | 主题回退,跨机器不一致 | 宋体 / 黑体显式指定 |
| 行距 | 单倍 | 1.5 倍(预留批注空间) |
| 页眉页脚 | 无 | 横线 + 第 X 页 / 共 Y 页 |
这些差异的直接影响是:用 pandoc 默认模板生成的 docx,在中文正式文书场景下几乎都需要二次手工调整。typeset 做的事情,就是把这一套调整固化为可复用的构建脚本。
基本用法
从模板起步:
cp templates/contract.md 我的合同.md
编辑 Markdown 内容后,执行构建:
python3 scripts/build.py 合同.md
默认输出同目录下的 合同.docx,排版参数按国内公司合同最常见的范式(方案 A)生成。
如果需要更多样式选择,可以用 --all 一次生成四套不同封面与签章方案的版本:
python3 scripts/build.py 合同.md --all
输出会带上方案后缀,方便打开对比挑一个。
验证:结构 lint + 渲染检查
verify.py 提供了两层检查,两层都通过后依然需要在 Word 里做最终确认,但这两层能提前过滤掉大部分问题。
python3 scripts/verify.py 合同.docx --render
第一层:结构 lint
检查 docx 内部的结构是否符合预期,不依赖任何外部渲染器,跑得很快。能检出常见的结构问题,比如表格跨页被劈成两半、条款标题孤零零留在页底、签章区甲方在上一页乙方在下一页——这些都是“在 Word 里打开才能看见”但确实会破坏正式文书观感的问题。
第二层:转 PDF + 逐页渲染成 JPG
--render 会调用 LibreOffice 把 docx 转成 PDF,再把每一页渲染成独立的 JPG 图片。然后你会看到类似这样的输出:
第 1 页: 封面
第 2 页: 条款 1-3
第 3 页: 条款 4-6(表格跨页)
...
这一步的真正价值是让你真的去看那些 JPG。前面每一步都通过、文档在 Word 里能打开,版面依然可能很难看。只有一页一页扫过渲染图,才能发现表格被拦腰切断、签章区只剩甲方、页眉横线没对齐这类问题。
字体替换问题与分页差异
verify.py 会自动检测字体是否被替换并给出提示。这一点比想象中更重要。
LibreOffice 在 macOS 上默认匹配不到“宋体/黑体”,会回退到 Arial Unicode MS。替换字体的度量不同,连页数都会变——同一份 docx,Word 打开是 17 页,LibreOffice 转出来可能变成 27 页。差 10 页不是小数目,签章区、附录、空白页的位置全都不一样。
所以 verify.py 的 --render 模式用 LibreOffice 转 PDF/JPG,定位是:
-
验结构:表格有没有被劈开、签章区有没有散、标题孤行有没有出现 -
不代替 Word 做最终排版确认
最终分页与字体外观,必须在 Word 里打开确认。如果某个页面在 LibreOffice 渲染图里看起来“版面有点怪”,但结构 lint 没报错,再去 Word 里核对——很多时候 Word 里的实际效果是好的,这就是字体度量差异导致的分页漂移。
四套封面与签章方案
--all 生成的四个版本,封面和签章区布局不同,适用场景也不同:
| 方案 | 特点 | 适用场景 |
|---|---|---|
| A 复刻参考版 | 国内公司合同最常见的范式 | 默认方案,没特殊要求时选它 |
| B 严格对齐版 | 标签-值两列 + 填空线 | 打印后手填的纸质版合同 |
| C 公文庄重版 | 信息块加外框、标题放大 | 正式函件、对上级/对外公文 |
| D 现代简洁版 | 左对齐 + 细线包夹,无页眉线 | 对内方案书、服务确认单 |
这四个方案只在封面和签章区有区别,正文字体、行距、页眉页脚保持一致。所以选方案其实就是选“第一页长什么样”和“最后一页怎么落款”。
实际操作中,如果拿不准选哪个,跑一次 --all,四份都打开,封面页截图放在一起对比,挑视觉上最顺眼的那个。后面内容改动了,再用对应方案重新生成。
修改排版风格
排版参数集中在 scripts/build.py 顶部的常量块,想换字体、字号、边距,改那里就行,不用翻到代码各处去改。
取值依据写在 references/house-style.md 里。比如为什么标题用黑体而不是宋体加粗,为什么行距定 1.5 倍而不是“多倍行距 1.25”,这些判断在 house-style 里都有说明。改参数前先看依据,避免凭感觉调出一个“看起来差不多但整体不协调”的版本。
快速操作清单
-
安装依赖: brew install pandoc poppler+brew install --cask libreoffice -
克隆仓库到 ~/.agents/skills/typeset(或任意目录后软链到对应位置) -
复制模板: cp templates/contract.md 我的合同.md -
编辑内容,然后构建: python3 scripts/build.py 我的合同.md -
需要对比方案时用 --all生成四份 -
验证: python3 scripts/verify.py 我的合同.docx --render -
查看每页渲染 JPG,重点关注表格跨页和签章区 -
最后在 Word 里打开确认字体和最终分页 -
改排版参数时只改 scripts/build.py顶部的常量块
FAQ
Q:pandoc 直接转不就行了吗,为什么还要这套工具?
A:pandoc 默认模板面向英文场景,中文正式文书需要的 A4 纸型、宋体/黑体显式指定、1.5 倍行距、页眉页脚页码都不在默认配置里。手工调一份可以,每次都要调就不如固化下来。
Q:verify.py 的 --render 检查通过后,还需要在 Word 里看吗?
A:需要。--render 依赖 LibreOffice 做转换,而 LibreOffice 在 macOS 上会把宋体/黑体替换成 Arial Unicode MS,导致分页与 Word 不一致。--render 的意义在于验结构(表格、签章区、孤行),最终字体和分页在 Word 里确认。
Q:--all 生成四份文档,内容一样吗?
A:正文内容完全一样,只有封面和签章区的排版方案不同。
Q:字体被替换了怎么办?
A:verify.py 会检测到并给出提示。如果你需要在 Linux/macOS 无 GUI 环境里做更准确的渲染验证,可以在系统里安装中文字体(如 fonts-noto-cjk),但即便如此,LibreOffice 和 Word 的排版引擎仍然有差异,不能完全替代 Word 确认。
Q:我只想改页眉文字,不想动其他参数,改哪里?
A:在 scripts/build.py 顶部的常量块里找 HEADER_TEXT 相关变量。不要在转换后的 docx 里手工改——下次构建会被覆盖。所有定制都回到 Markdown 源文件和 build.py 的常量块。
Q:这个工具只能生成合同吗?
A:不只合同。协议、服务确认单、方案书、正式函件都适用。模板是合同骨架,但排版参数是通用的中文正式文书规范。

