1. 从 WebRTC 到 Realtime API:一个人和一个时代的连接点

聊人机实时语音绕不开一个人:Justin Uberti。WebRTC 的架构核心,DTLS/SRTP 加密传输、ICE 连接协商这套如今几乎所有实时音视频 SDK 都在用的底层设计,他就是主要创造者之一。后来他去了 OpenAI,负责 Realtime API 和实时 AI 方向。这么一个把"浏览器里做实时音视频"从不可能变成可能的人,转过头来做人机语音交互,他的视角本身就值得认真记一笔。

这篇学习笔记我不会复述新闻,而是想把 Justin Uberti 这条职业路径背后真正重要的东西拆开讲: WebRTC 当年的架构决策为什么成了今天 AI 语音的底层约束? 以及 当语音对像从"人"变成"模型"时,RTC 架构哪些地方必须重塑,哪些地方反而可以原封不动继承?

我的判断是:Voice Agent 这个赛道,真正卡脖子的不是大模型上下文有多长,也不是 TTS 音色够不够自然,而是实时音频传输和交互控制这套"管道"到底能不能跟上模型推理的速度。对开发者来说,理解 Uberti 做过什么、现在在解决什么问题,几乎等于提前拿到一张 Voice Agent 架构的避坑地图。

先说个背景:WebRTC 从 2011 年开源到成为 W3C 标准,它的核心命题一直是" 让两个浏览器之间能实时传音视频 "。这个"实时"指的是 100~300 毫秒内的端到端延迟,还要扛住丢包、抖动、NAT 穿透这些现实网络的毒打。当时的架构设计,本质上是在不可靠的互联网之上,用一整套协议栈人为造出一条"看起来可靠"的实时管道。

到了 OpenAI Realtime API 时代,问题变了:一端不再是浏览器里的真人,而是云端的大模型。模型不是按帧持续发声的,它是 按需生成、按轮响应 的。这条管道要传的不再只是音频数据,还有事件、中断信号、会话状态。这意味着 Uberti 当年设计的很多机制仍然有效,但架构的优先级、瓶颈和失败模式完全不一样了。

这篇文章我会从 WebRTC 的底层设计逻辑讲起,然后落到 Realtime API 的会话架构,最后给出我自己在 Voice Agent 项目里的实测经验和设计建议。全程不写代码,只讲架构逻辑和取舍,尽量用工程语言把事情说透。

2. WebRTC 架构的底层逻辑:给实时通信奠基的那些设计决策

2.1 为什么 WebRTC 选择 UDP 而不是 TCP

很多人第一次接触 WebRTC 都会问:传音频为什么不用 TCP?TCP 不是更可靠吗?

这个问题的答案,就是理解整个 WebRTC 架构的钥匙。TCP 的可靠性来自重传和拥塞控制,但代价是 延迟不可控 。一个包丢了,TCP 会停下来等重传,后面的数据全部排队。视频通话里如果某个音频包迟到 400 毫秒,那这一帧就不用播了——人耳对延迟的容忍度极低,超过 200~300 毫秒的音频延迟就会明显感到"卡"。

所以 WebRTC 选择在 UDP 之上自己做一层可靠性的折中。它用 RTP(Real-time Transport Protocol)封装音频帧,每个包带时间戳和序列号;用 RTCP 反馈接收质量;再用 DTLS 做加密握手,SRTP 做媒体加密。这一整套协议栈解决的核心问题是: 如何在尽力而为的网络上,做到延迟优先、按需丢包、快速恢复 。

NACK(Negative Acknowledgment)重传是典型例子。接收端发现某个序列号的包丢了,会立刻请求重传,但只会对"还来得及赶上播放时间"的包做重传请求。来不及的就直接跳过,让解码器做丢包隐藏。这种"能救则救,救不了就放弃"的思路,和 TCP 的"必须全部到达"是两种截然不同的哲学。

2.2 ICE 与 NAT 穿透:WebRTC 最被低估的贡献

如果说 RTP/RTCP 是 WebRTC 的骨架,ICE(Interactive Connectivity Establishment)就是它的神经系统。

