第 1 章:智能语音对话系统全貌

16 阅读8分钟

第 1 章:智能语音对话系统全貌

当你开口说话,背后发生了什么

想象这样一个场景:你对着手机说了一句话,不到一秒钟,AI 用流畅的语音回答了你。

这一秒钟里,至少发生了以下这些事:

  • 麦克风捕捉到你的声音,转成数字信号
  • 系统判断你什么时候开始说、什么时候说完
  • 语音被识别成文字
  • 大模型理解文字,生成回复
  • 回复文字被合成成语音
  • 音频从服务器传回你的设备,播放出来

每一步都在争夺时间。每多一毫秒,体验就差一分。

本章的目标是让你在脑子里建立起这个系统的完整地图——不是某一个模型有多厉害,而是这些模块如何协作,构成一个真实可用的语音对话系统


1.1 一次完整对话的数据流

我们先从宏观视角看整个系统。下图是一次完整对话的数据流向:

用户设备(浏览器 / 手机)
────────────────────────────────────────────
  [麦克风]
     │ PCM 音频流(16kHz, 16bit, mono)
     ↓
  [VAD] ←── 检测说话开始 / 结束
     │ 有效语音片段
     ↓
  [WebSocket 客户端] ──→ 音频分帧发送
────────────────────────────────────────────
           ↕ WebSocket 双向连接
────────────────────────────────────────────
服务端
  [WebSocket 网关] ←── 接收音频帧
     │
     ↓
  [ASR] ──── 语音 → 文字(流式)
     │ "今天天气怎么样"
     ↓
  [LLM Agent] ──── 理解 + 生成回复(流式)
     │ "今天北京晴,气温 18 度……"
     ↓
  [TTS] ──── 文字 → 音频(流式合成)
     │ PCM 音频块(48kHz)
     ↓
  [WebSocket 网关] ──→ 分块回传
────────────────────────────────────────────
           ↕ WebSocket 双向连接
────────────────────────────────────────────
用户设备
  [音频播放器] ←── 边收边播
     │
  [扬声器] 🔊

注意几个关键词:流式分块双向。整个系统不是"等全部处理完再返回",而是一边处理一边传递。这是实现低延迟的核心思路,我们会在后续章节深入讲解每一个环节。


1.2 各模块职责

收音端:VAD(Voice Activity Detection)

VAD 解决的问题是:用户什么时候在说话?

你可能觉得这很简单,但实际上麦克风是一直开着的。如果把所有音频都发给服务器处理,既浪费带宽,又会让 ASR 识别出一堆背景噪声。VAD 的职责就是在用户设备上完成这个判断,只在检测到真实语音时才开始传输。

时间轴:
──────[静音]──────[说话开始]──────[说话内容]──────[说话结束]──────[静音]──
                      ↑                                    ↑
                  VAD 触发                             VAD 关闭
                  开始传输                             停止传输

VAD 运行在客户端(浏览器或移动端),这样可以在本地做判断,不需要任何网络请求。


收音端:音频采集与传输

VAD 触发之后,音频需要从客户端传到服务端。这里有几个细节:

  • 格式:麦克风原始输出通常是 48kHz 浮点数,而 ASR 模型通常需要 16kHz 16-bit 整数。客户端需要做重采样
  • 协议:使用 WebSocket 保持长连接,实时传输音频帧
  • 分帧:不是等录完再发,而是每隔几十毫秒发一帧,让服务端尽早开始处理

服务端:ASR(Automatic Speech Recognition)

ASR 把语音转成文字。现代 ASR 支持两种模式:

模式特点适用场景
离线(Offline)等用户说完再识别,准确率高对延迟不敏感的场景
流式(Streaming)边说边识别,实时返回中间结果对话系统、实时字幕

对话系统通常用流式 ASR,这样 LLM 可以尽早拿到文字开始处理,而不是等用户说完整句话之后再启动。


服务端:LLM Agent

LLM Agent 是整个系统的"大脑"。它接收 ASR 输出的文字,结合对话历史,生成回复。

在一个完整的 VoiceAI 系统中,LLM Agent 不只是调用大模型 API,它还需要:

  • 管理对话上下文:记住多轮对话的内容
  • 流式输出:不等完整回复生成,每产出几个字就立刻传给 TTS
  • 工具调用(Tool Use):查天气、搜索资料、调用外部 API
LLM Agent 内部流程:

用户输入 ──→ [构建 Prompt] ──→ [调用 LLM API(流式)]
                                        │
                          每生成一个 token 就往下传
                                        ↓
                          [按标点切分句子] ──→ 发给 TTS

切分句子这一步很关键:TTS 需要完整的句子才能合成,但 LLM 是逐 token 生成的。所以我们需要积累到一个自然停顿点(句号、问号等)再触发 TTS,这是降低首字延迟的核心技巧。


