DLAI-生产级人工智能语音助手笔记-全-
DLAI 生产级人工智能语音助手笔记(全)
001:课程介绍 🎤

在本节课中,我们将介绍《构建生产级AI语音助手》这门课程的目标、讲师团队以及课程的核心项目案例。你将了解我们将要学习的关键组件和挑战。
欢迎来到由Ruslan、Shane、Emily和Naina Tlliveva主讲的《构建生产级AI语音助手》课程。Ruslan是Livekit的联合创始人兼CEO,Shane是Livekit的开发者布道师。Naina是Ro Avatar的AI负责人,并与DeepLearning.AI团队共同开发了一款对话式虚拟形象。Ro Avatar也是AI Ts的一个投资组合公司,我领导着这个专注于能与用户对话的智能体的团队。事实证明,这正成为人们与AI智能体互动的一种重要方式。
DeepLearning.AI和Ro Avatar团队,包括Naina,在使用Livekit构建对话式虚拟形象方面拥有丰富的经验。我个人也非常喜欢在各种其他项目中使用Livekit。在本课程中,我们希望与您分享构建语音智能体的一些最佳实践。
让我描述一下我们将作为贯穿课程示例的项目。我们从一个类似于您可能在之前的课程中见过或构建过的对话式智能体开始。我们开发了一个智能体工作流,让系统尝试选择词语,以在不同情境下说出类似于我会说的话。在输入侧,我们添加了一个语音转文本模型,将用户的音频语音转换为文本,供智能体工作流处理。在输出侧,我们添加了一个文本转语音模型,将文本输出转换为语音,然后可以使用来自11 Labs的模型生成音频并播放给用户。该模型被训练成模仿我的声音,我认为音频效果相当不错,稍后你会听到并可以自行判断。我们希望这个系统能够扩展到大量用户,因此我们迁移到了一个能够支持许多并发用户的云基础设施。最后,该服务的用户可能遍布世界各地,这带来了网络问题和音频集成挑战。

我们的解决方案使用云资源来支持虚拟形象的前端,后端则运行智能体工作流,并集成Livekit来提供通信基础设施。Naina、Shane和Ruslan将在课程中详细介绍这些内容。

在第一课中,你将学习语音管道的组件,包括语音转文本和文本转语音模型,以及语音活动检测和话轮结束检测。你还将了解延迟的重要性以及一些保持低延迟的策略。
然后,我们将试用一个语音智能体。你将了解语音智能体与其他应用程序的真正不同之处:语音智能体具有状态,并且为了有效,必须具有临场感,就像对话的另一端有另一个人一样。
在第四课和第五课中,你将构建一个可以在课程中使用或下载到自己机器上的语音智能体。你将学习如何测量语音管道中的延迟,以实现自然的对话。
许多人共同努力创建了这门课程。我要感谢来自Livekit的Theo Manom和来自Gi Bla A I的Jeff Ladwayig。此外,我还要感谢来自11 Labs的4 Shave,他创建了本课程中将使用的语音转文本模型,并为本课程提供了支持。



