做一个"AI 生成 PPT"的工具,最难的部分不是让大模型写出像样的文案——那部分今天已经很便宜了。

真正难的是后半段:怎么把一堆文字变成一个在 PowerPoint、WPS、Google Slides 里都能正常打开、并且能被人继续编辑的 .pptx 文件。

这篇文章拆一下这条链路。以 PPT Maker 的 Agent Slides 模式为参照(aipptmaker.ai),讲清楚每一环在解决什么问题、坑在哪。

说明:下面描述的是这类系统的通用工程链路,部分实现细节是我基于可观察行为做的合理推断,不代表官方架构。


一、整体链路

用户输入(一句话 / 大纲 / PDF / Word)
        ↓
① 意图与约束解析
        ↓
② 叙事结构生成(Outline)
        ↓
③ 逐页内容填充(Copy + 要点 + 备注)
        ↓
④ 视觉资产检索(图 / 图标 / 图表)
        ↓
⑤ 版式求解(Layout Solving)
        ↓
⑥ 序列化为 OOXML(.pptx)
        ↓
⑦ 校验与回环修复

②③ 是 LLM 的活,④⑤⑥⑦ 是工程活。而决定这个工具"能不能用"的,恰恰是后面这四步。


二、① 意图解析:把自然语言变成参数

用户说的是"做一份 Q3 复盘,面向管理层,12 页左右",系统真正需要的是一组结构化参数:

{
  "topic": "Q3 私域运营复盘",
  "audience": "management",
  "slide_count": 12,
  "sections": ["背景", "目标回顾", "关键数据", "问题归因", "下一步"],
  "tone": "formal",
  "language": "zh-CN",
  "brand_kit_id": "optional"
}

这一步的难点是隐含约束。"面向管理层"意味着结论前置、信息密度低、少细节;"面向执行层"则相反。这些映射关系如果不在 prompt 层固化,生成出来的东西永远是对的废话。

页数约束尤其要处理。实测经验:告诉模型"12 页",它倾向生成 14–18 页。所以页数不能在 prompt 里靠自觉,必须在 ② 之后做硬截断 + 合并:先按 section 权重分配页数配额,超出的部分强制合并或降级为附录。


三、② 叙事结构:先定骨架

Outline 生成的关键是先把叙事模型挑出来,而不是直接让模型自由发挥。

常见的几套骨架:

类型结构适用
SCQA情境-冲突-问题-答案提案、复盘
金字塔结论先行 + 三层支撑汇报、向上沟通
时间线过去-现在-未来战略、规划
问题树现象-归因-对策分析类
FAB特性-优势-利益产品介绍

选错骨架,后面所有页都是歪的。这一步通常用分类器或规则命中,而不是让 LLM 裸选。


四、⑤ 版式求解:这是分水岭

很多"AI PPT"产品在这里偷懒——直接把整页渲染成一张 PNG 塞进去。用户看着挺美,但一个字都改不了。

真正输出可编辑形状,意味着要解决一个二维装箱问题:

已知:一块 13.33 × 7.5 英寸(16:9)的画布,若干内容块(标题、正文、图、图表、页脚),每块有最小尺寸和优先顺序。

求:每块的 x/y/w/h、字号、行距,使得:

  • 不重叠
  • 不溢出画布
  • 正文可读(字号 ≥ 阈值)
  • 视觉层级正确(标题 > 副标题 > 正文)
  • 整体留白均衡

实际工程上不会真的跑通用求解器,而是用**栅格 + 模板槽位(slot)**的方式:

# 伪代码:槽位填充
layout = pick_layout(content_profile)   # 按内容形态选骨架
for slot in layout.slots:
    block = assign_block(content, slot.role)
    block.text = fit_text(block.text, slot.box, min_font=14)
    block.font_size = autofit(block.text, slot.box)   # 二分收缩字号
    place(block, slot.x, slot.y, slot.w, slot.h)

autofit 是核心。文字超出容器时,常见策略有三种:

  1. 缩字号:简单,但缩到 10pt 以下就不可读了,必须设下限
  2. 拆页:内容太多时自动分页,体验最好但实现复杂
  3. 裁文案:让模型重写一版更短的

