> 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-unity-sdk/features/narrative-design/troubleshooting-and-diagnostics.md).

# 排查叙事设计问题

使用内置验证与诊断工具，解决触发器状态失败、Inspector 配置错误、获取错误和队列超时问题。

大多数 Narrative Design 问题都属于三类之一：触发器未触发、章节事件无响应，或者后端获取失败。本页将涵盖这三种情况，先从内置状态系统开始，位于 `ConvaiNarrativeDesignTrigger` 并逐步排查 Inspector 中最常见的配置错误。

### 首要排查

当某些功能不工作时，在深入查看具体症状之前先按此检查清单逐项排查。大多数问题在第 2 步或第 3 步就能解决。

{% stepper %}
{% step %}

#### 检查触发器上的 CurrentStatus

选中 `ConvaiNarrativeDesignTrigger` 在 Inspector 中的 GameObject。 **当前状态** 显示在组件顶部。除 `Ready` 之外的任何值都会立即告诉你触发器正在等待什么——请参阅下方的 TriggerStatus 参考表获取解决方案。
{% endstep %}

{% step %}

#### 启用诊断并重现问题

在 Trigger 组件中，启用 **启用诊断**。按下 Play 并重复应触发触发器的操作。每一次状态转换——区域进入/退出、队列开始、角色就绪检测、触发发送——都会记录到 Console。按从上到下的顺序阅读日志，找出链路在哪一步中断。

```csharp
// 或通过代码启用
trigger.SetDiagnosticsEnabled(true);
```

{% endstep %}

{% step %}

#### 验证角色 ID 和 API 密钥

打开 **Edit > Project Settings > Convai SDK** 并确认 API 密钥已存在。选择你角色的 GameObject，并确认 **角色 ID** 上的字段 `ConvaiCharacter` 不为空。如果其中任意一项缺失，从触发器的角度看，获取操作和会话连接都会静默失败。
{% endstep %}

{% step %}

#### 导出完整触发器状态

调用 `PrintDiagnostics()` 从测试脚本中调用，或者按下 **Invoke** / **重置** 在 Play Mode 下组件上显示的按钮。导出内容会一次性显示所有字段，因此不匹配一目了然：

```csharp
trigger.PrintDiagnostics();
```

{% endstep %}

{% step %}

#### 运行 ValidateConfiguration

```csharp
if (!trigger.ValidateConfiguration())
{
    foreach (string warning in trigger.ValidationWarnings)
        Debug.LogWarning($"Trigger validation: {warning}");
}
```

或者启用 **启动时验证** 在 Inspector 中的该选项，这样它会在每次 Play 会话开始时自动运行。
{% endstep %}
{% endstepper %}

### TriggerStatus 参考

`ConvaiNarrativeDesignTrigger.CurrentStatus` 会始终报告触发器的当前状态。用它来了解为什么触发器没有触发。

| 状态                          | 原因                                    | 解决方案                                                    |
| --------------------------- | ------------------------------------- | ------------------------------------------------------- |
| `Ready`                     | 正常——等待激活条件。                           | 无需操作。                                                   |
| `AlreadyFired`              | `TriggerOnce` 已启用且触发器已触发。             | 调用 `ResetTrigger()` 以重新武装它，或禁用 **仅触发一次** 在 Inspector 中。 |
| `QueuedWaitingForCharacter` | 触发器已被接受，但角色尚未进入活动对话。                  | 等待会话打开。触发器会自动触发。调用 `CancelQueuedTrigger()` 以中止队列。       |
| `ConfigurationError`        | `ValidateConfiguration()` 检测到一个或多个问题。 | 读取 `ValidationWarnings` （参见以编程方式验证配置）并修复每个问题。           |
| `Disabled`                  | 该组件或其父级 GameObject 已被禁用。              | 启用该组件或 GameObject。                                      |

### 常见问题

