机器人接入 AI 连续语音后,端云架构要改什么?
机器人接入连续语音后,端云架构要改什么
摘要:连续语音进入机器人后,声音停止不等于播放、任务或物理动作同时停止。本文把系统拆成媒体、交互控制、物理动作三个平面,用五类身份、播放进度代理、动作准入和渐进迁移步骤重新建立端云一致性,并明确 IMPLEMENTED、VERIFIED 与 UNKNOWN 的证据边界。
关键词:机器人语音、WebRTC、端云协同、播放确认、动作安全、Voice Agent

一、先拆三个平面:媒体、交互控制、物理动作

1. 媒体面回答“声音在哪里”
媒体面包括采集、AEC/NS、编码、RTP、jitter buffer、解码、播放队列和扬声器。它关心帧、序号、时间戳、丢包、缓冲和实际播放位置。
OpenAI 当前 Voice Agents 文档把实时语音分成 speech-to-speech 与 chained pipeline 两条架构,并明确 WebRTC 或 WebSocket 可以承载实时会话。[S1] Realtime VAD 还会产生 speech_started、speech_stopped 等语音活动事件。[S2] 这些公共能力可以帮助建立输入和响应链路,但它们不知道一段音频是否已经穿过机器人端的 jitter buffer,更不知道扬声器是否真的发声。


图:OpenAI Voice Agents 官方文档聚焦裁片(检查于 2026-08-24)。它证明公共语音架构入口,不证明机器人端已经实现播放确认或动作停止。查看官方页面

图:OpenAI Realtime VAD 官方文档聚焦裁片(检查于 2026-08-24)。它证明公共语音边界事件存在,不证明机器人场景的回声、旁人声与动作错误代价已经被解决。查看官方页面

图:OpenAI Realtime WebRTC 官方文档聚焦裁片(检查于 2026-08-24)。它证明媒体轨与事件通道的公共接口边界,不证明当前机器人链路已经通过真实 TURN 与设备 E2E。查看官方页面
因此服务端的 sent_at 不是用户听见的时间,客户端的 received_at 也不是播放完成。机器人端必须提供软件层的播放进度代理,例如:
{
"type": "playback.progress",
"session_id": "sess_42",
"response_id": "resp_18",
"playback_id": "pb_18",
"received_until_ms": 1840,
"buffered_until_ms": 1520,
"played_until_ms": 960,
"device_monotonic_ns": 938472993822
}
played_until_ms 仍只是播放器软件上报的进度代理,不是声学传感器对“用户确实听到”的证明。但它比服务端“已发送”更接近历史修复和停止判断所需的真值。
2. 交互控制面回答“哪件事仍然有效”
交互控制面维护输入、话权、响应、后台任务、工具调用和历史。它不直接搬运每一帧音频,而是决定哪些事件属于同一意图,哪个 response 可以继续,哪个 task 已过期,哪个工具结果还能进入当前会话。
传统回合系统常用一个 round_id 包办所有关系。连续语音需要把它拆成至少五类身份:
| 身份 | 代表什么 | 不能被什么替代 |
|---|---|---|
session_id |
一次持续会话 | 不能当作逐轮 trace |
utterance_id |
一段候选输入语音 | 不能等同完整意图 |
response_id |
一次可撤销输出 | 不能用当前 session 代替 |
playback_id |
一次客户端播放实例 | 不能用 response 已发送代替 |
task_id / action_id |
后台工作或物理动作 | 不能用工具名或当前轮次代替 |

此外还需要逐次追踪用的 trace_id。session_id 可以跨很多轮存在,不能拿它替代真正的 per-turn trace。否则一次会话里的两个并发 task、两次 response 和一次重连会被挤进同一条日志,问题无法还原。
3. 物理动作面回答“机器人实际做了什么”
物理动作与播放不同。音频通常可以停止后丢弃;机器人动作可能已经改变世界:底盘已经移动,机械臂已经抓取,门锁已经打开,消息已经发送。
因此模型产生一个工具调用,不应直接等于设备执行。更安全的动作生命周期是:
proposed → authorized → dispatched → acknowledged → running
→ completed | cancelled | failed | compensation_required
proposed:模型或规则提出候选动作。authorized:权限、上下文、参数、风险与确认条件通过。dispatched:命令已发给设备或业务系统。acknowledged:对端确认收到,并不等于完成。completed:以设备传感器、控制器状态或业务回执确认结果。cancelled:只对仍可取消的阶段成立。compensation_required:副作用已发生,不能假装回滚成功。