感谢你,Andrew。很高兴能成为这门课程的一部分。我希望你会发现对话式AI智能体和我们一样引人入胜,并愿意花时间不仅探索11 Labs的文本转语音技术,还有我们功能齐全的对话式AI平台,它允许你在几分钟内为你的智能体添加语音功能。我们迫不及待想看到你将构建出什么。这听起来很棒。让我们开始下一课,概述语音智能体。
002:语音助手概述 🎙️
在本节课中,我们将学习AI语音助手的基础知识。我们将了解其核心组件,如语音转文本、文本转语音和大语言模型,并分析语音助手技术栈每一层引入的延迟。我们将探讨像LiveKit这样的平台如何通过提供优化的网络基础设施和实现低延迟通信协议来缓解这些延迟挑战。最后,我们将通过一个Python构建语音助手的最小示例,并探讨评估和提升语音助手性能的实用方法。
什么是AI语音助手?
在深入之前,你可能会问,究竟什么是AI语音助手?简单来说,AI语音助手将语音能力与基础模型的推理能力相结合,以实现实时、类人的对话。语音助手在多种场景中都非常有用。在教育领域,它们可以指导个性化技能发展或进行模拟面试。在商业领域,它们可以帮助处理客户服务电话,例如在餐厅预订餐桌或协助销售。由于语音助手交互是免提的,它们还能增强可访问性。想象一下,患者可以使用语音助手描述症状或在家进行谈话治疗。
语音助手技术栈剖析
现在,我们来剖析一下语音助手的技术栈。该系统以用户的语音(如问题或请求)作为输入,并产生语音响应。在某些情况下,音频输出也可能与视频同步,例如一个会说话的头像,但本课程将专注于纯音频交互。
在设计语音助手内部结构时,我们有两个主要选项。第一种是使用“语音到语音”或实时API。这种选项实现起来更简单,但对助手行为的控制灵活度较低。第二种,也是本课程主要关注的方法,是“流水线”方法。
语音助手流水线由三个组件组成:一个语音转文本模型或API、一个LLM或智能体框架,以及一个生成最终音频输出的文本转语音模型或API。
流水线组件详解
让我们更详细地看看语音助手流水线的每个组件。
第一个组件是自动语音识别,也称为语音转文本。 这涉及将给定的音频信号(通常是波形)转录为文本。输入是原始音频,输出是相应的转录文本。
第二个组件是大语言模型或更广泛的智能体工作流。 它基于转录的文本生成响应。这一层可能涉及一个或多个LLM智能体,通常通过工具使用、记忆或规划能力进行增强。附带一提,语音助手也可以生成带有支持材料(如图像或链接)的转录文本,作为其功能的副产品。这个流水线可以推广以支持此类多模态LLM响应,从而在需要时同时显示语音输出和视觉上下文。
第三个组件是文本转语音,也称为语音合成。 这是将生成的文本转换回听起来自然、清晰可懂的语音的任务。这里的输入是文本,输出是音频。在稍后你将看到的演示中,合成的声音是Andrew的。
除了这三个主要组件,还需要强调两个在ASR步骤之前发生、对于正确处理人类语音至关重要的任务。
第一个任务是语音活动检测。 它用于确定音频信号中是否存在人类语音。例如,未检测到语音可能对应于自然的停顿或主要由背景噪音主导的部分。
第二个任务是说话轮次结束检测。 它用于识别说话者何时完成了他们在对话中的轮次。这是一个不小的挑战,因为语音通常包含不同长度的停顿,这取决于说话者的语言、习惯和表达风格。
如何构建这些组件?
既然我们已经回顾了两种语音助手架构的核心组件,下一个问题是:我们如何实际构建这些组件?幸运的是,我们不需要从零开始。相反,我们可以专注于对我们特定用例最重要的技术栈部分。例如,根据应用的不同,某些组件可能需要比其他组件更多的关注。
如果你正在为临床环境开发语音助手,ASR组件就变得至关重要。你需要准确识别专业的医学词汇,并满足严格的精度要求。另一方面,如果你正在开发餐厅预订助手,LLM或智能体工作流就变得更加重要,因为你需要强大的推理能力和可靠的工具使用来避免诸如超额预订餐桌等问题。
除非你的用例需要专门的或设备端模型,否则你可以从众多提供商中选择TTS、STT和LLM服务。在本页幻灯片上,我们在灰色框中列出了一些选项。正如你所见,有许多提供商可供选择,值得在演示中探索。在本课的演示中,我们使用OpenAI进行STT,使用ElevenLabs进行TTS。对于文本转语音输出,我们使用Andrew声音的录音训练了一个ElevenLabs自定义语音模型,以创建一个一致且个性化的AI语音克隆用于语音合成。最后,对于LLM组件,由于低延迟是关键要求,你可能希望探索由快速推理提供商(如Groq、Cerebras或Together AI)提供的开源Llama模型。
如果你选择使用“语音到语音”或实时API方法构建语音助手,也有几个提供商支持该工作流。这些API抽象了底层流水线的大部分复杂性,非常适合快速部署比精细控制更重要的用例。
延迟挑战与优化
无论你选择哪种智能体架构,都将面临一个主要挑战:时机。人类期望在很窄的时间窗口内得到响应。如果系统延迟,交互很快就会显得不自然。为了保持流畅的对话流程,你的基础设施必须支持低延迟音频流,并有效管理流水线中的输入和输出流。
例如,在流水线方法中,你需要协调多个用户的实时交互,同时确保在VAD、STT、LLM和TTS等组件之间无缝切换,而不会在任何阶段引入明显的延迟。
在考虑延迟时,从一个基准开始是有帮助的:在自然对话中,人类期望多快得到响应?研究表明,平均而言,人们期望在对话伙伴说完话后的236毫秒内得到回应。然而,标准差相当高,大约在520毫秒左右,这反映了人类语音的自然变异性。同样重要的是要注意,这些数字是基于英语使用者的。其他语言可能表现出显著更快或更慢的响应时间。
现在,如果你看幻灯片上的表格,我们可以看到语音助手流水线每一步引入的延迟。在最佳情况下,通过高效的输入/输出流处理,完整语音助手响应的延迟下限约为540毫秒。这使其刚好处于人类期望值的一个标准差范围内。然而,根据你所用提供商的服务水平协议,延迟可能增加到超过一秒半,用户几乎肯定会注意到。
那么,我们如何接近符合自然人类对话的低延迟界限呢?关键在于实时点对点通信,它支持设备之间的直接数据交换,绕过中间服务器,从而显著减少延迟。在这种设置中,你的客户端(如网络浏览器或移动设备)充当一个对等点,而你的语音助手后端则充当另一个对等点。
LiveKit的基础设施旨在通过一个用于媒体转发的全球分布式网状网络来支持这一点。系统的核心是几项技术:首先,WebRTC 是一个开源项目,通过标准化API为Web和移动应用程序提供实时通信能力。其次,WebSocket 用于建立客户端-服务器握手,实现高效的信号传递和会话管理。最后,LiveKit的开源实现依赖于异步处理和输入/输出流以及流式API的仔细管理,特别是对于STT、TTS和LLM组件。这确保了整个语音助手流水线的流畅、低延迟性能。
虽然底层点对点基础设施很复杂,Rus将在课程后面带你深入了解,但LiveKit抽象了大部分复杂性,使得仅用几行代码定义AI语音助手变得非常简单。在本页幻灯片上,你可以看到一个如何设置语音助手后端的最小示例。有三个主要组件需要关注:首先是定义智能体本身,包括任何提示词;其次是智能体会话,它将你选择的语音转文本、LLM和文本转语音提供商链接到一个功能性的流水线中;第三是入口点函数,它作为每个新点对点通信的主函数执行。你将在课程后面更深入地了解代码和配置。现在请注意,在本课的演示中,我们将代码中的TTS_VOICE_ID变量设置为引用一个我们训练过的自定义ElevenLabs语音克隆,以匹配真实的头像。
构建语音应用的独特挑战
为了结束本节,我想强调构建基于语音的应用时面临的一些独特挑战。首先,言语障碍,如填充词(如“嗯”)或长停顿,可能会在转录中引入伪影,并影响说话轮次结束检测。这些问题随后会传播到给LLM的输入中,可能降低输出质量。其次,如果你正在开发多语言语音助手,请记住,多语言ASR模型的表现通常不如英语ASR模型。