服务端:TTS(Text-to-Speech)

TTS 把文字转成语音。和 ASR 一样,现代 TTS 也支持流式合成——文字进去,音频块陆续出来,不需要等整句话合成完再播放。

TTS 的输出会实时回传给客户端,客户端边收边播,进一步压缩延迟。


服务端:WebSocket 网关

WebSocket 网关是客户端和服务端之间的唯一通道。它负责:

  • 接收客户端发来的音频帧、控制信令(比如"用户开始说话了")
  • 发送服务端产生的 TTS 音频块、文字结果、状态更新

这个双向通道贯穿整个系统的生命周期——从用户进入页面,到对话结束。


1.3 三个核心工程挑战

理解了各模块之后,我们来看这个系统里最难的三个问题。


挑战一:延迟

用户说完最后一个字,到听到 AI 开始说话,这段时间叫做 TTFS(Time to First Speech)。对话场景下,用户能接受的 TTFS 大约在 1 秒以内,超过 1.5 秒就会感觉"卡"。

延迟来自每一个环节的叠加:

TTFS = VAD 尾端检测延迟
     + 网络传输延迟(客户端 → 服务端)
     + ASR 识别延迟
     + LLM 首 token 延迟
     + TTS 首帧合成延迟
     + 网络传输延迟(服务端 → 客户端)
     + 音频播放缓冲延迟

每一项单独看都不大,加起来就很可观了。整本书里,降低延迟是贯穿始终的主题,我们会在第 18 章专门系统性地分析和优化。


挑战二:中断(Barge-in)

正常的人类对话里,你可以随时打断对方。但对 VoiceAI 系统来说,这需要特殊处理:

  1. AI 正在说话时,用户开口了
  2. 客户端检测到用户开始说话,立刻通知服务端
  3. 服务端立刻停止 TTS 合成和音频回传
  4. 客户端立刻停止播放正在播放的音频
  5. 系统切换到接听用户输入的状态

这个过程需要客户端和服务端的精确协调,任何一个环节延迟都会导致 AI"说话说到一半被打断,但还在继续说"的尴尬体验。


挑战三:并发

一个真实部署的系统需要同时服务多个用户,而每个用户的对话都有自己的状态:对话历史、当前播放进度、TTS 队列……这些状态必须严格隔离,不能相互干扰。

在 Python 里,我们用 asyncio 的异步模型来处理并发,每个会话是一个独立的异步任务集合。这也是为什么第 3 章要专门讲异步编程。


1.4 我们将要构建的系统

本书会带你从零实现一个完整的 VoiceAI 对话系统,最终长这样:

# 最终效果:5 行代码启动一个语音对话服务
from voicebot import VoiceBot, Config

config = Config.from_file("config.json")
bot = VoiceBot(config)
bot.run(host="0.0.0.0", port=8080)
// config.json:换模型不改代码
{
    "asr": { "type": "StreamingASR", "model": "qwen-asr" },
    "llm": { "type": "OpenAIAgent", "model": "qwen-plus" },
    "tts": { "type": "StreamingTTS", "model": "cosyvoice" }
}

前端只需要打开浏览器,手机和电脑都可以直接使用。

整个项目我们叫它 VoiceBot,每一章都会往这个项目里添加新功能,从一个空目录开始,最终构建出一个生产可用的系统。


1.5 技术选型

在开始之前,先明确本书使用的技术栈:

层次技术原因
服务端语言Python 3.11+asyncio 成熟,AI 生态丰富
Web 框架FastAPI原生支持 async,WebSocket 支持好
前端原生 JavaScript不引入框架依赖,专注音频逻辑
ASR(云端)阿里云实时语音识别有免费额度,延迟低
ASR(本地)SherpaOnnx轻量,支持离线
LLM任意 OpenAI 兼容接口可接 Qwen、GPT、本地 Ollama
TTS(云端)CosyVoice API中文效果好,有免费额度
TTS(本地)Kokoro82M 参数,CPU 可跑

每个模块都会提供云端 API 方案(成本低,适合快速验证)和本地模型方案(无网络依赖,适合生产部署),你可以按需选择。


1.6 本章小结

本章建立了整个系统的全局视图:

  • 数据流向:麦克风 → VAD → WebSocket → ASR → LLM → TTS → WebSocket → 扬声器
  • 各模块职责:每个模块只做一件事,通过标准接口协作
  • 三大挑战:延迟、中断、并发——这三个问题将贯穿全书
  • 我们的目标:构建 VoiceBot,一个从零开始、配置驱动、生产可用的语音对话系统

下一章,我们从音频信号的基础知识开始——在写任何代码之前,先搞清楚你的麦克风采集到的数据到底长什么样。


本章没有代码,因为在动手之前,先在脑子里跑通整个系统更重要。从第 2 章开始,每章都有可运行的代码示例。