| 症状                                     | 可能原因                               | 修复方法                                                                                                                                            |
| -------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| 在以下操作后章节列表为空 **与后端同步**                 | API 密钥缺失或无效                        | 验证你的 API 密钥——请参阅 [配置 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/getting-started/configure-api-key.md)；检查 **上次获取错误** 在 Manager 上 |
| 在以下操作后章节列表为空 **与后端同步**                 | 未设置角色 ID                           | 设置 **角色 ID** 在 `ConvaiCharacter` 组件                                                                                                             |
| `OnTriggerActivated` 触发了但章节始终不变        | 触发器名称与仪表板边缘名称不完全匹配（区分大小写）          | 点击 **获取** 在 Trigger 上，从下拉菜单中重新选择正确的触发器                                                                                                          |
| `OnSectionStart` 尽管章节变化了却从未触发          | 本地章节 ID 与仪表板不同步                    | 点击 **与后端同步** 在 Manager 上；如果仍然有问题，请调用 `ClearAllSectionConfigs()` 并重新同步                                                                           |
| `OnPlayerEnterZone` 从未触发（Collision 模式） | **Is Trigger** 在 Collider 上被禁用     | 启用 **Is Trigger** 在 Collider 组件上                                                                                                                |
| `OnPlayerEnterZone` 从未触发（Collision 模式） | 没有 `Rigidbody` 在任一对象上              | 添加一个 `Rigidbody` 到触发器 GameObject 或玩家                                                                                                            |
| `OnPlayerEnterZone` 从未触发（Collision 模式） | Player GameObject 的标签未设置为 `Player` | 将标签设置为 `Player` 在 Inspector 中                                                                                                                   |
| 错误的对象触发了触发器                            | **玩家层** 掩码设置为 `无` (0)              | 设置 **玩家层** 到玩家所在的图层                                                                                                                             |
| 未识别 Player 标签                          | 该标签未在 Unity 的 Tag Manager 中定义      | 在以下位置添加该标签 **Edit > Project Settings > Tags and Layers**                                                                                        |
| “发现多个 ConvaiCharacters” 警告             | `自动查找角色` 无法消除歧义                    | 在以下位置显式指定目标角色 **Character** 字段                                                                                                                  |
| 章节显示 **孤立** 徽标                         | 在本地同步后，章节已从仪表板中删除                  | 如果这是有意的：手动移除条目。如果是误删：在仪表板上恢复，然后点击 **与后端同步**                                                                                                     |
| 模板键对角色对话没有影响                           | 键名与仪表板占位符大小写不匹配                    | 精确比对键： `{playerName}` 在仪表板上 → 键 `playerName`，而不是 `PlayerName`                                                                                   |

### 启用诊断

`ConvaiNarrativeDesignTrigger` 内置诊断日志记录器。可从 Inspector 或代码中启用：

```csharp
trigger.SetDiagnosticsEnabled(true);
```

启用诊断后，每一次状态转换——区域进入/退出、队列开始、角色就绪检测、触发发送——都会通过以下方式记录到 Console： `ConvaiLogger.Debug`.

要随时将触发器的完整当前状态输出到 Console：

```csharp
trigger.PrintDiagnostics();
```

`PrintDiagnostics()` 日志：

```
[ConvaiNarrativeDesignTrigger] === DIAGNOSTICS ===
  GameObject：TriggerZone_Checkpoint1
  状态：QueuedWaitingForCharacter
  已触发：False
  仅触发一次：True
  触发器名称：'CheckpointReached'
  触发器 ID：'a1b2c3d4-...'
  激活模式：Collision
  已分配角色：SafetyInstructor
  角色就绪：False
  玩家在区域内：True
  玩家 Transform：PlayerController
  已加入就绪队列：True
  上次错误：无
  验证警告：0
===========================
```

在 Play Mode 下，Inspector 还会显示一个 **Invoke** 按钮（触发 `InvokeTrigger()`）以及一个 **重置** 按钮（触发 `ResetTrigger()`），可直接在 Inspector 中使用，无需编写任何代码。

### 以编程方式验证配置

```csharp
bool valid = trigger.ValidateConfiguration();

if (!valid)
{
    foreach (string warning in trigger.ValidationWarnings)
        Debug.LogWarning($"Trigger validation: {warning}");
}
```

`ValidateConfiguration()` 会执行四项自动检查：

