For the complete documentation index, see llms.txt. This page is also available as Markdown.

Turn 生命周期和消息顺序

了解 Live API 轮次传递,包括旧版文本、规范输出、动作结果续接、关联和顺序保证。

一次 Live API 会话会通过并行的媒体和数据载体传递一个逻辑轮次。请将消息顺序、逻辑轮次关联和客户端工具完成视为彼此独立的问题。

载体
承载内容
格式

WebRTC 音频轨道

实际的语音音频

标准 WebRTC 媒体轨道(或 audio-data 如果你启用了数据通道路由,则为消息)

机器人输出流

机器人的回复文本和说话状态转换

数据通道,事件类型位于 顶层

自定义服务器消息

规范化的模型输出、动作、情绪、转录、动画和生命周期

数据通道,事件类型嵌套在 data.type

只有在启用以下设置时,音频才会出现在数据通道流中: audio_routing: "data_only""both" 中的 audio_config。请参见 通过数据通道传输的音频数据.


两种封装形式

数据通道承载两种不同的封装结构。你的消息处理器必须同时检查这两种情况。

形式 A — 机器人输出流。 事件类型位于顶层 type:

{ "label": "rtvi-ai", "type": "bot-llm-text", "data": { "text": "当然,马上就到。" } }

形式 B — 自定义服务器消息。 顶层 type 始终是 "server-message",而真正的事件类型嵌套在:

{
  "label": "rtvi-ai",
  "type": "server-message",
  "data": { "type": "action-response", "actions": [{ "name": "Move To", "target": "cube" }] }
}

按如下方式解析实际事件类型:

function eventType(message) {
  return message.type === "server-message" && message.data?.type
    ? message.data.type
    : message.type;
}

服务器响应 是第三种旧版结构。其字段位于顶层,而不是位于一个 server-message 封装。参见 服务器响应.


机器人输出流

这些消息使用 形式 A。它们是机器人的回复文本唯一出现的位置。

消息
负载
含义

bot-llm-started

{}

模型已开始生成本轮内容

bot-llm-text

{ text }

所选旧版或原始文本投影的增量片段。按到达顺序拼接即可重建该投影

bot-llm-stopped

{}

生成完成

bot-tts-started

{}

本轮的语音合成已开始

在省略某些能力或 bot_llm_text_mode: "legacy", bot-llm-text 时,承载经过过滤的对话文本。在 bot_llm_text_mode: "raw"时,它承载在结构化输出解析和对话过滤之前、对提供方可见的文本。原始输出不是值得信任的可渲染或可执行内容。参见 响应契约与解析.

说话状态消息

bot-started-speakingbot-stopped-speaking 标记本轮的音频边界。这些消息使用 形式 B 并且还会重复 labeldata:


响应生命周期元数据

有三条消息—— bot-started-speaking, bot-stopped-speaking以及 bot-turn-completed ——可能携带可选的关联字段。每个字段都只会在 被设置时才会包含,因此不同轮次的键集合会不同。

字段
类型
说明

response_id

字符串

此机器人响应的标识符,在整个轮次中保持稳定

neurosync_turn_id

整数

NeuroSync 轮次标识,用于关联 blendshape 流

epoch

整数

NeuroSync 连接/会话纪元

sequence

整数

每轮消息序号

使用 response_id 用于将 blendshape 和取消消息与产生它们的轮次关联起来。不要假定这些字段一定存在。

协商 model output v2 的客户端会收到一个或多个 model-output 封装。使用 output_id 来去重封装。使用可选的 logical_turn_id 来将属于一个逻辑轮次的文本、语义动作和客户端工具调用封装分组。不同封装可以共享一个 logical_turn_id.


一个完整的旧版轮次

用户说 “去拿那个立方体”。一个代表性的 v1 消息序列如下:

本轮的语音音频会播放在 WebRTC 音频轨道上,与上面的消息并行。

对于协商启用 model output v2 的客户端,Convai 还可以发出共享同一逻辑轮次 ID 的独立规范封装:

最终:true 完成一个封装。它不会结束整个逻辑轮次。


顺序保证