现在,让我们简要谈谈延迟优化。在实践中准确测量延迟是具有挑战性的,尤其是在试图将客户端延迟与服务器端延迟分开时。为了通过设计帮助最小化这些延迟,LiveKit提供了低延迟网络基础设施。在STT-LLM-TTS流水线中,LLM组件通常是延迟的主要来源。为了减少它,你可以在自托管时使用更小或量化的模型,或者如果你依赖LLM API,可以选择更快的推理提供商。你还可以提示LLM生成更短或分阶段的回复,以减少感知到的响应延迟。
演示与实践

现在让我们看看实际效果。我将向你展示我们用于Andrew头像的语音助手的简短演示。语音助手后端在我的笔记本电脑上本地运行。对于前端,我们将使用LiveKit Playground,这是一个多功能Web前端,可以轻松测试你的多模态AI智能体,而无需担心UI,直到你对后端满意为止。
(演示过程描述:左侧显示语音助手代码,与之前展示的最小示例代码非常相似。右侧后端显示代码在本地计算机命令行上运行。浏览器中运行着LiveKit Playground,已为课程创建了项目。通过连接和对话,演示了语音助手的响应、语音活动检测和打断功能。)
总结

在本节课中,我们一起学习了AI语音助手的基础概念。我们了解了其核心架构,包括语音转文本、大语言模型和文本转语音三大组件构成的流水线。我们探讨了构建过程中面临的延迟挑战,以及如何通过实时点对点通信和优化基础设施来应对。最后,我们通过一个实际演示,看到了一个功能完整的语音助手是如何工作的,并了解了评估和优化其性能的一些关键考量。下一节课,我们将深入了解语音助手的端到端架构细节。
003:端到端架构 - 第一部分

概述
在本节课中,我们将学习如何为AI语音助手设计端到端架构。我们将重点探讨用户设备与服务器端语音代理之间的通信,分析不同网络协议的优劣,并了解如何选择最适合实时语音流传输的技术方案。
网络协议基础

上一节我们介绍了构建语音助手的基本概念,本节中我们来看看连接用户与服务器的网络基础。
互联网建立在IP(互联网协议)之上。IP负责为每个设备分配一个地址,就像房屋的地址一样。如果一个设备想向另一个设备发送信息,类似于在两个房屋之间发送实体邮件,有几种建立在IP之上的协议可以实现这一点:TCP和UDP。它们各自提供了不同的方法。
TCP协议:可靠性优先
TCP优先考虑可靠性而非低延迟。我们可以想象用户正在使用TCP向代理发送一些语音数据包。互联网就像世界的道路系统,每个发送出去的数据包在网络中可能采取不同的路由。在这个例子中,数据包1和3首先到达代理,而数据包2仍在传输中。TCP不会向你的应用程序(本例中是代理)提供数据包1和3的访问权限,直到数据包2到达。如果数据包2在传输中丢失(这有可能发生),接收端的TCP协议会要求发送方重新发送数据包2。与此同时,你的代理程序必须继续等待,直到数据包2成功到达。
现在,请想象一个现实世界的语音代理示例,其中每秒有成千上万个音频数据包被发送。即使其中一小部分数据包丢失或到达代理的速度较慢,也可能导致队列积压或停滞。你可能会在其他地方看到这个问题,被称为队头阻塞。TCP的设计对于语音代理应用来说是有问题的,因为它最终会导致音频播放结巴或冻结,从而带来糟糕的用户体验。
UDP协议:低延迟优先
另一方面,UDP优先考虑低延迟而非可靠性。与TCP不同,使用UDP时,协议会在收到数据包的瞬间就将它们全部交给你的代理。具体来说,如图所示,你的代理可以立即访问数据包1和3,即使数据包2仍在传输中。这意味着你的代理实际上可以决定在这种情况下该怎么做:它可以等待数据包2,忽略数据包2,甚至在数据包1和3之间进行插值,或者可能直接跳过数据包1和2,从数据包3开始处理。

对于像AI语音助手这样的实时流媒体应用,UDP是更合适的选择,因为它让我们在糟糕的网络状况下能完全控制如何处理数据。
高层网络协议选择
既然我们知道UDP是我们的用例的理想选择,我们该如何使用它呢?它是一个底层协议,因此直接使用它需要编写大量代码。幸运的是,有一些更易于使用的高层网络协议。有三种协议在所有浏览器、桌面和移动设备上得到广泛支持,那就是HTTP、WebSocket和WebRTC。
HTTP协议及其局限性
HTTP建立在TCP之上,我们现在知道TCP并非我们构建应用的理想选择。它是一个无状态协议,意味着它并非为需要持续来回流式传输数据的长连接而设计。
使用HTTP时,发送方连接到接收方,发送一些数据,然后断开连接。忽略其底层的TCP劣势不谈,如果我们仍然想使用HTTP在用户和代理之间交换语音数据,我们必须弄清楚在发送方要缓冲多长时间的音频,建立到接收方的连接,发送该缓冲区,然后在发送完成后断开连接。这不仅难以做好,而且每次连接和断开都需要额外的时间,这会增加整体延迟,并使处理用户中途打断代理等事情变得困难。


