14b - 语音克隆与 TTS-STT
本文是《AI Agent 实战手册》第 14 章第 2 节。 上一节:14a-语音AI平台对比 | 下一节:14c-AI电话Agent构建
概述
语音克隆(Voice Cloning)、文本转语音(TTS)和语音转文本(STT)是构建语音 AI Agent 的三大核心技术。语音克隆让你用几秒钟的音频样本创建逼真的 AI 语音;TTS 将 Agent 的文本回复转化为自然流畅的语音输出;STT 则将用户的语音输入实时转录为文本供 LLM 处理。本文将从零开始,手把手教你完成语音克隆设置、TTS 流式配置和 STT 实时集成,覆盖 ElevenLabs、Resemble.ai(含开源 Chatterbox)和 Deepgram 三大平台,并提供 Python 和 TypeScript 的完整代码示例。
1. 语音克隆(Voice Cloning)
语音克隆是用少量音频样本”复制”一个人的声音特征,使 AI 能用该声音生成任意文本的语音。2025-2026 年,语音克隆技术已从实验室走向生产环境,仅需 10 秒音频即可创建可用的克隆语音。
1.1 语音克隆工具推荐
| 工具 | 克隆类型 | 所需音频 | 质量 | 价格 | 适用场景 |
|---|---|---|---|---|---|
| ElevenLabs IVC | 即时克隆 | 10 秒-5 分钟 | ⭐⭐⭐⭐ | 免费计划含 3 个克隆 | 快速原型、个人项目 |
| ElevenLabs PVC | 专业克隆 | 30 分钟+ | ⭐⭐⭐⭐⭐ | Pro 计划起($99/月) | 商业配音、品牌语音 |
| Resemble.ai 快速克隆 | 即时克隆 | 10 秒 | ⭐⭐⭐⭐ | $2/月/语音 | 企业语音、安全合规 |
| Resemble.ai 专业克隆 | 专业克隆 | 3 分钟+ | ⭐⭐⭐⭐⭐ | $5/月/语音 | 高保真企业语音 |
| Chatterbox(开源) | 零样本克隆 | 几秒 | ⭐⭐⭐⭐ | 免费(MIT 许可) | 本地部署、隐私优先 |
| Chatterbox Turbo | 零样本克隆 | 几秒 | ⭐⭐⭐⭐ | 免费(MIT 许可) | 低延迟语音 Agent |
1.2 ElevenLabs 语音克隆
ElevenLabs 提供两种语音克隆方式:即时语音克隆(IVC)和专业语音克隆(PVC)。
即时语音克隆(Instant Voice Cloning)
IVC 不训练自定义模型,而是利用预训练知识对语音特征进行”有根据的推测”,因此速度极快(秒级完成),但精度略低于 PVC。
音频样本要求:
- 最少 10 秒,建议 1-5 分钟
- 清晰的单人语音,无背景噪音
- 自然说话风格(非朗读)
- 支持格式:MP3、WAV、M4A、FLAC
- 文件大小上限:10MB
操作步骤
步骤 1:安装 SDK 并配置 API Key
# Python
pip install elevenlabs
# TypeScript/Node.js
npm install elevenlabs步骤 2:Python — 即时语音克隆
from elevenlabs import ElevenLabs
import os
client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
# 步骤 1:上传音频样本创建即时克隆语音
voice = client.voices.add(
name="我的克隆语音",
description="用于中文客服场景的克隆语音",
files=["my-voice-sample.mp3"], # 本地音频文件路径
# labels={"language": "zh", "use_case": "customer_service"}
)
print(f"语音克隆成功!Voice ID: {voice.voice_id}")
# 步骤 2:使用克隆语音生成 TTS
audio = client.text_to_speech.convert(
voice_id=voice.voice_id,
text="你好,欢迎致电智能客服中心,请问有什么可以帮助您的?",
model_id="eleven_flash_v2_5", # 低延迟模型
output_format="mp3_44100_128"
)
# 步骤 3:保存音频文件
with open("output.mp3", "wb") as f:
for chunk in audio:
f.write(chunk)
print("音频生成完成:output.mp3")步骤 3:TypeScript — 即时语音克隆
import { ElevenLabsClient } from "elevenlabs";
import * as fs from "fs";
const client = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_API_KEY,
});
async function cloneAndGenerate() {
// 步骤 1:上传音频样本创建即时克隆
const voice = await client.voices.add({
name: "我的克隆语音",
description: "用于中文客服场景的克隆语音",
files: [fs.createReadStream("my-voice-sample.mp3")],
});
console.log(`语音克隆成功!Voice ID: ${voice.voice_id}`);
// 步骤 2:使用克隆语音生成 TTS
const audioStream = await client.textToSpeech.convertAsStream(
voice.voice_id,
{
text: "你好,欢迎致电智能客服中心,请问有什么可以帮助您的?",
model_id: "eleven_flash_v2_5",
output_format: "mp3_44100_128",
}
);
// 步骤 3:保存音频
const chunks: Buffer[] = [];
for await (const chunk of audioStream) {
chunks.push(Buffer.from(chunk));
}
fs.writeFileSync("output.mp3", Buffer.concat(chunks));
console.log("音频生成完成:output.mp3");
}
cloneAndGenerate();专业语音克隆(Professional Voice Cloning)
PVC 会训练一个专属 AI 模型,需要更多音频数据(建议 30 分钟以上),但语音还原度显著高于 IVC。适合品牌语音、有声书等对质量要求极高的场景。
音频样本要求:
- 最少 30 分钟高质量录音
- 专业录音环境(低噪音、无混响)
- 多种语调和情感表达
- 需要通过 ElevenLabs 的验证流程(确认你有权使用该语音)
# ElevenLabs 专业语音克隆(PVC)
from elevenlabs import ElevenLabs
import os
client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
# 步骤 1:创建 PVC 语音
voice = client.voices.add(
name="品牌专属语音",
description="公司品牌语音,用于所有对外语音交互",
files=[
"recording_part1.wav",
"recording_part2.wav",
"recording_part3.wav",
],
)
# 步骤 2:等待训练完成(PVC 需要几小时)
# 可通过 Dashboard 或 API 查询状态
voice_info = client.voices.get(voice_id=voice.voice_id)
print(f"语音状态: {voice_info.name}")💡 IVC vs PVC 选择建议:如果你只需要快速验证语音效果或用于内部项目,IVC 足够;如果是面向客户的品牌语音或商业配音,建议投入时间做 PVC。
1.3 Resemble.ai 语音克隆
Resemble.ai 的语音克隆以安全合规为核心卖点,内置深伪检测和 AI 水印功能,特别适合企业场景。
操作步骤
步骤 1:安装 SDK
pip install resemble步骤 2:Python — Resemble.ai 快速克隆
import resemble
import os
resemble.api_key = os.getenv("RESEMBLE_API_KEY")
# 步骤 1:创建项目
project = resemble.v2.projects.create(
name="客服语音项目",
description="智能客服系统使用的克隆语音",
language="zh"
)
project_uuid = project["item"]["uuid"]
# 步骤 2:上传音频样本创建语音
# 快速克隆:仅需 10 秒音频
voice = resemble.v2.voices.create(
name="客服克隆语音",
dataset_url="https://your-storage.com/voice-sample.wav",
consent="https://your-storage.com/consent-recording.wav", # 授权录音
clone_type="rapid" # rapid(快速)或 professional(专业)
)
voice_uuid = voice["item"]["uuid"]
print(f"语音创建成功:{voice_uuid}")
# 步骤 3:使用克隆语音生成音频
clip = resemble.v2.clips.create_sync(
project_uuid=project_uuid,
voice_uuid=voice_uuid,
body="欢迎使用我们的智能客服系统,请问有什么可以帮助您的?",
output_format="wav",
sample_rate=44100
)
# 下载生成的音频
audio_url = clip["item"]["audio_src"]
print(f"音频生成完成:{audio_url}")⚠️ Resemble.ai 授权要求:创建克隆语音时必须提供
consent参数——一段录音,其中语音所有者明确同意其声音被用于 AI 语音合成。这是 Resemble.ai 的合规要求。
1.4 Chatterbox 开源语音克隆(本地部署)
Resemble.ai 开源的 Chatterbox 是 2025 年最受关注的开源 TTS 模型之一。基于 0.5B Llama 骨干网络,在 50 万小时清洗数据上训练,支持零样本语音克隆和情感夸张控制。MIT 许可证,可自由商用。
Chatterbox 家族包含三个模型变体:
| 模型 | 参数量 | 特点 | 适用场景 |
|---|---|---|---|
| Chatterbox | 0.5B | 最高质量,情感控制 | 有声书、高质量配音 |
| Chatterbox Turbo | 350M | 6× 实时速度,内置水印 | 低延迟语音 Agent |
| Chatterbox Multilingual | 0.5B | 多语言支持 | 跨语言内容 |
操作步骤
步骤 1:安装 Chatterbox
# 基础安装
pip install chatterbox-tts
# 或从源码安装(获取最新功能)
git clone https://github.com/resemble-ai/chatterbox.git
cd chatterbox
pip install -e .步骤 2:Python — Chatterbox 零样本语音克隆
import torch
import torchaudio
from chatterbox.tts import ChatterboxTTS
# 加载模型(首次运行会自动从 HuggingFace 下载)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = ChatterboxTTS.from_pretrained(device=device)
# 零样本语音克隆:用参考音频的声音生成新文本
text = "你好,我是你的 AI 助手,今天有什么可以帮你的吗?"
reference_audio = "reference_voice.wav" # 几秒钟的参考音频
# 生成语音
wav = model.generate(
text=text,
audio_prompt_path=reference_audio,
exaggeration=0.5, # 情感夸张度:0.0(平淡)到 1.0(夸张)
cfg_weight=0.5 # 引导权重:控制与参考音频的相似度
)
# 保存输出
torchaudio.save("cloned_output.wav", wav, model.sr)
print("克隆语音生成完成:cloned_output.wav")步骤 3:Chatterbox Turbo(低延迟版本)
from chatterbox.tts import ChatterboxTTS
# 加载 Turbo 模型
model = ChatterboxTTS.from_pretrained(
device="cuda",
model_id="ResembleAI/chatterbox-turbo" # Turbo 变体
)
# Turbo 支持副语言标签(paralinguistic tags)
text = "哈哈 [laugh],这个问题很有趣 [chuckle]。让我想想..."
wav = model.generate(
text=text,
audio_prompt_path="reference_voice.wav",
exaggeration=0.7 # 更高的情感表达
)
torchaudio.save("turbo_output.wav", wav, model.sr)💡 Chatterbox vs 商业 API:Chatterbox 的优势在于完全本地运行、无 API 费用、数据不出服务器。缺点是需要 GPU(推荐 NVIDIA RTX 3090+),且不如 ElevenLabs 的 API 方便集成。适合对隐私要求高或需要大规模离线生成的场景。
1.5 语音克隆的伦理与法律
语音克隆技术的滥用风险不容忽视。2025-2026 年,全球多个司法管辖区已出台或正在制定相关法规。
关键法规
| 法规 | 地区 | 核心要求 |
|---|---|---|
| EU AI Act | 欧盟 | AI 生成的音频必须明确标注为合成内容 |
| ELVIS Act | 美国(田纳西州) | 保护个人语音权利,未经授权的语音克隆违法 |
| Federal Deepfake Prevention Act | 美国(联邦) | 要求企业实施深伪检测系统 |
| 个人信息保护法 | 中国 | 语音数据属于生物识别信息,需明确同意 |
合规清单
语音克隆合规检查清单:
□ 获取语音所有者的书面同意(含使用范围和期限)
□ 录制语音所有者的口头授权确认
□ 明确标注 AI 生成的语音内容
□ 实施 AI 水印技术(如 Resemble.ai 的内置水印)
□ 建立语音使用审计日志
□ 制定语音数据的保留和删除策略
□ 禁止用于冒充、欺诈或未经授权的用途
□ 定期审查合规状态提示词模板
你是一个语音克隆技术顾问。请根据以下需求帮我设计语音克隆方案:
项目类型:[品牌语音 / 有声书 / 客服 / 游戏角色 / ...]
语音来源:[自己的声音 / 配音演员 / 已有录音]
质量要求:[高保真 / 可接受 / 快速原型]
部署方式:[云端 API / 本地部署 / 混合]
预算范围:[$X/月]
合规要求:[GDPR / 中国个保法 / 无特殊要求]
使用场景:[实时对话 / 离线生成 / 批量生产]
请推荐:
1. 最适合的克隆平台和方案
2. 音频样本准备建议
3. 预估成本
4. 合规注意事项2. TTS(文本转语音)配置
TTS 是语音 AI Agent 的”嘴巴”——将 LLM 生成的文本回复转化为自然语音。在实时对话场景中,TTS 的延迟和流式能力直接决定用户体验。
2.1 TTS 工具推荐
| 工具 | 模型 | 延迟(TTFB) | 质量 | 价格 | 适用场景 |
|---|---|---|---|---|---|
| ElevenLabs Flash v2.5 | 商业 | ~75ms | ⭐⭐⭐⭐ | $5/月起 | 实时对话、语音 Agent |
| ElevenLabs v3 | 商业 | ~300ms | ⭐⭐⭐⭐⭐ | $5/月起 | 有声书、高端配音 |
| Deepgram Aura-2 | 商业 | ~90ms | ⭐⭐⭐⭐ | $0.030/千字符 | 企业级语音 Agent |
| Chatterbox Turbo | 开源 | 取决于硬件 | ⭐⭐⭐⭐ | 免费 | 本地部署、隐私优先 |
| Resemble.ai TTS | 商业 | 实时流式 | ⭐⭐⭐⭐ | $0.03/分钟 | 企业语音、安全合规 |
| OpenAI TTS | 商业 | ~200ms | ⭐⭐⭐⭐ | $15/百万字符 | OpenAI 生态集成 |
2.2 ElevenLabs TTS 配置
HTTP 流式 TTS
最简单的集成方式——发送 HTTP 请求,流式接收音频数据。
# ElevenLabs HTTP 流式 TTS — Python
from elevenlabs import ElevenLabs
import os
client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
def stream_tts(text: str, voice_id: str = "JBFqnCBsd6RMkjVDRZzb"):
"""流式生成 TTS 音频"""
audio_stream = client.text_to_speech.convert_as_stream(
voice_id=voice_id,
text=text,
model_id="eleven_flash_v2_5", # 低延迟模型
output_format="mp3_44100_128",
voice_settings={
"stability": 0.5, # 稳定性:0.0-1.0
"similarity_boost": 0.75, # 相似度增强:0.0-1.0
"style": 0.0, # 风格:0.0-1.0(仅 v3 支持)
"use_speaker_boost": True # 说话人增强
}
)
return audio_stream
# 使用示例
stream = stream_tts("你好,我是你的 AI 助手。今天天气不错,有什么可以帮你的吗?")
# 方式 1:保存到文件
with open("tts_output.mp3", "wb") as f:
for chunk in stream:
f.write(chunk)
# 方式 2:实时播放(需要 pyaudio 或类似库)
# import pyaudio
# p = pyaudio.PyAudio()
# stream_out = p.open(format=pyaudio.paInt16, channels=1, rate=44100, output=True)
# for chunk in stream:
# stream_out.write(chunk)// ElevenLabs HTTP 流式 TTS — TypeScript
import { ElevenLabsClient } from "elevenlabs";
import * as fs from "fs";
const client = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_API_KEY,
});
async function streamTTS(text: string, voiceId: string = "JBFqnCBsd6RMkjVDRZzb") {
const audioStream = await client.textToSpeech.convertAsStream(voiceId, {
text,
model_id: "eleven_flash_v2_5",
output_format: "mp3_44100_128",
voice_settings: {
stability: 0.5,
similarity_boost: 0.75,
style: 0.0,
use_speaker_boost: true,
},
});
// 保存到文件
const writeStream = fs.createWriteStream("tts_output.mp3");
for await (const chunk of audioStream) {
writeStream.write(chunk);
}
writeStream.end();
console.log("TTS 音频生成完成");
}
streamTTS("你好,我是你的 AI 助手。今天天气不错,有什么可以帮你的吗?");WebSocket 实时 TTS
WebSocket 方式适合需要逐字/逐句发送文本的实时对话场景——例如将 LLM 的流式输出直接转为语音。
# ElevenLabs WebSocket 实时 TTS — Python
import asyncio
import websockets
import json
import os
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
VOICE_ID = "JBFqnCBsd6RMkjVDRZzb"
MODEL_ID = "eleven_flash_v2_5"
async def realtime_tts(text_chunks: list[str]):
"""
WebSocket 实时 TTS:逐块发送文本,逐块接收音频。
适合与 LLM 流式输出配合使用。
"""
uri = (
f"wss://api.elevenlabs.io/v1/text-to-speech/{VOICE_ID}"
f"/stream-input?model_id={MODEL_ID}"
f"&output_format=mp3_44100_128"
)
async with websockets.connect(
uri,
additional_headers={"xi-api-key": ELEVENLABS_API_KEY}
) as ws:
# 发送初始配置(BOS — Beginning of Stream)
await ws.send(json.dumps({
"text": " ", # 空格触发连接初始化
"voice_settings": {
"stability": 0.5,
"similarity_boost": 0.75
},
"generation_config": {
"chunk_length_schedule": [120, 160, 250, 290]
}
}))
audio_chunks = []
# 异步接收音频
async def receive_audio():
async for message in ws:
data = json.loads(message)
if data.get("audio"):
import base64
audio_chunks.append(base64.b64decode(data["audio"]))
if data.get("isFinal"):
break
receiver = asyncio.create_task(receive_audio())
# 逐块发送文本(模拟 LLM 流式输出)
for chunk in text_chunks:
await ws.send(json.dumps({"text": chunk}))
await asyncio.sleep(0.05) # 模拟 LLM 生成间隔
# 发送结束信号(EOS — End of Stream)
await ws.send(json.dumps({"text": ""}))
await receiver
# 合并音频
with open("realtime_output.mp3", "wb") as f:
for chunk in audio_chunks:
f.write(chunk)
print(f"实时 TTS 完成,共 {len(audio_chunks)} 个音频块")
# 模拟 LLM 流式输出
text_chunks = [
"你好,",
"我是你的 AI 助手。",
"今天有什么",
"可以帮你的吗?"
]
asyncio.run(realtime_tts(text_chunks))// ElevenLabs WebSocket 实时 TTS — TypeScript
import WebSocket from "ws";
const ELEVENLABS_API_KEY = process.env.ELEVENLABS_API_KEY!;
const VOICE_ID = "JBFqnCBsd6RMkjVDRZzb";
const MODEL_ID = "eleven_flash_v2_5";
async function realtimeTTS(textChunks: string[]): Promise<Buffer> {
const uri =
`wss://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}` +
`/stream-input?model_id=${MODEL_ID}&output_format=mp3_44100_128`;
return new Promise((resolve, reject) => {
const ws = new WebSocket(uri, {
headers: { "xi-api-key": ELEVENLABS_API_KEY },
});
const audioChunks: Buffer[] = [];
ws.on("open", async () => {
// 发送初始配置
ws.send(
JSON.stringify({
text: " ",
voice_settings: { stability: 0.5, similarity_boost: 0.75 },
generation_config: { chunk_length_schedule: [120, 160, 250, 290] },
})
);
// 逐块发送文本
for (const chunk of textChunks) {
ws.send(JSON.stringify({ text: chunk }));
await new Promise((r) => setTimeout(r, 50));
}
// 发送结束信号
ws.send(JSON.stringify({ text: "" }));
});
ws.on("message", (data: string) => {
const parsed = JSON.parse(data);
if (parsed.audio) {
audioChunks.push(Buffer.from(parsed.audio, "base64"));
}
if (parsed.isFinal) {
ws.close();
}
});
ws.on("close", () => resolve(Buffer.concat(audioChunks)));
ws.on("error", reject);
});
}
// 使用示例
const chunks = ["你好,", "我是你的 AI 助手。", "今天有什么", "可以帮你的吗?"];
realtimeTTS(chunks).then((audio) => {
require("fs").writeFileSync("realtime_output.mp3", audio);
console.log("实时 TTS 完成");
});💡 WebSocket vs HTTP 流式:WebSocket 适合需要逐字发送文本的场景(如 LLM 流式输出直接转语音),HTTP 流式适合文本已经完整的场景。WebSocket 的首字节延迟更低,但实现复杂度更高。
2.3 Deepgram Aura-2 TTS 配置
Deepgram 的 Aura-2 TTS 以企业级稳定性和低延迟著称,TTFB 低至 90ms。支持 REST API 和 WebSocket 两种方式。
⚠️ 注意:Aura-1 计划于 2026 年 2 月 13 日正式退役,建议直接使用 Aura-2。
REST API 方式
# Deepgram Aura-2 TTS — Python REST API
from deepgram import DeepgramClient, SpeakOptions
import os
deepgram = DeepgramClient(api_key=os.getenv("DEEPGRAM_API_KEY"))
def generate_tts(text: str, output_file: str = "deepgram_output.mp3"):
"""使用 Deepgram Aura-2 生成 TTS 音频"""
options = SpeakOptions(
model="aura-2-en-us", # Aura-2 英文模型
encoding="mp3", # 输出格式
sample_rate=24000, # 采样率
)
# 生成音频并保存到文件
response = deepgram.speak.v("1").save(
output_file,
{"text": text},
options
)
print(f"音频生成完成:{output_file}")
print(f"Content-Type: {response.content_type}")
return response
generate_tts("Hello, I am your AI assistant. How can I help you today?")// Deepgram Aura-2 TTS — TypeScript REST API
import { createClient } from "@deepgram/sdk";
import * as fs from "fs";
const deepgram = createClient(process.env.DEEPGRAM_API_KEY!);
async function generateTTS(text: string, outputFile: string = "deepgram_output.mp3") {
const response = await deepgram.speak.request(
{ text },
{
model: "aura-2-en-us",
encoding: "mp3",
sample_rate: 24000,
}
);
const stream = await response.getStream();
if (stream) {
const chunks: Uint8Array[] = [];
const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const buffer = Buffer.concat(chunks);
fs.writeFileSync(outputFile, buffer);
console.log(`音频生成完成:${outputFile}`);
}
}
generateTTS("Hello, I am your AI assistant. How can I help you today?");WebSocket 流式 TTS
WebSocket 方式适合实时对话场景,音频在生成的同时就开始传输,显著降低感知延迟。
# Deepgram Aura-2 WebSocket 流式 TTS — Python
from deepgram import DeepgramClient, SpeakWebSocketEvents, SpeakWSOptions
import os
import asyncio
async def stream_tts_websocket(text: str):
"""使用 Deepgram WebSocket 流式生成 TTS"""
deepgram = DeepgramClient(api_key=os.getenv("DEEPGRAM_API_KEY"))
# 创建 WebSocket 连接
dg_connection = deepgram.speak.websocket.v("1")
audio_chunks = []
# 注册事件处理器
def on_audio_data(self, result, **kwargs):
"""接收音频数据块"""
audio_chunks.append(result.data)
def on_flushed(self, result, **kwargs):
"""文本块处理完成"""
print("音频块刷新完成")
dg_connection.on(SpeakWebSocketEvents.AudioData, on_audio_data)
dg_connection.on(SpeakWebSocketEvents.Flushed, on_flushed)
# 配置选项
options = SpeakWSOptions(
model="aura-2-en-us",
encoding="linear16",
sample_rate=24000
)
# 启动连接
if dg_connection.start(options):
# 发送文本(可以分块发送)
dg_connection.send_text(text)
dg_connection.flush() # 触发音频生成
await asyncio.sleep(2) # 等待音频生成完成
dg_connection.finish()
print(f"流式 TTS 完成,共接收 {len(audio_chunks)} 个音频块")
return audio_chunks
asyncio.run(stream_tts_websocket("Hello, how can I help you today?"))2.4 TTS 参数调优指南
不同场景需要不同的 TTS 参数配置。以下是常见场景的推荐参数:
| 场景 | 模型选择 | stability | similarity_boost | 说明 |
|---|---|---|---|---|
| 实时客服对话 | Flash v2.5 / Aura-2 | 0.5 | 0.75 | 平衡自然度和一致性 |
| 有声书朗读 | Eleven v3 | 0.3 | 0.85 | 更多情感变化 |
| IVR 语音菜单 | Flash v2.5 / Aura-2 | 0.8 | 0.5 | 高一致性,清晰准确 |
| 游戏角色配音 | Eleven v3 | 0.2 | 0.9 | 最大情感表达 |
| 新闻播报 | Flash v2.5 | 0.7 | 0.6 | 专业、稳定 |
参数说明:
- stability(稳定性,0.0-1.0):值越高,语音越稳定一致;值越低,情感变化越丰富但可能不稳定
- similarity_boost(相似度增强,0.0-1.0):值越高,越接近原始语音特征;值越低,越”通用”
- style(风格,0.0-1.0,仅 v3):控制风格表达强度,高值可能增加延迟
- speed(语速,0.7-1.2):调整语音播放速度
# TTS 参数调优示例 — 不同场景的配置
TTS_CONFIGS = {
"customer_service": {
"model_id": "eleven_flash_v2_5",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 0.75,
"style": 0.0,
"use_speaker_boost": True
}
},
"audiobook": {
"model_id": "eleven_multilingual_v2",
"voice_settings": {
"stability": 0.3,
"similarity_boost": 0.85,
"style": 0.4,
"use_speaker_boost": True
}
},
"ivr_menu": {
"model_id": "eleven_flash_v2_5",
"voice_settings": {
"stability": 0.8,
"similarity_boost": 0.5,
"style": 0.0,
"use_speaker_boost": False
}
}
}2.5 TTS 延迟优化技巧
在实时对话场景中,TTS 延迟是用户体验的关键瓶颈。以下是经过验证的优化策略:
策略 1:选择低延迟模型
延迟排名(从低到高):
1. ElevenLabs Flash v2.5 — ~75ms TTFB
2. Deepgram Aura-2 — ~90ms TTFB
3. ElevenLabs Turbo v2.5 — ~135ms TTFB
4. OpenAI TTS — ~200ms TTFB
5. ElevenLabs v3 — ~300ms TTFB策略 2:使用流式输出
# 非流式(等待全部生成完再返回)— 延迟高
audio = client.text_to_speech.convert(
voice_id=voice_id,
text=long_text,
model_id="eleven_flash_v2_5"
)
# 流式(边生成边返回)— 延迟低
audio_stream = client.text_to_speech.convert_as_stream(
voice_id=voice_id,
text=long_text,
model_id="eleven_flash_v2_5"
)
# 第一个音频块在 ~75ms 后就到达
for chunk in audio_stream:
play_audio(chunk) # 立即播放策略 3:文本分块 + 并行生成
import asyncio
from elevenlabs import AsyncElevenLabs
async_client = AsyncElevenLabs(api_key="your-api-key")
async def parallel_tts(sentences: list[str], voice_id: str):
"""将长文本拆分为句子,并行生成 TTS"""
tasks = [
async_client.text_to_speech.convert_as_stream(
voice_id=voice_id,
text=sentence,
model_id="eleven_flash_v2_5"
)
for sentence in sentences
]
# 并行生成,按顺序播放
results = await asyncio.gather(*tasks)
return results
# 使用示例
sentences = [
"你好,欢迎致电客服中心。",
"我是你的 AI 助手小明。",
"请问有什么可以帮助您的?"
]
# asyncio.run(parallel_tts(sentences, "your-voice-id"))策略 4:预热连接
# WebSocket 连接预热 — 避免首次请求的连接建立延迟
import time
class TTSConnectionPool:
"""TTS WebSocket 连接池,保持连接预热"""
def __init__(self, api_key: str, voice_id: str, pool_size: int = 3):
self.api_key = api_key
self.voice_id = voice_id
self.pool_size = pool_size
self.connections = []
async def warmup(self):
"""预热连接池"""
for _ in range(self.pool_size):
conn = await self._create_connection()
self.connections.append(conn)
print(f"连接池预热完成:{self.pool_size} 个连接就绪")
async def get_connection(self):
"""获取一个可用连接"""
if self.connections:
conn = self.connections.pop(0)
# 异步补充连接
asyncio.create_task(self._replenish())
return conn
return await self._create_connection()
async def _create_connection(self):
"""创建新的 WebSocket 连接"""
# 实际实现中连接到 ElevenLabs WebSocket API
pass
async def _replenish(self):
"""补充连接池"""
conn = await self._create_connection()
self.connections.append(conn)提示词模板
你是一个 TTS 配置优化专家。请根据以下需求帮我优化 TTS 配置:
应用场景:[实时对话 / 有声书 / IVR / 游戏 / 播客]
目标延迟:[<100ms / <200ms / <500ms / 无严格要求]
语音质量要求:[最高 / 高 / 可接受]
目标语言:[中文 / 英文 / 多语言]
并发量:[X 路同时通话]
月度预算:[$X]
请推荐:
1. 最佳 TTS 模型和提供商
2. 推荐的参数配置(stability, similarity_boost 等)
3. 延迟优化策略
4. 预估月度成本3. STT(语音转文本)集成
STT 是语音 AI Agent 的”耳朵”——将用户的语音输入实时转录为文本,供 LLM 处理。在实时对话场景中,STT 的准确率和延迟直接影响 Agent 的理解能力和响应速度。
3.1 STT 工具推荐
| 工具 | 模型 | 延迟 | 准确率 | 语言数 | 价格 | 适用场景 |
|---|---|---|---|---|---|---|
| Deepgram Nova-3 | 商业 | ~150ms | 最高(WER 最低) | 36+ | $0.0077/分钟 | 实时转录、语音 Agent |
| Deepgram Flux | 商业 | 超低 | 高 | 英语 | $0.0077/分钟 | 语音 Agent(内置轮次检测) |
| ElevenLabs Scribe v2 | 商业 | ~150ms | 高 | 92+ | 按计划包含 | 全栈 ElevenLabs 集成 |
| AssemblyAI Universal-2 | 商业 | 实时 | 高 | 99 | $0.15/小时 | 多语言转录 |
| AssemblyAI Universal-3 Pro | 商业 | 标准 | 最高 | 6 | $0.21/小时 | 英语高精度 |
| OpenAI Whisper | 开源 | 取决于硬件 | 高 | 99 | 免费 | 本地部署 |
3.2 Deepgram STT 集成
Deepgram 的 Nova-3 是当前 STT 领域准确率最高的模型之一,WER(Word Error Rate)比竞品低 54.2%。支持实时流式转录和批量转录两种模式。
实时流式转录(Live Streaming)
实时流式转录是语音 Agent 的核心需求——用户说话的同时就开始转录,无需等待用户说完。
# Deepgram Nova-3 实时流式 STT — Python
from deepgram import (
DeepgramClient,
LiveTranscriptionEvents,
LiveOptions,
)
import os
import asyncio
async def realtime_stt():
"""Deepgram 实时流式语音转文本"""
deepgram = DeepgramClient(api_key=os.getenv("DEEPGRAM_API_KEY"))
# 创建实时连接
dg_connection = deepgram.listen.asyncwebsocket.v("1")
# 存储转录结果
transcript_parts = []
# 事件处理器:接收中间结果(interim results)
async def on_message(self, result, **kwargs):
sentence = result.channel.alternatives[0].transcript
if sentence:
if result.is_final:
# 最终结果 — 高置信度
transcript_parts.append(sentence)
print(f"[最终] {sentence}")
else:
# 中间结果 — 实时反馈,可能会修正
print(f"[中间] {sentence}")
async def on_utterance_end(self, result, **kwargs):
"""说话人停顿检测 — 用于判断用户说完了"""
print("[轮次结束] 用户可能说完了")
async def on_error(self, error, **kwargs):
print(f"[错误] {error}")
# 注册事件
dg_connection.on(LiveTranscriptionEvents.Transcript, on_message)
dg_connection.on(LiveTranscriptionEvents.UtteranceEnd, on_utterance_end)
dg_connection.on(LiveTranscriptionEvents.Error, on_error)
# 配置选项
options = LiveOptions(
model="nova-3", # 最新最准确的模型
language="zh", # 中文
smart_format=True, # 智能格式化(标点、数字等)
diarize=True, # 说话人分离
interim_results=True, # 启用中间结果(降低感知延迟)
utterance_end_ms=1000, # 停顿 1 秒判定为说完
vad_events=True, # 语音活动检测事件
encoding="linear16", # 音频编码
sample_rate=16000, # 采样率
channels=1 # 单声道
)
# 启动连接
if await dg_connection.start(options):
print("Deepgram 实时 STT 连接已建立")
# 模拟发送音频数据(实际场景中从麦克风或电话流获取)
# await dg_connection.send(audio_data)
# 保持连接
await asyncio.sleep(30)
# 关闭连接
await dg_connection.finish()
return " ".join(transcript_parts)
# asyncio.run(realtime_stt())// Deepgram Nova-3 实时流式 STT — TypeScript
import { createClient, LiveTranscriptionEvents } from "@deepgram/sdk";
const deepgram = createClient(process.env.DEEPGRAM_API_KEY!);
async function realtimeSTT() {
// 创建实时连接
const connection = deepgram.listen.live({
model: "nova-3",
language: "zh",
smart_format: true,
diarize: true,
interim_results: true,
utterance_end_ms: 1000,
vad_events: true,
encoding: "linear16",
sample_rate: 16000,
channels: 1,
});
const transcriptParts: string[] = [];
// 监听转录结果
connection.on(LiveTranscriptionEvents.Transcript, (data) => {
const sentence = data.channel.alternatives[0].transcript;
if (sentence) {
if (data.is_final) {
transcriptParts.push(sentence);
console.log(`[最终] ${sentence}`);
} else {
console.log(`[中间] ${sentence}`);
}
}
});
// 监听说话人停顿
connection.on(LiveTranscriptionEvents.UtteranceEnd, () => {
console.log("[轮次结束] 用户可能说完了");
// 在这里触发 LLM 处理
});
connection.on(LiveTranscriptionEvents.Error, (err) => {
console.error("[错误]", err);
});
connection.on(LiveTranscriptionEvents.Open, () => {
console.log("Deepgram 实时 STT 连接已建立");
// 发送音频数据(实际场景中从麦克风或 WebRTC 获取)
// connection.send(audioBuffer);
});
// 30 秒后关闭
setTimeout(() => {
connection.requestClose();
console.log("完整转录:", transcriptParts.join(" "));
}, 30000);
}
realtimeSTT();批量转录(Pre-recorded)
适合离线处理已录制的音频文件,如会议录音、客服通话记录等。
# Deepgram 批量转录 — Python
from deepgram import DeepgramClient, PrerecordedOptions
import os
deepgram = DeepgramClient(api_key=os.getenv("DEEPGRAM_API_KEY"))
def transcribe_file(audio_path: str):
"""转录本地音频文件"""
with open(audio_path, "rb") as audio:
source = {"buffer": audio.read()}
options = PrerecordedOptions(
model="nova-3",
language="zh",
smart_format=True,
diarize=True, # 说话人分离
paragraphs=True, # 自动分段
summarize="v2", # 自动摘要
detect_language=True, # 自动语言检测
punctuate=True, # 自动标点
)
response = deepgram.listen.rest.v("1").transcribe_file(source, options)
# 获取转录结果
transcript = response.results.channels[0].alternatives[0]
print(f"转录文本:{transcript.transcript}")
print(f"置信度:{transcript.confidence}")
# 说话人分离结果
if transcript.words:
current_speaker = None
for word in transcript.words:
if word.speaker != current_speaker:
current_speaker = word.speaker
print(f"\n[说话人 {current_speaker}]", end=" ")
print(word.punctuated_word, end=" ")
return transcript
transcribe_file("meeting_recording.mp3")// Deepgram 批量转录 — TypeScript
import { createClient } from "@deepgram/sdk";
import * as fs from "fs";
const deepgram = createClient(process.env.DEEPGRAM_API_KEY!);
async function transcribeFile(audioPath: string) {
const audioBuffer = fs.readFileSync(audioPath);
const { result } = await deepgram.listen.prerecorded.transcribeFile(
audioBuffer,
{
model: "nova-3",
language: "zh",
smart_format: true,
diarize: true,
paragraphs: true,
summarize: "v2",
detect_language: true,
punctuate: true,
}
);
const transcript = result.results.channels[0].alternatives[0];
console.log(`转录文本:${transcript.transcript}`);
console.log(`置信度:${transcript.confidence}`);
return transcript;
}
transcribeFile("meeting_recording.mp3");3.3 ElevenLabs Scribe v2 STT
ElevenLabs 的 Scribe v2 是 2025 年底推出的 STT 模型,支持 92+ 语言,实时延迟约 150ms。其独特优势在于与 ElevenLabs TTS 生态的无缝集成。
批量转录
# ElevenLabs Scribe v2 STT — Python
from elevenlabs import ElevenLabs
import os
client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
def transcribe_with_scribe(audio_path: str):
"""使用 ElevenLabs Scribe v2 转录音频"""
with open(audio_path, "rb") as audio_file:
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2", # Scribe v2 模型
language_code="zh", # 中文
diarize=True, # 说话人分离
tag_audio_events=True, # 标记音频事件(笑声、音乐等)
# keyterm_prompts=["AI Agent", "语音克隆"] # 关键词提示
)
print(f"转录文本:{result.text}")
print(f"语言:{result.language_code}")
# 逐词结果(含时间戳)
if result.words:
for word in result.words:
print(f" [{word.start:.2f}s - {word.end:.2f}s] {word.text}")
return result
transcribe_with_scribe("customer_call.mp3")实时流式转录
# ElevenLabs Scribe v2 实时 STT — Python
import asyncio
import websockets
import json
import os
async def scribe_realtime_stt():
"""ElevenLabs Scribe v2 实时流式 STT"""
uri = "wss://api.elevenlabs.io/v1/speech-to-text/realtime"
async with websockets.connect(
uri,
additional_headers={"xi-api-key": os.getenv("ELEVENLABS_API_KEY")}
) as ws:
# 发送初始配置
await ws.send(json.dumps({
"type": "config",
"config": {
"model_id": "scribe_v2_realtime",
"language_code": "zh",
"encoding": "pcm_16000",
"sample_rate": 16000
}
}))
# 接收转录结果
async def receive_transcripts():
async for message in ws:
data = json.loads(message)
if data.get("type") == "transcript":
text = data.get("text", "")
is_final = data.get("is_final", False)
if text:
prefix = "[最终]" if is_final else "[中间]"
print(f"{prefix} {text}")
receiver = asyncio.create_task(receive_transcripts())
# 发送音频数据(实际场景中从麦克风获取)
# await ws.send(audio_bytes)
await asyncio.sleep(30)
await ws.close()
# asyncio.run(scribe_realtime_stt())3.4 STT 关键参数详解
| 参数 | 说明 | 推荐值 | 影响 |
|---|---|---|---|
model | STT 模型选择 | nova-3 / scribe_v2 | 准确率和延迟 |
language | 目标语言 | zh / en / auto | 准确率 |
smart_format | 智能格式化 | true | 自动添加标点、格式化数字 |
diarize | 说话人分离 | true(多人场景) | 区分不同说话人 |
interim_results | 中间结果 | true(实时场景) | 降低感知延迟 |
utterance_end_ms | 停顿检测阈值 | 1000-1500ms | 判断用户是否说完 |
vad_events | 语音活动检测 | true | 检测说话开始/结束 |
punctuate | 自动标点 | true | 添加标点符号 |
detect_language | 自动语言检测 | true(多语言场景) | 自动识别语言 |
keywords | 关键词提示 | 领域术语列表 | 提升专业术语准确率 |
3.5 STT 准确率优化技巧
技巧 1:使用关键词提示(Keyword Boosting)
# Deepgram 关键词提示 — 提升专业术语识别准确率
options = LiveOptions(
model="nova-3",
language="zh",
keywords=[
"AI Agent:2", # 权重 2(最高)
"语音克隆:1.5",
"TTS:1.5",
"STT:1.5",
"ElevenLabs:1",
"Deepgram:1"
]
)技巧 2:音频预处理
# 音频预处理 — 提升 STT 准确率
import numpy as np
def preprocess_audio(audio_data: np.ndarray, sample_rate: int) -> np.ndarray:
"""
音频预处理管线:
1. 降噪
2. 音量归一化
3. 重采样到目标采样率
"""
# 1. 简单降噪(高通滤波,去除低频噪音)
from scipy.signal import butter, filtfilt
b, a = butter(4, 80 / (sample_rate / 2), btype='high')
audio_filtered = filtfilt(b, a, audio_data)
# 2. 音量归一化
max_val = np.max(np.abs(audio_filtered))
if max_val > 0:
audio_normalized = audio_filtered / max_val * 0.9
# 3. 确保 16kHz 采样率(STT 推荐)
if sample_rate != 16000:
from scipy.signal import resample
num_samples = int(len(audio_normalized) * 16000 / sample_rate)
audio_resampled = resample(audio_normalized, num_samples)
return audio_resampled
return audio_normalized技巧 3:多模型对比验证
# 多 STT 模型对比 — 选择最适合你场景的模型
import asyncio
import time
async def benchmark_stt(audio_path: str):
"""对比不同 STT 模型的准确率和延迟"""
results = {}
# Deepgram Nova-3
start = time.perf_counter()
dg_result = await transcribe_with_deepgram(audio_path, model="nova-3")
results["Deepgram Nova-3"] = {
"text": dg_result.transcript,
"confidence": dg_result.confidence,
"latency_ms": (time.perf_counter() - start) * 1000
}
# ElevenLabs Scribe v2
start = time.perf_counter()
el_result = await transcribe_with_elevenlabs(audio_path)
results["ElevenLabs Scribe v2"] = {
"text": el_result.text,
"latency_ms": (time.perf_counter() - start) * 1000
}
# 打印对比结果
for name, result in results.items():
print(f"\n{name}:")
print(f" 文本: {result['text'][:100]}...")
print(f" 延迟: {result['latency_ms']:.0f}ms")
if "confidence" in result:
print(f" 置信度: {result['confidence']:.3f}")
return results提示词模板
你是一个 STT 集成专家。请根据以下需求帮我设计 STT 集成方案:
应用场景:[实时对话 / 会议转录 / 呼叫中心 / 语音搜索]
目标语言:[中文 / 英文 / 多语言 / 方言]
音频来源:[麦克风 / 电话 / 视频会议 / 录音文件]
准确率要求:[最高 / 高 / 可接受]
延迟要求:[<200ms / <500ms / 无严格要求]
特殊需求:[说话人分离 / 情感分析 / 关键词检测 / PII 脱敏]
月度用量:[X 小时/月]
预算:[$X/月]
请推荐:
1. 最佳 STT 模型和提供商
2. 推荐的参数配置
3. 音频预处理建议
4. 准确率优化策略
5. 预估月度成本4. STT + LLM + TTS 完整集成
将 STT、LLM 和 TTS 串联起来,构建一个完整的语音对话管线。这是语音 AI Agent 的核心架构。
4.1 架构概览
用户语音 → [STT: Deepgram Nova-3] → 文本
↓
[LLM: GPT-4o-mini]
↓
回复文本
↓
音频输出 ← [TTS: ElevenLabs Flash] ← 回复文本4.2 完整集成示例(Python)
# 完整的 STT + LLM + TTS 语音对话管线 — Python
import asyncio
import os
import time
from openai import AsyncOpenAI
from elevenlabs import AsyncElevenLabs
from deepgram import DeepgramClient, LiveTranscriptionEvents, LiveOptions
class VoiceAgent:
"""语音 AI Agent:STT → LLM → TTS 完整管线"""
def __init__(self):
self.deepgram = DeepgramClient(
api_key=os.getenv("DEEPGRAM_API_KEY")
)
self.openai = AsyncOpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)
self.elevenlabs = AsyncElevenLabs(
api_key=os.getenv("ELEVENLABS_API_KEY")
)
self.voice_id = "JBFqnCBsd6RMkjVDRZzb"
self.conversation_history = []
self.system_prompt = """你是一个友好的中文 AI 客服助手。
- 用简洁、自然的口语回答问题
- 每次回复控制在 2-3 句话以内(适合语音输出)
- 如果无法解决问题,建议转接人工客服"""
async def process_speech(self, user_text: str) -> bytes:
"""
处理用户语音输入,返回 AI 语音回复。
完整流程:用户文本 → LLM 推理 → TTS 语音
"""
start_time = time.perf_counter()
# 步骤 1:LLM 推理
self.conversation_history.append({
"role": "user",
"content": user_text
})
llm_response = await self.openai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": self.system_prompt},
*self.conversation_history[-10:] # 保留最近 10 轮对话
],
max_tokens=150, # 限制回复长度(语音场景不宜过长)
temperature=0.7
)
assistant_text = llm_response.choices[0].message.content
self.conversation_history.append({
"role": "assistant",
"content": assistant_text
})
llm_time = time.perf_counter() - start_time
print(f"[LLM] {llm_time*1000:.0f}ms — {assistant_text}")
# 步骤 2:TTS 语音合成
tts_start = time.perf_counter()
audio_stream = await self.elevenlabs.text_to_speech.convert_as_stream(
voice_id=self.voice_id,
text=assistant_text,
model_id="eleven_flash_v2_5",
output_format="mp3_44100_128"
)
audio_chunks = []
async for chunk in audio_stream:
audio_chunks.append(chunk)
tts_time = time.perf_counter() - tts_start
total_time = time.perf_counter() - start_time
print(f"[TTS] {tts_time*1000:.0f}ms")
print(f"[总延迟] {total_time*1000:.0f}ms")
return b"".join(audio_chunks)
async def start_listening(self):
"""启动实时 STT 监听"""
dg_connection = self.deepgram.listen.asyncwebsocket.v("1")
async def on_transcript(self_dg, result, **kwargs):
sentence = result.channel.alternatives[0].transcript
if sentence and result.is_final:
print(f"\n[用户] {sentence}")
# 触发 LLM + TTS 处理
audio = await self.process_speech(sentence)
# 播放音频(实际场景中发送到用户端)
print(f"[音频] 生成 {len(audio)} 字节")
dg_connection.on(
LiveTranscriptionEvents.Transcript, on_transcript
)
options = LiveOptions(
model="nova-3",
language="zh",
smart_format=True,
interim_results=True,
utterance_end_ms=1000,
encoding="linear16",
sample_rate=16000,
channels=1
)
if await dg_connection.start(options):
print("语音 Agent 已启动,等待用户输入...")
# 实际场景中持续发送音频数据
# await dg_connection.send(audio_data)
# 使用示例
# agent = VoiceAgent()
# asyncio.run(agent.start_listening())4.3 完整集成示例(TypeScript)
// 完整的 STT + LLM + TTS 语音对话管线 — TypeScript
import { createClient, LiveTranscriptionEvents } from "@deepgram/sdk";
import { ElevenLabsClient } from "elevenlabs";
import OpenAI from "openai";
interface ConversationMessage {
role: "system" | "user" | "assistant";
content: string;
}
class VoiceAgent {
private deepgram = createClient(process.env.DEEPGRAM_API_KEY!);
private openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
private elevenlabs = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_API_KEY,
});
private voiceId = "JBFqnCBsd6RMkjVDRZzb";
private conversationHistory: ConversationMessage[] = [];
private systemPrompt = `你是一个友好的中文 AI 客服助手。
- 用简洁、自然的口语回答问题
- 每次回复控制在 2-3 句话以内
- 如果无法解决问题,建议转接人工客服`;
async processSpeech(userText: string): Promise<Buffer> {
const startTime = performance.now();
// 步骤 1:LLM 推理
this.conversationHistory.push({ role: "user", content: userText });
const llmResponse = await this.openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: this.systemPrompt },
...this.conversationHistory.slice(-10),
],
max_tokens: 150,
temperature: 0.7,
});
const assistantText = llmResponse.choices[0].message.content!;
this.conversationHistory.push({
role: "assistant",
content: assistantText,
});
const llmTime = performance.now() - startTime;
console.log(`[LLM] ${llmTime.toFixed(0)}ms — ${assistantText}`);
// 步骤 2:TTS 语音合成
const ttsStart = performance.now();
const audioStream = await this.elevenlabs.textToSpeech.convertAsStream(
this.voiceId,
{
text: assistantText,
model_id: "eleven_flash_v2_5",
output_format: "mp3_44100_128",
}
);
const chunks: Buffer[] = [];
for await (const chunk of audioStream) {
chunks.push(Buffer.from(chunk));
}
const ttsTime = performance.now() - ttsStart;
const totalTime = performance.now() - startTime;
console.log(`[TTS] ${ttsTime.toFixed(0)}ms`);
console.log(`[总延迟] ${totalTime.toFixed(0)}ms`);
return Buffer.concat(chunks);
}
async startListening() {
const connection = this.deepgram.listen.live({
model: "nova-3",
language: "zh",
smart_format: true,
interim_results: true,
utterance_end_ms: 1000,
encoding: "linear16",
sample_rate: 16000,
channels: 1,
});
connection.on(LiveTranscriptionEvents.Transcript, async (data) => {
const sentence = data.channel.alternatives[0].transcript;
if (sentence && data.is_final) {
console.log(`\n[用户] ${sentence}`);
const audio = await this.processSpeech(sentence);
console.log(`[音频] 生成 ${audio.length} 字节`);
}
});
connection.on(LiveTranscriptionEvents.Open, () => {
console.log("语音 Agent 已启动,等待用户输入...");
});
}
}
// 使用示例
// const agent = new VoiceAgent();
// agent.startListening();4.4 流式管线优化:LLM 流式输出 → TTS 流式输入
最高效的集成方式是将 LLM 的流式输出直接喂给 TTS 的流式输入,实现”边想边说”的效果。
# 流式管线:LLM 流式输出 → TTS WebSocket 流式输入
import asyncio
import json
import websockets
from openai import AsyncOpenAI
async def streaming_pipeline(user_text: str):
"""
流式管线:LLM 边生成文本,TTS 边合成语音。
用户感知延迟 = LLM 首 token 延迟 + TTS TTFB ≈ 200-400ms
"""
openai_client = AsyncOpenAI()
# 步骤 1:建立 TTS WebSocket 连接
voice_id = "JBFqnCBsd6RMkjVDRZzb"
tts_uri = (
f"wss://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
f"/stream-input?model_id=eleven_flash_v2_5"
f"&output_format=mp3_44100_128"
)
async with websockets.connect(
tts_uri,
additional_headers={
"xi-api-key": "your-elevenlabs-api-key"
}
) as tts_ws:
# 初始化 TTS 连接
await tts_ws.send(json.dumps({
"text": " ",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 0.75
}
}))
audio_chunks = []
# 异步接收 TTS 音频
async def receive_audio():
async for msg in tts_ws:
data = json.loads(msg)
if data.get("audio"):
import base64
chunk = base64.b64decode(data["audio"])
audio_chunks.append(chunk)
# 实时播放:play_audio(chunk)
if data.get("isFinal"):
break
receiver = asyncio.create_task(receive_audio())
# 步骤 2:LLM 流式生成 → 直接发送到 TTS
stream = await openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "用简洁的中文回答。"},
{"role": "user", "content": user_text}
],
stream=True,
max_tokens=150
)
buffer = ""
async for chunk in stream:
delta = chunk.choices[0].delta.content or ""
buffer += delta
# 按句子边界发送到 TTS(逗号、句号、问号等)
if any(p in buffer for p in [",", "。", "!", "?", ";", ",", ".", "!", "?"]):
await tts_ws.send(json.dumps({"text": buffer}))
print(f"[发送到 TTS] {buffer}")
buffer = ""
# 发送剩余文本
if buffer:
await tts_ws.send(json.dumps({"text": buffer}))
# 发送结束信号
await tts_ws.send(json.dumps({"text": ""}))
await receiver
return b"".join(audio_chunks)
# asyncio.run(streaming_pipeline("请介绍一下语音克隆技术"))💡 流式管线的关键:按句子边界(标点符号)将 LLM 输出分块发送给 TTS,而不是逐字发送。逐字发送会导致 TTS 无法正确处理语调和韵律;等全部生成完再发送则失去了流式的意义。
实战案例
案例 1:品牌语音克隆 + 多渠道部署
需求:某教育科技公司希望用创始人的声音作为品牌语音,部署到客服电话、App 内语音助手和课程配音三个渠道。
技术方案:
音频采集(30 分钟专业录音)
↓
ElevenLabs PVC 专业克隆
↓
┌─────────────────────────────────────────┐
│ 品牌语音(Voice ID) │
├─────────────┬──────────────┬────────────┤
│ 客服电话 │ App 语音助手 │ 课程配音 │
│ Flash v2.5 │ Flash v2.5 │ v3 模型 │
│ 低延迟优先 │ 低延迟优先 │ 质量优先 │
│ Vapi 编排 │ WebSocket │ 批量生成 │
└─────────────┴──────────────┴────────────┘实施步骤:
- 音频采集:在专业录音棚录制 30 分钟创始人语音,覆盖多种语调和情感
- 语音克隆:使用 ElevenLabs PVC 创建专业克隆语音
- 多渠道配置:
- 客服电话:Flash v2.5 + Vapi.ai 编排,延迟 < 500ms
- App 语音助手:Flash v2.5 + WebSocket 流式,延迟 < 300ms
- 课程配音:v3 模型批量生成,追求最高质量
成本估算(月度):
- ElevenLabs Pro 计划:$99/月(500K 字符)
- 客服电话(Vapi 编排):~$150/月
- App 语音助手:包含在 Pro 计划中
- 课程配音:包含在 Pro 计划中
- 月度总成本:约 $249
案例 2:开源方案 — Chatterbox + Whisper 本地语音 Agent
需求:一家医疗科技公司需要构建语音 AI 助手,但由于 HIPAA 合规要求,所有语音数据不能离开公司服务器。
技术方案:
患者语音 → [Whisper Large v3: 本地 STT] → 文本
↓
[本地 LLM: Llama 3]
↓
回复文本
↓
语音输出 ← [Chatterbox Turbo: 本地 TTS] ← 回复文本关键代码:
# 全本地语音 Agent — 无需外部 API
import torch
import torchaudio
import whisper
from chatterbox.tts import ChatterboxTTS
from transformers import AutoModelForCausalLM, AutoTokenizer
class LocalVoiceAgent:
"""全本地部署的语音 Agent(HIPAA 合规)"""
def __init__(self):
self.device = "cuda" if torch.cuda.is_available() else "cpu"
# 加载 STT 模型(Whisper)
self.stt_model = whisper.load_model("large-v3", device=self.device)
# 加载 TTS 模型(Chatterbox Turbo)
self.tts_model = ChatterboxTTS.from_pretrained(
device=self.device,
model_id="ResembleAI/chatterbox-turbo"
)
# 加载 LLM(本地 Llama)
self.tokenizer = AutoTokenizer.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct"
)
self.llm = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct",
torch_dtype=torch.float16,
device_map="auto"
)
self.reference_audio = "brand_voice.wav"
def transcribe(self, audio_path: str) -> str:
"""STT:语音转文本"""
result = self.stt_model.transcribe(
audio_path,
language="zh",
task="transcribe"
)
return result["text"]
def think(self, user_text: str) -> str:
"""LLM:生成回复"""
messages = [
{"role": "system", "content": "你是一个医疗咨询助手。"},
{"role": "user", "content": user_text}
]
inputs = self.tokenizer.apply_chat_template(
messages, return_tensors="pt"
).to(self.device)
outputs = self.llm.generate(
inputs, max_new_tokens=150, temperature=0.7
)
return self.tokenizer.decode(
outputs[0][inputs.shape[1]:], skip_special_tokens=True
)
def speak(self, text: str, output_path: str = "response.wav"):
"""TTS:文本转语音"""
wav = self.tts_model.generate(
text=text,
audio_prompt_path=self.reference_audio,
exaggeration=0.3,
cfg_weight=0.5
)
torchaudio.save(output_path, wav, self.tts_model.sr)
return output_path
def process(self, audio_path: str) -> str:
"""完整处理流程"""
# STT
user_text = self.transcribe(audio_path)
print(f"[用户] {user_text}")
# LLM
response = self.think(user_text)
print(f"[助手] {response}")
# TTS
output = self.speak(response)
print(f"[音频] {output}")
return output
# agent = LocalVoiceAgent()
# agent.process("patient_question.wav")硬件要求:
- GPU:NVIDIA A100 80GB(推荐)或 RTX 4090 24GB(最低)
- RAM:64GB+
- 存储:100GB+(模型文件)
成本估算:
- 硬件(一次性):$10,000-30,000(GPU 服务器)
- 云 GPU 租赁:$2-5/小时(如 RunPod、Lambda)
- API 费用:$0(全部本地运行)
- 适合场景:对数据隐私要求极高、月度通话量大(> 10,000 分钟)的企业
案例分析
两个案例展示了语音克隆与 TTS-STT 集成的两种典型路径:
- 案例 1 选择商业 API 方案,以 ElevenLabs PVC 为核心,通过同一个 Voice ID 实现多渠道一致的品牌语音体验。优势是开发速度快、维护成本低,适合中小规模使用
- 案例 2 选择全开源本地方案,将 Whisper + Llama + Chatterbox 部署在私有服务器上,实现零数据外泄。优势是完全合规、无 API 费用,但需要较高的硬件投入和运维能力
避坑指南
❌ 常见错误
-
语音克隆样本质量差
- 问题:使用有背景噪音、多人说话或手机录制的低质量音频做克隆,导致克隆语音失真、含杂音
- 正确做法:使用安静环境录制的清晰单人语音,建议使用专业麦克风(如 Blue Yeti、Rode NT-USB),采样率 ≥ 44.1kHz,WAV 或 FLAC 格式
-
忽略语音克隆的法律合规
- 问题:未经授权克隆他人声音,或未标注 AI 生成内容,可能违反 EU AI Act、ELVIS Act 等法规
- 正确做法:始终获取语音所有者的书面同意;在所有 AI 生成的语音内容上添加标注;使用 Resemble.ai 的 AI 水印功能实现内容溯源
-
TTS 参数使用默认值不调优
- 问题:不同场景(客服对话 vs 有声书)使用相同的 TTS 参数,导致语音效果不理想
- 正确做法:根据场景调整 stability、similarity_boost 等参数;实时对话场景优先选择低延迟模型(Flash / Aura-2)
-
STT 不启用 interim_results
- 问题:等待用户说完整句话才开始处理,导致感知延迟增加 1-3 秒
- 正确做法:启用
interim_results=True,在用户说话过程中就开始预处理;配合utterance_end_ms参数检测用户停顿
-
流式管线中逐字发送文本给 TTS
- 问题:将 LLM 的每个 token 直接发送给 TTS,导致 TTS 无法正确处理语调和韵律,生成的语音断断续续
- 正确做法:按句子边界(标点符号)缓冲文本,积累到一个完整的短句后再发送给 TTS
-
忽略 TTS 的字符/额度消耗
- 问题:ElevenLabs 按字符计费,长文本回复快速消耗额度;未设置 LLM 的 max_tokens 限制
- 正确做法:在 LLM 的 system prompt 中明确要求”每次回复控制在 2-3 句话以内”;设置
max_tokens=150;使用 Flash 模型(每字符消耗 0.5 个额度)
-
STT 不使用关键词提示
- 问题:专业术语(产品名、技术名词)识别准确率低,导致 LLM 收到错误的输入
- 正确做法:使用 Deepgram 的
keywords参数或 ElevenLabs 的keyterm_prompts提供领域术语列表
-
语音克隆后不做 A/B 测试
- 问题:直接将克隆语音部署到生产环境,用户反馈”听起来不自然”或”不像原声”
- 正确做法:克隆完成后,先用 5-10 个测试句子生成样本,与原声对比;邀请 3-5 个人盲测评分;根据反馈调整参数或重新录制样本
✅ 最佳实践
-
分级语音质量策略:实时对话使用低延迟模型(ElevenLabs Flash / Deepgram Aura-2),离线内容使用高质量模型(ElevenLabs v3)。同一个克隆语音可以在不同模型间切换
-
语音克隆样本多样性:录制样本时覆盖多种语调(陈述、疑问、感叹)、语速(快、中、慢)和情感(平静、热情、关切),这样克隆语音在不同场景下表现更自然
-
STT + TTS 端到端监控:记录每次交互的 STT 延迟、LLM 延迟、TTS 延迟和总延迟,设置告警阈值(如总延迟 > 1 秒),持续优化瓶颈环节
-
优雅降级机制:当主 TTS 提供商延迟过高或不可用时,自动切换到备选提供商;当 STT 识别置信度低于阈值时,请求用户重复
-
语音内容缓存:对于固定话术(欢迎语、菜单选项、常见回答),预生成音频并缓存,避免重复调用 TTS API,节省成本和延迟
-
定期更新克隆语音:如果语音所有者的声音随时间变化(如年龄增长),定期用新样本更新克隆语音,保持一致性
相关资源与延伸阅读
- ElevenLabs 语音克隆文档 — 即时克隆和专业克隆的完整产品指南
- ElevenLabs WebSocket 流式 TTS 文档 — 实时 TTS WebSocket API 的详细技术文档
- ElevenLabs Scribe v2 STT 文档 — Scribe v2 语音转文本 API 文档
- Deepgram 实时流式转录入门 — Nova-3 实时 STT 的快速入门指南
- Deepgram WebSocket 流式 TTS 文档 — Aura-2 WebSocket TTS 的技术文档
- Resemble.ai Chatterbox GitHub 仓库 — 开源 TTS 模型的源码、文档和使用示例
- Chatterbox Turbo 介绍 — Turbo 变体的特性介绍和性能基准
- Deepgram 语音 AI 工作流设计指南 — STT + NLP + TTS 完整管线的架构设计指南
- ElevenLabs 延迟优化最佳实践 — 官方的 TTS 延迟优化建议
- Resemble.ai 语音克隆法规合规指南 — AI 语音克隆的法律更新和合规建议
参考来源
- ElevenLabs Voice Cloning Documentation (2025 年持续更新)
- ElevenLabs Instant Voice Cloning API Quickstart (2025 年持续更新)
- ElevenLabs Professional Voice Cloning API Quickstart (2025 年持续更新)
- ElevenLabs Scribe v2 Realtime Launch (2025 年 11 月)
- ElevenLabs Streaming Guide (2025 年持续更新)
- Deepgram Nova-3 Introduction (2025 年 4 月)
- Deepgram TTS WebSocket Streaming (2025 年持续更新)
- Deepgram Live Streaming Audio Transcription (2025 年持续更新)
- Deepgram Voice AI Workflow Design (2025 年 7 月)
- Resemble.ai Chatterbox — HuggingFace (2025 年 6 月)
- Resemble.ai Chatterbox Turbo (2025 年 12 月)
- Chatterbox Turbo — PyPI (2025 年持续更新)
- ElevenLabs Voice Cloning Consent Policy 2025 (2025 年 2 月)
- AI Voice Cloning Regulation — Resemble.ai (2026 年 1 月)
- EU AI Act and Global Compliance Guide for Synthetic Voices (2025 年 6 月)
- Deepgram Aura-1 Retirement Notice — LiveKit Docs (2026 年 2 月)
📖 返回 总览与导航 | 上一节:14a-语音AI平台对比 | 下一节:14c-AI电话Agent构建