AI语音助手开发实战完全教程

教程简介

零基础AI语音助手开发实战完全教程,涵盖语音助手架构设计、ASR语音识别集成、LLM对话引擎、TTS语音合成、实时语音交互(WebSocket)、多轮对话管理、语音唤醒与VAD、多语言支持、智能家居/车载场景、性能优化与部署等核心技能,适合AI开发者系统学习。

AI语音助手开发实战完全教程

从架构设计到生产部署,手把手构建一个支持多轮对话、多语言的AI语音助手系统。


目录


一、语音助手架构设计

1.1 整体架构概览

一个完整的AI语音助手系统由以下核心模块组成:

┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   音频输入   │───→│  ASR语音识别  │───→│  LLM对话引擎  │───→│  TTS语音合成  │
│  (麦克风/流)  │    │ (Whisper等)  │    │  (GPT-4等)   │    │ (Edge TTS等) │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
       ↑                                                        │
       │              ┌─────────────┐                           │
       └──────────────│  播放输出    │←──────────────────────────┘
                      │  (扬声器)   │
                      └─────────────┘

1.2 技术栈选型

模块 推荐方案 备选方案 说明
ASR OpenAI Whisper FunASR, Paraformer Whisper多语言能力最强
LLM GPT-4o Claude, Qwen, DeepSeek 根据场景选择
TTS Edge TTS CosyVoice, Fish Speech Edge TTS免费且质量高
通信 WebSocket HTTP SSE, gRPC 实时交互用WebSocket
唤醒 Porcupine Whisper关键词检测 唤醒词专用引擎
VAD Silero VAD WebRTC VAD Silero准确率更高

1.3 项目结构

voice-assistant/
├── main.py                 # 主入口
├── config.py               # 配置管理
├── requirements.txt
├── core/
│   ├── __init__.py
│   ├── asr.py              # 语音识别模块
│   ├── llm.py              # 对话引擎模块
│   ├── tts.py              # 语音合成模块
│   ├── vad.py              # 语音活动检测
│   └── wake_word.py        # 唤醒词检测
├── session/
│   ├── __init__.py
│   └── manager.py          # 会话管理
├── transport/
│   ├── __init__.py
│   └── websocket_server.py # WebSocket服务
├── utils/
│   ├── __init__.py
│   └── audio.py            # 音频工具函数
└── tests/
    ├── test_asr.py
    ├── test_tts.py
    └── test_session.py

二、ASR语音识别集成

2.1 Whisper本地部署

OpenAI Whisper是目前最流行的开源语音识别模型,支持99种语言:

# core/asr.py
import whisper
import numpy as np
from typing import Optional

class ASREngine:
    """基于Whisper的语音识别引擎"""
    
    def __init__(self, model_size: str = "base", device: str = "cpu"):
        """
        初始化ASR引擎
        
        Args:
            model_size: 模型大小 tiny/base/small/medium/large
            device: 运行设备 cpu/cuda
        """
        self.model = whisper.load_model(model_size, device=device)
        self.sample_rate = 16000  # Whisper要求16kHz
    
    def transcribe(
        self,
        audio_data: np.ndarray,
        language: Optional[str] = None,
        task: str = "transcribe",
    ) -> dict:
        """
        转录音频数据
        
        Args:
            audio_data: 音频数据(float32, 16kHz, 单声道)
            language: 语言代码,None为自动检测
            task: "transcribe"转录 / "translate"翻译为英文
            
        Returns:
            {"text": str, "language": str, "segments": list}
        """
        # 确保音频格式正确
        if audio_data.dtype != np.float32:
            audio_data = audio_data.astype(np.float32)
        
        # 归一化
        if audio_data.max() > 1.0:
            audio_data = audio_data / 32768.0
        
        result = self.model.transcribe(
            audio_data,
            language=language,
            task=task,
            fp16=False,  # CPU模式下关闭fp16
        )
        
        return {
            "text": result["text"].strip(),
            "language": result.get("language", "unknown"),
            "segments": result.get("segments", []),
        }
    
    def transcribe_file(self, file_path: str, language: Optional[str] = None) -> dict:
        """转录音频文件"""
        result = self.model.transcribe(file_path, language=language)
        return {
            "text": result["text"].strip(),
            "language": result.get("language", "unknown"),
            "segments": result.get("segments", []),
        }


# 使用示例
if __name__ == "__main__":
    asr = ASREngine(model_size="base")
    result = asr.transcribe_file("test.wav")
    print(f"识别结果: {result['text']}")
    print(f"检测语言: {result['language']}")

2.2 流式识别方案

对于实时对话场景,需要边听边识别的流式方案:

# core/streaming_asr.py
import numpy as np
from collections import deque
import threading
import time

class StreamingASR:
    """流式语音识别,支持实时转录"""
    
    def __init__(self, asr_engine, chunk_duration=2.0, overlap=0.5):
        """
        Args:
            asr_engine: ASREngine实例
            chunk_duration: 每次识别的音频长度(秒)
            overlap: 重叠长度(秒),用于上下文连贯
        """
        self.asr = asr_engine
        self.chunk_samples = int(chunk_duration * 16000)
        self.overlap_samples = int(overlap * 16000)
        self.buffer = deque(maxlen=self.chunk_samples * 3)
        self.result_callback = None
        self._running = False
    
    def set_callback(self, callback):
        """设置识别结果回调"""
        self.result_callback = callback
    
    def feed_audio(self, audio_chunk: np.ndarray):
        """喂入音频数据"""
        self.buffer.extend(audio_chunk)
        
        if len(self.buffer) >= self.chunk_samples:
            # 取出一个chunk进行识别
            chunk = np.array(list(self.buffer)[:self.chunk_samples])
            
            # 保留overlap部分用于上下文
            for _ in range(self.chunk_samples - self.overlap_samples):
                self.buffer.popleft()
            
            # 异步识别
            threading.Thread(
                target=self._process_chunk,
                args=(chunk,),
                daemon=True,
            ).start()
    
    def _process_chunk(self, chunk: np.ndarray):
        """处理单个音频块"""
        result = self.asr.transcribe(chunk)
        if result["text"] and self.result_callback:
            self.result_callback(result)

2.3 FunASR阿里方案(中文优化)

# 适合中文场景的FunASR方案
from funasr import AutoModel

