做视频课程管理最耗时间的事情,就是把一小时的讲课内容变成一段能快速浏览的摘要和几个结构化的知识点。我这两年一直在折腾AI驱动的自动摘要流水线,核心就两件事:先用ASR把视频里的语音转成带时间戳的文本,再用LLM对文本做摘要和知识点提取。这条ASR + LLM流水线跑通之后,处理一节45分钟的课程,从原始视频到最终输出,人工只负责校对和审核,整体耗时从原来的两三个小时压到了十五分钟以内。
这个方案适合谁?如果你在做在线教育平台、知识付费课程、企业内部培训系统,或者你是一个需要定期把几十个视频课件整理成文档的课程运营,那这篇内容可以帮你省掉大量重复劳动。我会把流水线的技术选型、ASR转写工程化、LLM结构化输出、任务编排和排查经验全部分享出来,照着搭就能跑。
1. 先从业务痛点讲起:为什么需要ASR+LLM流水线
1.1 视频课程处理的三个老大难问题
课程视频不像文本,信息是线性流式存在的。用户想找某个知识点,只能拖动进度条盲猜;运营想给课程写简介,必须把整节视频看完;教研想评估课程质量,得手动记录时间点和内容。这三个问题本质上都是因为视频内容没有被结构化和索引。
人工处理一节课的成本很高,按45分钟课程粗略估算:完整听一遍至少45分钟,整理摘要和知识点还要30分钟以上,校对修改再算半小时,几乎所有运营都做不到每节课都处理。结果就是课程库里大量视频处于"无简介、无检索、无知识点"的三无状态。
我早期也试过纯人工协作,给每个课程配备一个编辑,用字幕文件做辅助,但速度依然跟不上更新频率。后来意识到,这类任务具备很强的重复性和规律性,完全可以用AI先跑一版,再由人审核兜底。关键不是让AI替代人,而是把人的时间从"逐字听写"中解放出来,集中到"内容质量判断"上。
1.2 技术选型思路:先把"听写"和"理解"分开
最初的方案是直接用多模态大模型处理视频,输入视频后让它生成摘要。实测下来问题很多:视频长度限制严重,45分钟视频大多数模型无法一次处理;即使能接受长视频,token成本高得吓人;模型对画面和语音混合内容的理解不稳定,容易出现关键信息遗漏。
于是我换了一条更朴素的路线:先通过ASR把语音转成文本,然后让LLM基于文本做理解。这样做有三层好处。第一,两个环节独立迭代,ASR准确率提升不会影响LLM,LLM升级也不需要重新转录。第二,文本是可审计的中间产物,人工可以只查转写稿来校对事实,甚至直接基于转写稿做修订。第三,基于文本可以做更多衍生,比如字幕生成、关键词检索、知识点切片、RAG知识库,这些都是多模态模型难以直接输出的结构化数据。
这个选择背后有一个基础认知:ASR解决的是"说了什么",LLM解决的是"什么意思"。这两个问题需要的模型架构和数据完全不同,硬揉在一起只会两头不讨好。把流程拆成流水线,每个环节各自用最合适的模型,反而更接近软件工程里的单一职责原则。
2. ASR转写工程化:别急着把文本丢给大模型
2.1 ASR模型怎么选:看清你的音频形态
ASR部分市面上可选的方案不少,我这里不打算做全量评测,只讲我在课程场景里的选型逻辑。课程视频的音频通常有几个特点:单人主讲为主、普通话居多(也可能有中英混讲)、音质比较干净、语速相对稳定。基于这些特点,我最常用的是两套模型,一套是faster-whisper,一套是FunASR。
faster-whisper是openai-whisper模型的CTranslate2加速版,在GPU上推理速度比原始whisper快很多,部署也比较简单,适合需要高精度、能接受一定资源消耗的团队。FunASR是阿里开源的语音识别工具包,中文效果不错,自带标点恢复和VAD模块,对国内课程场景开箱即用。如果你的环境是纯CPU推理,我会更推荐FunASR的小模型,速度能控制在实时率的数倍以上。
对于课程音频,ASR引擎不一定越大越好。我踩过一个坑:私自认为大模型准确率更高,结果发现whisper large-v3在专业名词上错误率反而高,因为模型没见过课程里的私有词汇。正确做法是先用小模型跑通流程,识别错误集中在专业词时,用热词表或上下文偏置去修正,而不是盲目换大模型。FunASR提供热词列表,whisper也可以通过prompt注入常用词,这两个手段的优先级远高于换模型。
注意,声音与画面分离的录屏视频,ASR只需要处理音轨,所以在进入模型前先用ffmpeg把音频单独抽取出来。这一步看似简单,但能显著降低预处理耗时和IO压力。
ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -f wav audio.wav这里我统一把音频转成16kHz单声道WAV,因为绝大多数ASR模型都是用这个采样率训练的。如果直接喂44.1kHz立体声,有的引擎会做隐式重采样,有的则不处理,识别效果就变得不可控。
| 方案 | 优势 | 适合场景 | 注意点 |
|---|---|---|---|
| faster-whisper | 精度高、支持批处理、社区生态好 | GPU资源充足、对错字敏感 | 需要额外做标点恢复 |
| FunASR | 中文效果好、自带VAD标点、CPU可跑 | 国内课程、普通话为主 | 长音频需要做切片 |
| 云端ASR API | 零运维、接口简单 | 快速验证、量不大 | 数据外送、按量计费 |
2.2 长音频切片与VAD过滤:解决漏字和重复
课程视频动辄一两个小时,直接把整段音频灌进ASR模型,会出现两个问题:显存或内存不够用,以及长音频尾部出现循环重复。我的处理流程是先用ffmpeg把音轨提取成16kHz单声道WAV,然后用VAD过滤掉静音段,再按检测到的语音段做切片和批处理。
VAD的加入非常关键。老师讲课过程中经常有停顿、喝水、翻页这些无语音片段,如果不切掉,ASR会产生大量空转或者胡乱识别。用silero-vad做端点检测,默认阈值0.5左右,在课堂场景下可以适当调到0.7,减少对收音噪声的敏感度。实测中,这个操作能让转写文本的无效内容减少约30%,同时节省计算时间。
切片策略我建议基于VAD的语音片段,而不是按固定长度硬切。硬切60秒一块虽然简单,但容易把一个完整句子从中间断开,导致后面LLM理解时上下文不连续。我的方案是把VAD检测出的语音段按累计时长聚合,每块控制在30到45秒之间,单块尽量保持语义完整。每个切片带上相对于原视频的起始时间偏移,后续LLM抽取知识点时才能拿到准确的"出现在第几分钟"。
切片聚合后可以批量送入ASR引擎,这里需要注意batch size。faster-whisper本身支持批处理,但显存和batch size是线性关系,我一般按显存大小把batch控制在8到16之间。推理完成后,把各切片的转写结果按原始时间偏移重新拼接,并保留segment级的时间戳,方便后续做字幕对齐。
2.3 说话人分离到底要不要做
在线教育场景里,大多数课程是单人讲授,不需要说话人分离。一旦引入,等于多跑一个音视频模型,耗时和成本都翻倍。我建议先用简单的规则判断:如果视频本身就只有一个讲师,直接跳过说话人分离。
但有一种情况值得做:访谈类课程、多人对谈类的知识节目,不同说话人对应不同观点,LLM在提取知识点时需要知道"这是老师说的还是学生问的"。这时候可以用pyannote.audio或FunASR的说话人分离模型先做diarization,再把时间区间与ASR结果对齐。实测下来,pyannote的默认权重在课程音频上能到85%左右的准确率,但需要微调才能达到可用状态。
替代方案更轻量:不单独训练说话人模型,而是让LLM根据转写稿中的提问句、语气和上下文去判断角色身份。这个方法在文本层做标注,成本很低,缺点是遇到两人抢话时容易标错。具体要不要做,取决于课程形态。如果只是单老师,别折腾,直接用单通道转写结果。
3. 让LLM稳定输出结构化知识点:Prompt工程与Token管理
3.1 Token的理解:Key、Query、Value三个映射
做这一步之前,团队里很多人不理解为什么LLM摘要质量忽上忽下,其实就是没把Token梳理清楚。我一直用一句话帮助大家记忆:LLM处理一个任务时,Key是你要模型看到的原始素材,Query是你要它回答的具体问题,Value是你要它产出的结构化信息。三段式设计Prompt,本质上是让模型的注意力集中在"从Key中找到与Query相关的片段,生成符合Value格式的内容"上。
对于课程摘要场景,Key就是ASR转写的大段文本,Query可以是"这节课讲了哪些核心概念?哪些案例有教学价值?",Value则是你要输出的JSON结构。先写清楚Value,再倒推Query,最后裁剪Key,开发效率会高很多。否则Prompt写得很花哨,模型却不知道你到底要什么。
Token的另一个维度是成本。中文文本转成token大概一个字1到1.5个token,一小时的课程转写稿大约有9000到14000个token。如果你使用4k或8k的上下文窗口,一次放不完整节课内容,必须分段。就算模型支持128k,单次调用也意味着高成本和潜在超时。所以Token管理不是技术焦虑,是真金白银的预算问题。
3.2 摘要Prompt设计:课程级和片段级分层
直接让LLM对一小时文本生成一个200字摘要,效果通常很灾难。原因是长文本的语义被稀释,模型容易只抓开头和结尾,遗漏中间核心部分。我的方案是map-reduce式分层摘要:先把转写稿按章节或时间片段拆分,每段生成一个局部摘要,再把所有局部摘要合并,生成课程级总摘要。
片段级Prompt我固定了几个要素:给模型提供原始文本片段、明确输出语言和风格、限定摘要字数、要求保留专有名词与时间节点。比如:"你是一名课程内容运营专家,请把以下课程片段提炼成150字以内的要点,保留核心定义和案例,不要添加原文没有的信息。" 这个Prompt简洁,但每次都要强调"不要添加原文没有的信息",因为LLM在摘要时很容易自行补全上下文。
课程级合并Prompt也类似,但更强调整体逻辑。我会给足局部摘要和每段的时间范围,要求生成"课程概述、学习目标、关键章节导读"三部分。这里的核心技巧是先定义输出结构,再让模型填充内容。直接让它自由发挥,出来的摘要结构不可控,后续排版和运营都无法复用。
3.3 知识点提取:用JSON Schema锁住输出格式
知识点提取比摘要更敏感,因为要结构化落地到数据库里。如果LLM输出的是自然语言,后续还要再写解析器去猜字段,非常麻烦。我的做法是在Prompt中给出JSON Schema示例,并要求模型只输出JSON,不用任何Markdown修饰。
实际可用的知识点结构大概包含这些字段:id、title、summary、start_time、end_time、level、relation_titles。start_time和end_time直接从ASR时间戳取段,Level可以用入门、进阶、高级三档。输出示例要具体,而不是只说"返回一个对象"。我通常会往Prompt里放一条真实风格的示例,让模型按这个模板产。
{ "id": "lesson_12_point_03", "title": "Transformer自注意力机制的计算过程", "summary": "通过Q、K、V三个矩阵的解释,说明注意力分数如何计算并加权求和。", "start_time": 142.5, "end_time": 169.8, "level": "进阶", "relation_titles": ["注意力机制", "编码器-解码器架构"] }但光靠Prompt不够,工程上还需要在输出端做校验。我们写了一个轻量校验模块:先判断LLM返回能否被json.loads解析,若失败就自动让模型重试一次;再检查必填字段是否存在、时间戳是否落在合理区间;最后把不合法字段丢弃,宁可少一个字段,也不要脏数据。后来不少开源工具支持JSON Mode或结构化输出,也可以用。比如OpenAI的response_format、vLLM的structured output,都可以在服务端对第一个token做约束,比纯靠Prompt稳定很多。
如果API不支持强约束,还有个土办法:在Prompt里加一句"如果某个字段不确定,用null代替",然后解析时过滤null。这个方法牺牲一点完整性,但能保证流程不断。
4. 流水线编排与工程落地
4.1 任务状态机设计:让每个环节都有据可查
ASR和LLM都是耗时操作,整个流程不适合在一个同步HTTP请求里完成。我设计了一个简单的状态机,把课程处理拆成五个状态:pending、transcribing、summarizing、extracting、completed,另外加一个failed状态用于处理异常。每个状态切换都记录日志、任务入队时间、完成时间和消耗Token数量。
这样设计的价值在于可观测性。之前没有状态机时,任务卡在中间只能靠日志搜,排查成本很高。现在每个任务都有明确的流转记录,哪个环节耗时多少、哪一步失败一目了然。这也是流水线工程和脚本最大的区别:脚本只能顺序执行,工程能让你看到执行到哪、卡在哪、成本花了多少。
具体落地时,我用Redis存任务状态,用消息队列触发各阶段处理。每个阶段由独立Worker消费任务。ASR阶段是GPU密集型,LLM阶段是网络IO密集型,两类Worker独立部署,防止ASR任务拖垮LLM任务。
| 状态 | 执行阶段 | 产出物 | 失败处理 |
|---|---|---|---|
| pending | 等待处理 | 任务记录 | 定时扫描超时任务 |
| transcribing | ASR转写 | 带时间戳的转写稿 | GPU异常则标记失败 |
| summarizing | 分段摘要与合并 | 课程级摘要 | LLM失败按策略重试 |
| extracting | 知识点生成 | 结构化JSON | 校验失败自动重抽 |
| completed | 完成 | 汇总结果入库 | 无 |
| failed | 异常终止 | 错误日志 | 告警通知 |
4.2 并发、重试与幂等控制
视频处理任务天然适合异步化,但并发控制不能只按最大吞吐设计。我的经验是:ASR Worker数量和GPU卡数对应,一张卡最多跑两个任务,否则会产生排队甚至OOM;LLM调用受API配额限制,必须做令牌桶限流,并发数控制在20左右,响应才能稳定。
重试逻辑也要分阶段对待。ASR失败多半是音频解析或显存问题,重试意义不大,直接记录失败原因并推送告警。LLM失败通常是网络抖动或429限流,可以在等待1秒、5秒、15秒后重试三次。但注意"幂等":VAD切片必须基于同一份原始时间戳,重试后不能重新创建切片,否则数据对不上。
LLM调用还有一个幂等陷阱:同样的输入,temperature>0时输出可能不同。业务上如果对重复处理敏感,可以在Prompt阶段固定seed,或者干脆接受一定随机性,用下游校验兜底。我们选择后者,因为摘要任务本身允许小范围措辞差异,校验字段即可。
4.3 把结果落到知识库:对接Dify与向量检索
流水线产出的摘要和知识点不应该只躺在数据库里,还可以喂给知识库系统,支撑课程问答和推荐。我们团队用Dify搭了一套内部知识库,把每节课的知识点结构化文本转成Markdown文档,上传后走Dify的索引和向量化流程。这样做的好处是:后续用户提问可以直接通过RAG检索对应知识点,相比全文搜索,答案更聚焦、也带上下文。
Dify知识库流水线的接入方式很灵活,既可以通过API把文档推给Dify应用,也可以在Dify里创建Workflow拉取数据库字段。我用的是前者:流水线生成知识点后,调用Dify的dataset创建接口,把时间戳信息和知识点标题一起写入文档元数据。检索时,Dify可以把时间戳返回给前端,用户点击直达视频对应位置,体验比纯文本摘要好很多。
如果你的知识库不是Dify,也没关系,核心是建立一份"以知识点为颗粒度"的文档集。每个知识点单独成一个文档,内容包含标题、摘要、视频所属课程、时间区间。向量化后,检索粒度远比整课摘要细,问答准确率也更高。这个设计我认为是整个流水线最有扩展价值的部分。
5. 常见问题与排查技巧实录
5.1 ASR转写断句错乱,摘要质量直线下降
转写稿如果断句错乱,LLM读起来非常痛苦,摘要经常出现答非所问。出现这个问题的根源是ASR引擎没有标点,或者标点恢复模型把断句位置搞错。我建议在ASR之后、LLM之前,增加一道标点修复。FunASR自带标点恢复,faster-whisper的输出则可以用开源的punct模型补充。
不过不要把标点修复完全交给规则。更有效的方式是用LLM做"文本规整":让模型对ASR转写稿重新分段,纠正明显的标点和分段错误,同时删除"嗯""啊""那那个"这类语气词。这一步虽然额外消耗token,但能极大提升后续摘要效果。我实测发现,规整后的文本喂给LLM,摘要忠实度能提高10个百分点以上,非常值得。
如果要进一步降低LLM理解负担,可以在转写文本中每60到120秒插入一个换行或者章节标记,方便模型定位上下文。
5.2 LLM幻觉让知识点出现了课程里没讲的内容
摘要和知识点提取最大的风险是模型编造内容。比如课程里只提了一句"Transformer在翻译任务中表现好",模型可能在知识点里扩写成"Transformer在翻译、文本分类、目标检测等任务中全面超越RNN"。为了解决幻觉,我做了三层防线。
第一层,Prompt中反复强调"仅基于提供的文本,不要依赖常识补充",并在示例中展示"不知道就说不知道"的输出。第二层,把知识点内容限制在原文的时间区间内,要求模型在summary中引用视频里的具体语句或关键词,这样便于人工复核。第三层,也是我后来一直在用的:把LLM当成"判断者"而不是"生成者"来做过滤。用另一个大模型对生成的知识点做事实核对,比对原文后打标签,再决定是否放行。
这种用LLM as Judge的方式,本质上是在流程里引入二次校验。虽然增加了一次模型调用,但对输出质量的要求远高于直接发布垃圾结果造成的运营成本。对课程运营来说,宁可漏一条知识点,也不能让错误知识点上线。
5.3 评估摘要做得好不好:别只看ROUGE
自动摘要的评估是个老大难。ROUGE分数只能衡量措辞重叠,无法判断语义是否靠谱。课程摘要里经常出现"内容都相关但表述完全不同"的情况,ROUGE分数很低,实际效果却不错。所以我现在采用人工抽检 + LLM多维评分的组合。
人工抽检很简单,每天随机抽取10节已处理课程,运营只评估三件事:关键概念是否覆盖、有没有错误、知识点时间戳是否准确。LLM多维评分则是让一个更强大的模型,例如GPT-4o或Claude,按忠实度、完整性、结构清晰度、可读性四项指标打分,每项1到5分。评分Prompt要给出具体参考标准,不能只让模型瞎评分。
我和团队用这套方法迭代Prompt和ASR参数,每改一版都跑30节课的对比测试。虽然不能自动化全量,但至少可以在改方案时给出量化反馈,而不是靠感觉判断好坏。
5.4 成本优化:让每一轮调用都不浪费Token
LLM调用成本是大头,而且容易失控。我总结了几条省钱经验:第一,分段摘要用小模型,课程级合并再用大模型,不要让小任务都跑旗舰模型;第二,缓存重复请求,同一课程视频如果只改了部分片段,就用视频指纹识别并只重跑变化段;第三,尽量压缩送入LLM的文本,ASR转写稿先做文本规整和去重,移除无意义语气词后再让模型处理。
另外要注意,LLM输出的JSON往往带有多余换行或无意义字段,如果解析失败后盲目重试,也会造成成本浪费。因此我在重试逻辑前先做一次轻量预解析,避免每个失败请求都触发高成本重试。
| 现象 | 常见原因 | 排查思路 | 解决手段 |
|---|---|---|---|
| 摘要答非所问 | ASR断句或标点错误 | 查看转写原文 | 增加文本规整步骤 |
| 知识点包含虚构内容 | LLM依赖常识补全 | 与原文逐句比对 | 用LLM as Judge过滤 |
| 时间戳严重偏差 | VAD切片偏移 | 核对切片offset | 统一时间戳基准 |
| Token消耗过高 | 长文本重复调用 | 查看状态机日志 | 分层摘要、缓存复用 |
我最终把这套流水线做成了内部平台的一个异步任务,每天处理上百节课。踩过的坑不少,但回头来看,技术选型不是最难的部分,最难的是让每个环节的输出都可校验、可追踪。如果你也在搭建类似的ASR + LLM流水线,建议从最小可用版本开始,先把状态机、日志和校验建立起来,再优化模型效果。