> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/conversation-flow.md).

# 对话流程

了解语音输入、播放状态、转录事件、动作队列执行、叙事触发器和中断处理。

在会话建立后，player 组件会转发音频或文本输入，Convai 返回转录和角色输出，而 chatbot 组件播放音频、更新面部和情绪数据，并将动作排入队列。了解当前 SDK 中哪些部分由事件驱动，以及哪些辅助函数是可靠的，有助于 Blueprint 在不依赖不受支持的状态假设的情况下驱动 UI 和游戏玩法。

### 播放和辅助状态

`UConvaiChatbotComponent` 公开多个 `蓝图纯函数` 状态和播放辅助函数：

| 函数                        | Blueprint 显示名称 | 当前行为                                                                                        |
| ------------------------- | -------------- | ------------------------------------------------------------------------------------------- |
| `GetIsTalking`            | 是否正在说话         | 返回该组件当前的音频播放标志。可用于字幕时序、动画切换以及中断按钮。                                                          |
| `GetTalkingTimeElapsed`   | —              | 返回当前音频回复的已播放时间。                                                                             |
| `GetTalkingTimeRemaining` | —              | 返回估计的剩余播放时间。                                                                                |
| `IsListening`             | 是否在监听          | 存在于 Blueprint API 中，但目前返回 `false` 在 SDK 源码中。                                                |
| `IsProcessing`            | 是否正在思考         | 存在于 Blueprint API 中，但目前返回 `false` 在 SDK 源码中。                                                |
| `IsInConversation`        | 是否正在对话中        | 组合这些辅助状态。由于 `IsListening` 和 `IsProcessing` 目前返回 `false`，因此这实际上等同于 `GetIsTalking` 在当前 SDK 中。 |

对于当前版本，请将 `GetIsTalking`、音频播放委托、转录事件和动作事件视为可靠的运行时信号。不要围绕 `IsListening` 或 `IsProcessing` 来构建关键 UI 逻辑，直到 SDK 实现发生变化。

```mermaid
stateDiagram-v2
    空闲 --> 输入已开启：Player 取消静音音频\n(UnmuteStreamingAudio)
    输入已开启 --> 等待回复：Player 将音频静音\n(MuteStreamingAudio)
    等待回复 --> 说话中：来自 Convai 的首个音频帧到达\n
    说话中 --> 空闲：音频播放结束
    说话中 --> 空闲：调用 InterruptSpeech
```

上图显示了概念性的理想路径。它并不是当前 SDK 中所有辅助函数的一一对应映射。

### 语音输入模式

`UConvaiPlayerComponent` 支持两种模式来控制何时将音频转发给 Convai。

#### 按住说话

在按住说话模式下，游戏逻辑会显式打开和关闭音频流。调用 `UnmuteStreamingAudio` 位于 `UConvaiPlayerComponent` 当玩家开始说话时，以及 `MuteStreamingAudio` 当他们停止时调用。player 组件仅在开启窗口期间转发音频。

在存在环境噪声的训练模拟中使用按住说话模式——例如机械声、教室环境或多个同地用户——因为自动语音检测可能会产生错误的轮次结束截断。

#### 语音活动检测

通过调用以下函数，可在 player 组件上切换语音活动检测（VAD）： `UpdateVadBP(bool EnableVAD)`。详细的 VAD 阈值位于 `FConvaiVADSettings` Convai 项目设置对象中，并且可以通过实用设置函数读取或更改。

| 字段                  | 类型      | 默认值    | 说明                                                               |
| ------------------- | ------- | ------ | ---------------------------------------------------------------- |
| `bUseServerDefault` | `bool`  | `true` | 当 `true`，则下面所有按字段设置的值都会被忽略，Convai 将应用其自身默认值。设置为 `false` 以覆盖各个字段。 |
| `置信度`               | `float` | `0.7`  | 某帧包含语音的最低 VAD 模型概率。提高此值可减少背景噪声导致的误报；如果角色漏掉了轻声说话者，则降低此值。          |
| `StartSecs`         | `float` | `0.2`  | 在触发“用户开始说话”事件之前，持续语音的秒数。值越高，越会忽略短暂的语音片段。                         |
| `StopSecs`          | `float` | `2.2`  | 达到 VAD 端点之前的静音秒数。值越低，轮次结束检测越快，但代价是会截断说话较慢的人。                     |
| `MinVolume`         | `float` | `0.6`  | 归一化振幅下限，低于此值的音频将被视为静音。提高此值可排除较轻的背景声音。                            |