把这件事处理正确,可以避免一大类集成错误。

保证的内容

  • bot-llm-text 片段按顺序到达。 按到达顺序拼接它们,即可还原所选文本投影。

  • 轮次边界是有序的。 bot-llm-started 先于任何 bot-llm-text,而后者先于 bot-llm-stopped. bot-started-speaking 先于 bot-stopped-speaking,而后者先于 bot-turn-completed.

  • 数组和项的顺序会被保留。 这并不要求客户端按顺序执行。

  • output_id 标识一个规范封装。 重复的 ID 视为重复项。即使共享 logical_turn_id.

  • 客户端工具调用会等待其关联结果或超时。 Convai 会在该工具继续执行之前,将在超时前被接受的结果提供给同一模型上下文。

  • bot-turn-completed 是终态 用于相关服务器响应生命周期,而不是证明客户端操作或播放已经完成。

什么是 保证的

具体来说,这意味着:

  • 无法 判断某个动作是打算发生在“第二句之后”。

  • 无法 判断哪些词 bot-emotion 适用于某个动作。情绪是 轮次级,而不是跨度级。

  • 旧版 v1 无法表示如下交错序列: 先说,再移动,再说一次。规范化 v2 可以将多个已完成的封装分组,但它不提供词级动作偏移。

  • action-response 通常在生成接近结束时到达,但它相对于 bot-llm-stopped不具契约性。不要把动作执行的触发条件建立在已经看到 bot-llm-stopped.

推荐处理方式: v1 客户端可以将 action-response 视为建议的动作计划。V2 客户端应使用 model-output.items 作为规范来源,并忽略重复投影。在两种模式下,都应在你的应用中授权并安排操作。仅在客户端操作达到终态后返回一个 action-result ,只有在客户端操作达到终态之后。


轮次完成

bot-turn-completed 表示一个 服务器端 终态:服务器已完成移交本轮所需的全部输出,或者该轮次已被中断或中止。

字段
类型
Presence
说明

was_interrupted

布尔值

始终可用

如果用户打断了机器人

was_aborted

布尔值

仅当

由于所需输出无法送达,本轮结束

error_reason

字符串

仅在中止时 设置

机器可读的中止原因;目前为 audio_delivery_failed

bot-turn-completed 并不是客户端播放确认。它不表示用户已经听完音频,也不表示 avatar blendshapes 或客户端工具已经完成。驱动本地音频播放的客户端、 isSpeaking 状态、口型同步或 avatar 动画,应在清空这些状态之前先清空各自的队列。

中断

当用户插话打断时,当前轮次以 was_interrupted: true结束。选择接收预先下发 NeuroSync 片段的客户端还会收到 neurosync-blendshapes-cancel,其中指定要保留多少已缓冲的视觉尾部。

在中断时,已经下发的动作和工具调用不会被撤回。如果你的体验需要取消进行中的客户端工作,请在你的应用中于 was_interrupted时处理,然后返回一个终态的 "已取消" 结果给受影响的 v2 工具调用。


字段存在规则

字段存在性 并不统一 在不同消息类型之间并不一致。当前有三种不同的约定;在编写假定某个键存在的客户端之前,请先查看此表。

约定
行为
适用于

始终存在

即使值为 null

moderation-response.reason,该键也会发出;每条消息上的所有必填字段

为空时省略

该键 缺失 于 JSON 中,而不是 null

server-response.message, server-response.extras, final-user-transcription.speaker_id / speaker_name / participant_id / message_id, user-idle-warning.message, llm-no-response.reason, bot-turn-completed.was_aborted / error_reason

嵌套时为 null 则省略

嵌套对象上的可选键会被移除

action-response.actions[].target

仅在设置时包含

关联元数据,每轮都可能不同

response_id, neurosync_turn_id, epoch, sequence

请采用防御式写法。使用可选访问(message.data?.target),而不要只检查 null。缺失的语义动作 目标 意味着该动作没有目标。v2 工具调用在 arguments中携带已验证的输入;其可选的 目标 字段不是授权决定。

对于 final-user-transcription,例如,最小实际负载是:


相关页面

最后更新于

这有帮助吗?