ASR 没听错,Voice Agent 的 Transcript 也可能是错的

ASR 没听错,Voice Agent 的 Transcript 也可能是错的

点击蓝字 关注我


9 月 20 日,Zian AI 发布了一份针对 Pipecat、LiveKit、ElevenLabs、AssemblyAI 等公开 issue 与 changelog 的技术审计,共整理出 11 种 Transcript 与真实通话发生偏差的机制,其中 10 种并非 ASR 识别错误,而是发生在 TTS、打断、消息聚合、会话关闭、录音和 SDK 这些环节。


这个结果值得警惕,因为 Voice Agent 里有一个很容易被默认的等式:


Transcript = 这通电话真正说过的话。


实际上,Transcript 更像是一份由整条实时 Pipeline 重建出来的会话记录。用户说了什么来自 STT,Agent“说了什么”可能来自 LLM 输出、TTS 文本或播放时间戳,中间还要经过打断、Tool Call、消息合并和 session close。只要这些状态没有完全对齐,ASR 可以一个字都没认错,最后留下来的 Transcript 仍然可能和用户耳朵真正听到的内容不同。

ASR 没听错,Voice Agent 的 Transcript 也可能是错的

最麻烦的一种:Transcript 里出现了用户根本没听见的话

Voice Agent 被用户打断时,问题最明显。


假设 Agent 原本生成了一句话:

“好的,我已经为你查询到订单,预计明天下午送达。”


TTS 刚播放到“好的,我已经为你查询到订单”,用户就插话了。用户真正听到的只有前半句,但如果系统缺少准确的 word timestamp,Pipeline 有可能已经把完整文本写进 Agent context 和 Transcript。


Pipecat 的公开 issue 就记录了这种情况:当 TTS Provider 没有返回词级时间戳时,完整生成文本可能在合成阶段被提交,即使后面的声音实际上没有播放。相关生产案例的提交者检查了 179 通电话,其中 18 通保存了不可能完整播放出来的最后一句 Agent 回复。这个比例只代表该提交者自己的技术栈,不能外推到所有 Voice Agent,但它证明这不是纯理论问题。


这里暴露出来的其实不是 TTS 准不准,而是一个更底层的问题:


“模型生成过”与“用户听见过”,是两个状态。


如果 Transcript 记录的是前者,拿它去复盘真实对话时,系统会凭空多出一段“幽灵台词”。


打断为什么会让 Transcript 变得这么麻烦?

OpenAI 的 Realtime API 文档里有一个很能说明问题的设计。


当客户端自己负责播放模型音频时,服务器并不知道用户到底已经听到了多少。发生打断后,客户端需要发送 conversation.item.truncate,告诉服务器音频真正播放到了哪个毫秒;系统随后删除未播放部分的音频以及对应 Transcript。OpenAI 还明确说明,由于模型没有足够信息把 Transcript 和音频精确对齐,截断后并不会给出一份重新计算好的完整文本。


LiveKit 处理 interruption 时也有类似逻辑:Agent 被打断后,会把 conversation history 截到用户实际听到的位置,而不是继续保留整段已经生成的回复。


这说明在实时语音里,Playback 本身已经变成 Conversation State 的一部分。


文字 Agent 没这个麻烦。模型输出一个字,这个字基本就已经呈现在用户面前;Voice Agent 中间多了一层真实时间,TTS 已经生成了多少、音频发出了多少、播放器播到了哪里,可能是三个不同的位置。


ASR 没听错,Voice Agent 的 Transcript 也可能是错的

语音被打断时,系统需要根据真实播放位置截断 conversation history,而不是按照模型已经生成的文本计算。来源:OpenAI。

Transcript 甚至可能把一句话放错人、放错位置

9 月 14 日,ElevenLabs 在 iOS SDK v3.3.1 中修复了一个很典型的问题:Agent 消息此前按照 event_id 而不是 response_id 对齐,在 Tool Call 前后存在多个 response 时,streaming text 或 correction 可能被挂到错误的 message 上。