class FunASREngine:
    """基于FunASR的中文优化语音识别"""
    
    def __init__(self):
        # 语音识别模型
        self.model = AutoModel(
            model="paraformer-zh",
            vad_model="fsmn-vad",      # 内置VAD
            punc_model="ct-punc",       # 自动标点
            device="cpu",
        )
    
    def transcribe(self, audio_path: str) -> dict:
        result = self.model.generate(input=audio_path)
        return {
            "text": result[0]["text"] if result else "",
            "timestamp": result[0].get("timestamp", []),
        }

# 使用
asr = FunASREngine()
result = asr.transcribe("recording.wav")
print(result["text"])

三、LLM对话引擎

3.1 对话引擎核心实现

# core/llm.py
import openai
from typing import List, Dict, Optional
from dataclasses import dataclass, field

@dataclass
class ConversationState:
    """对话状态"""
    messages: List[Dict] = field(default_factory=list)
    system_prompt: str = ""
    context: Dict = field(default_factory=dict)
    turn_count: int = 0

class LLMEngine:
    """LLM对话引擎"""
    
    def __init__(
        self,
        model: str = "gpt-4o-mini",
        api_key: Optional[str] = None,
        base_url: Optional[str] = None,
    ):
        self.client = openai.OpenAI(
            api_key=api_key,
            base_url=base_url,
        )
        self.model = model
        self.default_system_prompt = """你是一个友好的AI语音助手。
你的回答将被转换为语音播放,因此请遵循以下规则:
1. 回答简洁明了,避免过长的段落
2. 不要使用Markdown格式、代码块或特殊符号
3. 使用自然口语化的表达
4. 数字用中文读法(如"一百二十三"而非"123")
5. 如需列举,用"第一、第二"而非"1. 2. 3."
6. 单次回答控制在150字以内"""
    
    def chat(
        self,
        user_input: str,
        conversation: ConversationState,
        stream: bool = True,
    ) -> str:
        """
        处理用户输入,返回回复文本
        
        Args:
            user_input: 用户的文本输入(ASR识别结果)
            conversation: 对话状态
            stream: 是否流式输出
        """
        # 添加用户消息
        conversation.messages.append({
            "role": "user",
            "content": user_input,
        })
        
        # 构建完整消息列表
        full_messages = [
            {"role": "system", "content": conversation.system_prompt or self.default_system_prompt},
            *conversation.messages[-20:],  # 保留最近20轮对话
        ]
        
        if stream:
            return self._stream_chat(full_messages, conversation)
        else:
            return self._sync_chat(full_messages, conversation)
    
    def _sync_chat(self, messages: List[Dict], conversation: ConversationState) -> str:
        """同步调用"""
        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            max_tokens=500,
            temperature=0.7,
        )
        reply = response.choices[0].message.content
        conversation.messages.append({"role": "assistant", "content": reply})
        conversation.turn_count += 1
        return reply
    
    def _stream_chat(self, messages: List[Dict], conversation: ConversationState) -> str:
        """流式调用,逐句返回"""
        stream = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            max_tokens=500,
            temperature=0.7,
            stream=True,
        )
        
        full_reply = ""
        for chunk in stream:
            if chunk.choices[0].delta.content:
                token = chunk.choices[0].delta.content
                full_reply += token
        
        conversation.messages.append({"role": "assistant", "content": full_reply})
        conversation.turn_count += 1
        return full_reply

3.2 工具调用(Function Calling)

让语音助手能够执行实际操作:

# core/tools.py
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的天气信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称,如'北京'、'上海'",
                    },
                    "date": {
                        "type": "string",
                        "description": "日期,格式YYYY-MM-DD,空值表示今天",
                    },
                },
                "required": ["city"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "control_device",
            "description": "控制智能家居设备",
            "parameters": {
                "type": "object",
                "properties": {
                    "device": {
                        "type": "string",
                        "description": "设备名称,如'客厅灯'、'空调'",
                    },
                    "action": {
                        "type": "string",
                        "enum": ["on", "off", "set"],
                        "description": "操作类型",
                    },
                    "value": {
                        "type": "string",
                        "description": "设置值,如温度、亮度百分比",
                    },
                },
                "required": ["device", "action"],
            },
        },
    },
]

def execute_tool_call(tool_name: str, arguments: dict) -> str:
    """执行工具调用"""
    if tool_name == "get_weather":
        # 实际项目中对接天气API
        return f"{arguments['city']}今天晴,气温25度,适合出行"
    
    elif tool_name == "control_device":
        device = arguments["device"]
        action = arguments["action"]
        value = arguments.get("value", "")
        if action == "on":
            return f"已打开{device}"
        elif action == "off":
            return f"已关闭{device}"
        else:
            return f"已将{device}设置为{value}"
    
    return "未知操作"

四、TTS语音合成

4.1 Edge TTS方案(免费高质量)

# core/tts.py
import edge_tts
import asyncio
import io
from typing import Optional

class TTSEngine:
    """基于Edge TTS的语音合成引擎"""
    
    # 可用的中文语音
    VOICES = {
        "zh-female-warm": "zh-CN-XiaoxiaoNeural",      # 温暖女声
        "zh-female-sweet": "zh-CN-XiaoyiNeural",        # 甜美女声
        "zh-male-calm": "zh-CN-YunxiNeural",            # 沉稳男声
        "zh-male-lively": "zh-CN-YunjianNeural",        # 活力男声
        "en-female": "en-US-JennyNeural",               # 英文女声
        "en-male": "en-US-GuyNeural",                   # 英文男声
        "ja-female": "ja-JP-NanamiNeural",              # 日文女声
    }
    
    def __init__(self, voice: str = "zh-CN-XiaoxiaoNeural", rate: str = "+0%", volume: str = "+0%"):
        """
        Args:
            voice: 语音名称或预设别名
            rate: 语速调节,如"+20%"、"-10%"
            volume: 音量调节
        """
        self.voice = self.VOICES.get(voice, voice)
        self.rate = rate
        self.volume = volume
    
    async def synthesize(self, text: str) -> bytes:
        """
        合成语音,返回WAV格式的字节数据
        
        Args:
            text: 要合成的文本
            
        Returns:
            MP3格式的音频字节数据
        """
        communicate = edge_tts.Communicate(
            text=text,
            voice=self.voice,
            rate=self.rate,
            volume=self.volume,
        )
        
        audio_data = b""
        async for chunk in communicate.stream():
            if chunk["type"] == "audio":
                audio_data += chunk["data"]
        
        return audio_data
    
    def synthesize_sync(self, text: str) -> bytes:
        """同步版本的语音合成"""
        return asyncio.run(self.synthesize(text))
    
    async def synthesize_to_file(self, text: str, output_path: str):
        """合成并保存到文件"""
        communicate = edge_tts.Communicate(
            text=text,
            voice=self.voice,
            rate=self.rate,
            volume=self.volume,
        )
        await communicate.save(output_path)
    
    @staticmethod
    async def list_voices(language: str = "zh") -> list:
        """列出可用语音"""
        voices = await edge_tts.list_voices()
        return [v for v in voices if v["Locale"].startswith(language)]


