news 2026/7/26 12:43:07

低延迟不是更快地猜:EOU / Barge-in / Turn Protocol 必须统一(4 种结束 + Generation Fencing + 9 类可复现场景)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
低延迟不是更快地猜:EOU / Barge-in / Turn Protocol 必须统一(4 种结束 + Generation Fencing + 9 类可复现场景)

低延迟不是更快地猜:EOU、Barge-in 与 Turn Protocol 为什么必须统一

TL;DR

  • 场景:语音 Agent 把"停顿 → 提交工具 → 用户打断"误判为"用户取消",但旧工具请求已越过网络并最终修改生产环境,运行时把成功结果写进历史。问题不是单点失败,而是 EOU、Barge-in、提交、撤销没有共享同一时间线和身份。
  • 结论:EOU 不是阈值而是事务;Barge-in 是一组取消而不是一个静音按钮;Turn ID 还不够,必须有 Generation ID 与 cancel_epoch 做 fencing。延迟指标必须和误截断、误延长、陈旧结果共用同一时间锚点,否则所谓低延迟只会让错误更早并发。
  • 产出:OPEN/SPECULATIVE/COMMITTED/REVOKED 四态用户轮状态机;session_id/turn_id/generation_id/task_id/cancel_epoch 五键事件信封;可落地的事件信封 JSON;六条全局不变量;九种故障注入场景的可复现测试矩阵;并把"取消、撤销、提交"和"延迟"绑到同一时钟。

版本矩阵