这套动作状态不是 OpenAI API 字段,也不是 GPT-Live 私有协议,而是机器人系统必须自己承担的工程责任。Realtime 工具接口可以产生调用并接收应用回注的结果,[S4] 但设备权限、急停、幂等和物理完成仍在应用与设备侧。
二、端云职责不能按语言划分,要按时间与真值划分
“Go 做实时、Python 做 AI”是有用起点,却不够精确。真正稳定的边界应回答:哪一层最先看到事件,哪一层拥有不可替代的真值,哪一层可以在断网时独立保护设备。
Rust Client:拥有设备附近的低延迟真值
端侧最接近麦克风、扬声器和设备控制器,应承担:
- 音频采集、AEC/NS、编码与本地缓冲;
- 唤醒、按键、急停和可选的低延迟本地 VAD/KWS;
- 播放队列、
playback_id、实际软件播放进度和队列清空; - 网络中断时的本地安全动作;
- 设备动作回执与传感器状态上报;
- 单调时钟与端侧事件序号。
端侧不应自行决定复杂语义,但必须可以先执行安全优先的本地动作。例如用户在机器人靠近台阶时说“停”,系统不应等云端完成语义推理才停止驱动。可以先本地减速或急停,再让云端判断这句话是否还要改变会话与任务状态。
Go Realtime Edge:拥有连接、媒体边界和背压真值
Go Gateway 适合维护 WebRTC 连接、ICE/STUN/TURN、RTP/DataChannel、会话注册、媒体桥接、背压和事件转发。当前项目代码已经存在这些职责以及播放回报、旧播放不得影响新播放等测试证据。
连续语音改造后,Go 层还应:
- 校验
session_id、connection_id、序列号和协议版本; - 将 RTP 媒体与 DataChannel 控制事件绑定到同一会话;
- 对重复/迟到的
playback_interrupted做身份隔离; - 记录直连与 TURN 路径、排队、丢包和桥接耗时;
- 在 Python 编排暂时不可用时维持连接与明确降级;
- 对控制事件设定小而可解释的队列,不能用无限缓冲掩盖阻塞。
Go 层不应因为“更快”而吞并所有业务状态。它需要保护媒体和连接时序,但任务版本、权限、业务补偿和复杂对话策略仍属于更高层。
Python AI Orchestrator:拥有模型、任务与业务编排真值
Python 层适合连接 STT、LLM、MCP、TTS、后台任务与业务工具,并维护:
- ASR partial/final 与稳定前缀;
turn.action决策及其证据;response_id、TTS 生成和取消传播;task_id、goal_version、截止时间和结果新鲜度;- 工具参数、权限请求、幂等键和补偿信息;
- 对话历史按实际播放进度修复;
- 模型路线和降级策略。
是否把 Python Gateway 全部重写成 Go,不应由“架构统一”决定,而应由 trace 证明:连接建立、序列化、队列、事件循环、GC 或取消长尾确实是主要瓶颈,而且重写能改善该瓶颈而不破坏模型与业务迭代速度。否则大规模重写只会把连续交互迁移变成语言迁移项目。
三、五条关键一致性链必须端到端闭合
1. 输入链:音频活动不是最终意图
端侧 VAD 可以快速发现声音并发出 audio_start,云端 ASR 和语义判断再决定这是有效打断、附和、旁人对话还是噪声。Realtime VAD 公共文档允许 server_vad 或 semantic_vad,并可配置是否自动创建或打断 response。[S2] 这证明接口路径存在,不代表机器人场景的错误代价已经被模型处理。
对机器人动作而言,输入需要两阶段处理:
local safety signal → immediate safe action
cloud semantic decision → conversation/task/action reconciliation
本地安全信号可以减速、静音或暂停;云端决定是否取消当前 response、后台 task 和业务动作。两阶段结果都必须进入同一 trace。
2. 响应链:生成、传输、缓冲和播放不是同一状态
一个 response 至少会经过:
created → generating → chunk_sent → chunk_received
→ buffered → playing → completed
↘ cancel_requested → generation_stopped
→ queue_purged → playback_stopped
取消成功不能只看 generation_stopped。旧 chunk 可能仍在网络或客户端队列。服务端应等待与同一 playback_id 绑定的 queue_purged / playback_stopped,并忽略旧播放实例迟到的完成事件。
3. 历史链:只保留用户实际获得的语义
如果回答只播放到 960ms,服务端不能把完整文本都当成用户已经听见,也不能粗暴删除整条回答。可以用 TTS 的文本—音频时间对齐,将 played_until_ms 映射到最后一个稳定语义边界;映射不可靠时,下一轮显式澄清,而不是伪造精确历史。
这里的核心不是追求毫秒级完美,而是记录不确定性:
{
"response_id": "resp_18",
"played_until_ms": 960,
"semantic_commit": "partial",
"last_committed_span": "span_04",
"alignment_confidence": 0.81
}
4. 任务链:旧结果不能覆盖新目标
后台任务创建时应冻结 goal_version、输入快照和交付条件。用户中途补充、改口或取消时,不一定需要立即杀死所有计算,但返回结果必须重新经过准入:
task completed
→ goal_version still current?
→ deadline still valid?
→ side effect already happened?
→ result still relevant?
→ user currently interruptible?
→ deliver / summarize / store / discard
后台任务生命周期不在本文重复展开;机器人迁移需要把目标版本、截止时间和结果准入接进端云事件面,并把物理动作副作用纳入判断。
5. 动作链:取消语音不等于取消设备
动作命令必须携带独立 action_id、幂等键、风险级别、授权依据、设备目标和超时。取消 response 时,系统需要查询动作处于哪个阶段:
- 尚未授权:直接拒绝。
- 已授权未派发:撤销授权。
- 已派发未执行:发送设备取消并等待 ACK。
- 正在执行:进入受控停止或安全姿态。
- 已完成:不能写“取消成功”,只能评估补偿。
这也是为什么机器人连续语音必须增加动作面。纯聊天系统可以把错误回答当成内容问题;机器人系统会把错误意图变成物理结果。
四、AEC 优先级高,但不能写成一句“打开即可”
机器人扬声器和麦克风相对位置固定,TTS 播放时输入链仍然开启,残余回声可能被 VAD、ASR 或 KWS 识别成用户声音,造成自我打断。更强的 VAD 无法替代声学回声消除,因为 VAD 只判断是否像语音,不知道这段语音来自用户还是扬声器参考信号。
但“AEC 优先”不等于在配置里打开一个布尔值。上线前至少要确认:
- 播放参考信号是否在正确采样率、正确通道和正确时间进入 AEC;
- 设备播放、采集、重采样和网络时钟是否导致漂移;
- 双讲时用户语音是否被过度抑制;
- 音量、距离、房间反射和机器人电机噪声变化时是否仍稳定;
- AEC 发散后系统是继续误打断、临时降级还是重新收敛;
- 直连、TURN 和弱网条件是否改变控制事件与媒体的相对到达顺序。
可观测指标可以包括 ERLE、残余回声能量、双讲检测、播放期间 VAD 触发率、ASR 自回声片段率和误取消率。具体阈值必须来自目标设备实验,不能从通用文章抄一个数字。
五、渐进迁移:每一步都能停止、回退和解释