最后,HTTP代表超文本传输协议,而不是超音频、超语音或超语音协议,这意味着它没有用于来回发送音频数据的高层抽象。对于我们的用例来说,在客户端和服务器之间交换音频数据是我们主要做的事情,因此拥有强大的工具来做这件事会很好。
一个有趣的事实:十多年前,像Siri或Alexa这样的应用实际上为它们的语音代理使用HTTP。当用户有疑问时,他们的客户端应用(如Alexa设备)会将他们的语音录制到本地文件。一旦用户说完话,他们的客户端会向服务器端点发出HTTP请求,将包含用户查询的音频文件上传到亚马逊服务器。服务器应用处理他们的查询,生成一个音频文件响应,并在HTTP响应中发回该文件。一旦客户端应用下载了音频文件,它就会通过设备扬声器播放出来。现在你更了解HTTP在底层的工作原理,就能明白为什么那些早期的语音代理感觉不那么快速或像对话了。
理想架构:有状态连接

我们需要的是一个有状态架构,一个可以在用户和代理之间建立持久连接并持续来回流式传输音频的架构。任何一方都可以实时处理语音,就像人类用耳朵听一样,并在代理生成语音或用户说话时流式传输语音。有了有状态系统,代理可以建立对话历史,并实时检测用户何时说完话或何时打断它。
是否有协议可以帮助我们实现这一点?
WebSocket协议
WebSocket确实支持持久连接,并允许我们来回流式传输任意数据,但像HTTP一样,它建立在TCP之上,因此从根本上遭受同样的问题。它也没有任何用于来回发送音频数据的特殊设施。
WebRTC协议
WebRTC是另一种广泛支持的协议,支持长连接和双向数据流。它建立在UDP之上,并且是专门为在两台计算机之间传输音频或视频数据而设计的。

在协议层面,WebRTC实时测量网络状况,并调整音频数据包的发送节奏,以便它们尽可能平稳、一致地到达接收端。它还会在数据通过线路发送之前自动压缩音频数据,这有助于降低延迟。一方需要发送的数据越多,所需时间就越长。例如,通过HTTP请求发送的或通过WebSocket流式传输的5秒未压缩语音数据,在被WebRTC协议压缩后,数据大小仅为原来的3%。
最后,WebRTC会自动为通过线路发送的每个数据包加上时间戳,使得处理中断和准确知道中断发生的时间变得轻而易举。
WebRTC的挑战与解决方案
WebRTC被世界上一些最广泛采用的应用大规模使用。Discord、Google Meet、Zoom和TikTok都将其用于实时音频和视频流。
然而,WebRTC也带来了一些挑战。
挑战一:复杂性
它确实非常难以使用。这仅仅是在发送方和接收方之间建立一对一通话所需的完整调用栈。

挑战二:扩展性
标准的WebRTC协议是一个点对点协议。这意味着,如果我们为标准WebRTC用于我们的语音代理应用,你的用户和代理将直接连接。语音数据将通过公共互联网直接从源流式传输到目的地。
正如我们之前学到的,公共互联网就像世界的道路系统,有相当于高速公路、住宅街道、单车道、坑洼,甚至高峰时段。其他人的数据包和你的数据包在同一条道路上行驶。你的数据包需要行驶的距离越长,它们最终遇到这些道路危险的可能性就越大,这些数据包到达目的地所需的时间也就越长。
解决这个问题的一种方法是在世界各地部署你的代理,这样无论你的用户在哪里,他们与代理之间交换音频的路径都相对较短。然而,这是一项相当艰巨的任务,并且带来了很多操作复杂性。


幸运的是,有基础设施可以解决使用标准WebRTC带来的这两个挑战。
LiveKit:简化WebRTC
LiveKit是一个开源项目,它使得使用WebRTC构建和扩展语音代理比在客户端使用HTTP或WebSocket更容易。

在客户端,LiveKit拥有适用于所有平台的开源SDK,你可以将其集成到你的应用中。它简化了在用户和代理之间建立持久连接以及来回流式传输语音的过程。
在服务器端,LiveKit有一个开源框架,使得构建AI语音代理变得简单。我们将在下一课中更多地讨论代理端。
还记得我们学到的那个道路系统吗?事实证明,还有另一种避免交通拥堵的方法。与其走公共道路,不如让我们沿着互联网中的私人隧道行驶。
LiveKit Cloud是一组分布在世界各地的WebRTC服务器,它们形成了一个全球隧道网络。当你的用户想要向你的代理流式传输语音数据时,他们可以通过公共互联网将数据发送到最近的LiveKit Cloud服务器。从用户设备到最近站点的这一跳距离很短,因此增加的延迟不大。一旦数据包到达LiveKit Cloud服务器,它们就会通过这个隧道网络,沿着优化后的路径传输,几乎没有拥塞。数据包将在最靠近代理运行位置的服务器处退出LiveKit的网络,并完成到代理本身的最后一段短途旅行。

在实践中,这种策略将用户和你的代理之间的网络延迟降低了约20%到50%。

如果你有兴趣看到LiveKit的实际应用,OpenAI团队使用LiveKit构建了ChatGPT高级语音模式。当你与他们的语音代理交谈时,所有这些语音数据都通过LiveKit的云网络来回传输。