现实的网络环境里,绝大多数设备都在 NAT 后面,没有公网 IP。ICE 做的事是:同时尝试多种路径——本机直连 IP、STUN 反射地址、TURN 中继地址——然后通过连通性检测挑一条最快的可用路径。注意是"可用 + 最快",不是"一定最优"。有些网络环境下直连可能通,但丢包率很高,ICE 也会通过持续检测切换路径。

这个设计对后来所有实时音视频 SDK 都产生了深远影响。今天你调声网、Twilio、LiveKit 的 SDK,底层跑的基本都是 ICE 那套:先打洞,打不通就走 Relay。Uberti 在 Google 时期推动这套机制成为 W3C 标准,等于把"两个私有网络里的设备如何建立实时连接"这个全球性问题变成了一个标准化解决方案。

对 Voice Agent 开发者的启示是: 如果你的应用需要从用户端浏览器直连到你的媒体服务器,ICE 这套协商机制依然是你绕不开的基础设施 。不要以为现在用 WebSocket 传音频就不需要 ICE 了——WebSocket 走的是 TCP,延迟和弱网表现天然比 UDP 差一个量级,后面我会细说这个对比。

2.3 抖动缓冲与自适应码率:WebRTC 如何在烂网络上保持可用

WebRTC 被低估的第三个设计是抖动缓冲(Jitter Buffer)和拥塞控制。

网络抖动意味着包的到达时间不均匀,可能第 1 个包和第 2 个包间隔 5 毫秒,第 2 个和第 3 个间隔 80 毫秒。播放端不能等数据齐了再播,而是维护一个缓冲区,把收到的包按时间戳排好,然后以固定的节奏送给解码器。缓冲区越大越稳,但延迟越高。WebRTC 的抖动缓冲是动态调整的——网络好的时候缓冲浅一点,网络差的时候自动加深。

拥塞控制则负责判断当前带宽能传多少数据。WebRTC 用的是基于延迟和丢包的混合估计算法(GCC),通过 RTCP 反馈的接收端报告来调整发送码率。视频会降清晰度保流畅,音频会用更低的编码码率保连续。这套机制的巧妙之处在于: 它不依赖网络设备提供任何 QoS 保障,纯靠端到端测量就能自适应 。

所以在今天这个时间点回看,WebRTC 本质上是一套" 在尽力而为的互联网上,用端到端测量和自适应决策来逼近实时体验 "的完整体系。这套体系的每一个设计,都是围绕一个特定目标服务的:让处于恶劣网络环境中的两个真实人类,能像坐在一起那样说话。

3. 语音 Agent 为何逼着 RTC 架构做出改变

3.1 对话对象从"人"变成"模型",延迟预算变了

理解了 WebRTC 的底层逻辑,再看 Realtime API 的架构需求,差异就非常清晰了。

人跟人通话时,双方都是实时编码、持续发声的,端到端延迟的预算主要是网络传输 + 编解码,通常可以控制在 200 毫秒以内。但人跟 AI 语音 Agent 对话时,链路多了一个极其昂贵的环节: 模型推理 。语音先要经过 ASR 转成文本或语义 token,然后送进 LLM 生成响应,再把响应文本经 TTS 转回音频。这个 ASR + LLM + TTS 的完整链路,即使在优化很好的情况下也要 500 毫秒到 1 秒以上。

如果你在这条链路上叠加传统 WebRTC 端到端的互联网传输延迟,用户体验就会明显变差。人类对话时对"对方回应前的静默"容忍度大约在 500~700 毫秒,超过这个阈值,人就会觉得"对方是不是掉线了"或者"这 AI 反应好慢"。所以 Realtime API 在设计上做了一件很激进的事: 把媒体处理和模型推理放进同一个数据中心,让用户到模型之间的链路尽可能短 。

Justin Uberti 在公开分享里多次强调的一个观点是: AI 语音的延迟瓶颈已经不在网络上,而在模型生成的"思考时间"上 。网络传输那 30~80 毫秒的优化空间,和生成一个句子动辄几百毫秒的耗时相比,几乎可以忽略。架构重心因此从"优化端到端网络传输"转向"优化用户到模型的整体路径和模型本身的响应速度"。

