ASR、TTS 与实时语音对话架构

前言

随着 GPT-4o 和 OpenAI Realtime API 的发布,语音交互进入了“原生多模态”时代。然而,构建一个低延迟、高自然度的语音对话系统仍然面临诸多挑战。本文将详细介绍语音交互系统的核心组件与实战架构。


语音对话系统架构

传统的语音对话系统通常采用 ASR -> LLM -> TTS 的级联架构。

┌─────────────────────────────────────────────────────────────────┐
│                      语音对话流水线                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. [VAD] → 检测用户是否开始/停止说话                           │
│                                                                 │
│  2. [ASR] → 语音转文字 (Whisper / FunASR)                       │
│                                                                 │
│  3. [LLM] → 理解意图并生成文本回复                              │
│                                                                 │
│  4. [TTS] → 文字转语音 (OpenAI TTS / Fish Speech)               │
│                                                                 │
│  5. [播放] → 音频流式输出                                       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

语音识别 (ASR)

常用工具对比

工具 优点 缺点 适用场景
Whisper (OpenAI) 准确度极高,支持多语言 速度较慢(非流式) 离线转录
Groq Whisper 极速(<100ms) 云端 API 实时对话
FunASR (阿里) 中文优化好,支持流式 部署较重 国内生产环境
Faster-Whisper 本地推理优化 需要 GPU 本地部署

使用 Faster-Whisper

from faster_whisper import WhisperModel

model_size = "base"
model = WhisperModel(model_size, device="cuda", compute_type="float16")

def transcribe(audio_path: str):
    segments, info = model.transcribe(audio_path, beam_size=5)
    text = "".join([segment.text for segment in segments])
    return text

语音合成 (TTS)

常用工具对比

工具 优点 缺点 适用场景
OpenAI TTS 极其自然,简单易用 无法克隆声音 通用助手
Fish Speech 开源,支持中英日,效果惊人 部署复杂 高质量克隆
GPT-SoVITS 强大的声音克隆能力 训练门槛高 个性化角色
Edge-TTS 免费,速度快 机械感稍强 简单播报

使用 OpenAI TTS 流式输出

from openai import OpenAI

client = OpenAI()

def text_to_speech_stream(text: str):
    response = client.audio.speech.create(
        model="tts-1",
        voice="alloy",
        input=text,
    )
    # 流式写入文件或播放器
    response.stream_to_file("output.mp3")

---

#### 核心挑战:低延迟与打断处理

在语音对话中**延迟 (Latency)** 是用户体验的杀手如果回复延迟超过 1 对话就会变得尴尬

#### 1. VAD (静音检测) 与打断逻辑
系统必须知道用户什么时候开始说话什么时候说完
- **Silero VAD**目前最流行的轻量级 VAD 模型可以在 CPU 上实时运行
- **打断逻辑**当用户在 AI 说话时突然插话系统必须立即停止 TTS 播放并清空当前的生成队列

```python
# 打断逻辑伪代码
def on_user_speech_start():
    if tts_player.is_playing():
        tts_player.stop()
        llm_chain.cancel_current_generation()
        print("用户插话,已停止播放")

2. 流式级联 (Streaming Cascade)

不要等 LLM 生成完所有文字再传给 TTS。

  • 策略:LLM 每生成一个完整的句子(遇到句号、问号),就立即发给 TTS 进行合成。这样用户在听第一句时,系统正在合成第二句。

进阶:原生多模态 (OpenAI Realtime API)

传统的 ASR-LLM-TTS 架构存在“信息丢失”:ASR 丢失了用户的语气、情感;TTS 无法根据上下文调整语调。 OpenAI Realtime API 解决了这个问题:它直接在音频流上进行推理。

核心优势

  • 极低延迟:通过 WebSocket 实现全双工通信。
  • 情感感知:模型能听出用户的焦虑、兴奋或讽刺。
  • 原生打断:服务器端自动处理语音打断。
# Realtime API (WebSocket) 概念示例
import websockets

async def voice_chat():
    url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview"
    async with websockets.connect(url, extra_headers=headers) as ws:
        # 发送音频流
        await ws.send(audio_chunk)
        # 接收音频流并直接播放
        async for message in ws:
            if message.type == "response.audio.delta":
                play_audio(message.delta)

声音克隆与个性化 (TTS)

Fish SpeechGPT-SoVITS 让普通人也能拥有高质量的 AI 替身。

  • 1-shot 克隆:只需要 5-10 秒的样本音频,就能模仿一个人的音色。
  • 跨语言合成:用你的声音说出流利的德语或日语。

总结:构建语音助手的建议

  1. VAD 是灵魂:一个好的 VAD 能让对话感觉像真人在交流。
  2. 延迟优化:优先选择支持流式的 ASR 和 TTS。
  3. 关注情感:在 Prompt 中加入语气指导(如:“请用温柔、耐心的语气回答”)。
  4. 端侧处理:如果可能,将 VAD 和 ASR 放在客户端运行,减少网络往返。

语音交互是 AI 的终极形态。随着技术的进步,我们正在告别冰冷的文字框,迎来一个可以随时随地“聊天”的 AI 时代。


---

#### 实时性优化:低延迟架构设计

在语音对话中,延迟超过 1 秒就会让用户感到不自然。我们需要在每个环节进行极致优化。

#### 1. 语音活动检测 (VAD) 与打断处理

使用 `Silero VAD` 可以精准识别用户是否说话结束,并支持“打断”逻辑:如果用户在 AI 播放音频时开始说话,立即停止播放。

```python
import torch
import numpy as np

