第 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 系统来说,这需要特殊处理:
- AI 正在说话时,用户开口了
- 客户端检测到用户开始说话,立刻通知服务端
- 服务端立刻停止 TTS 合成和音频回传
- 客户端立刻停止播放正在播放的音频
- 系统切换到接听用户输入的状态
这个过程需要客户端和服务端的精确协调,任何一个环节延迟都会导致 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(本地) | Kokoro | 82M 参数,CPU 可跑 |
每个模块都会提供云端 API 方案(成本低,适合快速验证)和本地模型方案(无网络依赖,适合生产部署),你可以按需选择。
1.6 本章小结
本章建立了整个系统的全局视图:
- 数据流向:麦克风 → VAD → WebSocket → ASR → LLM → TTS → WebSocket → 扬声器
- 各模块职责:每个模块只做一件事,通过标准接口协作
- 三大挑战:延迟、中断、并发——这三个问题将贯穿全书
- 我们的目标:构建 VoiceBot,一个从零开始、配置驱动、生产可用的语音对话系统
下一章,我们从音频信号的基础知识开始——在写任何代码之前,先搞清楚你的麦克风采集到的数据到底长什么样。
本章没有代码,因为在动手之前,先在脑子里跑通整个系统更重要。从第 2 章开始,每章都有可运行的代码示例。