# 使用示例
if __name__ == "__main__":
    tts = TTSEngine(voice="zh-female-warm", rate="+10%")
    audio = tts.synthesize_sync("你好,我是你的AI语音助手,有什么可以帮你的吗?")
    
    with open("output.mp3", "wb") as f:
        f.write(audio)
    print(f"语音已保存,大小: {len(audio)} bytes")

4.2 流式TTS(首包延迟优化)

# core/streaming_tts.py
import edge_tts
import asyncio
from typing import AsyncGenerator

class StreamingTTSEngine:
    """流式语音合成,降低首包延迟"""
    
    def __init__(self, voice: str = "zh-CN-XiaoxiaoNeural", rate: str = "+0%"):
        self.voice = voice
        self.rate = rate
    
    async def stream_synthesize(self, text: str) -> AsyncGenerator[bytes, None]:
        """
        流式合成语音,逐块yield音频数据
        
        适合WebSocket场景:边生成文本边播放语音
        """
        communicate = edge_tts.Communicate(
            text=text,
            voice=self.voice,
            rate=self.rate,
        )
        
        async for chunk in communicate.stream():
            if chunk["type"] == "audio":
                yield chunk["data"]
    
    async def synthesize_sentences(self, text: str) -> AsyncGenerator[bytes, None]:
        """
        按句子分割,逐句合成
        
        适合长文本:每句话单独合成,降低整体延迟
        """
        sentences = self._split_sentences(text)
        
        for sentence in sentences:
            if sentence.strip():
                communicate = edge_tts.Communicate(
                    text=sentence.strip(),
                    voice=self.voice,
                    rate=self.rate,
                )
                
                async for chunk in communicate.stream():
                    if chunk["type"] == "audio":
                        yield chunk["data"]
    
    def _split_sentences(self, text: str) -> list:
        """将文本按句子分割"""
        import re
        # 支持中英文标点
        sentences = re.split(r'([。!?;\.\!\?\;])', text)
        result = []
        for i in range(0, len(sentences) - 1, 2):
            result.append(sentences[i] + sentences[i + 1])
        if len(sentences) % 2 == 1 and sentences[-1]:
            result.append(sentences[-1])
        return result

4.3 CosyVoice方案(本地部署)

# 适合需要本地部署、低延迟的场景
# 需要先安装 cosyvoice: pip install cosyvoice

from cosyvoice import CosyVoice
import torchaudio

class CosyVoiceTTS:
    """基于CosyVoice的本地TTS"""
    
    def __init__(self, model_path: str = "pretrained_models/CosyVoice-300M"):
        self.model = CosyVoice(model_path)
    
    def synthesize(
        self,
        text: str,
        speaker: str = "中文女",
        speed: float = 1.0,
    ) -> tuple:
        """
        合成语音
        
        Returns:
            (audio_tensor, sample_rate)
        """
        output = self.model.inference_sft(text, speaker, speed=speed)
        return output["tts_speech"], 22050
    
    def synthesize_with_clone(
        self,
        text: str,
        reference_audio: str,
        reference_text: str,
    ) -> tuple:
        """
        声音克隆模式:用参考音频的声音说新文本
        """
        output = self.model.inference_cross_lingual(
            text, reference_audio, reference_text
        )
        return output["tts_speech"], 22050

五、实时语音交互(WebSocket)

5.1 WebSocket服务端

# transport/websocket_server.py
import asyncio
import websockets
import json
import numpy as np
from typing import Dict, Set