# 加载 Silero VAD 模型
model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad', model='silero_vad')
(get_speech_timestamps, save_audio, read_audio, VADIterator, collect_chunks) = utils

def process_audio_stream(audio_chunk, is_ai_speaking):
    """
    处理实时音频流
    audio_chunk: 采样率为 16000 的音频片段
    is_ai_speaking: 当前 AI 是否正在播放声音
    """
    # 检测当前片段是否包含人声
    speech_prob = model(torch.from_numpy(audio_chunk), 16000).item()
    
    if speech_prob > 0.5:
        if is_ai_speaking:
            # 触发打断逻辑
            stop_ai_playback()
            clear_audio_buffer()
            print("检测到用户插话,停止 AI 播放")
        return True # 正在说话
    return False

2. 流式级联:Sentence-level Streaming

不要等待 LLM 生成全文。利用标点符号进行“断句流式输出”,将文本片段立即送入 TTS。

async def streaming_pipeline(user_audio):
    # 1. ASR (使用 Faster-Whisper 流式)
    text_stream = await asr.transcribe_stream(user_audio)
    
    # 2. LLM (流式生成)
    full_response = ""
    async for chunk in llm.astream(text_stream):
        full_response += chunk
        # 遇到句号、问号等结束符,立即合成语音
        if chunk in ["", "", "", ".", "!", "?"]:
            audio_segment = await tts.generate(full_response)
            await audio_player.play(audio_segment)
            full_response = "" # 清空缓冲区,准备下一句

进阶:Fish Speech 零样本声音克隆

Fish Speech 支持仅凭一段 10 秒的参考音频实现极高相似度的声音克隆。

from fish_speech import FishSpeechClient

client = FishSpeechClient(api_key="your_key")

async def clone_voice(text: str, reference_audio_path: str):
    """
    使用参考音频克隆声音并合成新文本
    """
    audio_content = await client.tts(
        text=text,
        ref_audio=reference_audio_path,
        format="mp3"
    )
    with open("cloned_voice.mp3", "wb") as f:
        f.write(audio_content)

OpenAI Realtime API

OpenAI 推出的原生多模态接口,跳过了 ASR/TTS 级联,直接进行语音到语音的交互。

import asyncio
import websockets
import json

async def realtime_chat():
    url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01"
    headers = {
        "Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}",
        "OpenAI-Beta": "realtime=v1"
    }

    async with websockets.connect(url, extra_headers=headers) as ws:
        # 发送配置
        await ws.send(json.dumps({
            "type": "session.update",
            "session": {
                "modalities": ["text", "audio"],
                "voice": "alloy"
            }
        }))

        # 发送音频数据 (Base64)
        # await ws.send(json.dumps({"type": "input_audio_buffer.append", "audio": "..."}))

完整实战架构:WebRTC 语音助手

对于 Web 应用,推荐使用 WebRTC 传输音频流。

  1. 前端:使用 MediaRecorder 采集音频,通过 WebRTC 传给后端。
  2. 后端
    • 接收音频流。
    • 使用 VAD 截断。
    • 异步调用 ASR
    • LLM 生成回复。
    • TTS 生成音频切片。
    • 通过 WebRTC 回传音频流。

常见问题与对策

  • 打断处理 (Interruption):当用户在 AI 说话时突然插话,系统需要立即停止当前的 TTS 输出并清空缓冲区。
  • 背景噪音:使用 DeepFilterNetRNNoise 进行前端降噪。
  • 方言支持:Whisper 对方言支持较好,但特定行业术语可能需要微调 ASR 模型。

总结

语音交互是 LLM 应用的高级形态。虽然级联架构(ASR+LLM+TTS)目前仍是主流且灵活,但原生多模态(如 Realtime API)代表了未来的方向。开发者应根据业务对延迟、成本和个性化(声音克隆)的要求选择合适的技术栈。


参考资源

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:《 LLM应用开发——语音交互系统实战 》

本文链接:http://localhost:3015/ai/%E8%AF%AD%E9%9F%B3%E4%BA%A4%E4%BA%92%E7%B3%BB%E7%BB%9F.html

本文最后一次更新为 天前,文章中的某些内容可能已过时!