简介这份资源面向需要快速产出专业演示文稿的开发者、职场人士与学生提供一套用大模型生成PPT的可运行源码方案。核心思路是先明确主题、内容与格式需求再借助DeepSeek等大模型生成结构清晰的Markdown大纲最后通过Kimi、通义千问或Coze等工具一键转换为PPT并支持后续版式、图表与动画的个性化调整。压缩包共3个文件以html页面、inscode工程配置与gitignore忽略规则为主整体约6KB体量轻巧便于直接运行与二次修改。已有241人学习关注读者可据此掌握从需求梳理、大纲生成到成品输出的完整链路理解Markdown作为大模型与PPT之间桥梁的作用并借助开源代码快速搭建自己的文档生成环境降低PPT制作的技术门槛提升内容策划与展示效率。1. 大模型生成PPT这件事到底卡在哪一步用大模型生成PPT很多人第一次试完的感受是文字挺像样排版一塌糊涂。你给它一段需求它哗哗输出一堆大纲和要点可一旦要落到真正的幻灯片文件上要么是纯文本堆在页面上要么是每页字数爆炸、层级混乱最后还得手动返工两小时。问题不在模型不会写内容而在于「内容生成」和「文件生成」之间缺了一层结构化的桥。这个标题要解决的就是这层桥让大模型输出的不是一段散文而是一份可被程序解析的页面结构再由代码把它渲染成真正的 .pptx 文件。适合两类人——一类是想给自己或团队做个自动化周报、方案初稿工具的开发者另一类是想搞清楚「大模型 文档生成」这条链路怎么搭、参数怎么控的工程师。读完你应该能自己跑通一条最小可运行链路并且知道哪里最容易翻车。2. 先定结构再谈生成为什么不能让模型直接吐PPT2.1 直接让模型输出pptx字节流是条死路最常见的错误思路是让大模型直接生成一个 .pptx 文件的二进制内容或者一段 python-pptx 的完整脚本。前者模型根本做不到它输出的是 token不是二进制后者看似可行但模型写出的脚本经常引用不存在的 API、参数顺序错乱、循环边界写错你调试脚本的时间比自己做 PPT 还长。正确的分工是模型只负责它擅长的事——把模糊需求拆成有层级的标题、要点、备注程序负责它擅长的事——把这些结构化数据映射到版式、字体、占位符。中间用一份约定好的 JSON schema 做契约。这样模型换了、版式换了两边互不影响。我一般会把 schema 定成「幻灯片数组」每张幻灯片有 layout 类型、title、bullets 数组、可选的 notes。bullets 支持一层嵌套就够了再深用户也看不清。这个 schema 一旦定下来后面所有 prompt 都围绕它写模型输出稳定性会明显提升。2.2 一份能落地的JSON结构长什么样先看结构定义这是整条链路的地基。字段不要贪多够用就行多一个字段就多一个模型填错的机会。{ deck_title: 季度技术复盘, slides: [ { layout: title, title: 季度技术复盘, subtitle: 某研发小组 · 内部初稿 }, { layout: bullets, title: 本季度三个主要进展, bullets: [ 构建流程耗时从 12 分钟降到 4 分钟, 核心模块测试覆盖率提升到 78%, 线上告警数量环比下降 40% ], notes: 重点讲第一条其余带过 } ] }逻辑说明layout是渲染时的分发依据title 页和内容页走不同分支bullets用字符串数组而不是对象数组是为了降低模型输出复杂度嵌套层级靠字符串前缀或单独字段控制。notes是演讲者备注很多人生成时忘了这块其实备注才是大模型最能发挥的地方。参数说明layout建议只保留三到四种取值比如 title、bullets、two_column、section取值越多模型越容易选错。bullets单页建议限制在 3 到 5 条超过就拆页这个约束要写进 prompt不能指望模型自觉。2.3 用prompt把模型约束到schema上光有 schema 不够得让模型知道必须按这个格式输出。常见做法是在 system prompt 里给出 schema 示例并明确要求「只输出 JSON不要任何解释文字」。下面是我常用的 prompt 骨架。SYSTEM_PROMPT 你是一个PPT大纲生成助手。 根据用户需求输出严格的JSON不要输出任何多余文字、不要用markdown代码块包裹。 JSON结构如下 { deck_title: 字符串, slides: [ {layout: title, title: 字符串, subtitle: 字符串}, {layout: bullets, title: 字符串, bullets: [字符串], notes: 字符串} ] } 约束 1. 每页bullets不超过5条每条不超过30字。 2. 第一页必须是layout为title的封面。 3. 总页数控制在8到15页。 def build_messages(user_need: str): return [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_need}, ]逻辑说明把 schema 直接写进 system prompt比事后用正则去修更省事。约束条目要具体到数字模型对「不超过5条」的执行率远高于「简洁一些」。build_messages单独抽出来是为了后面接不同模型时只改这一处。参数说明如果用的模型支持 JSON mode 或结构化输出务必打开能省掉大量解析失败的兜底逻辑。温度建议设低0.2 到 0.4 之间太高会让模型在字段名上自由发挥。max_tokens 要留够一份 12 页的大纲通常需要 1500 到 2500 token。3. 从JSON到pptx渲染层的实现与参数3.1 用python-pptx搭一个最小渲染器拿到 JSON 之后渲染这步用 python-pptx 就够了不需要更重的方案。核心思路是遍历 slides按 layout 分发到不同函数。下面是一个能跑的最小版本。from pptx import Presentation from pptx.util import Pt def render_deck(data: dict, out_path: str): prs Presentation() # 使用内置版式0为标题页1为标题内容 layout_title prs.slide_layouts[0] layout_bullets prs.slide_layouts[1] for slide in data[slides]: if slide[layout] title: s prs.slides.add_slide(layout_title) s.shapes.title.text slide[title] s.placeholders[1].text slide.get(subtitle, ) elif slide[layout] bullets: s prs.slides.add_slide(layout_bullets) s.shapes.title.text slide[title] body s.placeholders[1].text_frame body.clear() for i, item in enumerate(slide[bullets]): p body.paragraphs[0] if i 0 else body.add_paragraph() p.text item p.font.size Pt(20) if slide.get(notes): s.notes_slide.notes_text_frame.text slide[notes] prs.save(out_path)逻辑说明slide_layouts[0]和[1]是默认模板里的封面页和内容页直接复用能省掉手动摆文本框的麻烦。body.clear()很关键占位符默认带一个空段落不清掉会多出一行空白。备注写入notes_slide导出后演讲者视图能看到。参数说明Pt(20)是正文字号中文建议 18 到 22英文可以小一点。如果要点文字偏长字号要相应下调否则会溢出文本框。out_path记得带 .pptx 后缀python-pptx 不会自动补。3.2 版式映射内置layout不够用怎么办内置版式只有那么几种实际项目里往往需要自定义。常见做法是准备一个模板 .pptx 文件在里面把母版和占位符设计好代码里用Presentation(template.pptx)打开再按占位符索引或名称填充。prs Presentation(template.pptx) # 按占位符名称定位比索引更稳 def get_placeholder(slide, name): for ph in slide.placeholders: if ph.name name: return ph return None逻辑说明用名称定位比用索引稳因为模板改版时索引会变、名称一般不动。模板里给每个占位符起个有意义的名字比如 title、body、footer代码可读性会好很多。参数说明模板文件要放在代码能找到的路径部署时别漏了它。如果模板里用了特殊字体目标机器没装会回退重要场合建议把字体嵌入或用通用字体。3.3 中文字体和溢出这两个坑要提前处理中文场景下字体和溢出是最常见的两个翻车点。默认模板的字体对中文支持一般字号稍大就换行、稍长就溢出。我的做法是在渲染时统一设置字体并对超长文本做截断或降字号。from pptx.util import Pt from pptx.dml.color import RGBColor def style_run(run, size20, boldFalse): run.font.size Pt(size) run.font.bold bold run.font.name 微软雅黑 # 换成目标环境确定存在的字体 run.font.color.rgb RGBColor(0x33, 0x33, 0x33)逻辑说明font.name只对西文生效中文要额外设置run.font._rPr里的 east asian 字体或者干脆在模板母版里设好。颜色用深灰比纯黑柔和投影时更耐看。参数说明字号和文本框宽度要匹配经验值是每行中文不超过 18 到 20 字。超过就拆成两条要点别硬塞。截断是下策拆条才是上策。4. 避坑与排查生成PPT最容易翻车的五个地方4.1 模型输出带markdown代码块导致解析失败现象json.loads报错提示第一个字符是反引号。原因模型习惯性把 JSON 包在 json 里。解决解析前先剥掉代码块标记或者用正则提取第一个{到最后一个}之间的内容。更稳的做法是开 JSON mode从源头杜绝。4.2 字段名漂移这次叫bullets下次叫points现象渲染时报 KeyError。原因prompt 里没把字段名钉死模型自由发挥。解决在 system prompt 里明确「字段名必须完全一致」并在解析后做一次字段校验缺字段就补默认值或重试一次。别指望一次成功重试逻辑是必需品。4.3 单页要点过多导出后文字溢出页面现象PPT 打开后文字跑到页面外。原因模型没遵守条数和字数约束。解决渲染前做一次校验超过 5 条或单条超过 30 字就自动拆页或截断。校验放在渲染层不要只依赖 prompt。4.4 中文字体在别人机器上显示成方块现象自己电脑正常发给同事全是方框。原因目标机器没装你用的字体。解决用系统通用字体或者在模板里嵌入字体。重要交付前找一台干净环境试开一次这个后悔药没有。4.5 备注丢失或串页现象演讲者备注对不上内容。原因notes 字段在拆页或重排时没跟着走。解决把 notes 和 slide 绑在同一个对象里任何拆页操作都同步复制 notes。别用两个平行数组存迟早对不上。5. 进阶让生成质量再上一个台阶的几个技巧5.1 两段式生成先出大纲再逐页扩写一次性让模型生成整份带细节的 PPT页数一多质量就下滑。更稳的做法是两段式第一段只生成页面标题列表第二段对每页单独扩写要点。这样每页的上下文更聚焦要点质量明显更好。def gen_outline(need: str): # 第一段只要标题列表 prompt f根据需求生成PPT页面标题列表每行一个共8-12个{need} return call_llm(prompt).splitlines() def gen_slide_detail(title: str, need: str): # 第二段单页扩写 prompt f为标题「{title}」生成3-5条要点每条不超过30字背景需求{need} return call_llm(prompt)逻辑说明拆成两步后每步的 prompt 更简单模型出错概率下降。代价是调用次数变多成本上升但对质量敏感的场景值得。参数说明第一段温度可以稍高0.5 左右让标题更有想法第二段温度调低0.2 到 0.3保证要点收敛。两段的模型可以不同大纲用强模型扩写用便宜模型。5.2 用校验函数兜住模型的自由发挥不管 prompt 写得多严模型总有概率跑偏。在渲染前加一层校验把不合规的输出挡在门外比事后手动改省事得多。def validate_deck(data: dict) - list: errors [] if slides not in data or not data[slides]: errors.append(缺少slides字段或为空) return errors for idx, s in enumerate(data[slides]): if layout not in s or title not in s: errors.append(f第{idx1}页缺少layout或title) if s.get(layout) bullets: bullets s.get(bullets, []) if len(bullets) 5: errors.append(f第{idx1}页要点超过5条) for b in bullets: if len(b) 30: errors.append(f第{idx1}页存在超长要点) return errors逻辑说明校验函数返回错误列表为空才继续渲染否则触发重试或人工介入。把规则写成代码比记在脑子里可靠。参数说明条数和字数阈值按你的模板调整模板宽就放宽一点。校验失败的重试次数建议设 2 次再多就是模型能力问题换模型比死磕划算。5.3 一个我踩过的坑别在渲染层做内容决策早期我图省事在渲染函数里判断「这条要点太长就自动截断」。结果截出来的句子语义断裂读起来莫名其妙。后来改成渲染层只负责画内容层面的取舍全部交给生成层或校验层。职责一旦混在一起出了问题你都不知道该改哪。现在我的习惯是任何一条链路先画清楚「谁产出、谁校验、谁渲染」三段每段只干一件事。这个习惯帮我省下了大量排查时间。希望帮到你。本文还有配套的精品资源点击获取