class VoiceAssistantServer:
    """语音助手WebSocket服务"""
    
    def __init__(self, asr, llm, tts, session_manager):
        self.asr = asr
        self.llm = llm
        self.tts = tts
        self.sessions = session_manager
        self.clients: Set = set()
    
    async def handler(self, websocket, path=None):
        """处理WebSocket连接"""
        session_id = str(id(websocket))
        self.clients.add(websocket)
        conversation = self.sessions.create_session(session_id)
        
        print(f"Client connected: {session_id}")
        
        try:
            async for message in websocket:
                await self._process_message(websocket, session_id, message)
        except websockets.exceptions.ConnectionClosed:
            print(f"Client disconnected: {session_id}")
        finally:
            self.clients.discard(websocket)
            self.sessions.remove_session(session_id)
    
    async def _process_message(self, websocket, session_id: str, raw_message):
        """处理客户端消息"""
        if isinstance(raw_message, bytes):
            # 音频数据
            await self._handle_audio(websocket, session_id, raw_message)
        else:
            # JSON控制消息
            data = json.loads(raw_message)
            msg_type = data.get("type")
            
            if msg_type == "config":
                await self._handle_config(websocket, session_id, data)
            elif msg_type == "text":
                await self._handle_text(websocket, session_id, data)
            elif msg_type == "end_of_speech":
                await self._handle_eos(websocket, session_id)
    
    async def _handle_audio(self, websocket, session_id: str, audio_bytes: bytes):
        """处理音频流数据"""
        # 转换为numpy数组
        audio_array = np.frombuffer(audio_bytes, dtype=np.int16).astype(np.float32) / 32768.0
        
        session = self.sessions.get_session(session_id)
        session["audio_buffer"].extend(audio_array)
        
        # 通知客户端正在处理
        await websocket.send(json.dumps({
            "type": "status",
            "status": "listening",
        }))
    
    async def _handle_eos(self, websocket, session_id: str):
        """处理语音结束信号"""
        session = self.sessions.get_session(session_id)
        audio_buffer = np.array(session["audio_buffer"], dtype=np.float32)
        session["audio_buffer"] = []
        
        if len(audio_buffer) < 16000 * 0.5:  # 少于0.5秒
            await websocket.send(json.dumps({
                "type": "status",
                "status": "too_short",
            }))
            return
        
        # ASR识别
        await websocket.send(json.dumps({
            "type": "status",
            "status": "processing",
        }))
        
        asr_result = self.asr.transcribe(audio_buffer)
        user_text = asr_result["text"]
        
        if not user_text:
            await websocket.send(json.dumps({
                "type": "status",
                "status": "no_speech",
            }))
            return
        
        # 发送识别结果
        await websocket.send(json.dumps({
            "type": "asr_result",
            "text": user_text,
            "language": asr_result["language"],
        }))
        
        # LLM生成回复
        conversation = self.sessions.get_conversation(session_id)
        reply = self.llm.chat(user_text, conversation)
        
        # 发送文本回复
        await websocket.send(json.dumps({
            "type": "llm_result",
            "text": reply,
        }))
        
        # TTS合成并发送
        await websocket.send(json.dumps({
            "type": "status",
            "status": "speaking",
        }))
        
        audio_data = await self.tts.synthesize(reply)
        
        # 分块发送音频(每块4KB)
        chunk_size = 4096
        for i in range(0, len(audio_data), chunk_size):
            chunk = audio_data[i:i + chunk_size]
            await websocket.send(chunk)
        
        # 发送播放结束信号
        await websocket.send(json.dumps({
            "type": "audio_end",
        }))
    
    async def _handle_text(self, websocket, session_id: str, data: dict):
        """处理文本输入(跳过ASR)"""
        user_text = data["text"]
        conversation = self.sessions.get_conversation(session_id)
        reply = self.llm.chat(user_text, conversation)
        
        await websocket.send(json.dumps({
            "type": "llm_result",
            "text": reply,
        }))
        
        audio_data = await self.tts.synthesize(reply)
        await websocket.send(audio_data)
        await websocket.send(json.dumps({"type": "audio_end"}))
    
    def start(self, host: str = "0.0.0.0", port: int = 8765):
        """启动服务"""
        print(f"Voice Assistant Server starting on ws://{host}:{port}")
        start_server = websockets.serve(self.handler, host, port)
        asyncio.get_event_loop().run_until_complete(start_server)
        asyncio.get_event_loop().run_forever()

5.2 客户端实现

# client/voice_client.py
import asyncio
import websockets
import json
import pyaudio
import threading

class VoiceClient:
    """语音助手客户端"""
    
    def __init__(self, server_url: str = "ws://localhost:8765"):
        self.server_url = server_url
        self.audio = pyaudio.PyAudio()
        self.is_recording = False
        self.ws = None
    
    async def connect(self):
        """连接到服务端"""
        self.ws = await websockets.connect(self.server_url)
        print("Connected to voice assistant")
        
        # 启动接收和录音
        await asyncio.gather(
            self._receive_loop(),
            self._record_loop(),
        )
    
    async def _record_loop(self):
        """录音循环"""
        stream = self.audio.open(
            format=pyaudio.paInt16,
            channels=1,
            rate=16000,
            input=True,
            frames_per_buffer=1024,
        )
        
        print("🎤 按回车开始录音...")
        input()
        print("🔴 录音中... 按回车停止")
        self.is_recording = True
        
        # 在后台线程中等待停止信号
        def wait_for_stop():
            input()
            self.is_recording = False
        
        threading.Thread(target=wait_for_stop, daemon=True).start()
        
        while self.is_recording:
            data = stream.read(1024, exception_on_overflow=False)
            await self.ws.send(data)
            await asyncio.sleep(0.01)
        
        stream.stop_stream()
        stream.close()
        
        # 发送语音结束信号
        await self.ws.send(json.dumps({"type": "end_of_speech"}))
    
    async def _receive_loop(self):
        """接收服务端消息"""
        async for message in self.ws:
            if isinstance(message, bytes):
                # 音频数据,直接播放
                self._play_audio(message)
            else:
                data = json.loads(message)
                self._handle_message(data)
    
    def _handle_message(self, data: dict):
        """处理控制消息"""
        msg_type = data.get("type")
        
        if msg_type == "status":
            status = data["status"]
            if status == "listening":
                print("👂 正在聆听...")
            elif status == "processing":
                print("🧠 正在思考...")
            elif status == "speaking":
                print("🔊 正在回答...")
        
        elif msg_type == "asr_result":
            print(f"📝 你说: {data['text']}")
        
        elif msg_type == "llm_result":
            print(f"🤖 回复: {data['text']}")
        
        elif msg_type == "audio_end":
            print("✅ 回答完毕")
            print("\n🎤 按回车开始下一轮对话...")
            # 重新开始录音
            asyncio.ensure_future(self._record_loop())
    
    def _play_audio(self, audio_data: bytes):
        """播放音频"""
        stream = self.audio.open(
            format=pyaudio.paInt16,
            channels=1,
            rate=24000,
            output=True,
        )
        stream.write(audio_data)
        stream.stop_stream()
        stream.close()


# 运行客户端
if __name__ == "__main__":
    client = VoiceClient("ws://localhost:8765")
    asyncio.run(client.connect())

六、多轮对话管理

6.1 会话管理器

# session/manager.py
import uuid
import time
from typing import Dict, Optional
from dataclasses import dataclass, field
from core.llm import ConversationState

@dataclass
class Session:
    """会话数据"""
    session_id: str
    conversation: ConversationState
    created_at: float = field(default_factory=time.time)
    last_active: float = field(default_factory=time.time)
    audio_buffer: list = field(default_factory=list)
    metadata: Dict = field(default_factory=dict)