第 0 步:冻结当前链路和证据边界
记录实际部署 commit、Rust/Go/Python 版本、协议版本、模型配置、ICE 路径和设备型号。把当前能力标为 IMPLEMENTED、VERIFIED 或 UNKNOWN。没有这一步,后续体验变化无法归因。
第 1 步:统一五类身份和逐轮 trace
先在端、Go、Python 和设备事件中贯通 session_id、utterance_id、response_id、playback_id、task_id/action_id,并增加真正的 per-turn trace_id。旧字段可以兼容,但不得继续把 session 当 trace。
第 2 步:完成可取消播放闭环
先不改变模型。让每个音频 chunk 绑定 response/playback,端侧支持清队列与播放停止回报,服务端拒绝旧播放迟到事件。只有这一阶段稳定,后续自然打断才有安全基础。
第 3 步:接入 AEC 与双阶段输入判断
端侧负责快速声学事件和安全优先动作,云端负责语义动作分类。分别记录本地检测、云端确认和最终状态收敛时间。误判要能恢复,不得用“全部打断”掩盖策略缺失。
第 4 步:把任务和工具接入版本、权限与副作用协议
后台 task 携带目标版本和交付条件;机器人 action 使用 propose/authorize/dispatch/ack/complete。对不可逆操作增加显式确认或更保守策略。
第 5 步:在相同控制面下 A/B 模型路线
增强级联与原生 speech-to-speech 都输出相同的 turn.action、response、task 和 action 事件。这样模型切换才是可归因实验,而不是连媒体、协议和业务逻辑一起重写。
第 6 步:扩展到真实设备与弱网场景
先单设备、单动作、局域网,再到 TURN、网络切换、重连、多任务和长时间会话。每次只扩大一个风险维度,并保留上一阶段回退路线。
六、上线证据矩阵:什么可以说,什么仍然不能说