生产环境一般是 1 和 2 组合,3 作为兜底。只做 1 的工具,长文案一定会翻车。


五、⑥ 序列化:DrawingML 的真实复杂度

.pptx 本质是一个 zip 包,里面是 OOXML。一个文本框的 XML 大概长这样:

<p:sp>
  <p:nvSpPr>
    <p:cNvPr id="4" name="TextBox 3"/>
    <p:cNvSpPr txBox="1"/>
    <p:nvPr/>
  </p:nvSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="914400" y="1371600"/>
      <a:ext cx="6858000" cy="1143000"/>
    </a:xfrm>
    <a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
  </p:spPr>
  <p:txBody>
    <a:bodyPr wrap="square"><a:normAutofit/></a:bodyPr>
    <a:p><a:r>
      <a:rPr lang="zh-CN" sz="1800" b="1"/>
      <a:t>Q3 私域运营复盘</a:t>
    </a:r></a:p>
  </p:txBody>
</p:sp>

几个必须知道的坑:

  • 单位是 EMU,1 英寸 = 914400 EMU。所有坐标和尺寸都要换算,浮点误差累积会导致形状偏移。
  • 字号单位是 1/100 磅,sz="1800" 是 18pt。
  • a:normAutofit 依赖渲染器计算,PowerPoint 会自己缩,但 Google Slides 的表现不一致。要跨端一致,就不能指望渲染器 autofit,得自己算好再写死。
  • 主题(theme)继承:如果形状用了 theme 里的字体色板,换模板时颜色会跟着变,这是好事;但如果写死 hex,一键换肤就会失效。所以换肤功能能不能做,取决于序列化时有没有正确使用 theme 引用。
  • 图表不是画出来的,是 c:chart 引用一个内嵌 xlsx。<c:externalData> 指向 ppt/embeddings 下的工作簿。这意味着生成图表时要同时生成数据源文件。

上面这段是很多人低估的部分:能生成 PPT 和能生成"改得动的 PPT"之间,差的是对整个 OOXML 规范的覆盖度。


六、⑦ 校验回环

生成完不能直接返回,必须验证。实际做法:

# 1. 结构校验:zip 完整性 + XML schema
unzip -t deck.pptx
xmllint --schema pml.xsd ppt/slides/slide1.xml

# 2. 渲染校验:转 PDF 检查是否有文字溢出/元素重叠
soffice --headless --convert-to pdf deck.pptx
pdftotext deck.pdf - | wc -l   # 文字是否还在

渲染校验里最实用的是溢出检测:把 deck 转成 PDF,检查每页文字块的 bounding box 是否超出页面。这一条能拦住 80% 的"看起来生成了,打开发现文字糊成一团"的问题。


七、多语言:不只是翻译

支持 40+ 语言时,问题从"翻译准不准"变成"排版撑不撑得住":

  • 德语单词长度普遍比英语长 30%,同样的文案必然换行溢出
  • 中文按字符断行,日文有禁则处理,阿拉伯语是 RTL
  • 字体回退:中英混排时如果只指定一个 Latin 字体,中文会掉到系统默认字体,字号视觉不一致

所以多语言 deck 的正确做法是每种目标语言独立跑一遍 ⑤ 版式求解,而不是用源语言的版式硬套。


八、结论

把这条链路拆完,你会发现"AI 做 PPT"这个品类的技术门槛其实集中在两处:

  1. 版式求解——能不能在固定画布上把不确定长度的内容排好
  2. OOXML 覆盖度——生成的东西到底能不能被主流软件正确打开和编辑

这两点做不好,产品就是个"生成图片的玩具"。做好了,它才真的能替掉那 2 小时。

至于内容本身讲得对不对、逻辑顺不顺——那还是人的事。工具能做的,是把人从对齐字号里解放出来。


参考

  • 产品:https://aipptmaker.ai/?mode=agent
  • OOXML 规范:ECMA-376 Part 1
  • 相关库:python-pptx、PptxGenJS、LibreOffice headless
Logo

一站式 AI 云服务平台

更多推荐