概述

聊天界面主导了我们与AI的交互方式,但多模态AI领域的最新突破正在开启令人兴奋的新可能。高质量的生成模型和富有表现力的文本转语音(TTS)系统,使得构建更像对话伙伴而非工具的智能代理成为可能。 语音代理就是其中一个例子。你无需再依赖键盘和鼠标向代理输入信息,而是可以直接用语音与它交互。这可以成为一种更自然、更引人入胜的AI交互方式,在某些特定场景下尤其有用。

什么是语音代理?

语音代理是能够与用户进行自然语音对话的代理。这些代理结合了语音识别、自然语言处理、生成式AI和文本转语音技术,以创建无缝、自然的对话体验。 它们适用于多种用例,包括:
  • 客户服务支持
  • 个人助理
  • 免提接口
  • 辅导和培训

语音代理如何工作?

从高层次来看,每个语音代理都需要处理三个任务:
  1. 听 - 捕获音频并转录为文本
  2. 思 - 理解意图、进行推理、规划
  3. 说 - 生成音频并将其流式传输回用户
不同之处在于这些步骤的排序和耦合方式。在实践中,生产环境的代理主要遵循以下两种架构之一:

1. STT > 代理 > TTS 架构(“三明治”架构)

三明治架构由三个独立组件组成:语音转文本(STT)、基于文本的 LangChain 代理和文本转语音(TTS)。 优点:
  • 完全控制每个组件(可按需更换 STT/TTS 提供商)
  • 能够利用最新的文本模态模型能力
  • 行为透明,组件间界限清晰
缺点:
  • 需要编排多个服务
  • 管理管道增加了额外复杂性
  • 从语音到文本的转换会丢失信息(例如语气、情感)

2. 语音到语音架构(S2S)

语音到语音架构使用能够原生处理音频输入并生成音频输出的多模态模型。 优点:
  • 架构更简单,组件更少
  • 通常对于简单交互延迟更低
  • 直接处理音频,能捕捉语气等语音细微差别
缺点:
  • 可用模型有限,提供商锁定风险更大
  • 功能可能落后于文本模态模型
  • 音频处理过程透明度较低
  • 可控性和自定义选项减少
本指南演示了三明治架构,以平衡性能、可控性和对现代模型能力的利用。使用某些 STT 和 TTS 提供商时,三明治架构可以实现低于 700 毫秒的延迟,同时保持对模块化组件的控制。

演示应用程序概述

我们将逐步构建一个使用三明治架构的语音代理。该代理将管理一家三明治店的订单。该应用程序将演示三明治架构的全部三个组件,使用 AssemblyAI 进行 STT,使用 Cartesia 进行 TTS(不过也可以为大多数提供商构建适配器)。 完整的参考应用程序可在 voice-sandwich-demo 仓库中找到。我们将在此处详细介绍该应用程序。 该演示使用 WebSockets 实现浏览器和服务器之间的实时双向通信。相同的架构可适用于其他传输方式,如电话系统(Twilio、Vonage)或 WebRTC 连接。

架构

该演示实现了一个流式处理管道,每个阶段异步处理数据: 客户端(浏览器)
  • 捕获麦克风音频并将其编码为 PCM
  • 与后端服务器建立 WebSocket 连接
  • 实时向服务器流式传输音频块
  • 接收并播放合成的语音音频
服务器(Node.js)
  • 接受来自客户端的 WebSocket 连接
  • 编排三步管道:
    • 语音转文本(STT):将音频转发给 STT 提供商(例如 AssemblyAI),接收转录事件
    • 代理:使用 LangChain 代理处理转录文本,流式传输响应令牌
    • 文本转语音(TTS):将代理响应发送给 TTS 提供商(例如 Cartesia),接收音频块
  • 将合成的音频返回给客户端进行播放
该管道使用异步迭代器来实现每个阶段的流式传输。这使得下游组件可以在上游阶段完成之前开始处理,从而最大限度地减少端到端延迟。

设置

详细的安装说明和设置,请参阅仓库 README。

1. 语音转文本

STT 阶段将传入的音频流转换为文本转录。该实现使用生产者-消费者模式来并发处理音频流和转录接收。

关键概念

生产者-消费者模式:音频块被发送到 STT 服务,同时接收转录事件。这使得转录可以在所有音频到达之前开始。 事件类型:
  • stt_chunk:在 STT 服务处理音频时提供的部分转录
  • stt_output:触发代理处理的最终、格式化的转录
WebSocket 连接:维护与 AssemblyAI 实时 STT API 的持久连接,配置为 16kHz PCM 音频并自动格式化轮次。

实现

该应用程序实现了一个 AssemblyAI 客户端来管理 WebSocket 连接和消息解析。实现如下所示;也可以为其他 STT 提供商构建类似的适配器。

2. LangChain 代理

代理阶段通过 LangChain 代理 处理文本转录,并流式传输响应令牌。在本例中,我们流式传输代理生成的所有文本内容块。

关键概念

流式响应:代理使用 stream_events(version="v3") 配合 stream.messages 来在生成响应令牌时立即发出,而不是等待完整的响应。这使得 TTS 阶段可以立即开始合成。 对话记忆:检查点器 使用唯一的线程 ID 来维护跨轮次的对话状态。这使得代理可以引用对话中的先前交流。

实现

3. 文本转语音

TTS 阶段将代理响应文本合成为音频,并将其流式传输回客户端。与 STT 阶段类似,它使用生产者-消费者模式来并发处理文本发送和音频接收。

关键概念

并发处理:该实现合并了两个异步流:
  • 上游处理:传递所有事件并将代理文本块发送到 TTS 提供商
  • 音频接收:接收来自 TTS 提供商的合成音频块
流式 TTS:一些提供商(如 Cartesia)会在接收到文本后立即开始合成音频,使得音频播放可以在代理完成生成完整响应之前开始。 事件传递:所有上游事件都原样流过,允许客户端或其他观察者跟踪整个管道的状态。

实现

该应用程序实现了一个 Cartesia 客户端来管理 WebSocket 连接和音频流。实现如下所示;也可以为其他 TTS 提供商构建类似的适配器。

LangSmith

你使用 LangChain 构建的许多应用程序将包含多个步骤和多次 LLM 调用。随着这些应用程序变得越来越复杂,能够检查链或代理内部究竟发生了什么变得至关重要。做到这一点的最佳方法是使用 LangSmith。 在上方链接注册后,请确保设置你的环境变量以开始记录跟踪:

整合所有部分

完整的管道将三个阶段串联在一起:
每个阶段独立且并发地处理事件:音频一到达就开始转录,转录文本一可用代理就开始推理,代理文本一生成语音合成就开始。这种架构可以实现低于 700 毫秒的延迟,以支持自然的对话。 有关使用 LangChain 构建代理的更多信息,请参阅代理指南。