3.2 半双工还是全双工:一个被忽略的核心分歧点

WebRTC 是为全双工设计的——双方可以同时说话、同时收听。但现在的语音 Agent,大部分其实是半双工或"伪全双工":用户说话时模型在听,用户停止说话后模型才开始生成响应。

模型处理是纯串行的:没有听完一整句,就无法生成一个语义合理的回答。这导致 Realtime API 的交互模式本质上还是" 用户说完一整句 -> 模型生成一整句 "的轮次制。而 WebRTC 当年精心设计的那套"同时双向传输、拥塞控制动态调整、抖动缓冲自适应"的能力,在轮次制交互下其实有很大一部分是用不上的。

但这里有个关键的工程矛盾: 虽然语义上是轮次制,但音频传输层面必须保持连续 。因为你不知道用户什么时候会突然打断模型,也不知道模型什么时候会开始说话,两边都必须保持随时可收可发的状态。这就是为什么 Realtime API 还是要用 WebRTC 或类似的实时传输通道,而不是简单的 HTTP 请求-响应。HTTP 的握手开销和半双工特性,无法支撑"随时可能被打断"的交互需求。

用我的话说: 语音 Agent 在语义层是半双工餐厅点餐,在传输层却必须保持全双工电话待机 。这两个特性叠加在一起,才是 Realtime API 架构最微妙的地方。

3.3 中断处理:Voice Agent 最容易被低估的技术难点

人跟人通话时,打断对方是件很自然的事。你说着说着,对方插一句"等等",你会立刻闭嘴听她讲。但这件对人不假思索的事,对语音 Agent 来说是个巨大的工程挑战。

想象一个场景:模型正在回答"今天北京的天气怎么样?"刚说到"今天北京多云转晴,最高气温……"用户突然说"那明天呢?"。系统需要做到:

  • 立刻停止当前 TTS 播放(否则用户会听到模型还在自顾自地说)
  • 把用户的新问题送进 ASR 并识别出这是一句新指令
  • 决定是"放弃当前生成的剩余文本"还是"保留上下文并生成新回答"
  • 处理好模型端的生成状态,避免上下文错乱

这在 WebRTC 架构里没有对应物。人跟人之间不需要"中断令牌",但模型需要。Realtime API 中设计了专门的 interruption 事件和音频截断机制,目的就是让文本生成进程能收到"用户有新输入了"的信号,并快速响应。

我实测下来的体验是: 中断响应速度是衡量一个 Voice Agent 是否"像真人"的最直观指标 。如果模型 1.5 秒才停止播报,用户会明显觉得"这 AI 耳朵不好使"。如果模型能在一帧音频时间内(20~60 毫秒)感知到打断并暂停播放,交互体验会有质的提升。而要实现后者,传输层的细节——比如音频帧必须足够小、事件通道必须独立于媒体通道、缓冲策略必须支持快速冲刷——每一项都不简单。

4. 从 WebRTC 到 Realtime AI:架构重构的关键发力点

4.1 客户端到云端的链路:Realtime API 为什么依然选择类 WebRTC 通道

先明确一个事实:OpenAI 的 Realtime API 通过 WebRTC 或 WebSocket 两种方式接入,但 WebRTC 方式被官方标为推荐路径。为什么?因为 Realtime API 的媒体链路需要支持双向实时音频、需要处理 NAT 穿透、需要低延迟传输——这些正是 WebRTC 的看家本领。

我自己在集成 Realtime API 时测试过两种方式,差别非常明显。WebSocket 走 TCP,实现简单,但在弱网环境或者跨洲链路上,音频延迟和卡顿明显。WebRTC 走 UDP,配合 ICE 和拥塞控制,在丢包 5% 的网络下依然能保持相对流畅的语音。对面向 C 端用户的 Voice Agent 来说,用户的网络环境不可控,选 WebRTC 是更稳妥的工程决策。

这不是说 WebSocket 一无是处。如果产品场景是"按住说话、松开发送"这种明确半双工模式,WebSocket 完全够用且接入简单。但如果你做的是"真人对模型连续对话"的助手型产品,建议直接上 WebRTC,省掉后面为延迟和丢包问题折腾的时间。

