说实话,做播客这件事最劝退我的不是写稿,也不是录音,是后面那串永无止境的后期流程。你可能花三小时录音,然后要花一晚上剪掉那些“嗯”“啊”和吸气声,导出、压响度、做封面、传平台、填RSS,一套流程走下来,想做的第二集已经被劝退了。我一直在琢磨能不能做一个工具,让播客生成变成“输入主题、按回车、拿成品”的流程。这个想法后来落成了一个项目,叫podcast-maker,最近它刚更新到1x版本,也是我第一次敢把它拿出来见人的版本。这篇文章先聊聊我为什么要做这个工具,再说这次更新改了哪些关键位置,最后把整个跑通流程和踩坑经验一起放出来。如果你也在做内容批量生产,或者正被播客的剪辑和发布流程折磨到焦头烂额,这篇应该能帮你少走不少弯路。1. 为什么偏要做podcast-maker:播客制作链条上的真实痛点1.1 传统播客工作的完整流程有多重先来梳理一下,一次正经的播客发布到底包含哪些环节。首先是选题和写稿,哪怕你有访谈嘉宾、不写逐字稿,你也要准备问题大纲、开场白、结尾话术,这些内容敲出来少说两三个小时。然后是录音,录音这件事最大的问题不是“录”,而是“录了不满意”要重来——嘴瓢、环境噪音、语速忽快忽慢,一小时底稿往往对应两小时的素材。真正折磨人的是剪辑。去掉停顿、去掉口误、调节音量、加背景音乐、做淡入淡出,新手做一期20分钟的节目,剪三四个小时很正常。剪完之后还有响度标准化,不同平台对音频响度有不同要求,声音忽大忽小非常劝退。再往后还有封面设计,标题文案,生成RSS feed,提交到音频平台,等待审核。我算过一笔账:一期20分钟的单人播客,如果全程自己动手,从零到上线至少要花六到八小时。这个成本对一个想保持周更的内容创作者来说,几乎是不可持续的。这也是为什么很多人做播客做几期就停更了,不是没有表达欲,是被流程打败了。1.2 podcast-maker 的定位与需求拆解既然痛点在流程冗长,那核心思路就是把它拆成五个可自动化的模块:脚本生成、语音合成、音频拼接、元数据输出、发布辅助。用户只需要给一个主题和大概时长,工具负责把脚本写好、声音合好、封面和RSS生成好,剩下的人工操作只有“试听”和“提交”。设计上我给自己定了三个原则:配置化、可复现、中间产物可检查。配置化意味着音色、语速、背景音乐、输出目录都通过配置文件控制,而不是写死在代码里;可复现意味着每次生成的音频、文本、RSS都保留在本地,方便回溯和重新发布;中间产物可检查更关键,脚本生成完之后你要能预览,TTS合成完之后你要能试听,不能一股脑跑完再发现内容不对,那样浪费的是真金白银的API费用。技术栈上我选了Python做主力:把LLM生成脚本的请求、TTS合成音频的调用、音频处理命令、XML模板渲染全部串起来,胶水语言干这件事最顺手。语音合成我没有用还不太成熟的本地模型,而是接了云厂商的TTS接口,稳定性和音色数量都有保障。音频处理依赖开源命令行工具,静态图片用Pillow画一张简单的封面,RSS用Jinja2模板渲染。整体思路不复杂,但模块之间的边界一定要清晰,否则后面每次更新都像踩地雷。2. 1x更新到底动了什么:双人对话、配置化音频与RSS生成2.1 从单主播到双人对话:多音色脚本引擎0.x阶段我只能生成单人旁白,听感很像纪录片解说,知识密度有,但吸引人很难。1x更新最重要的一笔是加入了双人对话模式:让脚本引擎输出带role标签的结构化文本,再绑定不同音色进行合成。实现上我拆成了两步。第一步用LLM生成对话大纲,明确这期节目分几段、每段聊什么;第二步再让LLM基于大纲补全具体对话,同时给出角色标记和情绪提示。输出格式我强制要求为JSON数组,每个元素包含role、text、pause三个字段,role决定用哪种音色,pause决定这句话说完后停顿多少毫秒。这个结构化约束非常重要,没有它,TTS合成时根本不知道怎么切分和分配音色。[ {"role": "host", "text": "今天我们来聊聊,为什么你总是三分钟热度。", "pause": 600}, {"role": "guest", "text": "这个问题我太有感触了,我买过的健身卡估计能铺满一张床。", "pause": 400}, {"role": "host", "text": "那正好,先说说你上一次坚持最久的一件事是什么?", "pause": 800} ]真实做下来,我发现一个容易忽略的细节:纯靠文字脚本生成对话,语气会非常书面化。必须给LLM补充口语化指令,同时我还在文案里混入一些语气词,比如“嗯”“确实”“不过话说回来”,这些词能让合成语音的自然度提升一个档次。TTS再怎么拟真,也救不了一篇像新闻通稿的文本。2.2 语音合成的配置化与稳定性修复以前音色和语速是写死在代码里的,每次调整都要改源码再重跑,太痛苦。这次我把语音参数全部抽到了配置文件中,支持speed(语速系数)、pitch(音调偏移)、pause(句间停顿秒数)、volume(音量增益)四项调节。参数取值范围我的默认值说明speed0.8 ~ 1.20.95略低于默认语速,听感更松弛pitch-2 ~ 200表示原始音高,微调可用于区分角色pause200 ~ 1000ms500句间停顿,长句建议加大volume0.8 ~ 1.51.0合成后再做增益,不推荐超过1.2语音合成本身我坚持按句合成,而不是按整段合成。原因有三个:一是每句之间需要精确控制停顿时间,保证对话感;二是单次请求长度有限,整段长文本容易触发截断;三是按句切分后,哪一句合成失败就重试哪一句,不会因为一个错字推翻整段重来。这版顺手修了几个之前遗留的问题。最常见的是生成脚本偶尔返回空列表导致整个流程崩溃,现在加了严格的结构校验和重试机制。还有超长段落被TTS服务截断的问题,我在切分chunk时按标点边界再次切分,并限制单条文本的最大字符数。另外以前偶尔出现角色切换时首字延迟,这次在切换音色前强制加一个短静音段,听感上反而更自然。2.3 音频后处理:响度、爆音与格式统一播客音频最容易被忽略的是响度。同一期节目里,一句话声音小像蚊子叫,下一句突然像打雷,这种体验非常糟糕。1x更新加入了响度归一化流程,目标值按播客行业常见标准来,参考-16 LUFS左右,同时峰值限制在-1 dBTP,防止声音过大爆音。处理链路是:先做静音修剪,把音频头尾和句间过长的静音段收紧;再做峰值限制,最后做响度测量和目标归一化。背景音乐的处理也单独做了参数化,音乐轨音量压制到比人声低一截,同时头和尾各加1.5秒淡入淡出,避免音乐突然出现和消失。这些音频处理全部通过开源命令行工具完成,流程稳定后基本不需要人工介入。这个环节容易犯的错是只做“均衡音量”不做“响度归一化”——前者只是把波形整体放大缩小,后者才符合流媒体平台的内容响度标准。用耳朵听觉得音量差不多,一到手机外放就发现声音闷或者刺耳,区别就在这。2.4 RSS与封面的一站式生成播客投递这件事,底层逻辑全靠RSS。主流音频平台不会自动收录你的音频文件,它们只认一个公开可访问的RSS地址。这次更新把RSS生成做成了模板渲染,只需要填上节目信息和每一期的音频文件地址,就能输出一个规范的RSS 2.0文档,并带上播客平台需要的itunes命名空间字段。RSS结构里容易漏的几个字段我用表格整理出来了:字段说明常见坑title / link / description节目基础三件套description不能为空字符串image节目封面URL尺寸需要大于1400x1400,且必须是绝对地址language语言代码写错可能导致审核不通过item > enclosure单集音频文件位置url必须能公网访问,length要填字节数itunes:duration音频时长格式必须是 HH:MM:SS,不能写明文数字itunes:category节目分类有些平台要求至少填一个分类封面生成我用了最简单的方案:一个固定背景模板,叠上节目标题文字,直接用Pillow画出来。不需要多好看,至少要规范。很多平台驳回节目不是因为音频内容,而是封面尺寸不够或者图片上有敏感文字,这种低级错误能省必须省。3. 完整实操:把podcast-maker跑起来3.1 环境准备与配置文件开始之前你需要准备三样东西:一个Python环境,一个能调用的LLM API密钥,一个云TTS服务密钥。另外记得安装开源音频处理工具,音频后处理依赖它。项目依赖我整理在requirements.txt里,一次性装好:pip install -r requirements.txt配置文件采用JSON格式,核心内容包括输出目录、默认音色映射、语速、并发数、缓存路径等。我把密钥全部放到环境变量里读取,不写进任何配置文件,避免不小心提交到仓库里泄漏。{ "output_dir": "./output", "default_voice": "zh-CN-Xiaoqiu", "voice_roles": { "host": "zh-CN-Yunxi", "guest": "zh-CN-Xiaoyi" }, "speech": { "speed": 0.95, "pitch": 0, "pause_ms": 500 }, "audio": { "target_lufs": -16.0, "peak_limit_dbtp": -1.0, "music_volume_ratio": 0.15 }, "concurrency": 4, "cache_dir": "./cache" }3.2 从主题到脚本:一次可复用的Prompt设计安装完成后,我一般这样发起一次生成:python make_episode.py --topic "如何养成阅读习惯" --minutes 15 --style dialogue这个命令会先生成脚本。很多第一次用的人会直接让LLM自由发挥,然后发现生成出来的内容根本没有结构。我踩过这个坑之后,把Prompt固定成了一个模板,核心约束是输出JSON、控制时长占比、强调口语化。你是播客编剧。请围绕主题《如何养成阅读习惯》创作一期15分钟的双人对话播客脚本。 要求: 1. 对话双方为主持人host和嘉宾guest,host负责引导节奏,guest负责给出真实故事和具体方法。 2. 总字数控制在1800字左右,分4到5个小节。 3. 语气必须口语化,避免书面语和形容词堆砌。 4. 输出JSON数组,每个元素必须包含role、text、pause三个字段。 5. 每句话控制在60字以内,方便语音合成。脚本生成完之后不要急着合成,先完整读一遍。这一步在本地检查的成本为零,但如果脚本逻辑不对、案例不准确,后面每一步都在浪费API费用。我自己的习惯是先人工润色一遍再进入合成,尤其是嘉宾说的话,适当加一些“我自己的经验是”“有一次,我突然发现”这种带入感强的表达。3.3 语音合成与音频拼接的实现逻辑脚本确认后进入合成环节。合成模块按句依次调用TTS接口,默认并发数4,每句合成成功后立即存到本地临时目录。如果单句失败,最多重试两次,仍然失败会把错误信息单独写到日志文件里,不会中断整个流程。缓存机制是我强烈建议保留的:同一句文本如果已经合成过,下次直接复用本地文件。这个设计在微调脚本内容、重复测试时能省下大量费用。音频拼接的逻辑是按脚本顺序遍历每一句的音色、时长和停顿参数,句间插入指定的静音段,角色切换时把静音段适当加大。背景音乐轨单独合成,音量按配置压低后混入人声轨,最后经过响度归一化输出成品MP3。做拼接时有个细节容易被忽略:每一句合成出来的音频尾音长短不同,如果全部用固定停顿时间,听感会像机器人一格一格地说话。我后来改成在短句拼接时额外补偿一点停顿,在长句结束检测到静音段后,取静音起点作为拼接点,这样节奏感会自然很多。3.4 生成RSS并提交到平台音频处理完之后,运行RSS生成命令,工具会自动根据config里的节目信息、封面地址、音频文件路径渲染一份feed.xml。在提交之前,先用浏览器或者RSS阅读器打开本地文件检查一遍,确认XML格式合法、enclosure的url是绝对地址、length确实是字节数。这三个问题在审核环节是最常见的打回原因。托管这一步没有太复杂的技术选择:RSS和音频文件通常放在同一个目录,然后用任意静态Web托管或对象存储暴露到公网即可。把生成的feed.xml地址复制出来,到目标平台的后台提交,平台验证通过后会返回一个预览地址。提交后一般不会立刻生效,等几个小时甚至一两天都是正常的,不用反复刷新。4. 踩坑实录:最常见问题与排查速查表4.1 合成音频出现吞字、变调与串音吞字最常见的触发点是文本里的数字、英文缩写和特殊符号。TTS在读“2025年第3期”的时候,可能直接忽略“第”和“期”,读成“二零二五年第三期”,或者英文单词被强行按字母逐个拼读。解决方法是合成前先做文本清洗:数字转成中文口语表达,英文缩写前后加空格,特殊符号替换成中文标点。另一个容易出问题的是切分chunk太激进,一句话中间被硬切导致语义断了,合成出来语调就会很奇怪。我的切分规则是按逗号、问号、叹号切分,顿号和分号不切。串音问题则通常出在并发合成后拼接顺序错乱。要确保最终拼接顺序严格按照脚本数组索引执行,并发只是用于加快合成速度,结果必须以index为基准归队。4.2 对话听起来像念稿,缺少人味儿这个问题的根源往往不是TTS选型,而是文本本身太书面。你可以做一个简单测试:把一段真实聊天记录丢进TTS,再把一段新闻稿丢进TTS,对比听感,差距非常大。所以我在Prompt里增加了“必须使用短句,每句话不超过60字”“尽量用第一人称讲小故事”“允许使用语气词”这些硬约束。另一个低成本有效的办法是调节停顿。把默认句间停顿从500ms调到700ms左右,让对话节奏慢下来,听感会松弛很多。语速从默认1.0降到0.92到0.95之间,也会少一点“念稿感”。如果觉得音色本身的情绪表现弱,可以在文本里加入问号和叹号来引导语调变化,这种符号对TTS的语调影响比想象中大。4.3 RSS提交被驳回的几种原因与自查清单音频平台审核播客节目,本质上只是自动检查RSS里的几个关键字段,并不复杂。我在提交中收到过几种典型驳回:驳回提示原因解决无法解析feedXML格式错误或编码不对用编辑器校验XML,确保UTF-8编码封面尺寸不足image字段图片太小重新生成1400x1400以上封面音频地址不可访问enclosure的url无法直接下载确保文件公开访问,且不要防盗链duration缺失item里没有itunes:duration补上HH:MM:SS格式时长内容分类缺失没有itunes:category至少填一个分类自查时可以先用命令行工具确认一下文件是否可访问,比如用HTTP请求头检查RSS和音频文件都返回200状态码,再逐个核对必填字段。RSS这种机器读的东西,字段差一个都会被平台识别出来,人工检查的时候一定要对着表格逐项过。4.4 TTS费用飞涨的常见原因与控制技巧云TTS按字符计费,看起来很便宜,但跑批量任务时数字会在不知不觉间变大。最浪费钱的是反复重试:脚本改了一句话,就把整段重新合成一遍。我第一次测试时,为了一句话的语气调整,前后重跑了五次整个流程,费用翻了好几倍。控制成本的核心是缓存和预览机制。缓存已经说过,同一句话重复生成不会二次扣费;预览机制指的是在合成前用dry-run模式跑一遍脚本,只打印生成计划,不实际调用TTS接口。另外建议把并发数控制在4到6,并发太高除了容易触发限流,还会在出错时产生大量无效请求。我还在日志里记录每次请求的字符数和预估费用,每次跑完扫一眼,心里就有数。还有一个容易忽略的坑:日志文件里记录API Key。在排查错误时如果直接粘贴日志给其他人看,密钥就泄露了。我后来在日志模块里加了脱敏逻辑,任何密钥字段输出时自动替换成星号,这个习惯建议从一开始就养成。最后的几点实际体会这个工具做到现在,我最深的感受是:自动化并没有取代创作,它只是把录音棚和剪辑台搬到了后台。脚本内容好不好、观点有没有价值,仍然由人的判断决定,但重复劳动确实被压缩到了极限。我现在做一期15分钟的节目,从输入主题到拿到可以提交的RSS,大概只要十几分钟,剩下的时间全花在审核脚本和试听成品上,这比以前动辄一天一夜的生产周期轻松太多了。如果你也想搭一套类似的东西,我建议不要一上来就追求全自动。先跑通“脚本生成+单人TTS合成+音频拼接”这个最小闭环,体验一遍完整流程,再逐步加上双人对话、背景音乐、RSS生成。每次只加一个模块,出了问题也好定位,不会拆成一团乱麻。后面我打算给交互加一个Web界面,让不熟悉命令行的朋友也能直接输入主题、选择音色、一键生成。再往后想加入批量处理能力,一口气生成一个系列节目,而不是一集一集地手动跑。工具能走多远,取决于它到底替你省下多少时间,而省下来的时间拿去打磨内容,才是做这件事真正有价值的地方。
说实话,做播客这件事最劝退我的不是写稿,也不是录音,是后面那串永无止境的后期流程。你可能花三小时录音,然后要花一晚上剪掉那些“嗯”“啊”和吸气声,导出、压响度、做封面、传平台、填RSS,一套流程走下来,想做的第二集已经被劝退了。我一直在琢磨能不能做一个工具,让播客生成变成“输入主题、按回车、拿成品”的流程。这个想法后来落成了一个项目,叫podcast-maker,最近它刚更新到1x版本,也是我第一次敢把它拿出来见人的版本。这篇文章先聊聊我为什么要做这个工具,再说这次更新改了哪些关键位置,最后把整个跑通流程和踩坑经验一起放出来。如果你也在做内容批量生产,或者正被播客的剪辑和发布流程折磨到焦头烂额,这篇应该能帮你少走不少弯路。1. 为什么偏要做podcast-maker:播客制作链条上的真实痛点1.1 传统播客工作的完整流程有多重先来梳理一下,一次正经的播客发布到底包含哪些环节。首先是选题和写稿,哪怕你有访谈嘉宾、不写逐字稿,你也要准备问题大纲、开场白、结尾话术,这些内容敲出来少说两三个小时。然后是录音,录音这件事最大的问题不是“录”,而是“录了不满意”要重来——嘴瓢、环境噪音、语速忽快忽慢,一小时底稿往往对应两小时的素材。真正折磨人的是剪辑。去掉停顿、去掉口误、调节音量、加背景音乐、做淡入淡出,新手做一期20分钟的节目,剪三四个小时很正常。剪完之后还有响度标准化,不同平台对音频响度有不同要求,声音忽大忽小非常劝退。再往后还有封面设计,标题文案,生成RSS feed,提交到音频平台,等待审核。我算过一笔账:一期20分钟的单人播客,如果全程自己动手,从零到上线至少要花六到八小时。这个成本对一个想保持周更的内容创作者来说,几乎是不可持续的。这也是为什么很多人做播客做几期就停更了,不是没有表达欲,是被流程打败了。1.2 podcast-maker 的定位与需求拆解既然痛点在流程冗长,那核心思路就是把它拆成五个可自动化的模块:脚本生成、语音合成、音频拼接、元数据输出、发布辅助。用户只需要给一个主题和大概时长,工具负责把脚本写好、声音合好、封面和RSS生成好,剩下的人工操作只有“试听”和“提交”。设计上我给自己定了三个原则:配置化、可复现、中间产物可检查。配置化意味着音色、语速、背景音乐、输出目录都通过配置文件控制,而不是写死在代码里;可复现意味着每次生成的音频、文本、RSS都保留在本地,方便回溯和重新发布;中间产物可检查更关键,脚本生成完之后你要能预览,TTS合成完之后你要能试听,不能一股脑跑完再发现内容不对,那样浪费的是真金白银的API费用。技术栈上我选了Python做主力:把LLM生成脚本的请求、TTS合成音频的调用、音频处理命令、XML模板渲染全部串起来,胶水语言干这件事最顺手。语音合成我没有用还不太成熟的本地模型,而是接了云厂商的TTS接口,稳定性和音色数量都有保障。音频处理依赖开源命令行工具,静态图片用Pillow画一张简单的封面,RSS用Jinja2模板渲染。整体思路不复杂,但模块之间的边界一定要清晰,否则后面每次更新都像踩地雷。2. 1x更新到底动了什么:双人对话、配置化音频与RSS生成2.1 从单主播到双人对话:多音色脚本引擎0.x阶段我只能生成单人旁白,听感很像纪录片解说,知识密度有,但吸引人很难。1x更新最重要的一笔是加入了双人对话模式:让脚本引擎输出带role标签的结构化文本,再绑定不同音色进行合成。实现上我拆成了两步。第一步用LLM生成对话大纲,明确这期节目分几段、每段聊什么;第二步再让LLM基于大纲补全具体对话,同时给出角色标记和情绪提示。输出格式我强制要求为JSON数组,每个元素包含role、text、pause三个字段,role决定用哪种音色,pause决定这句话说完后停顿多少毫秒。这个结构化约束非常重要,没有它,TTS合成时根本不知道怎么切分和分配音色。[ {"role": "host", "text": "今天我们来聊聊,为什么你总是三分钟热度。", "pause": 600}, {"role": "guest", "text": "这个问题我太有感触了,我买过的健身卡估计能铺满一张床。", "pause": 400}, {"role": "host", "text": "那正好,先说说你上一次坚持最久的一件事是什么?", "pause": 800} ]真实做下来,我发现一个容易忽略的细节:纯靠文字脚本生成对话,语气会非常书面化。必须给LLM补充口语化指令,同时我还在文案里混入一些语气词,比如“嗯”“确实”“不过话说回来”,这些词能让合成语音的自然度提升一个档次。TTS再怎么拟真,也救不了一篇像新闻通稿的文本。2.2 语音合成的配置化与稳定性修复以前音色和语速是写死在代码里的,每次调整都要改源码再重跑,太痛苦。这次我把语音参数全部抽到了配置文件中,支持speed(语速系数)、pitch(音调偏移)、pause(句间停顿秒数)、volume(音量增益)四项调节。参数取值范围我的默认值说明speed0.8 ~ 1.20.95略低于默认语速,听感更松弛pitch-2 ~ 200表示原始音高,微调可用于区分角色pause200 ~ 1000ms500句间停顿,长句建议加大volume0.8 ~ 1.51.0合成后再做增益,不推荐超过1.2语音合成本身我坚持按句合成,而不是按整段合成。原因有三个:一是每句之间需要精确控制停顿时间,保证对话感;二是单次请求长度有限,整段长文本容易触发截断;三是按句切分后,哪一句合成失败就重试哪一句,不会因为一个错字推翻整段重来。这版顺手修了几个之前遗留的问题。最常见的是生成脚本偶尔返回空列表导致整个流程崩溃,现在加了严格的结构校验和重试机制。还有超长段落被TTS服务截断的问题,我在切分chunk时按标点边界再次切分,并限制单条文本的最大字符数。另外以前偶尔出现角色切换时首字延迟,这次在切换音色前强制加一个短静音段,听感上反而更自然。2.3 音频后处理:响度、爆音与格式统一播客音频最容易被忽略的是响度。同一期节目里,一句话声音小像蚊子叫,下一句突然像打雷,这种体验非常糟糕。1x更新加入了响度归一化流程,目标值按播客行业常见标准来,参考-16 LUFS左右,同时峰值限制在-1 dBTP,防止声音过大爆音。处理链路是:先做静音修剪,把音频头尾和句间过长的静音段收紧;再做峰值限制,最后做响度测量和目标归一化。背景音乐的处理也单独做了参数化,音乐轨音量压制到比人声低一截,同时头和尾各加1.5秒淡入淡出,避免音乐突然出现和消失。这些音频处理全部通过开源命令行工具完成,流程稳定后基本不需要人工介入。这个环节容易犯的错是只做“均衡音量”不做“响度归一化”——前者只是把波形整体放大缩小,后者才符合流媒体平台的内容响度标准。用耳朵听觉得音量差不多,一到手机外放就发现声音闷或者刺耳,区别就在这。2.4 RSS与封面的一站式生成播客投递这件事,底层逻辑全靠RSS。主流音频平台不会自动收录你的音频文件,它们只认一个公开可访问的RSS地址。这次更新把RSS生成做成了模板渲染,只需要填上节目信息和每一期的音频文件地址,就能输出一个规范的RSS 2.0文档,并带上播客平台需要的itunes命名空间字段。RSS结构里容易漏的几个字段我用表格整理出来了:字段说明常见坑title / link / description节目基础三件套description不能为空字符串image节目封面URL尺寸需要大于1400x1400,且必须是绝对地址language语言代码写错可能导致审核不通过item > enclosure单集音频文件位置url必须能公网访问,length要填字节数itunes:duration音频时长格式必须是 HH:MM:SS,不能写明文数字itunes:category节目分类有些平台要求至少填一个分类封面生成我用了最简单的方案:一个固定背景模板,叠上节目标题文字,直接用Pillow画出来。不需要多好看,至少要规范。很多平台驳回节目不是因为音频内容,而是封面尺寸不够或者图片上有敏感文字,这种低级错误能省必须省。3. 完整实操:把podcast-maker跑起来3.1 环境准备与配置文件开始之前你需要准备三样东西:一个Python环境,一个能调用的LLM API密钥,一个云TTS服务密钥。另外记得安装开源音频处理工具,音频后处理依赖它。项目依赖我整理在requirements.txt里,一次性装好:pip install -r requirements.txt配置文件采用JSON格式,核心内容包括输出目录、默认音色映射、语速、并发数、缓存路径等。我把密钥全部放到环境变量里读取,不写进任何配置文件,避免不小心提交到仓库里泄漏。{ "output_dir": "./output", "default_voice": "zh-CN-Xiaoqiu", "voice_roles": { "host": "zh-CN-Yunxi", "guest": "zh-CN-Xiaoyi" }, "speech": { "speed": 0.95, "pitch": 0, "pause_ms": 500 }, "audio": { "target_lufs": -16.0, "peak_limit_dbtp": -1.0, "music_volume_ratio": 0.15 }, "concurrency": 4, "cache_dir": "./cache" }3.2 从主题到脚本:一次可复用的Prompt设计安装完成后,我一般这样发起一次生成:python make_episode.py --topic "如何养成阅读习惯" --minutes 15 --style dialogue这个命令会先生成脚本。很多第一次用的人会直接让LLM自由发挥,然后发现生成出来的内容根本没有结构。我踩过这个坑之后,把Prompt固定成了一个模板,核心约束是输出JSON、控制时长占比、强调口语化。你是播客编剧。请围绕主题《如何养成阅读习惯》创作一期15分钟的双人对话播客脚本。 要求: 1. 对话双方为主持人host和嘉宾guest,host负责引导节奏,guest负责给出真实故事和具体方法。 2. 总字数控制在1800字左右,分4到5个小节。 3. 语气必须口语化,避免书面语和形容词堆砌。 4. 输出JSON数组,每个元素必须包含role、text、pause三个字段。 5. 每句话控制在60字以内,方便语音合成。脚本生成完之后不要急着合成,先完整读一遍。这一步在本地检查的成本为零,但如果脚本逻辑不对、案例不准确,后面每一步都在浪费API费用。我自己的习惯是先人工润色一遍再进入合成,尤其是嘉宾说的话,适当加一些“我自己的经验是”“有一次,我突然发现”这种带入感强的表达。3.3 语音合成与音频拼接的实现逻辑脚本确认后进入合成环节。合成模块按句依次调用TTS接口,默认并发数4,每句合成成功后立即存到本地临时目录。如果单句失败,最多重试两次,仍然失败会把错误信息单独写到日志文件里,不会中断整个流程。缓存机制是我强烈建议保留的:同一句文本如果已经合成过,下次直接复用本地文件。这个设计在微调脚本内容、重复测试时能省下大量费用。音频拼接的逻辑是按脚本顺序遍历每一句的音色、时长和停顿参数,句间插入指定的静音段,角色切换时把静音段适当加大。背景音乐轨单独合成,音量按配置压低后混入人声轨,最后经过响度归一化输出成品MP3。做拼接时有个细节容易被忽略:每一句合成出来的音频尾音长短不同,如果全部用固定停顿时间,听感会像机器人一格一格地说话。我后来改成在短句拼接时额外补偿一点停顿,在长句结束检测到静音段后,取静音起点作为拼接点,这样节奏感会自然很多。3.4 生成RSS并提交到平台音频处理完之后,运行RSS生成命令,工具会自动根据config里的节目信息、封面地址、音频文件路径渲染一份feed.xml。在提交之前,先用浏览器或者RSS阅读器打开本地文件检查一遍,确认XML格式合法、enclosure的url是绝对地址、length确实是字节数。这三个问题在审核环节是最常见的打回原因。托管这一步没有太复杂的技术选择:RSS和音频文件通常放在同一个目录,然后用任意静态Web托管或对象存储暴露到公网即可。把生成的feed.xml地址复制出来,到目标平台的后台提交,平台验证通过后会返回一个预览地址。提交后一般不会立刻生效,等几个小时甚至一两天都是正常的,不用反复刷新。4. 踩坑实录:最常见问题与排查速查表4.1 合成音频出现吞字、变调与串音吞字最常见的触发点是文本里的数字、英文缩写和特殊符号。TTS在读“2025年第3期”的时候,可能直接忽略“第”和“期”,读成“二零二五年第三期”,或者英文单词被强行按字母逐个拼读。解决方法是合成前先做文本清洗:数字转成中文口语表达,英文缩写前后加空格,特殊符号替换成中文标点。另一个容易出问题的是切分chunk太激进,一句话中间被硬切导致语义断了,合成出来语调就会很奇怪。我的切分规则是按逗号、问号、叹号切分,顿号和分号不切。串音问题则通常出在并发合成后拼接顺序错乱。要确保最终拼接顺序严格按照脚本数组索引执行,并发只是用于加快合成速度,结果必须以index为基准归队。4.2 对话听起来像念稿,缺少人味儿这个问题的根源往往不是TTS选型,而是文本本身太书面。你可以做一个简单测试:把一段真实聊天记录丢进TTS,再把一段新闻稿丢进TTS,对比听感,差距非常大。所以我在Prompt里增加了“必须使用短句,每句话不超过60字”“尽量用第一人称讲小故事”“允许使用语气词”这些硬约束。另一个低成本有效的办法是调节停顿。把默认句间停顿从500ms调到700ms左右,让对话节奏慢下来,听感会松弛很多。语速从默认1.0降到0.92到0.95之间,也会少一点“念稿感”。如果觉得音色本身的情绪表现弱,可以在文本里加入问号和叹号来引导语调变化,这种符号对TTS的语调影响比想象中大。4.3 RSS提交被驳回的几种原因与自查清单音频平台审核播客节目,本质上只是自动检查RSS里的几个关键字段,并不复杂。我在提交中收到过几种典型驳回:驳回提示原因解决无法解析feedXML格式错误或编码不对用编辑器校验XML,确保UTF-8编码封面尺寸不足image字段图片太小重新生成1400x1400以上封面音频地址不可访问enclosure的url无法直接下载确保文件公开访问,且不要防盗链duration缺失item里没有itunes:duration补上HH:MM:SS格式时长内容分类缺失没有itunes:category至少填一个分类自查时可以先用命令行工具确认一下文件是否可访问,比如用HTTP请求头检查RSS和音频文件都返回200状态码,再逐个核对必填字段。RSS这种机器读的东西,字段差一个都会被平台识别出来,人工检查的时候一定要对着表格逐项过。4.4 TTS费用飞涨的常见原因与控制技巧云TTS按字符计费,看起来很便宜,但跑批量任务时数字会在不知不觉间变大。最浪费钱的是反复重试:脚本改了一句话,就把整段重新合成一遍。我第一次测试时,为了一句话的语气调整,前后重跑了五次整个流程,费用翻了好几倍。控制成本的核心是缓存和预览机制。缓存已经说过,同一句话重复生成不会二次扣费;预览机制指的是在合成前用dry-run模式跑一遍脚本,只打印生成计划,不实际调用TTS接口。另外建议把并发数控制在4到6,并发太高除了容易触发限流,还会在出错时产生大量无效请求。我还在日志里记录每次请求的字符数和预估费用,每次跑完扫一眼,心里就有数。还有一个容易忽略的坑:日志文件里记录API Key。在排查错误时如果直接粘贴日志给其他人看,密钥就泄露了。我后来在日志模块里加了脱敏逻辑,任何密钥字段输出时自动替换成星号,这个习惯建议从一开始就养成。最后的几点实际体会这个工具做到现在,我最深的感受是:自动化并没有取代创作,它只是把录音棚和剪辑台搬到了后台。脚本内容好不好、观点有没有价值,仍然由人的判断决定,但重复劳动确实被压缩到了极限。我现在做一期15分钟的节目,从输入主题到拿到可以提交的RSS,大概只要十几分钟,剩下的时间全花在审核脚本和试听成品上,这比以前动辄一天一夜的生产周期轻松太多了。如果你也想搭一套类似的东西,我建议不要一上来就追求全自动。先跑通“脚本生成+单人TTS合成+音频拼接”这个最小闭环,体验一遍完整流程,再逐步加上双人对话、背景音乐、RSS生成。每次只加一个模块,出了问题也好定位,不会拆成一团乱麻。后面我打算给交互加一个Web界面,让不熟悉命令行的朋友也能直接输入主题、选择音色、一键生成。再往后想加入批量处理能力,一口气生成一个系列节目,而不是一集一集地手动跑。工具能走多远,取决于它到底替你省下多少时间,而省下来的时间拿去打磨内容,才是做这件事真正有价值的地方。