> 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/character-actions/dispatcher-and-batch-policies.md).

# 分发器和批处理策略

`ConvaiActionDispatcher` 是动作系统的运行时执行层。它会监听来自 Convai 的命令批次，将每个动作和目标与当前会话的配置进行解析，并一次一步地调用绑定的执行器组件。两种策略控制在执行过程中收到新批次时会发生什么，以及某一步失败时会发生什么。

### 组件概览

| 属性       | 值                                                                |
| -------- | ---------------------------------------------------------------- |
| **菜单路径** | `添加组件 → Convai → Convai Action Dispatcher`                       |
| **命名空间** | `Convai.Runtime.Actions`                                         |
| **约束**   | `DisallowMultipleComponent`, `RequireComponent(ConvaiCharacter)` |

该分发器必须位于同一个 `GameObject` 作为 `ConvaiCharacter`。每个角色只允许一个分发器。

<figure><img src="/files/e55d8b16b7de1d6a975f1d00b2eb83e35fdface2" alt="Unity Inspector showing the ConvaiActionDispatcher component with Batch Policy, Failure Policy, and lifecycle UnityEvent fields visible"><figcaption><p>检查器中的 ConvaiActionDispatcher——两个策略下拉框控制队列和失败行为；七个生命周期 UnityEvent 字段公开完整的批处理和步骤执行流水线。</p></figcaption></figure>

### Inspector 字段

| 字段                  | 类型                                 | 默认值         | 说明                      |
| ------------------- | ---------------------------------- | ----------- | ----------------------- |
| `_batchPolicy`      | `ConvaiActionBatchPolicy`          | `队列`        | 当另一个批次正在执行时，传入批次的行为方式   |
| `_failurePolicy`    | `ConvaiActionBatchFailurePolicy`   | `StopBatch` | 某一步失败后，是中止剩余批次还是允许其继续执行 |
| `_onBatchStarted`   | `UnityEvent`                       | —           | 在批次开始执行时触发              |
| `_onStepStarted`    | `ConvaiActionInvocationUnityEvent` | —           | 在每一步开始时触发               |
| `_onStepSucceeded`  | `ConvaiActionInvocationUnityEvent` | —           | 在步骤执行器返回时触发 `成功`        |
| `_onStepFailed`     | `ConvaiActionInvocationUnityEvent` | —           | 当某一步因任何原因失败时触发          |
| `_onStepUnhandled`  | `ConvaiActionInvocationUnityEvent` | —           | 当执行器返回时触发 `未处理`         |
| `_onBatchCompleted` | `UnityEvent`                       | —           | 当所有步骤都完成且未被中止时触发        |
| `_onBatchAborted`   | `UnityEvent`                       | —           | 当批次因失败策略而被提前截断时触发       |

`ConvaiActionInvocationUnityEvent` 是一个可序列化的 `UnityEvent<ConvaiActionInvocation>`。在检查器中将其像标准 `UnityEvent` 一样连接——事件参数承载完整的调用上下文（动作名称、目标、角色、批次和步骤索引）。

### 批处理策略

当 Convai 返回新的动作批次，而分发器仍在执行上一个批次时，批处理策略决定会发生什么。

| 策略               | 枚举值 | 行为                                                         |
| ---------------- | --- | ---------------------------------------------------------- |
| `队列`             | `0` | 新批次会在队列中等待。当前批次会先完成，然后下一个批次才开始。适用于大多数场景。                   |
| `ReplaceCurrent` | `1` | 取消当前正在执行的步骤并清除所有已排队的批次。新批次会立即开始。适用于中断驱动的场景（例如：“停下，改来这里。”）。 |
| `DropIncoming`   | `2` | 在当前批次及所有排队批次完成之前，丢弃新批次。用于正在进行的序列不能被中断的情况（例如，必须完成的安全演示）。    |

{% hint style="info" %}
`ReplaceCurrent` 取消 **当前正在运行的执行器步骤** 通过 `CancellationToken` 并在启动新步骤前清除所有待处理批次。执行器必须遵守取消令牌，这样才能立刻生效——参见 [编写自定义动作执行器](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/writing-custom-executors.md).
{% endhint %}

<figure><img src="/files/3689d64b2efb727ea09c0efd6e211c001db2062b" alt="Unity Inspector showing the Batch Policy dropdown on ConvaiActionDispatcher expanded with Queue, ReplaceCurrent, and DropIncoming options"><figcaption><p>批处理策略下拉框——Queue 是默认值，适用于大多数场景；ReplaceCurrent 处理中断驱动的 NPC 行为；DropIncoming 保护必须执行到完成的序列。</p></figcaption></figure>