1. **角色引用检查**：验证已分配角色，并实现 `IConvaiCharacterAgent`.
2. **触发器名称检查**：验证至少有一个 **触发器名称** 或 **触发消息** 非空。
3. **Collider 检查** （Collision 和 TimeBased 模式）：验证存在一个 `Collider` 位于同一个 GameObject 上，并且 **Is Trigger** 已启用，则自动查找。
4. **玩家检测检查**：验证 **玩家标签** 已在 Unity 的 Tag Manager 中定义，并在以下情况时发出警告 **玩家层** 设置为 `无` (0).

启用 **启动时验证** 在 Inspector 中这样设置，以便自动运行此检查，在 `Start()` 从 Play Mode 开始时就捕捉问题。

### 获取失败

如果 `FetchAndSyncFromBackend()` 失败：

1. **上次获取错误** 在 Manager 的 Inspector 中会显示确切的错误字符串。
2. 调用 `ClearFetchError()` 在解决问题后重置错误显示：

```csharp
narrativeManager.ClearFetchError();
```

常见原因：

| Error                                                | 原因                                                                                                                   |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `“未配置 API 密钥。请在 Project Settings > Convai SDK 中设置。”` | 未设置 API 密钥——请参阅 [配置 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/getting-started/configure-api-key.md) |
| `“需要角色 ID。”`                                         | 以下对象上的 Character ID 字段为空： `ConvaiCharacter`                                                                          |
| `“异常：...”`                                           | 网络错误，或无法访问 Convai                                                                                                    |
| `“未分配角色，或者角色没有 ID。”`                                 | Manager 没有角色引用，并且自动检测失败                                                                                              |

你还可以检查以下结果： `FetchAndSyncFromBackendAsync()` 在代码中：

```csharp
SectionSyncResult result = await narrativeManager.FetchAndSyncFromBackendAsync();
if (!result.Success)
    Debug.LogError($"Sync failed: {result.Error}");
```

### 待处理状态

当在角色会话打开之前发送模板键或触发器时，SDK 会将它们保存在内部队列中。它们会自动发送——你无需手动重新发送任何内容。

| 事件        | 发生了什么                                                             |
| --------- | ----------------------------------------------------------------- |
| 会话打开      | `FlushPending()` 会在内部调用；所有已排队的键和触发器都会按顺序发送。                       |
| 会话断开并重新连接 | `MarkPendingReplayAfterDisconnect()` 会在内部调用；最新的模板键快照会在下一次连接时重新发送。 |

你可以调用 `SetTemplateKey` 或 `InvokeTrigger` 在场景生命周期中的任何时刻——包括在 `Awake` 或在 Play Mode 完全运行之前——而 SDK 会在连接就绪后正确传递这些值。

### 队列超时

`ConvaiNarrativeDesignTrigger`的 **排队等待就绪** 功能每 0.25 秒轮询一次角色是否就绪。超时时间由 **最长等待时间** （默认： `30` 秒）控制。

当达到超时时间时， `OnTriggerFailed` 会触发并显示消息：

```
等待角色就绪超时，已超过 30 秒。
```

要在超时前取消已排队的触发器：

```csharp
trigger.CancelQueuedTrigger();
```

{% hint style="warning" %}
设置 **最长等待时间** 为 `0` 会完全禁用超时。在会话始终无法连接的构建中（例如网络中断），等待协程会无限运行，直到场景卸载。对于正式发布版本，请始终设置合理的超时时间并处理 `OnTriggerFailed` 以便通知用户或优雅降级。
{% endhint %}

### 控制台日志参考

以下日志消息会在 **启用诊断** 开启或运行时发生错误时出现。

{% hint style="info" %}
SDK 的日志器会自动在每条 Console 条目前添加 `[SourceFileName]`，取自记录它的源文件——例如 `[ConvaiNarrativeDesignTrigger]` 或 `[ConvaiNarrativeDesignManager]`。下面的消息是跟在该前缀之后的消息正文；在 Console 中请搜索消息文本，而不是整行。通过触发器内部诊断助手记录的仅诊断行还会带有第二层内部前缀，即 GameObject 的名称，因此这些行显示为 `[ConvaiNarrativeDesignTrigger] [<GameObject name>] <message>`.
{% endhint %}

