> 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).

# 对话流程

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

### 播放与辅助状态

`UConvaiChatbotComponent` 提供若干 `BlueprintPure` 状态和播放辅助函数：

| 函数                        | Blueprint 显示名称     | 当前行为                                                                                        |
| ------------------------- | ------------------ | ------------------------------------------------------------------------------------------- |
| `GetIsTalking`            | 正在说话               | 返回组件当前的音频播放标志。可用于字幕时机、动画过渡和中断按钮。                                                            |
| `GetTalkingTimeElapsed`   | —                  | 返回当前音频响应的已播放时间。                                                                             |
| `GetTalkingTimeRemaining` | —                  | 返回估计的剩余播放时间。                                                                                |
| `IsListening`             | Is Listening       | 存在于 Blueprint API 中，但当前返回 `false` 在 SDK 源码中。                                                |
| `IsProcessing`            | 正在思考               | 存在于 Blueprint API 中，但当前返回 `false` 在 SDK 源码中。                                                |
| `IsInConversation`        | Is In Conversation | 组合这些辅助状态。因为 `IsListening` 和 `IsProcessing` 当前返回 `false`，所以这实际上在 `GetIsTalking` 于当前 SDK 中绑定。 |

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

```mermaid
stateDiagram-v2
    Idle --> InputOpen : 玩家取消静音音频\n(UnmuteStreamingAudio)
    InputOpen --> WaitingForResponse : 玩家将音频静音\n(MuteStreamingAudio)
    WaitingForResponse --> Talking : 来自 Convai 的第一帧音频到达
    Talking --> Idle : 音频播放结束
    Talking --> Idle : 调用 InterruptSpeech
```

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

### 语音输入模式

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

#### 按住说话

在按住说话模式下，游戏逻辑会显式打开和关闭音频流。请在玩家开始说话时调用 `UnmuteStreamingAudio` 在 `UConvaiPlayerComponent` ，并在 `MuteStreamingAudio` 时调用。玩家组件仅在打开窗口期间转发音频。

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

#### 语音活动检测

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

| 字段                  | 类型      | 默认值    | 描述                                                             |
| ------------------- | ------- | ------ | -------------------------------------------------------------- |
| `bUseServerDefault` | `bool`  | `true` | 当 `true`时，下面所有按字段设置的值都会被忽略，Convai 将应用其默认值。设置为 `false` 以覆盖单独字段。 |
| `Confidence`        | `float` | `0.7`  | 帧中包含语音的最低 VAD 模型概率。提高该值可减少背景噪音造成的误报；如果角色漏掉了轻声说话者，则降低该值。        |
| `StartSecs`         | `float` | `0.2`  | 在触发“用户开始说话”事件之前持续语音的秒数。更高的值会忽略短暂的语音片段。                         |
| `StopSecs`          | `float` | `2.2`  | VAD 到达终点前的静音秒数。更低的值会更快检测到句尾，但代价是可能截断语速较慢的说话者。                  |
| `MinVolume`         | `float` | `0.6`  | 归一化振幅下限，低于该值的音频会被视为静音。提高该值可拒绝较轻的背景声音。                          |

VAD 适用于免手操作或移动场景，在这些场景中按住说话按钮并不现实。

### 转录

转录通过 `OnTranscriptionReceivedDelegate`公开， `BlueprintAssignable` 委托，位于 `UConvaiConversationComponent` （由 chatbot 和 player 组件共同继承）。该子系统会将用户转录内容转发到玩家会话，并将机器人转录内容转发到 chatbot 会话。

委托参数如下：

| 参数                     | 类型                              | 描述                                                                      |
| ---------------------- | ------------------------------- | ----------------------------------------------------------------------- |
| `Speaker`              | `UConvaiConversationComponent*` | 广播该转录事件的组件。当前广播位置传入 `this`.                                             |
| `Listener`             | `UConvaiConversationComponent*` | 在委托签名中存在。当前广播位置传入 `nullptr`.                                            |
| `转录`                   | `FString`                       | 此时该发言中的转录文本。                                                            |
| `IsTranscriptionReady` | `bool`                          | 当前转录路径中的就绪标记。机器人的转录文本通过 `true`转发；用户转录文本可能以 `false`到达，随后再以空的最终标记 `true`. |
| `IsFinal`              | `bool`                          | `true` 表示这是该发言的最终更新。                                                    |

