核心摘要

实时语音 AI Agent 不是“带麦克风输入的聊天机器人”,而是强延迟约束下的流式多模态系统。生产架构必须协调流式 ASR、轮次检测、LLM 推理、工具调用、TTS 流式合成、用户打断和 WebRTC 传输。最关键的体验指标是首个音频响应时间:用户可以接受答案继续生成,但无法接受每一轮都尴尬停顿。本文给出低延迟语音 Agent 的架构、延迟预算、代码模式和可观测性清单。

目录

核心要点

  • 语音 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 提前做意图识别、上下文检索和短反馈生成。

参考架构

flowchart LR A["浏览器麦克风"] --> B["WebRTC 媒体通道"] B --> C["语音网关"] C --> D["VAD + 轮次检测"] C --> E["流式 ASR"] D --> F["对话编排器"] E --> F F --> G["LLM + 工具调用"] G --> H["流式 TTS"] H --> I["播放缓冲"] I --> A F --> J["Trace 存储"]

对话编排器是核心。它负责对话状态、取消过期模型调用、决定何时回答,并为每一轮输出可追踪事件。

流式 ASR 与轮次检测

轮次检测要判断用户是否说完,不能只依赖静音。更稳妥的方式是结合音频和文本信号:

  • VAD 置信度和静音时长
  • ASR partial transcript 是否稳定
  • 是否出现句末语气或标点概率
  • 用户意图类别
  • 当前 AI 是否正在播放 TTS
typescript
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 编排

语音回答应该比文本回答更短、更口语化。系统提示词要明确要求模型以口语输出:

text
你是实时语音 Agent。
用短句回答,适合直接朗读。
避免 Markdown、表格和长列表。
如果工具调用需要时间,先给一句确认,再继续。
如果用户打断,以最新用户话语为准。

工具调用建议拆成两阶段:

  1. 即时确认:“我帮你查一下。”
  2. 工具返回后的有依据回答

这样即使后端需要时间,用户也不会听到长时间沉默。

TTS 流式合成与打断处理

打断处理允许用户在 AI 说话时插话。没有打断能力的语音 Agent 很像传统电话菜单,缺少真实对话感。

用户在 TTS 播放期间开口时,系统应执行:

  1. 停止或降低当前音频播放。
  2. 清空未播放 TTS chunk。
  3. 取消或暂停 LLM 生成。
  4. 提交用户新一轮输入。
  5. 将 AI 已说出的内容写入对话状态。
python
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 平台音频会话差异大

实现模式

建议使用事件驱动协议:

json
{
  "type": "voice.turn.committed",
  "sessionId": "sess_123",
  "turnId": "turn_009",
  "transcript": "帮我查一下订单状态",
  "audio": {
    "sampleRate": 16000,
    "durationMs": 2140
  }
}

后端状态机可以这样定义:

typescript
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 可观测性工程

最佳实践

  1. 所有环节都流式化:ASR、LLM、TTS 和播放都应增量执行。
  2. 从第一天设计打断:取消路径不是边界情况,而是核心体验。
  3. 控制回答长度:长文本直接朗读会显得不自然。
  4. 分离控制通道和媒体通道:控制事件不要与音频帧竞争带宽。
  5. 衡量体感延迟:首个音频响应比后端完成时间更重要。

常见问题

生产级语音 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 提升传输质量,从第一天实现打断处理,并把首个音频响应时间作为核心体验指标。

相关资源