4.2 会话状态管理:从"连接"到"上下文"的范式转移

WebRTC 时代,一个连接对应的是"两个端点之间的媒体会话"——连接建立后主要任务是传数据,状态管理非常简单。但 Realtime API 的会话里,同一个连接上持续流动的不只是音频,还有 完整的对话上下文 。

这个差异在工程上的体现是:你需要管理模型侧的状态——当前会话的 system prompt、函数调用列表、历史消息、正在生成的响应、用户是否已经打断……每一个状态变化都要通过事件机制与客户端同步。这就引出 Realtime API 里事件驱动架构的重要性:所有交互都被建模为事件(用户音频到达、模型响应开始/结束、函数调用触发、错误发生……),客户端通过这些事件来感知会话状态。

我做 Voice Agent 集成时踩过的最大坑是:没有把"音频流"和"事件流"当两个独立维度处理。音频流是连续的,事件流是离散的。如果只监听音频而忽略事件,你会在"模型是否已经说完了这句话"的判断上出错。 音频沉默不等于生成结束 ——模型可能正在生成中间暂停了,也可能已经结束但还有后续。正确做法是同时订阅音频帧和事件通知,以事件为准来切换 UI 状态。

4.3 音频格式与打包策略:模型生成语音和人类说话的不同节奏

WebRTC 当初为人类语音编码设计的音频参数(采样率 48kHz、20ms 一帧、Opus 编码),在 Realtime API 里依然是基础,但模型生成的语音有两个人类没有的特性,直接影响了传输策略。

第一,模型生成的语音可能是"突发的"——上一秒还沉默,下一秒就开始流式输出一整句。WebRTC 的音频引擎为持续语音优化的某些参数(比如抖动缓冲深度)可能会在突发语音场景下引入不必要的延迟。我实测中会针对这个场景调浅缓冲,或者用客户端逻辑提前触发"即将开始播放"的预期。

第二,模型生成的语音中间可能有非自然的停顿。TTS 模型在句号、逗号、省略号处的停顿时间其实和人类很不一样,有时过长,有时过短。这个"节奏感"问题在传输层无解,只能在 TTS 侧调整参数,或者在播放端做静音压缩。我在项目里用的是后端对 TTS 输出做后处理——把超长停顿裁剪到合理范围——效果比客户端处理稳定得多。

从架构角度看,Realtime API 把音频生成封装成了"稳定的流",但开发者必须意识到:这个流的"内容节奏"是模型决定的,不是人类决定的。所有针对人类语音模式做的网络优化假设,在 AI 语音场景下都要重新审视。

4.4 从"端到端加密"到"端到端 AI 编排":媒体服务器的角色转变

WebRTC 时代的典型架构是:客户端 A 和客户端 B 通过 SFU(Selective Forwarding Unit)转发媒体流。SFU 不关心内容,只做转发、混流、录制。但 Realtime API 时代的架构里,媒体服务器不再只是转发,它要扮演"编排者"的角色——管理音频流、事件流、模型推理任务之间的关系。

我把这个过程抽象成三个层次:

  • 媒体层 :负责音频的采集、播放、编解码、传输,这一层 WebRTC 的积累完全适用。
  • 会话层 :负责管理连接状态、错误恢复、重连策略、中断事件,这是 WebRTC 的"连接"概念向"会话"概念的延伸。
  • 智能层 :负责把语音转成模型输入、管理上下文窗口、触发工具调用、协调多模型协同,这是全新的一层。

这三层里,第一层你可以直接复用现成的 RTC 库,第三层依赖具体 AI 平台的能力,中间的第二层才是考验架构设计功力的地方。我在自己的 Voice Agent 框架里,把这三层做成了可以独立扩展的模块,确保换不同的 ASR/TTS/LLM 服务商时,会话层和媒体层不需要大改。

5. 给 Voice Agent 开发者的实践建议与选型经验

5.1 什么时候选 WebRTC,什么时候选 WebSocket

这个问题我在前面提过,但还是想单独展开说。因为这是绝大多数 Voice Agent 项目启动时第一个需要做的技术决策,而且选错之后的返工成本非常高。

