大数跨境

DSH插件开发实录-从零搭一个AI生成PPT的工具

DSH插件开发实录-从零搭一个AI生成PPT的工具 创见AI实验室
2026-10-10
11
导读:这篇文章讲的是在 DSH 里"造一个会写 PPT 的小插件"的真实过程:从一个死板的早期版本,逐步换工具链、加工程化能力,到现在跑出和参考级 deck 接近的产物。

这篇文章讲的是我最近在 DSH 里"造一个会写 PPT 的小插件"的真实过程:从一个死板的早期版本,逐步换工具链、加工程化能力,到现在跑出和参考级 deck 接近的产物。文里所有插图都来自真实跑通的代码、真实的 .pptx 文件,文中不展示超链接,需要的请按文中的项目名自行搜索。

前置说明:这个插件目前还在完善中,暂时不会开源。写出来是想把"真实路径"摆出来,欢迎有经验的朋友交流思路——这个路线我自己走完仍然觉得"差得远",尤其是"AI 输出稳定好看"和"流截断容错"这两块,欢迎评论或私信分享你的方案。


0. 起因:DSH 用了一段时间,最后留下来的插件都是自己写的

自 DeepSeek Harness 开源以后,我就一直在尝试用它做各种日常开发的事。期间也装过不少社区插件——但是陆续都卸载了。最真实的体会:适合自己的才是最好的。尤其是 DSH 提供了创造模式以后,基于自己日常工作习惯来创建的插件才是真正的效率神器。

朋友经常要做 PPT,最近找过来想让我帮他做一个公司内部可以稳定、长期用的「AI 做 PPT」小工具。他之前试用过好几款付费产品,但来回换着订阅、续费、迁数据,很烦。于是想让我做一个"装在 DSH 里、公司内网就能跑"的版本给他用。

关于 PPT 制作,其实我最初的思路是开发一个独立的 Web 系统:前端表单收集主题和材料,后端调 LLM 再渲染成 PPTX。但认真推演了一遍就放弃了——Web 系统要自己做交互、做模型接入、做文件管理,光"能用"就要写一堆和业务无关的代码,后面维护更是个长期负担。最终决定以 DSH 插件的形式承载:交互有 DSH 的界面框架,模型接入有 DSH 的 LLM 服务,文件输出有 DSH 的本地能力——chat AI 功能 DSH 本身已经很优秀,可以少走很多弯路。而且这样沉淀下来的需求,以后还可以拆成不同的插件各自演进。

于是我按这条路先做了一版。结果做出来的东西很死板。后来发现 hugohe3 的 ppt-master 仓库(一个独立的、给 AI Agent 用的 PPT 创作 skill)解决了同一件事但效果好得多,于是把它的工具链搬进了 DSH 插件。这就是本文要讲的事——一条走了弯路、最后才换轨的路径。


1. 两条技术路径的对比

我先解释一下为什么前期那么糟糕、后来又为什么值得做。两条路径对比放在一起很直观:

路径 A:LLM 写 JSON + python-pptx 排版

最朴素的方案。让 LLM 输出一个结构化 JSON(title / bullets / body 等字段),python-pptx 收到后按模板填色块、加文字。

这条路的好处是写起来快——schema 几行,模板一段。但是产物很死板:

  • 文字密度大,视觉留白靠模板硬塞
  • 视觉语言单一——不管什么主题,出来的都是「白底 + 蓝强调色 + 微软雅黑」
  • 偶尔能塞一张图位占位框,但本质还是文字堆

我当时跑出来的东西长这样(v0.3 时期):


路径 B:hugohe3 的 ppt-master 路线 —— 视觉设计在 SVG 里,工具链翻译成原生 PowerPoint

直到我看见 hugohe3 的 ppt-master 仓库示例页——那批 deck 一看就和「程序员 PPT」不是一回事:


这批 deck 的设计哲学和路径 A 正好反过来:

  • 视觉设计放在 SVG 里
  • 用 svg_to_pptx.py 把 SVG 逐元素翻译成原生 DrawingML 形状
  • <rect> → Rectangle,<path> → Freeform,<text> → TextBox
  • 颜色直接用 #RRGGBB,1 EMU 不差

具体能做出什么、什么边界、什么"明确不做",可以去读 hugohe3 的 ppt-master 仓库 roadmap 文档(按 Ctrl+F 搜 "ppt-master roadmap" 就能找到 GitHub 仓库 docs/zh 目录下的 roadmap.md)。这里最重要的两条结论我直接引用:

「主轴是原生深度:逐版本创作或保留更多 PowerPoint 自身的对象模型、行为与可复用结构——持续向 PowerPoint 本身靠拢。」

「产品形态明确为运行在支持 Agent 的 AI 工具中的对话式工作流 / skill。不会做:独立 CLI、SaaS Web 服务、Electron 桌面壳。所有『让它脱离 chat 独立运行』的提案都会被拒。chat 是交互核心,不是包装层。」

第二条直接决定了我的工作方式:ppt-master 不可能是一个独立 CLI 工具——但它可以作为一个 Python 包被 DSH 插件 host 端调起。DSH 插件的"host 端"恰好就是这种"在 AI 工具里跑代码"的角色,完美匹配。

发现它的优点以后,再集成进来才真正形成可用的插件——先有 A 路径的失败、看到 B 路径的好处、才决定换轨。


2. 工具链打包进 DSH 插件

DSH 插件本身不复杂:一个 npm 包 + 一份 cordis.patch.yml,声明一行 entry,host 端 JS 加载后往 cordis context 注册服务。

具体的整合工作分三块:

(1) 把 ppt-master 整个 Python 包打包进插件目录

xiaochuang-docs/ppt-master/scripts/ 里就放了 svg_quality_checker.py + svg_to_pptx.py 以及它们依赖的 ~70 个文件。最终的 npm tarball 大约 4MB(去掉了 docs/ projects/ tests/ 这些用不上的子目录)。

(2) 写一个本地的"假 npm registry"

DSH 的 plugin_manager 通过 npm 装包,但 ppt-master 不在 npm 公共 registry。所以我搭了个 Python 起的 http server(30 行),监听 127.0.0.1:47231,把我本地的包目录打成 tgz 提供。这样 plugin_manager install xiaochuang-docs 就能装上。这个本地 registry 一直跑着,每次 bump 版本就重新打 tgz。

(3) 安装 Python 依赖

ppt-master 需要 python-pptx、skia-pathops、uharfbuzz、Pillow 等。一条 pip install -r ppt-master/requirements.txt 搞定。DSH 插件的 peerDependencies 写了 @deepseek-ai/cordis,但不写 Python 依赖——config.pythonCmd 默认 python,调用方自己装。


3. 让 DSH 知道有个叫"小创文档"的客户端

DSH 客户端插件通过 slot 系统挂载——在 apply(ctx) 里调 ctx.slots.register(...) 把自己的 React 组件塞到 DSH 早已定义好的槽位上。

这个插件用了两个槽位:

  • sidebar.panellist —— 在侧栏加一个图标按钮(烧瓶 + 文档 SVG)
  • main —— 点了图标就显示中央面板(key 与 panellist 的 id 一致就行)

客户端 bundle 声明依赖 slots 服务。整个过程插件不需要"侵入" DSH 主程序——这正是 DSH 槽位机制设计得好的地方。


4. 关键技术节点

插件从 v0.1 走到 v0.6.5,每一步都是为了解决"上一个版本跑出来不像 PPT"的某个具体问题。核心是几条工程化防线,按重要性排:

4.1 LLM 中段截断的容错(v0.3 起)