class SessionManager:
    """会话管理器,支持多用户并发"""
    
    def __init__(self, max_sessions: int = 100, timeout: int = 1800):
        """
        Args:
            max_sessions: 最大并发会话数
            timeout: 会话超时时间(秒)
        """
        self.sessions: Dict[str, Session] = {}
        self.max_sessions = max_sessions
        self.timeout = timeout
    
    def create_session(self, session_id: Optional[str] = None) -> Session:
        """创建新会话"""
        self._cleanup_expired()
        
        if len(self.sessions) >= self.max_sessions:
            self._remove_oldest()
        
        sid = session_id or str(uuid.uuid4())
        session = Session(
            session_id=sid,
            conversation=ConversationState(),
        )
        self.sessions[sid] = session
        return session
    
    def get_session(self, session_id: str) -> Optional[Session]:
        """获取会话"""
        session = self.sessions.get(session_id)
        if session:
            session.last_active = time.time()
        return session
    
    def get_conversation(self, session_id: str) -> ConversationState:
        """获取对话状态"""
        session = self.get_session(session_id)
        if not session:
            session = self.create_session(session_id)
        return session.conversation
    
    def remove_session(self, session_id: str):
        """移除会话"""
        self.sessions.pop(session_id, None)
    
    def _cleanup_expired(self):
        """清理过期会话"""
        now = time.time()
        expired = [
            sid for sid, session in self.sessions.items()
            if now - session.last_active > self.timeout
        ]
        for sid in expired:
            self.sessions.pop(sid)
    
    def _remove_oldest(self):
        """移除最旧的会话"""
        if self.sessions:
            oldest = min(self.sessions, key=lambda s: self.sessions[s].last_active)
            self.sessions.pop(oldest)

6.2 上下文记忆增强

# core/memory.py
from typing import List, Dict
import json

class ConversationMemory:
    """对话记忆管理,支持长期记忆"""
    
    def __init__(self, max_short_term: int = 10, max_long_term: int = 50):
        self.short_term: List[Dict] = []    # 短期记忆(当前对话)
        self.long_term: List[Dict] = []     # 长期记忆(跨会话)
        self.entity_memory: Dict[str, str] = {}  # 实体记忆
        self.max_short_term = max_short_term
        self.max_long_term = max_long_term
    
    def add_turn(self, role: str, content: str):
        """添加一轮对话"""
        self.short_term.append({
            "role": role,
            "content": content,
            "timestamp": time.time(),
        })
        
        # 超出容量时转移到长期记忆
        if len(self.short_term) > self.max_short_term:
            overflow = self.short_term[:len(self.short_term) - self.max_short_term]
            self.short_term = self.short_term[-self.max_short_term:]
            self.long_term.extend(overflow)
            
            # 长期记忆也有上限
            if len(self.long_term) > self.max_long_term:
                self.long_term = self.long_term[-self.max_long_term:]
    
    def extract_entities(self, text: str):
        """从文本中提取关键实体(简化版)"""
        # 实际项目中使用NER模型
        import re
        # 提取可能的名字
        names = re.findall(r'我叫(\w+)|我是(\w+)|我的名字是(\w+)', text)
        for match in names:
            name = next(m for m in match if m)
            self.entity_memory["user_name"] = name
    
    def get_context_messages(self) -> List[Dict]:
        """获取用于LLM的上下文消息"""
        messages = []
        
        # 添加长期记忆摘要
        if self.long_term:
            summary = self._summarize_history(self.long_term[-10:])
            messages.append({
                "role": "system",
                "content": f"之前的对话摘要:{summary}",
            })
        
        # 添加实体记忆
        if self.entity_memory:
            entities = ", ".join(f"{k}是{v}" for k, v in self.entity_memory.items())
            messages.append({
                "role": "system",
                "content": f"已知用户信息:{entities}",
            })
        
        # 添加短期记忆
        for turn in self.short_term:
            messages.append({
                "role": turn["role"],
                "content": turn["content"],
            })
        
        return messages
    
    def _summarize_history(self, history: List[Dict]) -> str:
        """摘要历史对话"""
        # 简化版:实际项目中用LLM生成摘要
        topics = set()
        for turn in history:
            topics.add(turn["content"][:50])
        return "讨论了:" + "、".join(list(topics)[:5])

七、语音唤醒与VAD

7.1 VAD语音活动检测

# core/vad.py
import torch
import numpy as np

class SileroVAD:
    """基于Silero的语音活动检测"""
    
    def __init__(self, threshold: float = 0.5, sample_rate: int = 16000):
        self.model, _ = torch.hub.load(
            repo_or_dir='snakers4/silero-vad',
            model='silero_vad',
            force_reload=False,
        )
        self.threshold = threshold
        self.sample_rate = sample_rate
        self.model.eval()
    
    def is_speech(self, audio_chunk: np.ndarray) -> bool:
        """
        检测音频块是否包含语音
        
        Args:
            audio_chunk: 音频数据,float32格式
            
        Returns:
            True表示检测到语音
        """
        if len(audio_chunk) < 512:
            return False
        
        tensor = torch.from_numpy(audio_chunk).float()
        if len(tensor.shape) == 1:
            tensor = tensor.unsqueeze(0)
        
        with torch.no_grad():
            prob = self.model(tensor, self.sample_rate).item()
        
        return prob > self.threshold
    
    def process_stream(self, audio_stream, chunk_size: int = 512):
        """
        处理音频流,yield语音片段
        
        用法:
            for speech_chunk in vad.process_stream(audio_stream):
                process_speech(speech_chunk)
        """
        speech_buffer = []
        silence_count = 0
        max_silence = 15  # 连续静音块数(约0.5秒)
        
        for chunk in audio_stream:
            if self.is_speech(chunk):
                speech_buffer.append(chunk)
                silence_count = 0
            else:
                if speech_buffer:
                    silence_count += 1
                    speech_buffer.append(chunk)
                    
                    if silence_count >= max_silence:
                        # 语音结束
                        yield np.concatenate(speech_buffer)
                        speech_buffer = []
                        silence_count = 0

7.2 唤醒词检测

# core/wake_word.py
import pvporcupine
import pyaudio
import struct

class WakeWordDetector:
    """基于Porcupine的唤醒词检测"""
    
    # 内置唤醒词
    BUILTIN_KEYWORDS = [
        "hey google", "alexa", "hey siri",
        "jarvis", "computer", "picovoice",
    ]
    
    def __init__(
        self,
        access_key: str,
        keywords: list = None,
        sensitivities: list = None,
    ):
        """
        Args:
            access_key: Picovoice访问密钥
            keywords: 唤醒词列表
            sensitivities: 灵敏度列表(0-1)
        """
        keywords = keywords or ["computer"]
        sensitivities = sensitivities or [0.5] * len(keywords)
        
        self.porcupine = pvporcupine.create(
            access_key=access_key,
            keywords=keywords,
            sensitivities=sensitivities,
        )
        
        self.audio = pyaudio.PyAudio()
        self.stream = self.audio.open(
            rate=self.porcupine.sample_rate,
            channels=1,
            format=pyaudio.paInt16,
            input=True,
            frames_per_buffer=self.porcupine.frame_length,
        )
    
    def listen(self, callback=None):
        """
        持续监听唤醒词
        
        Args:
            callback: 唤醒时的回调函数
        """
        print("🎧 等待唤醒词...")
        
        try:
            while True:
                pcm = self.stream.read(self.porcupine.frame_length)
                pcm = struct.unpack_from("h" * self.porcupine.frame_length, pcm)
                
                keyword_index = self.porcupine.process(pcm)
                
                if keyword_index >= 0:
                    print(f"✨ 检测到唤醒词!(index={keyword_index})")
                    if callback:
                        callback(keyword_index)
        except KeyboardInterrupt:
            print("停止监听")
        finally:
            self.cleanup()
    
    def cleanup(self):
        """释放资源"""
        self.stream.close()
        self.audio.terminate()
        self.porcupine.delete()