当你需要用户发言转录时，绑定到玩家组件。当你需要机器人回复转录时，绑定到 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)` 在成功时调用
5. 调用 `HandleActionCompletion(false)` 在失败时调用。Convai 会收到通知，并可能生成恢复响应。
6. 如果某个动作发生无法恢复的失败——例如目标 Actor 不再存在——请调用 `AbortActionSequence` 以丢弃队列中所有剩余动作。

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

### 中断

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

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

该 `OnInterruptedEvent` 委托会在聊天机器人正在说话或处理中应用中断时触发。当前实现会广播聊天机器人组件并传入 `nullptr` 适用于玩家组件。

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

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

两个 `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` 适用于一次性、自由形式的提示，其精确措辞可在运行时变化。当触发器名称是与 Narrative Design 约定好的稳定契约时，请使用 `InvokeNarrativeDesignTrigger` 。
{% endhint %}

这两个函数都在 Blueprint API 中公开了 `InGenerateActions` 和 `InReplicateOnNetwork` 参数。在当前实现中， `ExecuteNarrativeTrigger` 通过 `AddContextEvent` 进行路由，并且不使用这两个参数。 `InvokeNarrativeDesignTrigger` 使用内部触发器路径，并在会话建立之前将断开的触发调用排队。

### 使用示例

#### 按住说话进行角色交互

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

1. 绑定一个 **Pressed** 事件到交互输入动作，以 **Unmute Streaming Audio** 调用在玩家组件上——这会打开音频流。
2. 绑定 **Released** 事件到 **Mute Streaming Audio** ——这会关闭音频流。
3. 从输入事件中跟踪你自己的录音指示器。使用 `GetIsTalking` 和音频播放委托，在角色响应播放时显示字幕或说话指示器。

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

#### 主持人文本注入

一个训练模拟场景，主持人可以输入一条消息，让 AI 角色接收并回应，而无需使用麦克风。

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

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

### 故障排查

| 症状                                         | 可能原因                                                                   | 修复                                                                                                                             | 验证                                                        |
| ------------------------------------------ | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- |
| 输入后角色没有开始说话                                | 会话未连接、音频未发送，或者文本消息未提交                                                  | 检查 `GetChatbotConnectionState`，确认玩家组件已初始化，并验证你的输入事件是否调用了 `MuteStreamingAudio` 或 `SendText`.                                    | `GetIsTalking` 变为 `true` ，在第一段音频响应播放时。                    |
| 录音指示器从不关闭                                  | UI 绑定到了 `IsListening`，而该函数当前返回 `false`                                 | 请根据输入的按下/释放事件来驱动录音 UI，而不是依赖 `IsListening`.                                                                                     | 该指示器会完全跟随按钮状态。                                            |
| 动作已到达 `OnActionReceivedEvent_V2` 但没有执行任何操作 | `FetchFirstAction` 未在事件处理器内部调用，或者 `HandleActionCompletion` 未在每次动作执行后调用 | 调用 **Fetch First Action** 在 **On Actions Received** 处理器。执行动作后，务必调用 **Handle Action Completion** 与 `true` 在成功时调用，或 `false` 失败时。 | 一个 **打印字符串** 在获取到的动作名称上调用，以确认已接收。每次完成调用后，序列中的下一个动作就会变为可用。 |
| `InterruptSpeech` 没有明显效果                   | 在 `GetIsTalking` 为 `false` 期间调用——没有音频在播放                               | 用一个 **Get Is Talking** 检查来保护该调用。仅在角色处于说话状态时调用 `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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

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

The question should be specific, self-contained, and written in natural language.
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.