### 失败策略

失败策略控制当执行器返回非成功结果（`失败`, `未处理`, `Canceled`，或 `超时`).

| 策略              | 枚举值 | 行为                                            |
| --------------- | --- | --------------------------------------------- |
| `StopBatch`     | `0` | 批次中的剩余步骤会被跳过。 `OnBatchAborted` 会触发。           |
| `ContinueBatch` | `1` | 无论是否失败，执行都会继续到下一步。 `OnBatchCompleted` 会在末尾触发。 |

使用 `ContinueBatch` 适用于彼此独立的动作——失败的“指向”不应阻止后续的“挥手”。在 `StopBatch` （默认值）中用于相互依赖的序列——失败的“移动到”应该阻止后续原本也会失败的“拾取”。

<figure><img src="/files/fd04a444c58dd3f74de5d6c6877959de55ca2941" alt="Unity Inspector showing the Failure Policy dropdown on ConvaiActionDispatcher expanded with StopBatch and ContinueBatch options"><figcaption><p>失败策略下拉框——StopBatch（默认）会中止剩余步骤并触发 OnBatchAborted；ContinueBatch 会让失败继续向后执行，并在末尾触发 OnBatchCompleted。</p></figcaption></figure>

### 生命周期事件

分发器会在批处理和步骤执行的每个重要阶段触发事件。可以通过 UnityEvent 字段在检查器中订阅，也可以通过属性在 C# 中订阅。

<figure><img src="/files/15270201fa35bb13d1231aee246b75289d72f62d" alt="Unity Inspector showing the ConvaiActionDispatcher lifecycle UnityEvent fields: OnBatchStarted, OnStepStarted, OnStepSucceeded, OnStepFailed, OnStepUnhandled, OnBatchCompleted, and OnBatchAborted"><figcaption><p>分发器生命周期 UnityEvent 字段——在检查器中连接这些字段，以响应批处理和步骤转换，而无需编写分发器侧 C# 代码。</p></figcaption></figure>

#### 事件触发顺序

```
OnBatchStarted
  → OnStepStarted       （每个步骤）
  → OnStepSucceeded     （如果执行器返回 Succeeded）
     或
  → OnStepFailed        （如果执行器返回 Failed、Canceled 或 TimedOut）
     或
  → OnStepUnhandled     （如果执行器返回 Unhandled）
OnBatchCompleted  （所有步骤完成，或 ContinueBatch 允许失败继续执行）
  或
OnBatchAborted    （StopBatch 策略在失败后提前终止了批次）
```

#### 在 C# 中订阅

```csharp
using Convai.Runtime.Actions;
using UnityEngine;

public sealed class ActionFeedback : MonoBehaviour
{
    [SerializeField] private ConvaiActionDispatcher _dispatcher;

    private void OnEnable()
    {
        _dispatcher.OnBatchStarted.AddListener(HandleBatchStarted);
        _dispatcher.OnStepSucceeded.AddListener(HandleStepSucceeded);
        _dispatcher.OnStepFailed.AddListener(HandleStepFailed);
        _dispatcher.OnBatchCompleted.AddListener(HandleBatchCompleted);
        _dispatcher.OnBatchAborted.AddListener(HandleBatchAborted);
    }

    private void OnDisable()
    {
        _dispatcher.OnBatchStarted.RemoveListener(HandleBatchStarted);
        _dispatcher.OnStepSucceeded.RemoveListener(HandleStepSucceeded);
        _dispatcher.OnStepFailed.RemoveListener(HandleStepFailed);
        _dispatcher.OnBatchCompleted.RemoveListener(HandleBatchCompleted);
        _dispatcher.OnBatchAborted.RemoveListener(HandleBatchAborted);
    }

    private void HandleBatchStarted() => Debug.Log("批次已开始");
    private void HandleStepSucceeded(ConvaiActionInvocation inv) =>
        Debug.Log($"步骤成功：{inv.Command.Name}");
    private void HandleStepFailed(ConvaiActionInvocation inv) =>
        Debug.LogWarning($"步骤失败：{inv.Command.Name}");
    private void HandleBatchCompleted() => Debug.Log("批次已完成");
    private void HandleBatchAborted() => Debug.LogWarning("批次已中止");
}
```

### 手动批次注入