# 简易唤醒方案(不需要Porcupine)
class SimpleWakeWord:
    """基于关键词匹配的简易唤醒检测"""
    
    def __init__(self, asr_engine, wake_phrase: str = "你好助手"):
        self.asr = asr_engine
        self.wake_phrase = wake_phrase.lower()
    
    def check(self, audio_data: np.ndarray) -> bool:
        """检查音频中是否包含唤醒词"""
        result = self.asr.transcribe(audio_data, language="zh")
        text = result["text"].lower()
        return self.wake_phrase in text

八、多语言支持

8.1 语言检测与路由

# core/multilingual.py
from typing import Optional

class MultilingualRouter:
    """多语言路由器:自动检测语言并选择对应的ASR/TTS"""
    
    # 语言代码映射
    LANG_MAP = {
        "zh": {"name": "中文", "tts_voice": "zh-CN-XiaoxiaoNeural", "asr_lang": "zh"},
        "en": {"name": "English", "tts_voice": "en-US-JennyNeural", "asr_lang": "en"},
        "ja": {"name": "日本語", "tts_voice": "ja-JP-NanamiNeural", "asr_lang": "ja"},
        "ko": {"name": "한국어", "tts_voice": "ko-KR-SunHiNeural", "asr_lang": "ko"},
        "fr": {"name": "Français", "tts_voice": "fr-FR-DeniseNeural", "asr_lang": "fr"},
        "de": {"name": "Deutsch", "tts_voice": "de-DE-KatjaNeural", "asr_lang": "de"},
        "es": {"name": "Español", "tts_voice": "es-ES-ElviraNeural", "asr_lang": "es"},
    }
    
    def __init__(self, default_lang: str = "zh"):
        self.current_lang = default_lang
        self.default_lang = default_lang
    
    def detect_and_route(self, asr_result: dict) -> dict:
        """
        根据ASR检测到的语言,返回对应的TTS配置
        
        Args:
            asr_result: ASR识别结果,包含language字段
            
        Returns:
            包含语言配置的字典
        """
        detected_lang = asr_result.get("language", self.default_lang)
        
        # 语言切换逻辑
        if detected_lang in self.LANG_MAP:
            self.current_lang = detected_lang
        
        config = self.LANG_MAP.get(self.current_lang, self.LANG_MAP[self.default_lang])
        
        return {
            "language": self.current_lang,
            "language_name": config["name"],
            "tts_voice": config["tts_voice"],
            "asr_language": config["asr_lang"],
            "system_prompt_suffix": self._get_lang_prompt(self.current_lang),
        }
    
    def _get_lang_prompt(self, lang: str) -> str:
        """获取对应语言的系统提示词后缀"""
        prompts = {
            "zh": "请用中文回答。",
            "en": "Please respond in English.",
            "ja": "日本語で回答してください。",
            "ko": "한국어로 대답해 주세요.",
            "fr": "Veuillez répondre en français.",
            "de": "Bitte antworten Sie auf Deutsch.",
            "es": "Por favor responda en español.",
        }
        return prompts.get(lang, prompts[self.default_lang])
    
    def set_language(self, lang: str):
        """手动设置语言"""
        if lang in self.LANG_MAP:
            self.current_lang = lang

8.2 多语言对话示例

# 多语言使用示例
router = MultilingualRouter(default_lang="zh")

# 用户说中文
asr_result = {"text": "今天天气怎么样?", "language": "zh"}
config = router.detect_and_route(asr_result)
# → {"language": "zh", "tts_voice": "zh-CN-XiaoxiaoNeural", ...}

# 用户切换到英文
asr_result = {"text": "What's the weather like today?", "language": "en"}
config = router.detect_and_route(asr_result)
# → {"language": "en", "tts_voice": "en-US-JennyNeural", ...}

# 在LLM提示词中加入语言指令
system_prompt = f"""你是一个多语言AI助手。
{config['system_prompt_suffix']}
保持简洁口语化。"""

九、智能家居/车载场景实战

9.1 智能家居语音控制

# scenarios/smart_home.py
from typing import Dict, List
from dataclasses import dataclass

@dataclass
class Device:
    """智能家居设备"""
    name: str
    device_type: str  # light, ac, tv, speaker, curtain, etc.
    room: str
    state: Dict  # 当前状态

