让 AI 像真人一样"边听边说"、能被打断、还能自然接上——它靠的从来不是一个更会说话的 LLM,而是把 VAD / ASR / LLM / TTS 和一个 事件驱动的实时调度器整合成的一整套持续运行的流式系统。这一篇把它从头拆到尾。
The whole system, on one page.
整个实时语音系统不是一个 LLM。它是若干模块通过流式接口串起来,再由一个中央调度器统一指挥的持续运行系统。从麦克风到扬声器,数据全程 streaming——没有任何一步在等前一步"全部完成"再进入下一步。
关键在于:没有任何一步是在等前一步完成。用户音频还在采集,VAD 已经在判断是否讲话;VAD 还没结束,ASR 已经开始识别;ASR 还在输出文字,LLM 已经开始推理;LLM 还在生成 token,TTS 已经开始把最早的 token 转成音频推给扬声器。整条管线里,任意时刻都有五件事在并发进行。
普通 ChatGPT 是"回合制":输入 → 等待 → 输出 → 结束。实时语音是"总在进行中":while true: Listen & Think & Speak——三件事同时发生,从不真正结束。
Turn-based vs. always-on — a table.
把普通 ChatGPT 和 Realtime Voice 摆在一起对照,最本质的差异不在"能力",而在时间结构。
| 普通 ChatGPT · 回合制 | Realtime Voice · 持续在线 |
|---|---|
| 用户输入必须结束,LLM 才开始推理 | ASR 一有 token 出来,Scheduler 就可能启动 LLM |
| LLM 输出全部完成,才返回给用户 | LLM 一有 token,TTS 立刻转成音频往下推 |
| 每一步都在等前一步结束 | 五个模块永远同时在跑 |
| 有明确的"输入结束 / 输出结束"两个时点 | 没有"结束"这个概念——系统一直保持运行 |
整个 Realtime 流程用伪代码表达大概是:
while True: Listen() & Think() & Speak() —— 关键是三个动作并发,不是顺序。每一步都以 streaming 的方式在管线里持续流动。
The most important layer in the system.
很多人认为 LLM 是核心。实际上——
Realtime Voice 最大的难点从来不是 LLM,而是 Scheduler。
Scheduler 自己不"思考"。它像剧场里的总导演,专门决策什么时候发生什么事——
你听到 ChatGPT 语音回你时觉得"像真人",本质上不是 LLM 更强了,而是 Scheduler 的这一层把无数微小的时序决策做对了——它决定了"这一秒到底该干嘛"。
Everything happens as an event.
Scheduler 维护的一份实时状态
Scheduler 内部维护着一份持续更新的 Conversation State,简化看大致长这样:
user_speaking · assistant_speaking · current_asr_result · current_llm_output · current_audio_playing · conversation_history · pending_tokens · interrupt_flag · playback_position · confidence · voice_activity
一次典型 tick 内发生的事情
用户说了一句"我想知道"——这一秒里 Scheduler 内部大致是这样一条时间线:
全都是事件
Realtime 系统里几乎所有行为都是 Event:UserStartSpeak UserStopSpeak AssistantStartSpeak AssistantStopSpeak ASRUpdate LLMTokenGenerated TTSChunkGenerated AudioFinished Interrupt Reconnect Timeout。
Scheduler 的主循环也非常朴素:
while True: event = WaitEvent(); Handle(event) —— 几乎所有实时系统都是这种架构:一个持续消费事件的循环,加上一份不断更新的状态。
Not a rule — a fused signal.
Scheduler 并不是"听到一句话就立刻回答"。它每一帧都在计算一个 Reply Score——一个由很多信号融合而成的分数。
典型输入信号:
所有信号加权融合,得到最终 Reply Score,跟阈值比较:
所以"要不要回答"从来不是一条规则能决定的——是十几个信号一起投票的结果。
Interrupt Score, and what actually happens when you cut in.
6.1 为什么"嗯""啊"不打断
ASR 的确可能识别出你嘴里蹦出的"嗯""啊""嘿""嘶",甚至连你的呼吸都能识别成词。但是识别成功 ≠ 一定打断。
Scheduler 还会再算一个 Interrupt Score,融合更多维度:
这就是为什么它真人感那么强——不该被打断的时候不打断,该被打断的时候毫秒级就停。
6.2 真正打断发生了什么
假设 Assistant 正在念A B C D E F G H,你突然说"不是,我想问另一个"。Scheduler 内部会发生:
立刻停止音频播放,把还在 buffer 里没播的 chunk 全部丢弃。
冻结当前状态。注意——不是把 LLM 还没说完的 F G H 写进历史,而是只保留已经真正播放出来的部分。这一层特别重要:模型的"未来"不应污染上下文。
把 assistant 的部分回复(比如 A B C D)加进历史,然后 append 用户的新输入。
基于新的 Conversation State 重新调用 LLM 生成——不是在 token 里插 token,而是"重新组织上下文 → 重新推理"。
整个动作在几十毫秒内完成,对用户而言几乎是"话说到一半瞬间切掉"。
Why the first token arrives so fast, and where the audio comes from.
7.1 LLM 为什么这么快
因为它不会每次都重新计算全部 token。现代推理层通常叠加多种优化:
| 技术 | 作用 |
|---|---|
| KV Cache | 缓存历史 token 的 Attention Key / Value,避免每轮重算整段上下文 |
| Incremental Decode | 每次只算新增的 token,而不是重跑整段序列 |
| Speculative Decode | 用小模型先预测候选 token,大模型快速验证——对就直接采用,错就回退 |
| Streaming Decode | 一边生成一边把 token 推出去,不等整段回答完成 |
所以你听到的不是"等 LLM 全部想完再一次性说给你",而是——
Token1 → 立刻发送 → Token2 → 立刻发送 → Token3 → ……
而不是全部生成 → 一次发送。
7.2 TTS 是本地还是云端
目前行业主流有两种方案:
| 方案 A · 本地 TTS | 方案 B · 云端 Streaming TTS(主流) |
|---|---|
| 延迟低 · 可离线 | 音色多样 · 更新方便 · 质量随云端模型持续升级 |
| 模型体积大 · 更新困难 · 音色有限 | 强依赖网络,但用分块流式抵消延迟 |
| 链路:LLM → 文本 → APP 内置模型 → 音频 | 链路:LLM → Streaming Token → Cloud TTS → Streaming Audio → APP 播放 |
方案 B 里,APP 更像一台播放器:不断收到 Chunk1 · Chunk2 · Chunk3 · …,边收边播。所以用户感觉几乎没有等待——事实上从"LLM 出第一个 token"到"扬声器出第一个音节",只走了一次很短的 chunk pipeline。
The LLM is only one of the modules.
很多人以为:
"ChatGPT 实时语音 = 一个会说话的 LLM。"
更准确的理解是——它是一个Realtime AI System:
真正让 ChatGPT 实时语音像真人聊天的,是这五件事的合力:
If you only remember one thing.
实时语音 AI 的突破,不只是 LLM 更强,而是把 VAD、ASR、LLM、TTS 和一个事件驱动的实时调度器整合成了持续运行的流式系统。真正让它像真人对话的,不是单一模型,而是整个低延迟、可中断、状态一致的系统工程。