`EnqueueActions(IReadOnlyList<ConvaiActionCommand> actions)` 以编程方式向分发器提交一个批次，并遵循当前的批处理与失败策略。可用于脚本化演示流程、自动化测试运行，或由游戏事件而非玩家语音触发的 NPC 行为。

```csharp
using System.Collections.Generic;
using Convai.Runtime.Actions;
using Convai.Shared.Types;
using UnityEngine;

public sealed class DemoTrigger : MonoBehaviour
{
    [SerializeField] private ConvaiActionDispatcher _dispatcher;

    public void RunSafetyDemo()
    {
        _dispatcher.EnqueueActions(new List<ConvaiActionCommand>
        {
            new ConvaiActionCommand("Move To", "Extinguisher"),
            new ConvaiActionCommand("Pick Up", "Extinguisher"),
            new ConvaiActionCommand("Move To", "Exit")
        });
    }
}
```

分发器会按顺序执行这些步骤。如果 `BatchPolicy` 为 `队列`，则该批次会排在任何已在进行中的批次之后等待。

### 绕过分发器

如果你希望在不经过分发器的目标解析和执行流水线的情况下响应原始动作命令，请订阅 `ConvaiCharacter.OnActionsReceived` ：

```csharp
using System.Collections.Generic;
using Convai.Runtime.Components;
using Convai.Shared.Types;
using UnityEngine;

public sealed class ManualActionHandler : MonoBehaviour
{
    [SerializeField] private ConvaiCharacter _character;

    private void OnEnable() =>
        _character.OnActionsReceived += HandleActions;

    private void OnDisable() =>
        _character.OnActionsReceived -= HandleActions;

    private void HandleActions(IReadOnlyList<ConvaiActionCommand> commands)
    {
        foreach (ConvaiActionCommand cmd in commands)
            Debug.Log($"动作：{cmd.Name}，目标：{cmd.Target}");
    }
}
```

{% hint style="warning" %}
绕过分发器意味着没有自动目标解析、没有批处理/失败策略，也没有生命周期事件。这适用于只读观察或自定义分发流水线，但不适用于 SDK 应驱动行为的典型游戏玩法。
{% endhint %}

### 分发器生命周期行为

| 情况          | 分发器行为                                         |
| ----------- | --------------------------------------------- |
| 分发器已禁用      | 活动工作被取消；队列被清空                                 |
| 分发器被销毁      | 与禁用时相同                                        |
| 收到空批次       | 静默忽略——不触发任何事件                                 |
| 动作名称不在本地定义中 | 步骤失败： `OnStepFailed` 触发； `StopBatch` 中止批次     |
| 未分配执行器字段    | 步骤失败： `OnStepFailed` 触发                       |
| 未满足目标要求     | 步骤失败： `OnStepFailed` 触发                       |
| 执行器返回 `未处理` | `OnStepUnhandled` 触发；在……中被视为失败 `StopBatch` 策略 |

### 使用示例

#### 示例 1——培训清单集成

**场景：** 企业入职模拟。NPC 完成每个设备演示后，清单 UI 会前进一步。

连接 `OnBatchCompleted` 在检查器中将其连接到 `TrainingChecklistManager.AdvanceStep()`。每当 NPC 完成一个完整序列时，清单会自动前进。

```csharp
// TrainingChecklistManager.cs
public void AdvanceStep()
{
    _currentStep++;
    UpdateChecklistUI();
}
```

分发器侧不需要额外代码——只需将 `OnBatchCompleted` UnityEvent 在检查器中连接即可。

#### 示例 2——导航失败时的备用对话

**场景：** 当 NPC 无法到达目标（NavMesh 路径被阻挡）时，它应该说出一条备用台词，而不是静默停止。

订阅 `OnStepFailed` 并注入一个动态上下文更新：

```csharp
private void HandleStepFailed(ConvaiActionInvocation invocation)
{
    if (invocation.Command.Name == "Move To")
    {
        string targetName = invocation.Command.Target ?? "那个位置";
        // 注入到动态上下文中，以便 NPC 自然地承认失败
        _character.DynamicContext.AddEvent($"无法到达 {targetName}——路径被阻挡了。");
    }
}
```

### 下一步

{% content-ref url="/pages/c5598abd0ddd72fa75a0989ad602a5b4d12e16d7" %}
[编写自定义动作执行器](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/writing-custom-executors.md)
{% endcontent-ref %}

{% content-ref url="/pages/0341126fa4c492311dab4fb6aca6d0c64191016b" %}
[角色动作脚本参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/actions-scripting-reference.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-unity-sdk/features/character-actions/dispatcher-and-batch-policies.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.