从我的实际经验出发,给一个相对清晰的判断标准:

  • 如果你做的是 助手型产品 ,用户可能会在任何时候开口说话,且随时可能打断模型——选 WebRTC 。
  • 如果你做的是 指令型产品 ,交互模式是"用户说完 -> AI 执行 -> 用户再说"的明确轮次,且对延迟不敏感——选 WebSocket 也能用。
  • 如果你的产品 需要跑在浏览器里且面向 C 端海量用户 ,弱网环境不可控——请认真评估 WebRTC 路径,不要因为 WebSocket 接入简单而妥协。

我见过不少团队因为 WebSocket 接入简单、文档友好而选择它,最后在延迟优化到极限后被迫迁移到 WebRTC,代价相当大。记住一个原则: 传输层选型是 Voice Agent 的地基,地基换起来比想象中痛苦得多 。

5.2 事件驱动架构:让 UI 状态和 AI 状态解耦

在做 Voice Agent 的客户端时,很多人会把 UI 状态直接绑在音频播放状态上——"音频在播就显示 AI 在说话,音频停了我就可以说话"。这个逻辑在某些场景下能用,但很不健壮。真实情况是:音频可能在播放,但模型已经接收到用户打断并开始处理新请求了;或者音频已经停了,但模型还在生成上下文相关的后续内容。

所以架构上我的建议是: UI 状态机应该基于事件驱动,而不是基于音频驱动的推断 。Realtime API 的事件流里,有 response.created、response.audio_transcript.delta、response.done、input_audio_buffer.speech_started 这类事件,你要把这些事件作为 UI 状态切换的唯一事实来源。音频只是一个"呈现层",用来播放声音,不承载"语义状态"。

这样做还有一个好处:存证和日志变得非常干净。你可以直接按事件时间线回溯一次完整的交互过程——用户说了什么、模型什么时候开始响应、中间有没有中断、函数调用结果如何——这对调试复杂的多轮对话有巨大价值。

5.3 中断与打断的工程实现:Beyond WebRTC 的边界

刚才说中断处理是 Voice Agent 最难的点之一。这里我展开讲讲工程实现层面的细节,因为这是 WebRTC 文档里完全找不到答案的地方。

一次完整的打断处理流程,我建议拆成四个阶段:

  1. 检测阶段 :客户端通过 VAD(语音活动检测)判断用户是否开始说话。VAD 的灵敏度需要调,太灵敏会误触发(用户咳嗽就打断模型),太迟钝会漏触发(用户说完了模型还在播)。关键指标是"打断延迟"——从用户开口到系统感知,这个时间越短越好。

  2. 信号阶段 :客户端把"用户开始说话"这个信号通过事件通道发送给服务端,同时本地立刻暂停播放/压低音量(ducking)。注意这里要 先本地暂停播放,再向服务端发信号 ,顺序不能反。因为网络往返有延迟,你等确认再暂停,用户会多听几百毫秒模型声音。

  3. 服务端处理阶段 :服务端收到打断信号后,向模型发送截断指令,模型停止当前生成。此时要处理一个竞态:模型可能刚好在这几毫秒内生成了新的音频帧且已经下发。所以客户端的"丢弃策略"很重要——收到打断信号后,缓冲区里等待播放的音频帧要全部丢弃,不能让它继续播出来。

  4. 恢复阶段 :模型处理完用户的新问题后开始生成新回答,此时要正确重置上下文,避免把旧回答的残渣混进新上下文里。我遇到的一个典型 bug 是:用户打断后说的新问题,会被 ASR 附带上前一段模型语音的尾音,导致模型理解错语义。解决思路是打断瞬间把 ASR 的音频输入也做静音窗口处理。

这四个阶段环环相扣,每一处的时序控制都影响最终体验。我强烈建议团队做 Voice Agent 时,把"打断体验"作为核心指标来度量和优化,而不是把它当边缘场景处理——在真实用户使用中,打断发生的频率比你想象的高得多。

5.4 多模态状态同步:文本、音频、上下文三者的一致性