VAD 适用于免手持或移动场景，此时按住说话按钮并不现实。

### 转录

转录通过以下方式暴露： `OnTranscriptionReceivedDelegate`、一个 `可在 Blueprint 中分配` 委托，位于 `UConvaiConversationComponent` （由 chatbot 和 player 组件共同继承）。该子系统会将用户转录转发到 player 会话，并将机器人转录转发到 chatbot 会话。

该委托的参数为：

| 参数                     | 类型                              | 说明                                                                                         |
| ---------------------- | ------------------------------- | ------------------------------------------------------------------------------------------ |
| `说话者`                  | `UConvaiConversationComponent*` | 广播转录事件的组件。当前广播点传入 `this`.                                                                  |
| `监听者`                  | `UConvaiConversationComponent*` | 存在于委托签名中。当前广播点传入 `nullptr`.                                                                |
| `转录`                   | `FString`                       | 该话语此时的转录文本。                                                                                |
| `IsTranscriptionReady` | `bool`                          | 来自当前转录路径的就绪标记。机器人转录文本通过以下方式转发： `true`；用户转录文本可以通过以下方式到达： `false`，随后是一个带有空内容的最终标记，使用 `true`. |
| `IsFinal`              | `bool`                          | `true` 当这次更新是该话语的最终更新时。                                                                    |

当你需要用户话语转录时，请绑定到 player 组件。当你需要机器人回复转录时，请绑定到 chatbot 组件。对于用户字幕，请显示非空的 `转录` 有效载荷，而不是仅依据 `IsTranscriptionReady`.

### 文本输入

玩家也可以发送文本而不是音频。 `UConvaiPlayerComponent::SendText` 接受一个目标 `UConvaiConversationComponent` 参数以及一个 `FString`，但当前实现会将文本通过子系统作为一个 `user_text_message` 进行发送，并且不会使用目标参数进行路由。它也不会直接广播 `OnTranscriptionReceivedDelegate` 提交的文本。对于辅助功能输入、训练模拟中的主持人控制覆盖，以及注入脚本化对话而无需麦克风输入的自动化测试框架，请使用此路径。

### 动作队列执行

当 Convai 返回包含角色动作的回复时， `OnActionReceivedEvent_V2` 会触发，并将该序列添加到 `ActionsQueue`。如果队列为空，新序列就成为队列。如果队列中已包含一个动作，则保留当前第一个动作，而新序列会替换剩余的排队项。

Blueprint 中标准的队列驱动执行模式：

1. 绑定到 `OnActionReceivedEvent_V2` 在 `BeginPlay`.
2. 当事件触发时，调用 `FetchFirstAction` 以读取队列中的第一个 `FConvaiResultAction` 动作。
3. 在你的游戏逻辑中执行该动作（移动到某个位置、播放动画、打开门）。
4. 调用 `HandleActionCompletion(true)` 以表示成功。插件会将结果报告给 Convai，下一条排队动作（如果有）即可供获取。
5. 调用 `HandleActionCompletion(false)` 以表示失败。Convai 会收到通知，并可能生成恢复响应。
6. 如果某个动作发生不可恢复的失败——例如，目标 Actor 不再存在——请调用 `AbortActionSequence` 以丢弃队列中所有剩余动作。

该 `bWaitForBotSpeech` 动作模板上的标志会门控 `StartFirstAction` 新到达序列中的第一个动作。该门控可以在机器人开始说话、机器人说话结束、回复没有机器人音频，或者等待计时器到期时释放。后续队列推进由 `HandleActionCompletion`.

### 中断

`InterruptSpeech` 位于 `UConvaiChatbotComponent` 通过在以下时长内淡出音频来停止角色当前播放： `InVoiceFadeOutDuration` 秒。淡出时长也可以通过以下项作为默认值进行配置： `InterruptVoiceFadeOutDuration` 组件上的属性。

该类还公开 `Broadcast_InterruptSpeech` 作为一个 `NetMulticast Reliable` 用于全网络中断路径的 RPC。 `InterruptSpeech` 它本身会在调用它的组件上应用淡出请求。

该 `OnInterruptedEvent` 当 chatbot 正在说话或处理时应用中断，该委托会触发。当前实现会广播 chatbot 组件并传入 `nullptr` 用于 player 组件。

插件支持渐进式淡出而不是立即切断的原因在于，音频突然停止会产生感知伪影。淡出时长让设计师可以控制中断听起来是自然还是突兀。

### 调用语音和叙事触发器

两个 `BlueprintCallable` 这些函数可让 Blueprint 在无需玩家输入的情况下驱动角色说话：