功能状态说明
Deepgram FluxEagerEndOfTurn/TurnResumed/EndOfTurn/turn_index状态机✅ 已验证Deepgram 官方 Flux launch 文档明确:EagerEndOfTurn 用于"medium confidence for speculative response generation";TurnResumed 表示用户续说,需取消已准备响应;EndOfTurn 为高置信度提交
Deepgram Fluxeot_threshold默认 0.7,eot_silence_threshold_ms默认 5000ms✅ 已验证官方 launch 文档原话:“developers only need to set: eot_threshold: confidence level required to trigger EndOfTurn (default = 0.7). eot_silence_threshold_ms: fallback silence duration to force turn end (default = 5000ms)”
Deepgram Flux eager 模式会多 50-70% LLM 调用✅ 已验证官方 launch 文档原话:“With eager_eot_threshold set to 0.3–0.5, you can expect EagerEndOfTurn 150–250ms earlier than EndOfTurn, at the cost of 50–70% more LLM calls”
Deepgram Flux EndOfTurn 95% 在 1.5s 内触发✅ 已验证官方 launch 文档原话:“Flux typically achieves a p90 (p95) latency of 1 second (1.5 seconds)”
OpenAI Realtimeserver_vad/semantic_vadturn detection✅ 已验证官方文档 turn_detection 配置支持 type=server_vad(按静音分块)与 semantic_vad(按语义估计是否完成并支持 eagerness)
OpenAI Realtimeconversation.item.truncate截断未听音频✅ 已验证官方 Twilio DemosessionManager.ts代码:interrupt 时计算audio_end_ms = elapsedMs,发送conversation.item.truncate强制服务端上下文与用户实际听到时长匹配
OpenAI RealtimecancelResponse(id, sampleCount)行为✅ 已验证官方 reference client 文档原文:“This method will cause the model to immediately cease generation, but also truncate the item being played by removing all audio after sampleCount and clearing the text response”
OpenAI Realtime WebRTC/SIP vs WebSocket 缓冲归属不同✅ 已验证官方 Realtime 文档:WebRTC/SIP 由服务端掌握输出缓冲可在用户打断时自动截断;WebSocket 由客户端管理播放,必须发送conversation.item.truncate
Twilio Media Streamsclear清空缓冲 /mark双重触发✅ 已验证官方 Twilio Media Streams 文档:clear清空服务端缓冲音频;mark既可能因音频正常播完返回,也可能因缓冲被 clear 返回,不能一律解释为"用户听完"
LiveKit 默认中断路径停止讲话 + 截历史到用户听到部分✅ 已验证LiveKit 官方 Turns 文档:默认中断路径会停止讲话并把历史截到用户实际听到的部分;这是框架语义,不是 WebRTC 本身提供的事务保证
gRPC 取消语义 + 取消前修改不回滚✅ 已验证gRPC 官方 Cancellation 文档原文:“A cancellation terminates the RPC immediately so that no further work is done. Changes made before a cancellation are not rolled back”
gRPC 库不能直接中断应用层 handler✅ 已验证gRPC 官方 Cancellation 文档:“the client cancellation operation should propagate to the whole call chain so each end can cancel in time. For server-side, the server can check whether the specific RPC has timed out, or how much time is left”
Web AudioAudioScheduledSourceNode.stop()只控制本地音频节点⚠️ 待验证本文引用了规范层面的"stop() 后该 source 输出静音",但本轮 search 未直接命中 W3C Web Audio 1.1 规范原文;建议直接核对 W3C TR
WebRTCremoveTrack/replaceTrack(null)不会传播为 Agent 取消⚠️ 待验证本文按 WebRTC 规范语义给出该结论,本轮 search 未直接命中 W3C WebRTC 规范原文;建议核对 W3C TR 原文
LiveKit STT 模式min_delay会在 STT end-of-speech 后再加一次等待⚠️ 待验证本文按 LiveKit Turn Detector 文档引用该行为;本轮 search 未直接命中 livekit.io 官方原页;建议核对 livekit.io/agents/logic/turns/turn-detector 原页
取消契约的精细分类(cancel_observed/cancel_completed/cancel_unsupported/too_late/side_effect_committed⚠️ 本文方法这是本文给出的协议设计要求,不是某家供应商现有事件

发布边界:协议、状态机和预算属于工程设计;供应商事件名只在对应产品边界内成立,不冒充作者已完成的线上实测。

摘要

语音 Agent 的低延迟不只是缩短静音阈值。EOU 决定何时允许一轮产生后果,Barge-in 决定旧一代工作何时失去提交资格,延迟指标必须证明取消、静音和结果丢弃发生在同一时间线上。本文给出统一 Turn Protocol、Generation fencing、已听前缀和可复现实验方法。

关键词

EOU、Barge-in、Turn Protocol、Generation ID、语音 Agent

目录

  • 先把四种“结束”拆开
  • EOU 不是一个阈值,而是一笔事务
  • Turn ID 还不够,必须有 Generation ID
  • Barge-in 是一组取消,不是一个静音按钮
  • 状态提交必须以“用户实际听到什么”为准
  • 延迟必须和正确性共用时间锚点
  • 可复现测试矩阵
  • 结论:先定义失效,再谈快

用户说:“把客厅空调调到二十度……”系统在停顿处判定一轮结束,LLM 发出工具调用,TTS 开始播“好的,正在为你……”。用户立刻打断:“算了,先别动。”

音频前端做对了表面上的事:停掉扬声器,清空播放队列。用户听不到旧回答了,界面也显示 Agent 正在听。但旧工具请求已经越过网络。随后,它返回成功,设备真的被调到二十度;运行时还把结果写进会话历史。下一轮模型看到的是“操作已完成”,用户感知到的却是“我已经打断”。这不是单纯的 Barge-in 失败,也不是 TTS 停得不够快,而是旧一轮的执行权没有随着打断一起失效。

这类竞态说明:EOU(End of Utterance,话语结束)、Barge-in 和端到端延迟不是三个可以分别调参的模块。EOU 事件只能提出“用户可能说完”的候选,应用层 EOT(End of Turn)或 turn commit 才把输入从“仍可能修订”提升为“允许执行”;Barge-in 决定哪一代工作从此失去提交资格;延迟指标则必须证明这次提交、撤销、静音和结果丢弃发生在同一条时间线上。三者若不共享 Turn ID、取消契约、状态提交规则和时间锚点,所谓低延迟只会让错误更早并发、更快越过不可逆边界。

先把四种“结束”拆开

工程中最常见的误区,是把所有结束事件都压成一个布尔值final=true。实际系统至少存在四类信号,它们的输入、输出和可证明的事实不同。

机制主要输入典型输出能证明什么,不能证明什么
VAD波形、能量、频谱及声学特征speech_startedspeech_stopped或 speech/non-speech 状态能说明声学活动发生变化;不能说明一句话、一个意图或一轮对话已经完整
EndpointingVAD 状态加静音持续时间,部分实现再结合 STT 状态停顿边界、供应商特定的结束标记能说明出现了足够长的停顿;不能证明用户不再续说,也不能自动等价为语义提交
UtteranceEnd已转写词及其时间戳、词间空档词间空档达到阈值后的事件能绕开部分非语音噪声造成的 VAD 问题;仍是基于转写空档的启发式,不是语义完成证明
语义 EOU转写文本、上下文,有时结合声学特征完成概率、EndOfTurn或动态等待决策能利用句法、语义和上下文判断“是否像说完了”;仍受模型、语言、领域和阈值约束,不是跨供应商标准

Deepgram 的文档把这些边界写得很清楚。其 Endpointing 基于 VAD 检测从语音到静音的转换,达到配置时长后返回speech_final=trueUtteranceEnd则查看 finalized 与 interim 结果中的词时间,在词间空档足够长时独立发事件。两者可以同时启用,也可能先后或只出现其一。12因此,把UtteranceEnd当成更高级的speech_final,或者把两者做 OR 后直接执行高风险工具,都会丢掉原始语义。

is_final也不是整轮结束。在 Deepgram 的流式转写中,is_final=true表示某个音频片段的文本不再修订;长输入可能先后产生多个 finalized 片段,而speech_final仍为 false。完整 utterance 需要累计 finalized 片段,再以结束信号决定何时提交。官方示例甚至出现is_final=falsespeech_final=true的组合,说明两个字段本来就在不同轴上。13“转写分段完成”和“用户整轮完成”必须使用不同状态字段。

供应商命名也不能拼成虚构标准。OpenAI Realtime 把server_vadsemantic_vad都放在 turn detection 配置下:前者按静音分块,后者按用户所说内容估计是否完成,并通过 eagerness 调整等待策略。4Deepgram Flux 使用EagerEndOfTurnTurnResumedEndOfTurnturn_index;其eot_thresholdeager_eot_thresholdeot_timeout_ms只适用于 Flux/v2,并非通用参数。5LiveKit 又把 VAD、STT endpointing、语义 turn detector、realtime model 内建检测和手动提交列为不同模式。67设计内部协议时,可以把它们归一到“候选结束”“恢复说话”“确认结束”等抽象事件,但必须保留providerprovider_event、置信度和原始载荷,不能假设字段同义。

EOU 不是一个阈值,而是一笔事务

EOU 的正确抽象不是“何时调用 LLM”,而是“何时允许这一轮产生可提交后果”。建议把用户轮建模为状态机:

OPEN -> SPECULATIVE -> COMMITTED -> COMPLETED

其中任何尚未完成的状态都可以进入REVOKEDSPECULATIVE还可以因用户续说回到OPEN。候选 EOU 只允许系统做可丢弃的工作,例如启动草稿生成、预取只读数据、准备 TTS 文本切分。确认 EOU 才授予正式提交权:把用户消息写入权威历史、允许有副作用的工具进入 commit 阶段、把可播放回复绑定到当前 generation。

这正是 eager EOT 的真实成本。Deepgram 明确说明,降低 eager 阈值会更早触发,也会产生更多 false starts;若随后收到TurnResumed,在途回复应被取消或丢弃,且 eager 模式会增加 LLM 请求。8因而“降低阈值减少等待”只描述了收益的一半。另一半是误截断、无效模型调用、错误工具规划和更多待撤销音频。若运行时没有 speculative/committed 边界,提前几十或几百毫秒启动的草稿就会越过工具与状态提交点,优化立即变成一致性缺陷。

确认也不能只看事件名。一个稳健的提交动作至少应校验:当前turn_id仍处于开放状态;候选所依据的transcript_revision未被后续转写替换;当前 generation 未被打断;供应商事件满足本产品的提交策略;硬超时只作为降级路径而非“语义正确”的证明。Deepgram Flux 保证同一生命周期中EndOfTurn文本与紧邻的EagerEndOfTurn文本匹配,并在续说时先发TurnResumed,这是该供应商的状态机契约,不应外推到其他 STT。6

还有一个常被忽略的尾延迟来源:重复 endpointing。LiveKit 文档说明,在 STT 模式下,运行时的min_delay会加在 STT 供应商的 end-of-speech 信号之后。9如果 STT 已等一次静音,Agent Runtime 又无条件再等一次,P95/P99 会出现并非模型慢、而是两个结束策略串联造成的“误延长”。所有 EOU 延迟都应分解为供应商检测等待、网络传输、运行时二次等待和提交排队,而不是统称“ASR latency”。

Turn ID 还不够,必须有 Generation ID

一轮用户输入可能触发多次候选提交:第一次短停顿启动草稿,用户续说后撤销;第二次候选又启动新草稿;最终确认才成为正式响应。它们属于同一个turn_id,却不是同一代工作。因此协议至少要有以下关联键:

  • session_id:会话范围;
  • turn_id:一轮用户意图的逻辑身份;
  • generation_id:该轮的一次推理/执行尝试;
  • task_id:LLM、工具、TTS、播放等子任务;
  • tool_call_idaudio_segment_id:外部调用与可播放片段身份;
  • cancel_epoch或 fencing token:用于拒绝旧代迟到结果。

一个可落地的事件信封如下。字段名不是标准,关键是所有层共享同一组身份和时间锚点。

{"session_id":"s-7f","turn_id":"t-18","generation_id":"g-18.2","cancel_epoch":4,"event_id":"e-991","parent_event_id":"e-977","kind":"tool.result","phase":"speculative|committed|revoked|completed","transcript_revision":12,"provider":"internal-or-vendor","provider_event":"raw-event-name","seq":1842,"ts_mono_ns":4829910020031,"ts_wall_utc":"2026-07-23T20:15:31.842Z","payload":{}}

generation_id的核心作用是 fencing,而不只是日志关联。任何异步结果进入 reducer、会话历史、设备状态或播放队列之前,都必须验证:“这个 generation 是否仍是该 turn 的有效持有者,且当前 phase 是否允许这种提交?”验证失败的结果进入stale_result_dropped审计流,不得靠调用方“尽量别返回”来保证安全。

Barge-in 到来时,正确顺序是先在本地原子撤销旧 generation 的提交资格,再向各下游发送取消。伪代码可简化为:

on_interrupt(new_user_audio): old = active_generation atomic: old.phase = REVOKED old.cancel_epoch += 1 deny_future_commits(old) active_generation = open_new_turn_or_generation() fanout_cancel(old) playback_drop(old)

这个顺序解决最危险的竞态:即使工具结果在fanout_cancel之前或期间到达,它也因 fencing 校验失败而不能污染权威状态。反过来,若先发网络取消、后标记本地失效,迟到结果可能正好穿过窗口。

Barge-in 是一组取消,不是一个静音按钮

完整 Barge-in 至少包含五条链路。

第一,检测链路确认用户开始说话,并区分真实语音、回声、环境噪声和短促非语音。检测事件只负责提出 interrupt,不直接证明新一轮已完整。

第二,运行时撤销旧 generation,停止接受其模型 token、工具计划、工具结果和历史写入。对于已经开始的 LLM 请求,发送 provider 支持的 cancel;但本地必须继续丢弃取消后的 token,因为“已发送取消”不等于“远端已经停止”。

第三,工具链路按副作用等级处理。只读工具可以在撤销后直接丢结果;幂等写操作必须携带 idempotency key、turn/generation metadata 和可查询终态;不可逆动作不应在 speculative 阶段发出,必要时采用 prepare/commit、显式确认或补偿事务。gRPC 的官方取消指南指出,库通常不能直接中断应用层 handler,服务端需要主动检查取消并停止处理;向上游的取消传播在不同语言实现中也不完全相同。10因此客户端的cancel_requested只是意图,不是远端停止执行、停止计费或撤销副作用的证明。协议应区分cancel_observedcancel_completedcancel_unsupportedtoo_lateside_effect_committed

第四,TTS 生成链路停止继续合成。Deepgram TTS 的Clear清除其服务端内部文本与音频生成缓冲,并尽快停止发送新音频块;它不代表浏览器、移动端、电话网关或声卡里的已收音频被清除。11

第五,播放链路立即停当前 source,清掉所有属于旧 generation 的排队 chunk,并拒绝取消后迟到的音频。Deepgram Voice Agent 的UserStartedSpeaking也明确要求客户端停播并丢弃缓冲,但这仍是客户端侧动作。12Web Audio 规范规定,AudioScheduledSourceNode.stop()后该 source 输出静音,但这只描述本地音频节点,不会替你取消远端模型、工具或 TTS。13即使在 WebRTC 层调用removeTrackreplaceTrack(null),规范定义的也是停止媒体发送,不会自动传播成 Agent Runtime 的模型或工具取消。14Deepgram 的AgentAudioDone也只表示服务端发完最后一个音频块,不表示用户已经听完;客户端仍需观察本地输出队列。15

供应商在这里有不同责任边界。OpenAI Realtime 的 WebRTC/SIP 连接由服务端掌握输出缓冲,可在用户打断时自动截断未播放音频;WebSocket 连接则由客户端管理播放,客户端必须停播、记录已播放时长,并发送conversation.item.truncate删除未听部分。16Twilio 双向 Media Streams 的clear会清空其缓冲音频;mark既可能因音频正常播完返回,也可能因缓冲被 clear 返回,所以应用仍要记录清空原因与 generation 状态,不能把收到 mark 一律解释为“用户听完”。17LiveKit 的默认中断路径会停止讲话并把历史截到用户实际听到的部分,这是框架语义,不是 WebRTC 本身提供的事务保证。7

由此可得一个硬规则:停止声音、停止生成、停止执行、停止提交是四个独立动作。Barge-in 必须把它们绑定到同一个取消域,但不能把任一动作的成功当作其他动作已经成功。

状态提交必须以“用户实际听到什么”为准

语音 Agent 的会话历史不应只记录“模型生成了什么”,而应区分:

  1. 模型生成文本;
  2. TTS 已生成音频;
  3. 音频已进入播放队列;
  4. 音频实际播放到哪个 sample 或毫秒位置;
  5. 哪一部分因打断被截断。

否则下一轮模型会以为用户听过整段旧回答,产生“如我刚才所说”之类的错位。OpenAI 的 WebSocket 截断流程要求客户端记录已播放时长,正是因为服务端不知道耳端进度。16Deepgram 也明确区分服务端发完音频与用户听完音频。15

建议把 assistant 输出拆成generated_contentdelivered_prefixcommitted_history。模型 token 可以持续写入临时缓冲;只有可映射到已播放音频的前缀进入 delivered 记录。发生中断时,权威历史提交 heard prefix,未听部分标为 revoked。文本与音频无法精确对齐时,不要伪造逐字截断;保留音频播放游标、原始文本、对齐置信度和截断策略,让后续模型知道这是近似历史。

工具状态也要分层:tool_plannedtool_dispatchedtool_side_effect_committedtool_result_receivedtool_result_applied。撤销后收到结果,可以阻止applied,却未必能逆转side_effect_committed。把两个状态混成一个tool_done,正是开篇竞态无法审计的原因。

延迟必须和正确性共用时间锚点

端到端延迟不能只测“用户停说到首包音频”。那会奖励提前误判 EOU、提前启动无效 LLM、提前播出随后被截断的回答。Deepgram 将 transcript latency 与 EOT latency 分开,并提醒 finalized 结果会混入 endpoint 等待;精确 EOT 还需要真实 speech-end 锚点。其文档同时建议看代表性样本上的 P50、P95、P99,而不是单次或平均值。18

一条可重放时间线至少记录:

audio.user_speech_start_ground_truth audio.user_speech_end_ground_truth vad.speech_started / vad.speech_stopped eou.candidate_received turn.speculative_started turn.resumed turn.committed llm.request_sent / first_token / cancel_sent / cancel_ack / terminal tool.dispatched / cancel_sent / side_effect_committed / result_received / result_applied tts.request_sent / first_audio_received / clear_sent / cleared playback.enqueued / first_sample / last_sample / queue_cleared / output_silent barge_in.ground_truth_start / detected / generation_revoked stale_result_dropped

同一进程的时长用 monotonic clock 计算,跨节点关联保留 UTC wall clock、时钟同步状态和单调seq。不要直接拿供应商词时间戳当毫秒级墙钟;Deepgram 明确说明其 transcriptstartduration不保证适合精确延迟测量。18其 Voice Agent 可观测性指南也建议给每个收发帧加自有时间戳和序列号,并保存 function call、barge-in 与 latency 事件。19

核心指标应成组发布:

  • EOU commit latency:turn.committed - speech_end_ground_truth
  • response-to-ear:playback.first_sample - speech_end_ground_truth
  • barge detection latency:barge_in.detected - barge_in.ground_truth_start
  • residual playback:playback.output_silent - barge_in.ground_truth_start,并另报从 detection 起算的系统处置时长;
  • cancel propagation:从 generation revoked 到 LLM、tool、TTS、playback 各自 terminal/ack;
  • false truncation rate:标注仍属同一用户轮,却已提交或开始不可逆执行的比例;
  • false extension rate:标注已结束,但提交超过产品自定 SLO 的比例;
  • speculative waste:被撤销的模型请求、token、TTS 音频和未播放字节;
  • stale tool execution:generation 撤销后仍开始或完成副作用的次数;
  • stale result drop:迟到结果被 fencing 拒绝的次数。

P50 说明常态,P95/P99 暴露抖动、排队、网络与重复 endpointing;误截断、误延长、残留播放和 stale tool execution 则约束“快但错”。这些指标必须按语言、噪声、回声、设备、网络、句式和打断位置分层,不能用一个平均延迟掩盖尾部竞态。

可复现测试矩阵

测试不需要虚构“线上二百轮”。更可靠的做法是用双轨音频语料、确定性 fake service 和故障注入构造可重复实验:一轨是用户近讲,另一轨是 Agent 扬声器回灌;语料带人工标注的 speech start、speech end、意图边界和 barge-in 起点。Fake LLM、tool、TTS 可配置首包延迟、取消是否协作、结果乱序、重复投递和“副作用已提交后才收到取消”。网络层注入 jitter、丢包、重连与跨通道乱序。

场景注入方式必须成立的协议断言主要观测
句中自然停顿后续说在一个意图中插入不同长度静音候选 EOU 可启动草稿,但不得提前提交不可逆工具;续说后旧 generation 被撤销false truncation、speculative waste
真正结束但有背景噪声叠加音乐、敲击或电话铃声VAD、UtteranceEnd、语义 EOU 的原始事件分别留存;最终只提交一次EOU P50/P95/P99、false extension
LLM 生成中打断首 token 前后分别触发 barge-in本地先 revoke;取消后 token 全部被丢弃;新轮不继承未听旧文本cancel propagation、stale token drop
工具请求在途时打断工具设置可协作取消、不可取消、too-late 三种模式迟到结果不得 apply;副作用终态可审计;重复请求由 idempotency key 抑制stale execution、side-effect committed
TTS 已生成但未播放延长客户端队列TTS clear 与本地 queue clear 都执行;旧 generation 后续音频不得入队未播放字节、queue clear latency
正在播放时打断在不同播放游标触发output 进入静音;历史只提交 heard prefix;旧 chunk 全部失效residual playback、截断游标
回声造成假打断提高扬声器回灌并切换 AEC不得无条件撤销;检测置信度和恢复路径可追踪false barge-in、恢复延迟
取消与结果乱序让 result 先于或后于 cancel ack 到达fencing 决定能否提交,消息到达顺序不得改变权威结果stale result drop、终态唯一性
断线重连与重复投递重放事件、复用 tool_call_id每个 turn/generation 只有一个终态;副作用不重复duplicate suppression、审计完整率

除场景断言外,还应做六条全局不变量测试:被撤销 generation 的结果永不进入权威历史;不可逆工具默认不得在 speculative phase 发出;旧 generation 音频在 queue clear 后不能再次入队;每个 generation 只有一个终态;每次副作用都有幂等键和可查询终态;用户历史与实际听到的前缀一致。只要其中一条不成立,低延迟数据就不具备发布价值。

结论:先定义失效,再谈快

实时语音系统的关键单位不是 ASR 请求、LLM 请求或一段 TTS 音频,而是带身份、阶段和提交权的一代 turn execution。EOU 提出或确认一次提交;Barge-in 撤销旧代提交权;LLM、工具、TTS 和播放器通过同一个 generation fencing 决定结果是否仍可进入系统;可观测性用同一组时间锚点证明撤销是否及时、尾部是否稳定、旧结果是否被隔离。

没有这层 Turn Protocol,团队会得到一组彼此“优化成功”的局部指标:ASR 更早 final,LLM 更早发请求,TTS 更早出首包,播放器更快静音。与此同时,误截断增加、无效调用增加、旧工具继续执行、历史记录与用户耳中内容分叉。协议的作用不是让系统变慢,而是把推测、提交、撤销和交付变成可验证的状态变化。只有在旧工作能够被可靠失效之后,提前计算才是真正的低延迟,而不是更快地产生竞态。

FAQ

VAD 检测到静音后能不能直接调用工具?

不建议。VAD 只证明声学活动变化,应先进入可撤销候选阶段;有副作用工具需要确认提交和代际校验。

收到取消请求是否代表远端任务已经停止?

不代表。取消可能只是表达不再需要结果,远端 handler 仍可能执行,因此还需要 fencing 和提交前有效性检查。

低延迟最重要的单一指标是什么?

没有单一指标。结束延迟必须与误截断、误延长、打断静音和陈旧结果一起观察。

参考资料


错误速查卡

症状根因定位修复
用户听不到旧回答,但旧工具已修改生产Barge-in 只停了扬声器,工具结果仍按原 generation apply 写历史检查 generation phase 是否被原子置为 REVOKED、cancel_epoch 是否单调递增先原子撤销提交权 → fanout_cancel → playback_drop;fencing 校验失败必须进 stale_result_dropped
误把"用户说完了"提交给 LLM,续说后整段失效EOU 候选事件被当作提交信号,缺少 SPECULATIVE/COMMITTED 边界检查 EOU commit 是否校验 turn_id open + transcript_revision 未被替换把 user turn 建模为 OPEN/SPECULATIVE/COMMITTED/REVOKED 状态机
工具重复执行同一条写操作不可逆操作在 speculative 阶段发出,没有 idempotency key检查 tool_call_id + idempotency_key 是否唯一并由 generation 持有不可逆动作必须 prepare/commit;带幂等键;可查询终态
旧 generation 的 token 写入对话历史“已发送取消"被当作"远端已停止”,本地继续接 token检查 cancel_observed/cancel_completed/cancel_unsupported 三个事件是否区分协议应区分 cancel_observed、cancel_completed、cancel_unsupported、too_late、side_effect_committed
下一轮模型引用"如我刚才所说"但用户没听到历史只记录了 generated_content,没有 delivered_prefix检查 committed_history 是否只含 heard prefix拆 generated_content / delivered_prefix / committed_history;中断时只提交 heard prefix
P95 偏高但 P50 正常,被误归因为"网络慢"重复 endpointing(STT 内部 min_delay + 运行时 EOU 等待)拆解 latency:供应商检测等待 + 网络传输 + 运行时二次等待 + 提交排队取消运行时 min_delay 或允许运行时基于 STT end-of-speech 直接提交
同一段 LLM 输出被记录两次取消后迟到 token 仍进入 reducer检查 generation_id + cancel_epoch 校验reducer 入口做 fencing;迟到结果进 stale_result_dropped 审计流
Twilio mark 一律被解释为"用户听完"mark 既可能因音频正常播完返回,也可能因 clear 返回检查 mark 事件与 clear 事件是否同时记录及原因字段应用必须记录 mark 触发原因(normal_end / cleared)与 generation 状态
Web Audio stop() 后以为远端也停了AudioScheduledSourceNode.stop()只控制本地音频节点检查本地 source 是否停了,但远端 LLM/TTS 未撤销同步撤销 Playback / Gateway / TTS / LLM-Tool / History 五条链路
WebRTC removeTrack 以为能取消模型/工具规范定义的 removeTrack/replaceTrack 只停止媒体发送检查 RtpSender.setTrack(null) 与 Agent Runtime 取消是否独立Agent Runtime 必须独立撤销 generation,不能依赖 WebRTC track 状态传播
cancel_requested当作远端已停止客户端意图被当作远端执行保证检查远端是否到达 cancel_observed / cancel_completed协议必须区分 cancel_requested(意图)与 cancel_observed(远端观察)和 cancel_completed(已停止)
VAD 检测到静音就直接调用工具VAD 误当作整轮结束检查 VAD 与 EOU commit 之间是否有 SPECULATIVE 阶段VAD 只能进 SPECULATIVE;COMMIT 必须在 turn.committed 之后
is_final=true当作整轮完成文档已说明is_final是片段级而非 utterance 级检查 speech_final 与 is_final 是否同时使用累计 finalized 片段 + 完整结束信号才提交;区分 is_final / speech_final / EndOfTurn
UtteranceEnd OR speech_final 当作更高置信度两者语义不同轴,OR 后丢失原始信息检查 OR 之前是否分别记录了原始事件与 confidence保留 provider / provider_event / confidence;不私自 OR
取消前已做的副作用无法回滚却被承诺"已撤销"gRPC 官方明确"Changes made before a cancellation are not rolled back"检查 side_effect_committed 事件是否与 cancel 分离记录协议必须区分 too_late 与 side_effect_committed;幂等键 + 可查询终态是底线
回声造成假打断,旧 generation 被错误撤销AEC 未开或置信度低时仍按 interrupt 撤销检查 interrupt 事件是否带 AEC 置信度不无条件撤销;保留检测置信度与恢复路径;可回滚
eot_threshold调得很低但 false start 暴增eager 阈值降低会多 50-70% LLM 调用,false starts 也增加检查 speculative_waste / false_truncation 是否同步上升把 eot_threshold 调整到 P95 EOT latency 与 false_truncation 联合最优点
同一 turn 多次 candidate 提交互相污染只有 turn_id 没有 generation_id检查事件信封是否带 generation_id + cancel_epoch五键事件信封:session_id / turn_id / generation_id / task_id / cancel_epoch
OpenAI WebSocket 模式没发 conversation.item.truncate客户端以为 WebSocket 也会自动截断检查 sessionManager 是否发送 truncateWebSocket 模式客户端必须记录已播放时长并显式发送 conversation.item.truncate
网络 jitter 大时取消乱序导致权威状态被旧 generation 覆盖先发网络 cancel,后置本地 REVOKED检查 on_interrupt 的原子顺序顺序必须为:原子置 REVOKED + cancel_epoch++ → fanout_cancel → playback_drop
取消与 LLM token 到达 race 导致 fence 失效reducer 在 fence 校验前已写历史检查 reducer 入口的 generation_id + cancel_epoch 校验顺序所有异步结果必须先过 fencing 才进 reducer / 历史 / 设备状态

  1. Endpointing,官方或第一方资料,访问日期 2026-07-23。 ↩︎ ↩︎

  2. End of Speech Detection While Live Streaming,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  3. Configure Endpointing and Interim Results,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  4. Voice Activity Detection (VAD),官方或第一方资料,访问日期 2026-07-23。 ↩︎

  5. Configure the Voice Agent,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  6. Understanding the Flux State Machine,官方或第一方资料,访问日期 2026-07-23。 ↩︎ ↩︎

  7. LiveKit Turns Overview,官方或第一方资料,访问日期 2026-07-23。 ↩︎ ↩︎

  8. Optimize Voice Agent Latency with Eager End of Turn,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  9. LiveKit Turn Detector,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  10. gRPC Cancellation,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  11. TTS WebSocket Clear,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  12. User Started Speaking,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  13. Web Audio API 1.1,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  14. WebRTC: Real-Time Communication in Browsers,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  15. Agent Audio Done,官方或第一方资料,访问日期 2026-07-23。 ↩︎ ↩︎

  16. Realtime Conversations: Interruption and Truncation,官方或第一方资料,访问日期 2026-07-23。 ↩︎ ↩︎

  17. Twilio Media Streams: WebSocket Messages,官方或第一方资料,访问日期 2026-07-23。 ↩︎

  18. Measuring STT Latency,官方或第一方资料,访问日期 2026-07-23。 ↩︎ ↩︎

  19. Session Observability,官方或第一方资料,访问日期 2026-07-23。 ↩︎

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/26 12:40:24

快速掌握C二分查找:gh_mirrors/dsa/DSA中的BinarySearcher使用教程

快速掌握C#二分查找:gh_mirrors/dsa/DSA中的BinarySearcher使用教程 【免费下载链接】DSA Data structures and algorithms in C# 项目地址: https://gitcode.com/gh_mirrors/dsa/DSA 二分查找是计算机科学中最经典的高效搜索算法,在有序数据集中…

作者头像 李华
网站建设 2026/7/26 12:37:44

TMS320VC5409A DSP时序分析:IAQ、McBSP与HPI接口设计指南

1. 项目概述:为什么DSP时序分析是硬件工程师的必修课如果你正在设计一个基于TMS320VC5409A这类高速定点DSP的系统,无论是做音频编解码、电机控制还是通信基带处理,那么你迟早会碰到一个绕不开的“硬骨头”——时序分析。数据手册里那些密密麻…

作者头像 李华
网站建设 2026/7/26 12:36:01

screen_capture_lite性能优化指南:降低CPU占用的5个实用技巧

screen_capture_lite性能优化指南:降低CPU占用的5个实用技巧 【免费下载链接】screen_capture_lite cross platform screen/window capturing library 项目地址: https://gitcode.com/gh_mirrors/sc/screen_capture_lite screen_capture_lite是一款跨平台的屏…

作者头像 李华
网站建设 2026/7/26 12:35:20

3分钟快速上手:163MusicLyrics无损歌词下载终极指南

3分钟快速上手:163MusicLyrics无损歌词下载终极指南 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 还在为找不到高质量音乐歌词而烦恼吗?163Musi…

作者头像 李华