多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Octo-ASR+OCTO工作流:从语音转写到会议纪要自动生成与待办派发

Octo-ASR+OCTO工作流:从语音转写到会议纪要自动生成与待办派发 开完项目会录音躺在文件夹里群里已经开始有人问“纪要呢”这类场面你可能比我更熟。以前我的做法是把录音拖进播放器边听边敲键盘一小时的会至少搭进去两小时整理最后列出来的待办还总是漏项等项目复盘时被问“当时不是说了要跟进吗”只能尴尬翻录音。后来我把 Octo-ASR 接进 OCTO 工作流让语音转写自动跑完再由工作流里的 LLM 节点把口语化的流水账整理成结构化会议纪要最后把待办拆出来直接派发给对应的 Agent整条链路跑通之后会一开完任务清单基本就在工作台上排好了。这篇文章就把这套用法完整拆一遍包括我接入时调过的参数、测试过的模型组合、踩过的一些坑以及最后的可扩展方向。如果你也在做 agent 相关开发尤其是想把“会上说的事”变成“系统里能执行的任务”这套流程应该能给你不少可落地的参考。1. 先想清楚转写、纪要与派单分别解决什么问题很多人在搭这类系统时容易犯一个错误以为把 ASR 的结果丢给大模型直接就能输出纪要并派单。我最初也这么干过结果发现中间省略了太多关键环节。Octo-ASR 输出的是一段带时间戳和说话人标签的文本它并不理解“谁该对这件事负责”OCTO 工作流里的 LLM 节点虽然能做归纳和判断但如果输入的文本太原始模型也会被口语中的冗余信息带偏。所以第一步不是写代码而是把整条流程拆清楚。1.1 Octo-ASR只负责“转写”不负责“理解”Octo-ASR 这类开源 ASR 工具的核心价值是“把声音变成文字”。它做得好的地方在于语音识别准确率、说话人分离diarization和较长音频的批量处理能力。但它有一个严格的工作边界它不会判断哪些内容是闲聊、哪句话是真正的决策、谁在分配任务。这些语义层面的工作Octo-ASR 完全不参与。我之前在测试时遇到过一种尴尬情况把会议录音转写出来后文本里出现了“小刘你回头跟客户确认一下时间”这样的句子。ASR 能准确识别出每个字也能标出这是“发言者 A”说的但它不会告诉你“这是一个待办任务”。如果要让系统自动把这条语句变成一条派发给小刘的待办需要下游的 LLM 节点结合上下文去推断这句话包含一个明确的动作确认时间、一个明确的负责人小刘因此符合待办条件。所以Octo-ASR 在整条链路中的角色是一个“高质量原材料提供者”而不是最终的决策者。只要转写文本足够干净、说话人区分足够准确后续的 LLM 节点才能有饭吃。这也是我后来在接入 OCTO 工作流时最强调的一点先把转写质量做扎实再谈智能化。1.2 从转写文本到会议纪要OCTO工作流里真正干活的是LLM节点OCTO 工作流的定位是一个流程编排平台它可以把多个节点串联起来ASR 转写节点、文本增强节点、LLM 摘要节点、待办提取节点、Agent 派发节点等。每个节点之间通过 JSON 传递数据节点各自处理一个独立任务。以我的实现为例OCTO 工作流里跑的主要是三步ASR 节点把录音文件转成带时间戳和说话人的纯文本LLM 节点拿到这段纯文本用固定的提示词模板做信息抽取和摘要输出一个结构化的 JSON里面包含会议主题、关键决议、行动项、负责人和截止时间路由节点根据 JSON 里的负责人字段把每一个行动项派发给对应的 Agent 实例Agent 再去做后续的日程提醒、消息推送或任务创建。这个架构看起来不复杂但每一步都有很多细节。尤其是第二步的 LLM 节点它的输出格式如果不做严格的 JSON Schema 约束就会出现字段名不统一、待办和风险项互相混淆的问题。我前面说“直接丢给大模型”不够用原因也在这里大模型需要的是结构化任务的拆分而不是一次性自由发挥。所以在设计 OCTO 工作流时我建议把“纪要整理”和“待办提取”拆成两个节点而不是让一个提示词既做摘要又做任务分解。拆分的好处是每一段的任务更单纯模型的表现也更稳定。纪要整理节点负责把口语转成有条理的会议概要待办提取节点再基于概要找出所有包含责任人、动作和时限的句子形成待办清单。这样即使纪要节点出一个字段错误也不会拖垮待办提取节点。2. Octo-ASR接入前的准备模型选型、音频预处理与输出格式接入 Octo-ASR 之前需要做三件事选模型、搞音频、定输出格式。这三件事看起来基础但它们决定了后面所有环节的地基。2.1 模型选型先想好离线还是在线实时还是非实时Octo-ASR 有不同规格的模型可用大模型和小模型的识别准确率差异明显但也要看你具体的使用场景。离线批量转写如果会议已经录制完不要求实时字幕就用大模型。它的中文长音频识别能力更强对专有名词的容错率也更高。我这边跑一小时会议录音离线批量模式大概用 5 到 8 分钟左右完成转写具体耗时看 GPU 配置。在线实时转写如果要做直播字幕或实时纪要就得用轻量级模型配合流式接口。轻量模型在安静环境下满足日常使用但会议场景里的多人重叠发言容易乱需要额外做 VAD语音活动检测和降噪处理。有一点容易忽略Octo-ASR 的模型对中文口语表达的优化程度并不均衡。有些版本对英文表现很好但中文语速快、口音重时识别错误率会明显上升。我在接入前专门拿了三场真实会议录音做对比测试最后选了中文适配更好的模型底座把热词表加上之后人名和项目代号基本都能正确识别了。建议在接入之前先拿你所在团队的真实会议录音做一个基准测试而不是直接用默认模型上生产。因为每个团队的专有名词不同直接上线大概率会遇到识别率低的问题。2.2 音频预处理采样率、降噪和切分不能省Octo-ASR 对输入音频有一定要求常见的是 16kHz 单声道 WAV。很多会议录音原始文件是 48kHz 双声道直接喂给 ASR 虽然不会报错但会造成特征提取不一致影响识别准确率。我在实测中遇到过一次同一段录音用原文件转写和用先转成 16kHz 单声道再转写错误率能差 2 到 4 个百分点。预处理步骤大致是这样用 ffmpeg 把音频统一转成 16kHz 单声道 WAV做简单的降噪处理去掉空调声和风扇声如果整段录音很长先做 VAD 切分再分段转写。VAD 切分有一个实际意义它能把“无人说话”的空档去掉避免 ASR 在静音段产生幻觉文本。我遇到过最离谱的情况是一整段静音被转写成了“会议开始”后面还带了几句编造的内容。后来我在转写前加了 VAD 过滤这类幻觉基本消失。关于切分的粒度我建议分段控制在 30 秒到 60 秒之间。太短会导致上下文丢失太长则容易在多人说话时互相串扰。Octo-ASR 本身支持长音频但内部还是会做分块处理你切分的边界和它内部的边界错位时可能出现句子被拦腰截断的问题。加了上下文重叠之后转写质量会更稳。2.3 输出格式直接影响下游解析成本Octo-ASR 的输出一般支持纯文本、SRT 字幕和带完整元信息的 JSON。如果你只是自己听录音SRT 就够了但如果要接 OCTO 工作流一定要用 JSON 格式。一个好的 JSON 输出至少包含这些信息字段说明用途start句子开始时间秒便于回溯定位end句子结束时间秒便于回溯定位speaker说话人编号或名称角色指代识别text转写文本供 LLM 分析confidence置信度分数用于过滤低质量转写低置信度的句子建议单独标记出来不要让它们混入正常的纪要素材。我之前试过把置信度 0.3 以下的句子也喂给 LLM结果模型把一段“嗯嗯嗯好的好”也总结成了“与会者表示同意”非常误导。接入 OCTO 工作流时ASR 节点的输出 JSON 会直接作为下一个节点的输入。用 JSON 的好处是字段清晰后续的 LLM 节点提示词里可以直接引用text和speaker不需要做额外的文本解析。3. OCTO工作流里的“会议纪要整理”节点转写文本到手之后下一步是把口语化的内容整理成会议纪要。这一步是整个流程中最容易被低估的环节。很多人以为只要把文本丢给大模型说一句“帮我整理会议纪要”就行但真实场景里模型会被各种干扰信息带偏。3.1 提示词模板要从“流水账”中提取“五要素”我给纪要节点设计的提示词不是简单的“总结一下”而是要求模型从文本中提取五类核心信息会议主题与目标关键议题与讨论过程最终决议行动项谁在什么时间前做什么遗留问题与风险。实践下来效果比开放式总结稳定得多。模型不需要发挥只需要做信息抽取和归类漏内容的概率大幅下降。我的提示词模板大概长这样你是会议纪要助手。下面是一段会议转写文本包含说话人标签和时间戳。 请提取以下五类信息 1. 会议主题 2. 关键议题及结论 3. 明确决议 4. 行动项必须包含负责人、动作、时间限制如果有 5. 遗留问题与风险 要求 - 只基于文本中确有依据的信息不要补充原文没有的内容。 - 行动项必须使用如下格式输出负责人 | 动作 | 截止时间 | 原句摘录。 - 如果某类信息为空请输出 无。 - 输出为 JSON不要使用 Markdown 表格。 转写文本 {asr_text}注意最后两条要求很重要。很多第一次写提示词的人会忽略“输出为 JSON”和“不要使用 Markdown 表格”结果模型返回一段富文本下游就傻眼了。我在 OCTO 工作流里给 LLM 节点配置了 Response Format 强制 JSON但提示词里再写一遍会更保险模型输出更稳定。3.2 说话人角色归一化避免“小刘”“刘工”指代混乱真实会议里一个人可能有多种称呼。上一句叫“小刘”下一句叫“刘工”再后来说“小刘总”。如果直接把说话人标签带入待办提取会出现同一个人被拆成多个负责人的情况。解决办法是在纪要节点里增加一步角色归一化先让 ASR 输出每个说话人的编号比如speaker_0、speaker_1上一步之后用一个单独的 LLM 节点根据上下文把每个说话人编号映射到实际姓名或角色在提示词里指定一个已知团队名单名称列表让模型在名单里选择最可能的对应人。例如转写文本里出现“让我们部门确认一下排期”而团队名单里有“王明后端负责人”纪要节点就应该把这句话挂到王明的名下。这一步如果没有做待办派发时会出现“负责人小刘”这种让下游 Agent 无法识别的名称。我建议把团队成员名单做成一个静态配置文件放在工作流里作为上下文注入。名单字段不需要很复杂维护一个“常用称呼到正式姓名”的映射表就够了。团队不大时用字典映射最直接团队很大时可以让模型根据历史纪要学习称呼归属。3.3 纪要去噪哪些内容可以丢哪些必须留会议录音里的废话比例通常不低。我在测试时发现一段 60 分钟的会议录音去掉寒暄、点外卖、闲聊和口头禅之后有效内容常常不到 40 分钟。如果这些干扰信息全部留给后面的待办提取节点误判概率会显著上升。我的去噪策略分两层第一层在 ASR 输出阶段把置信度低的句子标记为low_confidence纪要节点直接忽略这些句子不参与总结。第二层在 LLM 提示词中明确告诉模型哪些内容不属于纪要范围。比如以下内容应被忽略 - 寒暄与闲聊如今天天气不错 - 口头禅与重复语句如嗯嗯就是说 - 与会议主题无关的日常事务如中午吃什么 - 单纯的附和如对是的这听起来很基础但真的能明显减少纪要的篇幅和质量问题。模型在提取信息时会更有目标性不会把“下午三点前把方案发我”这种句子丢掉因为它在任务语句里。去噪还有一层深意它不是把信息丢掉而是把信息从“所有人说的一堆话”中分离出来。一个合格纪要的产出应该让读者只看纪要就能了解会议全貌而不用翻回原始转写文本。这是我在实际使用中体会最深的一点。4. 待办提取与Agent派发最难也最容易出错的一段纪要整理出来之后最核心的环节就是待办提取与派发。这一步之所以难是因为它要求系统不仅能识别“这是一件待办”还要能判断“这件待办该给谁、什么时候要做完、优先级高不高”。4.1 待办字段设计负责人、时限、优先级、原句摘录缺一不可我先设计了一个待办的 JSON 结构后来在真实项目里不断调整最终稳定成了这样{ id: todo-20250115-001, action: 确认客户新版接口的接入时间, assignee: 王明, due_date: 2025-01-20, priority: high, source_text: 这个接口的时间王明你去跟客户确认一下下周要定下来。, timestamp_start: 1523.4, timestamp_end: 1528.7, status: pending }字段看起来多但每一个都有实际用途source_text用于追溯派发给 Agent 后如果 Agent 执行时需要看上下文可以随时跳回原始会议文本甚至跳回录音时间点。timestamp_start和timestamp_end用于对齐录音团队中有争议时可以直接定位到会议上说的那一句话省去翻录音的麻烦。due_date是提取出来的“软时限”。如果原文说“下周之前”模型应该把它转成具体的2025-01-20这样 Agent 才能在排期里生成任务。在提示词里我要求模型对每一条待办都必须给出source_text。不给没关系模型很容易编造出原文没有的任务。加上原句摘录之后每一条待办都能在纪要里找到证据这是一个非常强的约束。4.2 从负责人到Agent实例的路由设计待办提取完成之后剩下的问题就是“怎么把待办交给正确的 Agent”。这里又分两种思路。第一种是静态路由在 OCTO 工作流里配置一个负责人到 Agent 实例的映射表。比如“王明”对应一个负责项目跟进的 Agent“李婷”对应一个负责日程管理的 Agent。待办 JSON 的assignee字段直接查表找到对应的 Agent API 就把待办推送过去。第二种是动态路由不配置固定映射而是让一个调度 Agent 根据待办的内容判断该交给谁。这种方式更灵活适合 Agent 数量多、职责边界不清晰的场景但会多一层推理开销。我建议第一天先做静态路由等到跑通了团队也确实需要更复杂的分发逻辑时再上动态路由。原因很简单动态路由一旦出错你很难判断是待办提取的问题还是调度 Agent 的问题。而静态路由逻辑透明任何一条派发失误都可以直接看路由映射表排查。路由消息本身也有讲究。不要把整个待办 JSON 全部塞给 Agent应该按目标 Agent 的接收能力做裁剪。比如有的 Agent 是通过 Webhook 接收消息它只关心action和due_date那source_text可以放到附注里。如果 Agent 对接的是 IM 机器人可能还需要把待办格式化成自然语言提醒你有一个待办任务 内容确认客户新版接口的接入时间 截止时间2025-01-20 优先级高 来源会议2025-01-15 项目评审会这一步看似琐碎但直接决定了 Agent 拿到消息之后能不能正确处理。我之前踩过坑把完整 JSON 发给一个只接受文本指令的 Agent结果它把所有 JSON 内容当作一条指令执行闹了笑话。4.3 派发确认与失败重试没有回执的派发等于白派待办派发之后工作流不能就此结束否则很容易出现“系统显示已派发但 Agent 根本没收到”的情况。我给派发环节加了三层保障ACK/NACK 回执每个 Agent 在接收待办后必须返回一个确认信号。收到 ACK 代表任务已经进入 Agent 自己的队列收到 NACK 或超时未响应则触发重试。有限重试重试次数我设置为 3 次间隔 1 分钟、5 分钟、15 分钟递增。重试超过 3 次后把待办转到一个“人工补发队列”由运维人员或项目助理手动处理。对齐兜底定期用待办列表与 Agent 内的任务列表做比对发现 Agent 侧缺失任务就重新推送。这一步适合对系统性可靠性要求高的团队。有了这三层保障派发才算闭环。第一次实现时我没有加回执结果有一场重要会议的 12 条待办里有 4 条 Agent 根本没收到没有人知道。后来检查日志才发现是 Agent 服务重启时把队列弄丢了。加入 ACK 回执后这类问题在 1 分钟内就能被暴露。5. 实测中的坑与调整从1小时录音到全员收到任务流程搭好后我找了一场真实会议做了完整测试一场一小时左右的线上项目评审会参会 6 人最后转写文本约 7000 字。下面说说实测结果、参数调整以及几个容易忽略的坑。5.1 实测数据转写、纪要与派发各用了多长时间这次实测的完整流程耗时如下环节耗时说明音频预处理转 16kHz VAD 切分约 20 秒用 ffmpeg 自动完成Octo-ASR 转写约 6 分钟使用离线大模型GPU 环境下纪要去噪与整理约 40 秒LLM 节点处理 7000 字文本待办提取约 10 秒独立 LLM 节点Agent 派发约 5 秒静态路由 ACK 回执整个过程接近 8 分钟。会议结束后我泡了杯茶回来Team 群里已经收到了任务提醒。这个速度当然不是“实时”但对于会议场景已经能接受。如果希望更快可以换成轻量模型加并行处理转写时间能压到 2 分钟左右代价是识别准确率略有下降。最终这场会议提取出 10 条待办对照人工整理的原始录音逐条核对准确检出 8 条漏掉 1 条因为原句表述太模糊“那个事再跟进一下”没有明确负责人和时限多提取 1 条把一句“要是没事的话就可以先这样”误判成了结束时间确认后来靠低置信度过滤和二次校验拦住了。5.2 多人同时说话时转写错乱用 VAD 和声纹分离缓解线上会议最常见的坑是多人同时开麦ASR 对重叠语音处理得很吃力。Octo-ASR 的说话人分离是基于声纹特征做的同一声源若被压缩得太厉害会频繁切换说话人标签。我实测中遇到过一个案例两位同事同时讲话转写结果被 ASR 识别成 5 个不同的说话人同一人在一句内来回切换身份标签标签之间没有逻辑关联。我的处理方案是在转写前做更细粒度的 VAD 切分只保留能量较高的语音段让重叠部分尽量各自独立若实在无法区分在 ASR 输出中标记为overlap并在纪要节点中让模型忽略这些片段避免它们对纪要产生干扰。这个方案能一定程度缓解问题但要彻底解决还是得从硬件出发。有条件的话给会议室装一个全向麦配合每个座位的独立麦克风阵列转写质量会上一个台阶但成本也高。预算有限就先在软件层做过滤。5.3 “回头再说”“之后同步”被误判成待办阈值和二次校验双重控制ASR 转写后的文本里“回头再说”“之后再同步给你”这类模糊语句出现频率极高。LLM 提取待办时很容易把它们当成行动项产生大量无效待办。我加了两个控制手段。第一个手段是置信度阈值在待办提取节点中要求模型输出的待办必须满足“明确负责人 明确动作”两个条件模糊语句直接跳过。没有通过这两个条件的一律不输出。第二个手段是二次校验新增一个校验节点用独立的提示词重新审视待办列表以下是提取出的待办清单。对于每一条待办请检查 1. 原句中是否真的包含负责人 2. 原句中的动作是否明确“回头再说”不算明确动作 3. 如果只有负责人的称谓但对任务描述模糊请标记为“需要人工确认”。二次校验比直接提取的准确率提升很多因为它相当于用另一个视角重新审了一遍本质上是“多重采样一致性”的简化版。之前没有加校验时误判率达到 15% 左右加上之后降到了 4% 以内。5.4 模型幻觉出的假任务最小校验链路必须要有大模型在处理长文本时偶尔会“脑补”。我在测试中遇到过一条不存在的待办模型把“如果方案的接口不稳定我们再想备选方案”提取成了“备选方案需要评估”但实际原文是讨论假设情况并不是安排任务。还有一次模型凭空造了一个负责人名字原文根本没有这个人出场。应对幻觉任务我总结出三个做法用source_text强制绑定每一条待办没有原句摘录的待办直接丢弃在提示词里明确写“只基于原文不要补充任何原文没有的信息”对置信度低的句子在待办提取之前就过滤掉防止模型基于低质量文本进行推断。这三个做法单独拿出来效果有限但叠加起来能有效降低幻觉概率。我还是那句话尽量不给模型自由发挥的空间让它做抽取而不是做创作。6. 这套流程还能往哪些方向扩展如果这套会议纪要和待办派发的链路你已经跑通了可以先别急着收工。我接下来打算把 OCTO 工作流往周边场景延伸这里一并分享三个阶段。6.1 第一阶段把会议纪要同步到知识库和项目空间会议纪要生成后可以直接推给企业的知识库系统自动归类到对应项目目录下。这样后期查找信息时不用在 IM 聊天记录里翻找直接去知识库搜索就行。同时纪要和待办可以关联到项目管理工具里让每条待办自带“会议来源”属性方便项目复盘时回溯决策过程。这个阶段的核心仍然是把数据格式整理干净。所以前面设计的 JSON 结构在扩展时能直接复用。6.2 第二阶段让Agent带着记忆执行待办如果把待办只发给 Agent 就算完那是比较浅的用法。更有意思的是让 Agent 具备记忆能力在多次会议之间积累上下文。比如这次会议提到“客户接口尚未确认”下一次会议又提到“接口确认了”Agent 如果能读取历史记忆就会知道这个待办已经闭环不必再次提醒。关于 Agent 的记忆体系短期记忆当前会议、中期记忆最近几周的待办、长期记忆项目历史决策记录是可以拆开做的。短期记忆直接存在工作流上下文里中期记忆存成任务列表长期记忆则可以让 Agent 定期把历史纪要里的重要结论写入向量库。这样 Agent 在接到新待办时可以通过语义检索找到以前的关联决策执行起来更准。6.3 第三阶段多Agent协作时把路由升级为动态调度当 Agent 数量增多静态路由的映射表会变得很难维护。此时可以考虑引入一个调度 Agent它读取待办内容结合所有 Agent 的能力描述决定由谁执行甚至可以把一条大任务拆成多个子任务分派给不同 Agent。这其实就是吴恩达在多 Agent 课程里讲的“三明治架构”在具体场景里的实践。不过我还是那个建议先静态、后动态。第一版系统不需要追求花哨稳定性是最重要的。等到你手里有三个月以上的真实数据知道各类待办实际会被哪些 Agent 正确处理了再做调度决策才有依据。最后说一个我个人的体会会议纪要自动整理这件事技术难点不在 ASR也不在 LLM而在流程设计与提示词约束。你要让模型在明确边界内做抽取而不是给它无限的自由度要让每一步输出都可追溯而不是黑盒一锅焖。先把 Octo-ASR 的转写质量调到能接受的水平再把 OCTO 工作流里的节点拆细、提示词写严最后的派发环节加上回执和重试这套流程在大部分团队里都是可以落地的。如果时间有限建议先只做“转写 待办提取”不要一上来就追求全套自动化。我见过很多项目是因为步子迈得太大最后卡在 Agent 派发的可靠性上连基础的前两步都没用起来。一步步来比什么都快。
返回列表