总结
本节课中,我们一起学习了AI语音助手端到端架构的第一部分。我们深入探讨了用户设备与服务器代理之间的通信机制,比较了TCP与UDP协议在实时语音传输中的优劣,并得出结论:基于UDP的WebRTC协议是构建低延迟、流畅语音交互的理想选择。我们还介绍了WebRTC的挑战以及如何利用LiveKit这样的基础设施来简化开发并提升全球网络性能。现在你已经很好地理解了用户设备和你的代理之间底层发生的情况,接下来我们将更多地讨论语音代理本身,以及一旦用户的语音到达服务器后,幕后发生了什么。
004:端到端架构(第二部分)🎤

概述
在本节课中,我们将深入探讨语音助手(Voice Agent)的核心架构,了解其如何通过一个有序的“流水线”模型来“听”、“想”和“说”。我们将重点解析语音转文本(STT)、大语言模型(LLM)和文本转语音(TTS)如何协同工作,并学习构建拟人化对话体验中最具挑战性的技术之一:话轮检测(Turn Detection)。
语音助手是什么?🤖
上一节我们介绍了如何通过WebRTC将客户端设备连接到语音助手。这很棒,用户现在可以用低于30-50毫秒的延迟与你的助手对话。
那么,语音助手究竟是什么?语音助手本质上是一个有状态的计算机程序,它能够消费和处理流入的语音数据(例如用户对着手机说话),并生成语音响应发送回用户。你的助手程序的大部分应用逻辑将针对你的具体用例,但使用LiveKit的Agent SDK构建的语音助手具有一个持久的WebRTC连接,将其与一个或多个客户端设备链接起来。

LiveKit的Agent SDK还负责管理对话上下文,并为每个想要与之对话的用户启动一个助手实例。每个助手实例可以保持数据库连接以执行诸如RAG(检索增强生成)之类的操作,与同一台机器上运行的库或服务交互,或发起HTTP请求,或建立WebSocket连接。

这些外部服务连接用于语音转文本或LLM推理等功能。在接下来的课程中,你将使用LiveKit的Agent SDK来构建你的语音助手。你将使用Python构建,但也可以使用Node.js。
助手的“听、想、说”流水线 🔄

我们如何赋予助手倾听、思考和回应用户的能力?让我们放大来看这部分。这就是所谓的流水线或级联组件模型语音架构。
当用户的语音输入数据流式传输到助手时,它会经过一系列有序的步骤,然后助手的语音响应才会被发送回用户。
以下是该流水线的核心步骤:
- 语音转文本(STT):助手将用户的语音转发给一个较小的语音转文本AI模型(常缩写为STT)。STT模型实时将语音转换为文本,并传回给助手。
- 大语言模型推理(LLM):当用户停止说话,助手获得了用户所说的完整转录文本后,它会将该完整转录作为用户的提示词(prompt)转发给一个LLM。LLM接收该提示词并对其进行推理。随着输出令牌(token)的生成,它们会从LLM流式传输回助手。
- 文本转语音(TTS):助手收集并组织这些令牌。对于它收集到的每一个句子,助手会将该句子转发给另一个较小的文本转语音模型(常缩写为TTS)。TTS模型将助手发送的句子转换回语音,并流式传输给助手。
- 音频流回传:助手接收这些数据,并将来自TTS的语音数据字节,通过我们在上一课中讨论过的持久WebRTC连接,实时转发回客户端设备。


这就是你的助手运行的完整端到端流水线:它接收用户语音,转换为文本,将该文本输入LLM,将LLM输出的令牌通过TTS管道传输,然后从TTS将音频流式传输回用户。
话轮检测:拟人对话的关键 🎯
现在,我想把注意力转向构建令人信服的拟人语音助手中最困难的问题之一:话轮检测。
在人类对话中,这种在说话和倾听之间交替的概念被称为话轮转换。人类非常擅长自动知道何时该说话或倾听。话轮检测是语音助手用来判断用户何时说完、可以做出响应的启发式方法。

话轮检测系统结合了两种信号:
- 信号处理:用户是否真的在说话?
- 语义处理:用户实际说了什么?
以下是其典型工作方式:
当用户音频流入时,它不仅被发送到STT,同时也会并行流式传输到一个叫做语音活动检测(简称VAD)的模块中。VAD分析音频信号,它是一个小型二元分类神经网络,简单地输出在输入样本中是否检测到人类语音。
当比特位从“检测到人声”翻转为“未检测到人声”时,VAD会启动一个计时器,计时器在开发者可配置的毫秒数后触发一个标记用户话轮结束的事件。如果在计时器触发前VAD再次检测到人声,则一切重置。

同时,当用户的语音被STT转换为文本并发送回助手时,助手也将转录文本转发给话轮检测系统的另一部分:一个语义话轮检测器模型。LiveKit有一个我们内部训练的开源模型。它接收用户转录的语音以及对话中前三四轮的转录文本,并基于用户所说的内容输出一个预测,判断它认为用户是否已经说完。
例如,如果VAD检测到静默并设置了计时器来触发话轮结束事件,但语义模型认为用户还没说完(可能只是在思考间隙停顿),那么话轮检测器会将计时器的触发延迟一段可配置的时间。
现在我们理解了话轮检测,这就是我们整合了该功能的整体语音助手架构图。只有当话轮检测系统触发了话轮结束事件时,助手才能继续将用户转录的语音转发给LLM进行推理。
中断处理与上下文管理 ⚡


VAD不仅用于话轮检测。它也用于中断处理,以模拟两个人对话的动态。
我们需要能够处理用户在助手说话中途打断的情况。这可能由于多种原因发生,包括LLM可能说得太多、用户改变了主意,或者用户想纠正自己。
在底层,由于用户的语音已经通过话轮检测传入VAD,我们使用人声的存在(而非话轮检测中的人声缺失)作为中断信号。当中断发生时,语音流水线下游的每个部分都会被刷新:如果LLM当时正在进行推理,则停止;如果有任何助手的语音正在由TTS生成,也同样停止。