同一批更新里,ElevenLabs 还修复了 Tool / Procedure Call 后出现重复 Agent 回复的问题,并明确处理了 Voice Conversation 中 unspoken streamed chat parts 不应被渲染的问题。


换句话说,Transcript 的偏差并不只有“多一个字、少一个字”。


它可能出现:一句话生成了,却没播出来;一句话明明播了,却没有被写进去;一段 correction 被挂到了错误 turn;被打断的完整回复仍留在历史里。


这些问题的共同点是,换一个 WER 更低的 ASR,基本解决不了。


Voice Agent 其实同时存在三条时间线

我们习惯把一次对话想成一条线:

用户说话 → Agent 回答 → Transcript 记录。


但真实的流式语音系统至少同时跑着三条线:

文本时间线:LLM 已经生成了什么。
音频时间线:TTS 实际合成和播放了什么。
记录时间线:最终有哪些事件被 Aggregator 写进 Transcript。


正常情况下,三条线看上去完全一致,于是大家很容易把 Transcript 当成 Ground Truth。真正发生打断、重试、Tool Call、TTS 失败或者 Session Close 时,它们才会突然露出缝隙。


Pipecat 最近的 issue 里甚至还能看到更极端的状态问题:Function Call Result 在用户仍然说话时到达,可能被静默丢弃;另外也有 turn management 问题导致用户仍在说话,系统却提前判定 User Turn 已经结束。


这时候 Transcript 记录的已经不是一个模型的问题,而是一套分布式实时状态机最终拼出来的结果。


真正危险的,是我们正在拿 Transcript 当 Ground Truth

Transcript 本身有误差并不可怕,可怕的是它现在被大量用在 Voice Agent 的下游。


客服质检看 Transcript,Agent Eval 看 Transcript,会话总结读 Transcript,训练数据回流也可能直接从 Transcript 抽取。一个被打断但没有真正说完的 Agent 回复,如果完整出现在记录里,评测系统可能会认为用户已经获得了这条信息;一段真正播放过但记录缺失的内容,又可能被判定为 Agent 漏答。


于是你可能不是在用 Transcript 评价一次真实通话,而是在用 Pipeline 自己重建出来的记录,评价这条 Pipeline 自己。🙄


这里会形成一个很隐蔽的闭环误差。


尤其是现在 Voice Agent 的评测越来越往任务、意图、轮次质量和自动 Judge 走,Transcript 越来越像一份基础数据。如果这层数据本身没有和真实音频做过校验,再精致的 Eval 也可能建立在一个不稳定的地基上。


Voice Agent 需要一个比 WER 更基础的检查

这篇审计给出的做法很朴素:拿真实电话的双通道录音和 Transcript 做 read-back,逐句确认有没有文字存在但没有对应音频、音频存在但没有文字、重复内容以及 Speaker/Turn 错位。它建议从最近 20 通电话开始检查,这个数量只是作者提供的实践方法,不是什么行业标准。


我反而觉得这暴露出一个目前 Voice Agent observability 里挺大的空位。


我们已经非常认真地测 WER、TTFT、TTFS、End-of-Turn、Interrupt Latency,却很少单独问一句:


最终保存下来的 Transcript,到底有多忠实于这通电话真正发生过的内容?


如果 Transcript 要继续承担 Eval、质检、训练和会话记忆的基础数据,它首先需要证明的可能不是“识别准确率有多高”,而是另一件更朴素的事情:


这里面的每一句话,用户真的说过,或者真的听见过吗?


这可能才是 Voice Agent 从 Demo 进入生产以后,一项很容易被低估的数据质量指标。


“

Realtime AI


ASR 没听错,Voice Agent 的 Transcript 也可能是错的


登录后查看剩余 30% 内容

© 版权声明
THE END
喜欢就支持一下吧
点赞464 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片