| 能力 | IMPLEMENTED 证据 | VERIFIED 证据 | 仍需 UNKNOWN/E2E |
|---|---|---|---|
| WebRTC 上下行 | Rust/Go 代码与配置 | 本地桥接/协议测试 | 生产 ICE/TURN 与真实设备稳定性 |
| 播放身份 | round_id / playback_id 路径 |
旧播放不影响新播放的测试 | 扬声器真实停止长尾 |
| 播放回报 | complete/interrupted 事件 | Go/Python 转发测试 | 进度代理与声学输出误差 |
| 输入打断 | DataChannel interrupt 路径 | 本地事件测试 | 回声、旁人声、双讲误判 |
| 机器人动作 | 工具或控制接口 | 协议/模拟器测试 | 真实设备 ACK、急停与完成回执 |
| 端云取消 | 局部取消路径 | 组件测试 | 模型、TTS、网络、播放、动作全链收敛 |
这张表的用途不是保守措辞,而是决定下一项测试。IMPLEMENTED 说明代码路径存在;VERIFIED 说明某个明确环境下的证据通过;UNKNOWN 说明不能据此宣传生产能力。单测、preflight、上传 ACK、mock 或本地 publish 都不能自动升级成真实硬件 E2E。
七、三个常见但代价很高的错误方向
错误一:先把 Python 全部重写成 Go
如果 trace 没有证明 Python 是排队、取消或延迟长尾的主要来源,重写只会增加协议迁移、回归与模型接入成本。先把事件和时间线补齐,瓶颈会自己暴露。
错误二:把 VAD 当成话权与急停系统
VAD 能发现声音或估计话语结束,不能完成语义动作分类,也不能替代本地安全回路。高风险动作必须有独立确认、权限与设备停止路径。
错误三:把模型事件当作设备真值
模型取消不代表 TTS 队列清空,TTS 停止不代表扬声器停止,工具返回 success 不代表机器人完成。每层都要由最接近真实状态的一方签字。
八、什么时候应该保留更简单的轮次式系统
连续语音不是所有机器人场景的默认答案。以下情况保留按键说话、唤醒后单轮或明确确认,可能更安全:
- 指令短、歧义代价高;
- 环境回声和噪声尚未被测量;
- 设备没有可靠取消或动作回执;
- 网络不稳定且端侧安全能力不足;
- 用户更需要可预测性而非自然重叠对话;
- 当前级联系统已经满足任务成功率和延迟目标。
真正成熟的迁移允许团队停在更简单的一层。目标不是获得“全双工”标签,而是让系统在自己声称的能力范围内正确、可观测、可回退。
结语:把连续语音当成一致性工程
机器人接入连续语音后,原有 Rust Client、WebRTC、Go Gateway、Python Orchestrator 和模型服务大部分都可以保留。最先要改的不是语言,而是关系:哪个输入触发哪个 response,哪段音频真正播放,哪个任务仍然新鲜,哪个动作已经越过可撤销边界。
媒体面、交互控制面和物理动作面必须分别收敛,再通过稳定身份与事件连接。端侧拥有播放与设备附近真值,实时网关拥有连接和媒体边界,AI 编排层拥有模型、任务与业务状态,设备控制器拥有动作完成真值。任何一层都不能替其他层签字。
当这些关系建立之后,团队才有资格比较增强级联和原生音频模型,才知道一次“自然打断”究竟是模型变强、AEC 稳定、播放器可取消,还是动作协议终于正确。否则,更快的模型只会更快地放大旧架构里的竞态。
参考资料
- OpenAI, Voice agents: https://developers.openai.com/api/docs/guides/voice-agents
- OpenAI, Voice activity detection: https://developers.openai.com/api/docs/guides/realtime-vad
- OpenAI, Realtime API with WebRTC: https://developers.openai.com/api/docs/guides/realtime-webrtc
- OpenAI, Realtime with tools: https://developers.openai.com/api/docs/guides/realtime-mcp
- OpenAI, Realtime conversations: https://developers.openai.com/api/docs/guides/realtime-conversations
- W3C, WebRTC 1.0: https://www.w3.org/TR/webrtc/
- IETF, RFC 6716 — Definition of the Opus Audio Codec: https://www.rfc-editor.org/rfc/rfc6716
- 当前项目只读证据:
dify_stream_test/README.md、CLAUDE.md、Go Gateway 播放/会话/桥接代码与测试、Python Gateway 会话和内部语音协议测试(访问 2026-08-09)
更多推荐




所有评论(0)