核心摘要
实时语音 AI Agent 不是“带麦克风输入的聊天机器人”,而是强延迟约束下的流式多模态系统。生产架构必须协调流式 ASR、轮次检测、LLM 推理、工具调用、TTS 流式合成、用户打断和 WebRTC 传输。最关键的体验指标是首个音频响应时间:用户可以接受答案继续生成,但无法接受每一轮都尴尬停顿。本文给出低延迟语音 Agent 的架构、延迟预算、代码模式和可观测性清单。
目录
- 核心要点
- 为什么语音 Agent 比聊天机器人更难
- 延迟预算
- 参考架构
- 流式 ASR 与轮次检测
- 面向语音的 LLM 编排
- TTS 流式合成与打断处理
- WebRTC 传输
- 实现模式
- 可观测性
- 最佳实践
- 常见问题
- 总结
核心要点
- 语音 Agent 优先优化首个音频响应时间,而不是完整回答耗时。
- 轮次检测是最难的产品问题:太敏感会抢话,太保守会造成尴尬沉默。
- 打断处理是自然对话的基础能力:用户会插话、纠正和补充,系统必须能取消旧输出。
- 级联架构更可控,原生语音模型更自然:生产系统常采用混合方案。
- 语音可观测性需要音频级 Trace:ASR partial、VAD 事件、LLM token、TTS chunk 和播放状态都要可追踪。
🔧 实用工具:使用 JSON 格式化工具 检查语音事件 payload;使用 Base64 编码解码工具 调试小型音频帧数据。
为什么语音 Agent 比聊天机器人更难
文本聊天机器人可以等用户输入完成,再调用模型并渲染完整答案。语音 Agent 不行。人类对口语对话的预期是可打断、响应快、连续且有节奏。任何延迟都会被听见。
语音流水线多了很多环节:
| 层级 | 职责 | 常见失败 |
|---|---|---|
| 音频采集 | 麦克风、浏览器权限、音频分帧 | 丢包、回声、爆音 |
| VAD/轮次检测 | 判断用户是否说完 | 过早截断或等待过久 |
| ASR | 语音转文本 | 转写错误、partial 不稳定 |
| LLM | 推理、工具调用、组织回答 | 首 token 慢、回答过长 |
| TTS | 文本转语音 | 声音机械、播放断流 |
| 播放 | 将音频流返回用户 | 抖动、打断 Bug |
更多 Agent 编排基础可参考 AI Agent 开发指南 和 多模态 AI 工程实战。
延迟预算
一个实用的生产目标是:简单轮次 800ms 内开始播放首个音频。复杂工具调用可以更久,但系统应先给用户一个自然反馈。
| 组件 | 目标耗时 | 说明 |
|---|---|---|
| 音频分帧 | 20-40ms | WebRTC 或 WebSocket 音频帧 |
| VAD 判断 | 100-250ms | 取决于静音阈值 |
| ASR partial 稳定 | 100-300ms | 尽早使用部分转写 |
| LLM 首 token | 200-700ms | 取决于模型和上下文 |
| TTS 首 chunk | 100-300ms | 必须使用流式 TTS |
| 播放缓冲 | 40-120ms | 防止音频断流 |
核心技巧是重叠执行:不要等最终 ASR 才开始准备。可以基于 partial transcript 提前做意图识别、上下文检索和短反馈生成。
参考架构
对话编排器是核心。它负责对话状态、取消过期模型调用、决定何时回答,并为每一轮输出可追踪事件。
流式 ASR 与轮次检测
轮次检测要判断用户是否说完,不能只依赖静音。更稳妥的方式是结合音频和文本信号:
- VAD 置信度和静音时长
- ASR partial transcript 是否稳定
- 是否出现句末语气或标点概率
- 用户意图类别
- 当前 AI 是否正在播放 TTS
type TurnEvent =
| { type: "speech_start"; ts: number }
| { type: "partial_transcript"; text: string; stable: boolean }
| { type: "speech_end"; silenceMs: number }
| { type: "turn_committed"; transcript: string };
function shouldCommitTurn(events: TurnEvent[]): boolean {
const lastSpeechEnd = [...events].reverse().find((event) => event.type === "speech_end");
const partial = [...events].reverse().find((event) => event.type === "partial_transcript");
if (!lastSpeechEnd || !partial || partial.type !== "partial_transcript") return false;
if (!partial.stable) return false;
return lastSpeechEnd.type === "speech_end" && lastSpeechEnd.silenceMs >= 350;
}
短命令场景可以更激进;陪伴、教学、销售和咨询场景需要更耐心,因为用户会边想边说。
面向语音的 LLM 编排
语音回答应该比文本回答更短、更口语化。系统提示词要明确要求模型以口语输出:
你是实时语音 Agent。
用短句回答,适合直接朗读。
避免 Markdown、表格和长列表。
如果工具调用需要时间,先给一句确认,再继续。
如果用户打断,以最新用户话语为准。
工具调用建议拆成两阶段:
- 即时确认:“我帮你查一下。”
- 工具返回后的有依据回答。
这样即使后端需要时间,用户也不会听到长时间沉默。
TTS 流式合成与打断处理
打断处理允许用户在 AI 说话时插话。没有打断能力的语音 Agent 很像传统电话菜单,缺少真实对话感。
用户在 TTS 播放期间开口时,系统应执行:
- 停止或降低当前音频播放。
- 清空未播放 TTS chunk。
- 取消或暂停 LLM 生成。
- 提交用户新一轮输入。
- 将 AI 已说出的内容写入对话状态。
class VoiceSession:
def __init__(self):
self.current_generation = None
self.tts_queue = []
self.transcript = []
async def on_user_barge_in(self, partial_text: str):
if self.current_generation:
self.current_generation.cancel()
self.tts_queue.clear()
self.transcript.append({"role": "user", "content": partial_text, "event": "barge_in"})
return {"action": "stop_playback", "reason": "user_interrupted"}
WebRTC 传输
当低延迟和网络韧性重要时,优先使用 WebRTC。WebSocket 更简单,但 WebRTC 在抖动处理、回声消除、拥塞控制和媒体传输方面更成熟。
| 传输方式 | 适合场景 | 代价 |
|---|---|---|
| WebSocket 音频帧 | 快速原型、服务端强控制 | 需要自己处理抖动和回声 |
| WebRTC | 浏览器语音 Agent、低延迟 | 信令和媒体逻辑更复杂 |
| SIP Bridge | 呼叫中心 | 受电话网络限制 |
| Native Mobile Audio | 移动 App | 平台音频会话差异大 |
实现模式
建议使用事件驱动协议:
{
"type": "voice.turn.committed",
"sessionId": "sess_123",
"turnId": "turn_009",
"transcript": "帮我查一下订单状态",
"audio": {
"sampleRate": 16000,
"durationMs": 2140
}
}
后端状态机可以这样定义:
type VoiceState =
| "idle"
| "listening"
| "thinking"
| "speaking"
| "interrupted"
| "failed";
interface VoiceTraceSpan {
turnId: string;
state: VoiceState;
startedAt: number;
endedAt?: number;
metadata?: Record<string, unknown>;
}
可观测性
语音系统需要时间线 Trace。纯文本日志无法解释为什么用户听到了 2 秒沉默。
| 指标 | 意义 |
|---|---|
| time_to_first_audio | 体感响应速度 |
| vad_false_commit_rate | 抢话和过早提交比例 |
| asr_word_error_rate | 转写准确率 |
| tts_underrun_count | 播放是否平滑 |
| interruption_rate | 对话自然度 |
| tool_latency_p95 | 后端瓶颈 |
| user_reprompt_rate | 用户不满意程度 |
如果已有 Agent Trace,可扩展音频事件。相关可观测性设计可参考 Agent 可观测性工程。
最佳实践
- 所有环节都流式化:ASR、LLM、TTS 和播放都应增量执行。
- 从第一天设计打断:取消路径不是边界情况,而是核心体验。
- 控制回答长度:长文本直接朗读会显得不自然。
- 分离控制通道和媒体通道:控制事件不要与音频帧竞争带宽。
- 衡量体感延迟:首个音频响应比后端完成时间更重要。
常见问题
生产级语音 AI Agent 应该达到什么延迟目标?
简单轮次建议 800ms 内开始播放首个音频,复杂知识型轮次建议 1.5s 内给出首个音频反馈。完整回答可以继续流式生成,但用户需要先听到系统响应。
语音 AI 中的打断处理是什么?
打断处理允许用户在 AI 说话时插话。系统需要停止播放、取消过期生成、捕获新的用户话语,并从最新上下文继续回答。
应该使用 ASR + LLM + TTS 还是原生语音到语音模型?
如果需要工具调用、合规审计、可观测性和精确控制,级联架构更合适。如果更看重自然韵律和极低延迟,可以使用原生语音到语音模型。生产系统常混合使用。
如何监控语音 AI 的生产质量?
需要同时监控首个音频响应时间、ASR 准确率、VAD 误判、打断率、TTS 断流、工具延迟和用户重问率。最好能按时间线回放每一轮。
为什么语音 Agent 经常出现尴尬停顿?
常见原因是串行处理:等最终 ASR,再等 LLM,再等完整 TTS。解决方法是流式化和并行化:基于 partial transcript 提前识别意图,流式生成回答,并立即合成首个 TTS chunk。
总结
语音 AI Agent 是实时多模态系统。架构必须围绕延迟、打断、音频质量和可观测性设计。建议从可控的 ASR + LLM + TTS 级联架构起步,引入 WebRTC 提升传输质量,从第一天实现打断处理,并把首个音频响应时间作为核心体验指标。