class SmartHomeController:
    """智能家居语音控制器"""
    
    def __init__(self):
        self.devices: Dict[str, Device] = {}
        self._init_devices()
    
    def _init_devices(self):
        """初始化示例设备"""
        devices_config = [
            {"name": "客厅灯", "type": "light", "room": "客厅", "state": {"on": True, "brightness": 80, "color": "暖白"}},
            {"name": "卧室灯", "type": "light", "room": "卧室", "state": {"on": False, "brightness": 50, "color": "暖白"}},
            {"name": "空调", "type": "ac", "room": "客厅", "state": {"on": True, "temp": 26, "mode": "制冷"}},
            {"name": "电视", "type": "tv", "room": "客厅", "state": {"on": False, "channel": 1, "volume": 30}},
            {"name": "窗帘", "type": "curtain", "room": "卧室", "state": {"open": True, "position": 100}},
        ]
        
        for cfg in devices_config:
            self.devices[cfg["name"]] = Device(
                name=cfg["name"],
                device_type=cfg["type"],
                room=cfg["room"],
                state=cfg["state"],
            )
    
    def get_tools_definition(self) -> List[Dict]:
        """获取工具定义(用于LLM Function Calling)"""
        return [
            {
                "type": "function",
                "function": {
                    "name": "control_device",
                    "description": "控制智能家居设备",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "device_name": {
                                "type": "string",
                                "description": f"设备名称,可选:{', '.join(self.devices.keys())}",
                            },
                            "action": {
                                "type": "string",
                                "enum": ["turn_on", "turn_off", "set_brightness", "set_temp", "set_color"],
                            },
                            "value": {
                                "type": "string",
                                "description": "设置值(亮度0-100、温度16-30、颜色名称)",
                            },
                        },
                        "required": ["device_name", "action"],
                    },
                },
            },
            {
                "type": "function",
                "function": {
                    "name": "query_device",
                    "description": "查询设备状态",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "device_name": {
                                "type": "string",
                                "description": f"设备名称,可选:{', '.join(self.devices.keys())}",
                            },
                        },
                        "required": ["device_name"],
                    },
                },
            },
        ]
    
    def execute(self, tool_name: str, arguments: dict) -> str:
        """执行设备控制"""
        if tool_name == "control_device":
            return self._control_device(arguments)
        elif tool_name == "query_device":
            return self._query_device(arguments)
        return "未知操作"
    
    def _control_device(self, args: dict) -> str:
        """控制设备"""
        name = args["device_name"]
        action = args["action"]
        value = args.get("value")
        
        device = self.devices.get(name)
        if not device:
            return f"未找到设备:{name}"
        
        if action == "turn_on":
            device.state["on"] = True
            return f"已打开{name}"
        elif action == "turn_off":
            device.state["on"] = False
            return f"已关闭{name}"
        elif action == "set_brightness" and device.device_type == "light":
            device.state["brightness"] = int(value)
            return f"已将{name}亮度设置为{value}%"
        elif action == "set_temp" and device.device_type == "ac":
            device.state["temp"] = int(value)
            return f"已将{name}温度设置为{value}度"
        
        return f"操作完成"
    
    def _query_device(self, args: dict) -> str:
        """查询设备状态"""
        name = args["device_name"]
        device = self.devices.get(name)
        if not device:
            return f"未找到设备:{name}"
        
        status_parts = []
        if "on" in device.state:
            status_parts.append("开启" if device.state["on"] else "关闭")
        if "brightness" in device.state:
            status_parts.append(f"亮度{device.state['brightness']}%")
        if "temp" in device.state:
            status_parts.append(f"温度{device.state['temp']}度")
        if "open" in device.state:
            status_parts.append("已打开" if device.state["open"] else "已关闭")
        
        return f"{name}当前状态:{','.join(status_parts)}"


# 使用示例
controller = SmartHomeController()

# 模拟LLM工具调用
result = controller.execute("control_device", {
    "device_name": "客厅灯",
    "action": "set_brightness",
    "value": "60",
})
print(result)  # "已将客厅灯亮度设置为60%"

9.2 车载语音助手

# scenarios/car_assistant.py

CAR_SYSTEM_PROMPT = """你是一个车载AI语音助手。你的职责包括:
1. 导航指引:帮助驾驶员查找目的地、规划路线
2. 车辆控制:调节空调、音乐、车窗等
3. 信息查询:天气、新闻、日程提醒
4. 安全提醒:疲劳驾驶提醒、超速提醒

安全规则:
- 驾驶时回复必须极简(20字以内)
- 不在驾驶时可以详细回复
- 涉及安全问题时优先提醒
- 紧急情况建议靠边停车"""

class CarVoiceAssistant:
    """车载语音助手"""
    
    def __init__(self, llm_engine, tts_engine):
        self.llm = llm_engine
        self.tts = tts_engine
        self.is_driving = True  # 驾驶状态
        self.speed = 0  # 车速
    
    async def handle_command(self, user_text: str) -> str:
        """处理车载语音命令"""
        # 根据驾驶状态调整回复策略
        if self.is_driving:
            max_tokens = 80  # 驾驶时限制回复长度
        else:
            max_tokens = 300
        
        # 特殊命令处理
        if "导航" in user_text or "怎么走" in user_text:
            return await self._handle_navigation(user_text)
        
        if "空调" in user_text or "温度" in user_text:
            return await self._handle_climate(user_text)
        
        if "音乐" in user_text or "播放" in user_text:
            return await self._handle_media(user_text)
        
        # 通用对话
        response = self.llm.chat(
            user_text,
            self.llm.create_conversation(system_prompt=CAR_SYSTEM_PROMPT),
        )
        return response
    
    async def _handle_navigation(self, text: str) -> str:
        """处理导航请求"""
        # 实际项目中对接地图API
        return "已为您规划路线,预计到达时间30分钟"
    
    async def _handle_climate(self, text: str) -> str:
        """处理空调控制"""
        if "调高" in text or "热" in text:
            return "已将温度调高至27度"
        elif "调低" in text or "冷" in text:
            return "已将温度调低至24度"
        return "请问您想调节到多少度?"
    
    async def _handle_media(self, text: str) -> str:
        """处理媒体控制"""
        return "正在为您播放音乐"

十、性能优化与部署

10.1 延迟优化策略

# 优化策略一览
optimization_strategies = """
1. ASR优化:
   - 使用较小的Whisper模型(base而非large)
   - 流式识别,边听边转录
   - 指定语言避免检测耗时
   
2. LLM优化:
   - 使用流式输出(stream=True)
   - 控制max_tokens避免过长回复
   - 使用更快的模型(GPT-4o-mini而非GPT-4o)
   - 缓存系统提示词的tokenization
   
3. TTS优化:
   - 流式合成,边生成边播放
   - 按句子分割,逐句合成
   - 预合成常用回复(如"好的"、"明白了")
   
4. 网络优化:
   - 使用WebSocket持久连接
   - 音频数据压缩(opus编码)
   - 就近部署,减少网络延迟
"""

10.2 完整的优化Pipeline

# core/optimized_pipeline.py
import asyncio
import time