我们整体架构的最后一个更新是上下文管理。当轮到助手思考和说话时,不仅发送用户最近一次说话的转录文本给LLM,还会一并发送该会话中迄今为止任何一方所说的所有内容的完整历史记录。这包括诸如函数调用及其结果等内容,这是大多数生产级语音助手的一部分。

LiveKit的Agent SDK还会在用户打断助手时自动同步LLM上下文。它使用时间戳来确定用户最后听到的助手回放内容,并将助手端的对话对齐到这一点。
总结 🎓
本节课中我们一起学习了语音助手的核心架构。我们拆解了“听-想-说”的完整流水线,深入探讨了实现自然对话的关键技术——话轮检测,它结合了VAD信号处理和语义分析。我们还了解了如何通过VAD实现中断处理,以及如何管理对话上下文以确保连贯性。
现在,我们已经将所有部分整合在一起。在下一课中,我们将把这里讨论的所有理论概念付诸实践,构建一个你可以与之对话的语音助手。



005:语音助手核心组件 🎙️

在本节课中,我们将深入探讨语音助手从用户开始说话到助手做出响应的整个流程中的各个核心构建模块。我们将分解流水线中的每个阶段,讨论其中的权衡取舍,并了解在哪些环节可以做出决策,从而真正塑造用户体验。无论你是优化速度、质量还是可控性,理解每一层的工作原理都将帮助你构建更智能、更高效的语音助手。
语音助手的两种主要类型
语音助手主要有两种类型。第一种是流水线式,这是我们之前详细介绍过的。第二种是语音到语音或实时助手,Naalina在第一课中介绍过。
语音到语音助手的实现通常更简单,听起来也更自然。但作为交换,你放弃了对中间过程的控制。由于模型直接接收语音并输出语音,因此很难查看或调整中间发生的事情。
另一方面,流水线式助手有更多的组成部分,是的,也更复杂,但你能对每个阶段进行细粒度的控制。你可以精确地查看和管理每个步骤的输入和输出,这可能非常重要。
现实应用中的权衡取舍
对于现实世界的应用,每个系统都存在权衡取舍。在某些时候,你可能需要在延迟、质量和成本之间做出选择。

使用流水线方法的一大优势是,你不需要全局性地做出这种权衡。你可以根据具体用例最看重的方面,更换系统中的不同部分。
以Nealina之前给出的例子来说,如果你在做餐厅预订这类事情,你可能希望优化语言模型的推理能力,从模型中获得尽可能好的响应。但如果你处理的是像医疗分诊这样需要精确转录的任务,那么将更多的延迟预算花在语音转文本层上可能更有意义。
设计各组件时的关键考量
接下来,我们谈谈在具体实施时真正重要的因素。以下是设计这些部分时需要牢记的一些关键点。
首先是语音活动检测。这个组件只在检测到有人实际说话时才发送音频。这非常重要。它减少了语音转文本模型的幻觉,并且由于不发送静默片段进行转录,从而降低了成本。
然后是语音转文本层。在这里,我们需要做出一些关键决策,例如我们希望支持哪些语言,是否进行直接语音翻译,以及是否希望在更窄的用例(如电话通信)中使用专门训练的模型来识别语音。
语音助手的最后两个步骤是大语言模型层和文本转语音层。
大语言模型层是人们已经最熟悉的部分。在这里,我们运行文本到文本的推理,从大语言模型获得响应。如果你想添加内容过滤等功能,就是在这个层进行。根据你使用的模型,这里也是延迟影响最大的地方。
最后是文本转语音层。这一层将LLM生成的文本转换回语音。在TTS层,你可以选择使用哪种声音或口音,以及是否希望对特定单词或短语应用发音覆盖,以便它们以某种特定方式说出来。
动手实践:编写代码
现在,让我们将所学的一切付诸实践,开始编写代码。
首先,我们将导入必要的LiveKit Agent类和插件,包括用于语音转文本的OpenAI、作为推理层的LLM、用于TTS的ElevenLabs以及用于语音活动检测的Clero。我们还将导入dotenv以便将环境变量加载到内存中,并导入logging以便查看代理的运行情况。
import asyncio
import os
from dotenv import load_dotenv
from livekit.agents import Agent, Room, VoiceActivityDetector, SpeechToText, TextToSpeech
from livekit.plugins import openai, elevenlabs, clero
load_dotenv()
我们定义一个继承自livekit.agents.Agent类的助手类。这个助手被赋予关于其角色的基本指令,并将跟踪到目前为止对话中说了什么。默认情况下,发送给LLM的请求是无状态的,但我们希望保持一个有历史记录的对话。助手会将我们来回发送的所有消息保存在上下文中,以便它能进行一个了解我们之前说过什么的对话。它还会跟踪轮到谁说话、是否可以被中断以及它可以使用哪些工具来回答用户的问题。今天,我们只设置instructions参数,并从基础代理继承所有其他默认值。
class MyAssistant(Agent):
def __init__(self):
super().__init__(
instructions="你是一个乐于助人的AI助手。请用友好、专业的语气回答用户的问题。"
)
接下来,我们将定义一个异步入口点函数,当LiveKit通知我们的代理需要时,它将运行。默认情况下,每个新房间都会请求一个代理。房间是将代理会话连接到用户的原始实体。当代理和用户进行对话时,对话就发生在一个房间内。
这个入口点函数逐步执行以下操作:连接到LiveKit房间,定义一个包含所有必要插件的代理会话(这些插件用于监听用户和与用户对话),并将我们的助手分配给该会话。
async def entrypoint(room: Room):
# 连接到房间
await room.connect()
# 定义插件
vad = clero.VoiceActivityDetector()
stt = openai.SpeechToText()
tts = elevenlabs.TextToSpeech(voice_id="EXAVITQu4vr4xnSDxMaL") # 示例语音ID
llm = openai.LLM()
# 创建代理会话
agent_session = Agent(
vad=vad,
stt=stt,
tts=tts,
llm=llm,
agent_class=MyAssistant
)
# 将代理附加到房间
await agent_session.attach(room=room)
最后,我们使用LiveKit Agent Jupiter CLI命令向LiveKit注册应用程序。这将允许我们的代理在房间需要时被调度。
if __name__ == "__main__":
from livekit.agents.cli import run_agent
run_agent(entrypoint)
当我们运行下一个单元时,我们将能够与我们的代理进行对话。
代理对话示例:
用户: Hello there.
代理: It‘s wonderful to have you here. How can I assist you today? 😊
用户: Hi there. What kind of things can you help with?
代理: Hi. I‘m here to help with a wide range of topics. Whether you need information, help solving a problem, or just want to chat. Feel free to ask about anything.
很好,我们的代理运行正常。
自定义代理声音
既然我们的代理正在运行,让我们把声音换成别的。
我们将向上滚动到定义自定义代理的地方,并添加一个语音ID。
tts = elevenlabs.TextToSpeech(voice_id="ANOTHER_VOICE_ID_HERE") # 更改为新的语音ID
现在当我们运行代理时:
用户: Hello there.
代理: It‘s wonderful to have you here. How can I assist you today?
用户: Hi, Roger, thanks for joining us. I love your voice. 😊
代理: Thank you so much. It‘s great to be here with you. How can I make your day better?
课程总结 🎯
本节课中,我们一起学习了语音助手的核心组件。我们首先介绍了流水线式和语音到语音两种主要架构及其权衡。然后,我们详细探讨了语音活动检测、语音转文本、大语言模型和文本转语音这四个关键层级的职责与设计考量。
在实践部分,我们成功运行了一个基础的语音助手,并通过修改代码轻松地更换了它的声音。这体现了流水线架构提供的灵活性和控制力。