| 日志消息                                                  | 组件                             | 含义                                                        |
| ----------------------------------------------------- | ------------------------------ | --------------------------------------------------------- |
| `触发器“<name>”已在角色“<character>”上成功调用。`                  | `ConvaiNarrativeDesignTrigger` | 触发器已被接受并成功发送到后端。                                          |
| `触发器“<name>”已排队。正在等待角色就绪（最长 <N> 秒）。`                  | `ConvaiNarrativeDesignTrigger` | 角色会话尚未打开。连接后触发器将自动触发。                                     |
| `[<GameObject name>] 角色在 <N> 秒后变为就绪，正在发送已排队的触发器`      | `ConvaiNarrativeDesignTrigger` | 会话已打开；延迟的触发器现在正在发送。仅在以下情况下出现： **启用诊断** 已开启。               |
| `等待角色就绪超时，已超过 <N> 秒。`                                 | `ConvaiNarrativeDesignTrigger` | `MaxWaitTime` 已过。处理 `OnTriggerFailed` 并增加超时时间或检查会话连接。     |
| `触发器已触发且 TriggerOnce 已启用。调用 ResetTrigger() 以允许其再次触发。` | `ConvaiNarrativeDesignTrigger` | `TriggerOnce` 是 `true` 且触发器已触发。                           |
| `验证：<detail>`                                         | `ConvaiNarrativeDesignTrigger` | 在 Start 时检测到配置问题。请阅读 detail 字符串以了解具体字段。                   |
| `找到多个 ConvaiCharacters（<N> 个）。无法自动分配。请显式指定一个。`        | `ConvaiNarrativeDesignTrigger` | 自动查找存在歧义。将正确的角色拖入 **Character** 字段。                       |
| `章节切换：Previous=<id> → New=<id>`                       | `ConvaiNarrativeDesignManager` | 已收到章节切换。如果 `OnSectionStart` 未触发，则该章节 ID 不在本地配置列表中——请重新同步。 |
| `同步完成：新增 <N> 个，更新 <N> 个，孤立 <N> 个，重新激活 <N> 个`          | `ConvaiNarrativeDesignManager` | 上次的摘要 **与后端同步** 次调用。孤立计数非零表示仪表板中的章节已被移除。                  |
| `获取失败：<error>`                                        | `ConvaiNarrativeDesignManager` | API 密钥、角色 ID 或网络问题。检查 **上次获取错误** 在 Inspector 中。           |

### 触发器未触发

```mermaid
flowchart TD
    A[触发器未触发] --> B[检查 CurrentStatus]
    B --> C{状态？}
    C -- AlreadyFired --> D[调用 ResetTrigger\n或禁用 Trigger Once]
    C -- QueuedWaitingForCharacter --> E[等待会话\n或检查 MaxWaitTime]
    C -- ConfigurationError --> F[读取 ValidationWarnings\n修复每个问题]
    C -- Disabled --> G[启用组件\n或父级 GameObject]
    C -- Ready --> H{IsCharacterReady?}
    H -- false --> I{QueueUntilReady?}
    I -- false --> J[启用 Queue Until Ready\n或在触发前等待会话]
    I -- true --> K[触发器已排队\n等待会话打开]
    H -- true --> L{TriggerName 已设置？}
    L -- empty --> M[获取触发器并选择一个\n或在代码中调用 SetTrigger]
    L -- set --> N[检查网络连接\n和后端图配置]
```

使用 `CurrentStatus` 若要立即诊断，请启用 `EnableDiagnostics` 以跟踪完整事件链，并使用“常见问题”表来解决最常见的配置错误。

### 下一步

{% content-ref url="/pages/87ddb3e30dd1b009eb7bf39b583b5a654f486dbb" %}
[配置叙事设计触发器](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/narrative-design/setting-up-narrative-design-triggers.md)
{% endcontent-ref %}

{% content-ref url="/pages/e2aeb655628e9664d3a8c2993eb219a88fcfeef0" %}
[叙事设计脚本参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/narrative-design/scripting-narrative-design.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-unity-sdk/features/narrative-design/troubleshooting-and-diagnostics.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.