class OptimizedVoicePipeline:
    """优化的语音处理流水线"""
    
    def __init__(self, asr, llm, tts, vad):
        self.asr = asr
        self.llm = llm
        self.tts = tts
        self.vad = vad
        
        # 预缓存常用回复
        self.cache = {}
        self._precache_common_responses()
    
    def _precache_common_responses(self):
        """预缓存常用短回复"""
        common_phrases = [
            "好的", "明白了", "请稍等", "没问题",
            "已为您完成", "请问还有什么需要帮助的吗?",
        ]
        for phrase in common_phrases:
            self.cache[phrase] = self.tts.synthesize_sync(phrase)
    
    async def process_audio_optimized(self, audio_data, conversation):
        """
        优化的音频处理流程
        
        关键优化点:
        1. ASR和VAD并行
        2. LLM流式输出 + TTS逐句合成
        3. 缓存常用回复
        """
        # 阶段1:ASR识别
        t0 = time.time()
        asr_result = self.asr.transcribe(audio_data)
        t_asr = time.time() - t0
        
        user_text = asr_result["text"]
        if not user_text:
            return None
        
        # 检查缓存
        if user_text in self.cache:
            return {
                "text": user_text,
                "reply": user_text,
                "audio": self.cache[user_text],
                "latency": {"asr": t_asr, "llm": 0, "tts": 0},
            }
        
        # 阶段2:LLM流式生成
        t1 = time.time()
        reply = self.llm.chat(user_text, conversation, stream=True)
        t_llm = time.time() - t1
        
        # 阶段3:流式TTS合成
        t2 = time.time()
        
        # 按句子分割,边合成边发送
        sentences = self._split_sentences(reply)
        audio_chunks = []
        
        for sentence in sentences:
            if sentence.strip():
                chunk = await self.tts.synthesize(sentence.strip())
                audio_chunks.append(chunk)
                # 可以在这里yield chunk给客户端
        
        full_audio = b"".join(audio_chunks)
        t_tts = time.time() - t2
        
        return {
            "text": user_text,
            "reply": reply,
            "audio": full_audio,
            "latency": {
                "asr": round(t_asr * 1000),
                "llm": round(t_llm * 1000),
                "tts": round(t_tts * 1000),
                "total": round((t_asr + t_llm + t_tts) * 1000),
            },
        }
    
    def _split_sentences(self, text):
        import re
        return re.split(r'(?<=[。!?;\.\!\?\;])', text)

10.3 Docker部署

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    portaudio19-dev \
    ffmpeg \
    && rm -rf /var/lib/apt/lists/*

# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制代码
COPY . .

# 下载Whisper模型
RUN python -c "import whisper; whisper.load_model('base')"

EXPOSE 8765

CMD ["python", "main.py"]
# docker-compose.yml
version: '3.8'

services:
  voice-assistant:
    build: .
    ports:
      - "8765:8765"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - ASR_MODEL=base
      - TTS_VOICE=zh-CN-XiaoxiaoNeural
      - LLM_MODEL=gpt-4o-mini
    volumes:
      - ./data:/app/data
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: '2.0'

10.4 性能基准

环节 目标延迟 优化手段
VAD检测 < 10ms Silero模型,GPU加速
ASR识别 < 1s Whisper base,指定语言
LLM回复 < 2s(首token) 流式输出,GPT-4o-mini
TTS合成 < 500ms(首包) 流式合成,按句分割
端到端 < 4s 全链路并行优化

10.5 监控与日志

# utils/monitor.py
import time
import logging
from functools import wraps
from dataclasses import dataclass, field
from collections import defaultdict

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("voice_assistant")

@dataclass
class Metrics:
    """性能指标收集"""
    latency_history: dict = field(default_factory=lambda: defaultdict(list))
    error_count: dict = field(default_factory=lambda: defaultdict(int))
    request_count: int = 0
    
    def record_latency(self, stage: str, latency_ms: float):
        """记录延迟"""
        self.latency_history[stage].append(latency_ms)
        # 只保留最近1000条
        if len(self.latency_history[stage]) > 1000:
            self.latency_history[stage] = self.latency_history[stage][-1000:]
    
    def record_error(self, stage: str):
        """记录错误"""
        self.error_count[stage] += 1
    
    def get_stats(self) -> dict:
        """获取统计信息"""
        stats = {}
        for stage, latencies in self.latency_history.items():
            if latencies:
                stats[stage] = {
                    "avg_ms": round(sum(latencies) / len(latencies), 1),
                    "p50_ms": round(sorted(latencies)[len(latencies) // 2], 1),
                    "p95_ms": round(sorted(latencies)[int(len(latencies) * 0.95)], 1),
                    "p99_ms": round(sorted(latencies)[int(len(latencies) * 0.99)], 1),
                    "count": len(latencies),
                }
        stats["errors"] = dict(self.error_count)
        stats["total_requests"] = self.request_count
        return stats

# 全局指标实例
metrics = Metrics()

def track_latency(stage: str):
    """延迟追踪装饰器"""
    def decorator(func):
        @wraps(func)
        async def async_wrapper(*args, **kwargs):
            start = time.time()
            try:
                result = await func(*args, **kwargs)
                latency = (time.time() - start) * 1000
                metrics.record_latency(stage, latency)
                logger.info(f"[{stage}] {latency:.1f}ms")
                return result
            except Exception as e:
                metrics.record_error(stage)
                raise
        
        @wraps(func)
        def sync_wrapper(*args, **kwargs):
            start = time.time()
            try:
                result = func(*args, **kwargs)
                latency = (time.time() - start) * 1000
                metrics.record_latency(stage, latency)
                return result
            except Exception as e:
                metrics.record_error(stage)
                raise
        
        return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
    return decorator

总结

本教程从架构设计到生产部署,完整覆盖了AI语音助手开发的全链路。核心要点回顾:

  1. 架构清晰:ASR → LLM → TTS 三段式架构,模块解耦
  2. 流式优先:无论是ASR、LLM还是TTS,都采用流式处理降低延迟
  3. 多轮管理:通过SessionManager和ConversationMemory实现上下文保持
  4. 场景适配:智能家居和车载场景有不同的交互策略
  5. 性能优化:预缓存、并行处理、按句合成等手段将端到端延迟控制在4秒内

随着语音技术的快速发展,建议持续关注以下方向:

  • 端到端语音模型(如GPT-4o的语音模式)可能简化整体架构
  • 本地小模型(如Qwen2-Audio)提供离线能力
  • 情感合成让语音助手更有"人味"
  • 多模态融合(语音+视觉)拓展应用场景

📅 最后更新:2025年
📝 作者:AI教程系列
🔗 相关资源:OpenAI Whisper | Edge TTS | Silero VAD

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录