* `ExecuteNarrativeTrigger` （Blueprint 显示名称 **Invoke Speech**） `EC_RunLLMOption::Always`。Blueprint 节点标记为 **Invoke Speech**；C++ 名称 `ExecuteNarrativeTrigger` 仅在代码中可见。
* `InvokeNarrativeDesignTrigger` （Blueprint 显示名称 **Invoke Narrative Design Trigger**）——通过 chatbot 组件排队或调用一个命名的 Narrative Design 触发器。

{% hint style="info" %}
使用 `ExecuteNarrativeTrigger` 适用于一次性、自由形式的提示词，其确切措辞可在运行时变化。使用 `InvokeNarrativeDesignTrigger` 当触发器名称与 Narrative Design 之间是稳定约定时。
{% endhint %}

这两个函数都公开 `InGenerateActions` 和 `InReplicateOnNetwork` 参数在 Blueprint API 中。当前实现中， `ExecuteNarrativeTrigger` 通过以下方式路由： `AddContextEvent` 并且不使用这两个参数。 `InvokeNarrativeDesignTrigger` 使用内部触发路径，并在会话建立之前将断开连接的触发调用排入队列。

### 使用示例

#### 按住说话的角色对话交互

一个医疗训练模拟，学习者通过按住按钮与患者角色交谈。

1. 绑定一个 **按下** 事件到交互输入动作，以 **取消流式音频静音** 绑定到 player 组件上的该事件——这会打开音频流。
2. 将 **释放** 事件以 **将流式音频静音** ——这会关闭音频流。
3. 从输入事件中跟踪你自己的录音指示器。使用 `GetIsTalking` 以及音频播放委托，在角色回复播放时显示字幕或说话指示器。

预期结果：只有在玩家按住按钮时，患者角色才会接收音频。回复播放指示器跟随 `GetIsTalking` 或播放委托。

#### 主持人文本注入

一个训练模拟，其中主持人可以输入一条消息，AI 角色会接收并作出回应，无需使用麦克风。

1. 创建一个简单的编辑器内或运行时 UI 小部件，包含一个文本框和一个 **发送** 按钮。
2. 将 **发送** 按钮的 **On Clicked** 事件以 **发送文本** 事件连接到 player 组件，并将文本框内容作为输入字符串传入。

预期结果：player 组件会通过子系统将输入的消息作为文本输入发送。若你需要主持人消息的本地字幕，请从你的 UI 状态中显示已提交的文本。

### 故障排查

| 症状                                         | 可能原因                                                                   | 修复                                                                                                | 验证                                                            |
| ------------------------------------------ | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| 输入后角色没有开始说话                                | 会话未连接、音频未发送，或者文本消息未提交                                                  | 检查 `GetChatbotConnectionState`，确认 player 组件已初始化，并验证你的输入事件是否调用了 `MuteStreamingAudio` 或 `SendText`. | `GetIsTalking` 会变成 `true` 当第一个音频回复播放时。                        |
| 录音指示器从不关闭                                  | UI 绑定到 `IsListening`，而它目前返回 `false`                                    | 请从输入的按下/释放事件驱动录音 UI，而不是依赖 `IsListening`.                                                          | 指示器会精确跟随按钮状态。                                                 |
| 动作到达于 `OnActionReceivedEvent_V2` 但没有任何内容执行 | `FetchFirstAction` 未在事件处理程序中调用，或者 `HandleActionCompletion` 未在每个动作执行后调用 | 调用 **获取第一个动作** 在……中 **在接收到动作时** 处理程序中。执行动作后，请始终调用 **处理动作完成** 并将 `true` 在成功时调用，或者 `false` 失败时返回。   | 一个 **Print String** 对获取到的动作名称进行确认以确认接收。每次完成调用后，序列中的下一个动作就会可用。 |
| `InterruptSpeech` 没有可见效果                   | 在以下情况下调用： `GetIsTalking` 是 `false` ——当前没有音频在播放                         | 使用一个 **获取是否正在说话** 检查进行保护。调用 `InterruptSpeech` 仅当角色处于说话状态时。                                        | `GetIsTalking` 返回 `false` 在淡出完成后。                             |

### 相关概念

{% content-ref url="/pages/a8878427b216a80d6b385f1a342c440aa9b398c9" %}
[会话生命周期](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/session-lifecycle.md)
{% endcontent-ref %}

{% content-ref url="/pages/ddcceab71734a05a1e99c8599b42f364e146005e" %}
[事件系统](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/event-system.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/conversation-flow.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