在下一课中,我们将学习一些关于性能指标的知识,以及如何优化我们的代理。
006:优化延迟


在本节课中,我们将学习如何优化AI语音助手的延迟。我们将逐一分析语音处理管道的每个阶段,找出延迟发生的位置,并探讨如何从语音检测到文本生成,再到语音输出的全流程中减少延迟。我们将介绍那些能让你的助手感觉快速、响应灵敏的关键调节手段。
概述:延迟的重要性与优化目标
语音助手的成败取决于延迟。一个响应迅速的助手能提供更好的用户体验。本节课程将引导你理解整个语音处理流程,识别瓶颈,并实施有效的优化策略。
客户端优化:WebRTC的作用

上一节我们介绍了语音管道的整体流程,本节中我们来看看客户端如何为低延迟做出贡献。一个保持系统快速运行的关键部分来自客户端。我们来详细谈谈WebRTC。
WebRTC是一个开源项目,它使得在网页浏览器和移动应用中直接进行实时通信成为可能。其核心在于,它允许你共享音频、视频和数据,而无需任何插件或额外软件。
以下是WebRTC的关键功能:
- 它使用
getUserMediaAPI 来访问你设备的摄像头和麦克风。 - 它还通过
getDisplayMedia方法支持屏幕共享。 - 如果你希望超越音视频,可以使用RTC数据通道进行直接的数据交换。
优化语音处理管道
现在,让我们来讨论如何优化语音处理管道。你可能还记得这里的主要组件。
我们拥有语音活动检测,用于识别用户何时在说话。还有话轮检测,用于管理说话者之间的转换。以及语音转文本,负责将音频转换为文字。
默认情况下,VAD和话轮检测是阻塞式的,这是有意为之的。我们不希望发送音频帧,除非我们确信那确实是语音。对于VAD,我们通常在每个话语开始时损失大约15到20毫秒,只是为了确认语音正在发生。
话轮检测则有些不同。它不会阻塞转录过程。它会监听用户话轮的结束,并在结束时触发一个事件,但在用户仍在说话时,它不会停止转录的进行。
以下是它在实践中的工作方式。如果某人正在说一段话,比如五个句子,语音转文本会在用户说话时连续地分段进行转录。最初的几个片段会实时发送给转录器。一旦话轮检测发出信号表明说话者已经结束,我们才会将完整的转录文本发送给LLM。所以,并不是所有内容都在等待一个大块数据,它是一个流,而话轮检测只是帮助我们知道何时向前推进。
优化大语言模型阶段
接下来是LLM阶段。LLM逐个令牌地生成响应。即使是模型本身,在完成之前也无法确切知道完整响应会有多长。因此,等待整个响应准备就绪对我们来说是没有意义的。
相反,我们在LLM生成响应的同时,将其输出流式传输到文本转语音引擎。这里需要跟踪的最重要指标是首令牌时间。这是模型生成其响应第一部分所需的时间。它通常定义了用户在有任何事情发生之前需要等待多久。在此之后的一切都是异步发生的:当LLM继续生成令牌时,我们已经将文本传递给TTS引擎开始合成语音。因此,如果你想减少总体响应时间,首令牌时间是你应该集中进行延迟优化的地方。
优化文本转语音流式传输
最后,我们来看文本转语音流式传输阶段。在这个阶段,我们直接从LLM流式传输到TTS引擎,这为我们提供了最佳的延迟。与LLM阶段以首令牌时间为关键指标不同,这里最重要的事情是关注首字节时间。这是我们实际开始听到音频从TTS引擎输出的时刻。
渲染完整响应所需的总时间不那么关键,只要渲染速度比引擎能说话的速度快即可。因为物理上说出一段话语需要时间,模型有一个缓冲区。所以,再次强调,对于TTS性能,需要优化的就是那个首字节时间。这决定了语音实际开始回应的速度。
实践:测量与优化代理速度
让我们看看代理实际上有多快,并跟踪一些指标。这里的第一个步骤将与上一个模块相同。
我们将导入我们的代理插件和模块。不过,我们需要添加一些额外的东西。我们将导入定义从语音管道每个部分收集的数据结构的度量类。这些类帮助我们访问性能信息,如响应时间、令牌计数、音频持续时间等。我们还将导入 asyncio,以便可以运行异步任务。这让我们能够处理指标收集和其他后台工作,而不会阻塞代理的主流程。
接下来,我们将像上一个代理一样定义我们的代理。但这次我们将称其为 metrics_agent。
接下来,我们将添加我们的指标收集钩子。这些处理器让我们从管道的每个部分收集性能数据,并在指标可用时触发回调函数。
我们添加的第一样东西是我们的LLM指标。这是针对首令牌时间和每秒令牌数的。接下来,我们将添加我们的STT指标包装器。这将告诉我们输入的持续时间以及是否使用了流式传输。然后,我们将添加我们的话语结束指标包装器。这个将告诉我们使用VAD检测到某人说话花了多长时间,以及转录花了多长时间。最后,是我们的文本转语音指标包装器。这个将是首字节时间和总渲染时间。这是说明代理开始对我们说话的速度有多快的指标。
现在我们已经定义了包装器,我们将实际定义那些将收集指标并将其打印到控制台的回调函数。
首先是LLM指标。我们在这里跟踪的是提示令牌、完成令牌、每秒令牌数以及那个至关重要的首令牌时间。接下来,我们将添加我们的语音转文本指标。即音频的总持续时间,以及响应是否被流式传输。接下来是话语结束指标。这个告诉我们语音转文本运行了多长时间以及VAD花了多长时间。最后,是我们的文本转语音指标。这是首字节时间,即我们实际能听到代理说话需要多长时间,以及音频持续时间和响应是否被流式传输。
接下来,我们将像上一个代理一样定义我们的入口点。然后我们就可以运行我们的代理了。
Hi, I wanted to see how fast you were.
Hello, I'm designed to respond quickly to your questions and requests. How can I assist you today?
现在,当我们向下滚动查看日志时,可以看到我们所有的语音转文本指标。我们可以看到我们的LLM指标,包括每秒令牌数和首令牌时间。然后我们可以看到那些关键的首字节花了多长时间才传过来。
好的,现在让我们做一个改变。目前,我们LLM的首令牌时间是0.84秒,但我想我们可以让它变得更好一点。我们将把我们的LLM模型从 gpt-4 改为 gpt-4o-mini。这是一个比 gpt-4 能力稍弱的模型,但它的响应速度要快得多。
让我们再次使用 gpt-4o-mini 与我们的代理对话。
Hi there, I just wanted to see how fast you are.
I'm ready to help. What do you need assistance with?
现在,如果我们向下滚动查看LLM指标,可以看到我们的首令牌时间几乎比使用 gpt-4 时快了一倍。
总结
本节课中,我们一起学习了如何系统性地优化AI语音助手的延迟。我们重建了代理,添加了跟踪各项性能指标的能力,并通过更换为更快的模型,将LLM的响应时间减少了近一半。关键要点在于:关注并优化管道中每个阶段的特定延迟指标,如LLM的首令牌时间和TTS的首字节时间,是打造快速响应语音助手的关键。