LLM 流式输出里"写到一半 finish"是高频事件。JSON 没写完就 的情况特别常见——{ "slides": [{ "file": "slide_1.svg", "svg": "..."}, { "file": "slide_2.svg", "svg": "<svg ...><rec —— 然后没了。

我做了 7 重容错,逐级放宽:

  1. 先把 ```json 围栏和控制字符剥掉
  2. 整段 [first, last+1] 试解析
  3. 扫描每个独立的 {...} 块按长度倒序试
  4. 关键一步:定位 slides 数组 + 单独 parse 一次(很多时候外层 JSON 坏了,但 slides 数组本身是完整的)
  5. 如果 slides 数组也没闭合:扫描到最后一个完整的 },截下来
  6. 数组内逐个页对象挑完整闭合的 {...} 拼回
  7. 实在不行报清晰错误,附上原始内容前 500 字符

第 4-6 步是这个版本最值的——LLM 流截断几乎都死在 slides 数组末尾,这部分能拼回,用户至少拿到一份能用的 deck。

4.2 SVG XML 自愈(v0.6.5)

LLM 偶尔输出XML 标签未闭合的 SVG。xml.etree.ElementTree.parse() 直接抛 mismatched tag,整次生成断在 svg_quality_checker 阶段。

我的策略:写入 project 之前先用纯 JS 做一层标签栈修复:

  • 剥控制字符(保留 \t \n \r)
  • 找最外层 <svg ...> 与最后一个 </svg> 边界
  • 扫描 body 里所有开标签 / 闭标签,开标签(非自闭合)压栈,闭标签弹到匹配项(容忍嵌套错乱)
  • 末尾未闭合的栈标签自动补</tag>

实测:缺 </g>、缺 </text>、末尾截断这些场景 95% 都能修好;只有"标签真的乱序"救不回来(极少见)。剩下救不回的才用最小占位 SVG 兜底。

4.3 点击立刻写历史 + 进度条(v0.5.x)

8 张 SVG + 3 步流程跑一次 10-60 秒,用户盯着空按钮会以为卡死。方案:

  • 点生成瞬间写历史 status: "generating"(切换菜单不丢)
  • Host 每阶段原地更新同一条历史的 stage(outline → quality → convert → done)
  • 客户端 1.5s 轮询 GET /api/history?id=<requestId> 拉 stage,画三阶段进度条

历史卡按状态着色:生成中黑边、失败红边、成功绿边——一眼区分。


4.4 风格模板(v0.6)

LLM 输出 SVG 已经像样了,但风格单一——每次都是「白底 + 蓝强调色 + 微软雅黑」。hugohe3 的 ppt-master-examples 仓库里有 60 多个示例 deck,覆盖 8 种典型视觉语言:学术蓝图、瑞士网格、数据新闻、毛玻璃 SaaS、孟菲斯、像素风、剪纸夜色、品牌红。

做法:

  • 每个风格下载一张"内容页 SVG"(不是封面——封面是 AI 配图,结构信息少)
  • 剥离 <image> 元素(占体积 95%,对 few-shot 无用)
  • 写一份蒸馏的 meta.json(label + styleName + summary + 来源 + 致谢)
  • 选完后把 6-22KB 的参考 SVG 作为 few-shot 嵌进 LLM 的 user prompt

效果是同主题不同风格能跑出截然不同的视觉走向——这是 prompt 字面描述做不到的。

学术蓝图风格

深蓝底 + 白色/青色线框 KPI 卡 + 时间线节点,和「自由发挥」的白底风格截然不同——few-shot 参考 SVG 真正传递了视觉语言。

毛玻璃风格

UI 上把"风格"色板和"风格模板"合并成互斥状态:选了模板就禁色板(视觉上 50% 透明 + cursor:not-allowed),切回"无(自由发挥)"色板自动恢复。语义清楚:模板是接管者,色板是被接管者。


5. 完整版本演进

版本
关键变化
v0.1
LLM 写 JSON + python-pptx 排版。颜色只有三套。产物能看但"平"。
v0.2
风格/密度/受众选项加入;JSON 解析容错 7 重;中段截断时尽量拼回。
v0.3
历史 Tab + 文件下载 + 配置持久化。
v0.4
7 个版式(cover/agenda/cards/chart/diagram/quote/closing),prompt 改成"看见式"导赏者写法。这版一节代码都没真用上——直接被 v0.5 替代。
v0.5
换轨道
:直接打包整个 ppt-master 工具链,LLM 改画 SVG,svg_to_pptx 翻译成原生形状。
v0.6
8 套 ppt-master-examples 风格模板(few-shot 注入 prompt);风格模板/色板互斥 UI。
v0.6.4
写入前 Python ET 校验每张 SVG,坏的那张用最小页 SVG 兜底。
v0.6.5
纯 JS SVG 标签自愈:剥控制字符 + 补全未闭合标签。多数 LLM 偶发能直接修好。

每一次升级都不"换主题"——v0.4 那 7 个版式看上去很完整,但最后没用上。判断哪个版本该走的方向,靠的不是想法好不好,是拿到真实生成物。我看到 v0.5 的 3 页 PPT 内部 XML 真的含 Freeform/Group 时,就知道这条路对了。


6. 现在的状态和接下来的事

真实状态:还差得远。 一期只做 PPT 生成,模板套用、编辑现有 .pptx、套公式、AI 生图配图——这些 ppt-master 都已经做了,但我都还没集成。尤其是稳定好看这一块:当前 LLM 输出的 SVG 风格密度远不如参考 deck,跑十次会有两三次出现奇怪的布局(这就是为什么我做了 SVG 自愈和 fallback)。

暂时不会开源。 这个插件目前只在我和朋友的本地环境跑,有两个原因:一是稳定性还差(如果别人装上跑不通我得花时间支持);二是很多东西是绑个人工作流的硬编码(保存目录、模型选择、风格模板的偏好)。等它真能在多种主题/多模型下稳定出参考级品质再说。

但这次写出来不是藏着掖着——以下几件事,如果你有经验,欢迎评论或私信交流(公众号后台回复即可):

  1. 「AI 输出稳定好看」 是这整套思路最大的瓶颈。我的 few-shot + SVG 自愈只解决了"输出能跑通",没解决"输出稳定好看"。你做 AI 画图 / 设计类工具时,怎么稳态控制视觉风格?
  2. 流截断容错 我用的 7 重 JSON 容错 + 标签自愈是 ad-hoc 的。你有没有更系统的方法处理"长流 LLM 输出不可靠"这个普遍问题?
  3. prompt 与 token 经济 — few-shot 注入 6-22KB 参考 SVG 是有效但贵。有没有更紧凑的"风格迁移"做法(风格 ID 编码?embedding 检索?)
  4. DSH 客户端 bundle 的可视化 — 我现在用 React.createElement 手写 UI(不用 JSX 因为 ModuleLoader 形式 bundle 不能走 Vite/Next 编译)。维护体验差。有没有更现代的客户端开发姿势?

7. 写在最后

DSH 是个克制的好工具——它不抢用户的工作流,只在用户愿意的地方插入能力。这种克制让"自造插件"成为它的第一公民。我现在的结论是:DSH 的可玩性不在它自带多少插件,而在它让你多快能造一个真正解决自己问题的插件。

我希望这个文章能讲清楚两件事:

  • 路径很重要。先选对工具链,再调 prompt;"AI 写 JSON + 排版"的上限就是 schema,决定了就不能靠"调 prompt 更好"。
  • 工程化容错是必须的。LLM 流的不可靠性不会因为你换更好的模型就消失,所有生产级 LLM 应用都得有一层"生成的产出物可不可信"的自检 + 修复 + fallback 流水线。ppt-master 的 svg_quality_checker 给了我这个流水线,剩下都是我自己的加项。

如果你也在用 DSH,聊聊你的插件、聊聊你走的路。

精选系列





【声明】内容源于网络
0
0
创见AI实验室
创见AI实验室,我们不只是介绍工具,我们共同创造工作方式的未来。
内容 216
粉丝 0
创见AI实验室 创见AI实验室,我们不只是介绍工具,我们共同创造工作方式的未来。
总阅读16.4k
粉丝0
内容216