态同步是 Voice Agent 架构里另一个容易踩坑的地方。在一个 Realtime 会话中,同一时刻可能有三套数据会并行流动:模型生成的音频、模型生成的文本(通常是辅助字幕或用户可见的对话内容)、上下文状态(上下文可以更新或清除的 token 记录)。

这三套数据之间有一致性约束。比如:模型返回一段"文字+普通音频"的响应,文字部分直接显示在聊天界面,音频部分正常播放。但如果用户中途打断,音频被截断了,聊天界面里已经显示的文字却还在——用户就会看到"模型说了一半但聊天记录里是完整的一句",这在视觉上非常奇怪。

我在项目里的做法是:把文本展示也设计为" 分段提交 ",模型每生成一个片段,文本才追加一个片段;一旦发生打断,未完成片段的文本要回退(回滚到上一次完成片段的结尾)。这就把一致性协调从"音频层"提升到了"会话层",也让聊天记录始终与用户实际听到的内容对齐。

5.5 自建 Media Server 还是用现成 RTC PaaS

最后聊一个选型层面的问题:做 Voice Agent 时,音视频传输层到底应该自建还是用现成的 RTC PaaS(如声网、LiveKit Cloud、Twilio)?

我的建议是分阶段看。原型验证阶段,直接用你选的 AI 平台自带的 Realtime API,通过官方 WebRTC 或 WebSocket 接入,最快速度跑通端到端体验。这个阶段的目标是验证产品逻辑,不是做传输优化。

到了要规模化或需要深度定制的时候,再考虑自建或引入独立的 RTC PaaS 作为媒体层。原因有三:

  • 传输质量需要专门优化 :不同国家的网络环境差异巨大,RTC PaaS 服务商在全球有节点和网络优化积累,自建要达到同样效果需要投入大量资源。
  • 会话管理需要独立于 AI 平台 :如果你不想被单一 AI 平台锁死,把媒体层从 AI 平台解耦出来是明智的。RTC PaaS 负责媒体传输,AI 平台负责智能处理,两层之间用标准协议对接。
  • 成本结构不同 :Realtime API 的 WebRTC 通道是按音频时长计费的,如果你有大量调试流量、低质量用户流量,用独立 RTC PaaS 可能成本更低。

但我的反思是:不要过早引入过多基础组件即服务。Voice Agent 的核心竞争力不在传输层,而在于你怎么处理会话状态、上下文编排、业务流程接入这些"AI 之外"的部分,例如如何将函数调用、业务逻辑和语音交互结合。先把这些做扎实,再考虑传输层的深度优化。

6. 我在 Voice Agent 学习中的三点体会

写到最后,说几点与具体技术无关的体会。

第一, WebRTC 不会消失,它会变成 Voice Agent 的基础设施 。就像 HTTP 没有因为 WebSocket 出现而消失一样,WebRTC 作为浏览器原生支持的实时音视频方案,会长期活在 Voice Agent 的传输层里。只是它的角色从"面向最终用户的通话技术"变成了"面向开发者的管道技术"。

第二, 真正难的不是 AI,是 AI 和现实世界的接口 。模型能力再强,也要通过麦克风、扬声器、网络、事件系统、业务 API 这些"现实接口"和用户交互。这些接口层面的工程细节,决定了一个 Voice Agent 产品是"demo 级"还是"生产级"。Uberti 从 WebRTC 到 Realtime AI 的职业路径,恰恰说明了"接口层"在整个 AI 应用栈里占据着多么重要的位置。

第三, 架构决策要服务于交互模式 。不要因为"AI 很厉害"就预设复杂架构,也不要因为"简单接入"就忽视传输层。你要先想清楚产品想让用户怎么和 AI 对话——是安静的房间、嘈杂的地铁、还是双手被占用的厨房?不同的交互场景对延迟、打断、弱网的要求完全不同,架构取舍也随之不同。

作为一个从 WebRTC 时代一路做音视频过来的开发者,我最大的感受是: 实时语音的"实时"二字,从网络问题变成了计算问题 。网络的问题,WebRTC 已经解决得够好了;计算的问题——如何让模型在用户的耐心耗尽之前生成出自然的语音响应——才是 Voice Agent 时代真正的架构挑战。

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