007:总结
在本课程中,我们学习了构建生产级AI语音助手所需的核心组件与系统架构。现在,让我们对所学内容进行回顾与总结。
课程概述

在本节课中,我们回顾了AI语音助手流水线的各个组成部分,并探讨了如何将它们组合成一个具备低延迟通信和智能体托管能力的完整系统,以构建一个实用的对话式AI智能体。
核心内容回顾
上一节我们介绍了系统的具体实现细节,本节中我们来对整个课程进行总结。
以下是本课程涵盖的核心组件:
- 语音识别:将用户的语音输入转换为文本。
- 自然语言理解:理解转换后文本的意图和关键信息。
- 对话管理:根据理解的结果管理对话状态和流程。
- 自然语言生成:根据对话状态生成合适的文本回复。
- 语音合成:将生成的文本回复转换为自然语音输出。
这些组件通过精心设计的低延迟通信协议连接,并部署在可靠的托管平台上,共同构成了一个高效的AI语音助手系统。
总结
本节课中我们一起学习了构建一个可用于生产环境的AI语音助手的完整流程。从识别语音到理解意图,再到管理对话并生成回应,每个环节都至关重要。通过将各个组件有效集成,并确保系统间的低延迟通信,我们能够打造出流畅、自然的对话体验。
希望本课程对你有所帮助。我们期待在智能体构建的道路上与你继续交流。

浙公网安备 33010602011771号