> 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/update-actions-at-runtime.md).

# 在运行时更新角色动作

在会话进行中发送一个动作配置补丁，跟踪其更新 ID，并在确认后端已确认之前不要假定更改已生效。

使用 `ConvaiActionConfigPatch` 使用 `ConvaiCharacter.DynamicContext.Apply` 用于在不断开会话的情况下替换已连接角色的动作、对象、角色或注意力目标。场景在连接后发生变化——出现了新对象，某个目标变得不可用——并且角色的可供性需要同步时使用此功能。只有在 Convai 针对其更新 ID 返回成功确认后，此补丁才会生效。

### 前置条件

* 一个 `ConvaiCharacter` 已连接（`IsInConversation` 返回 `true`).
* 本地 `ConvaiActionDefinition` 对于补丁添加的任何动作名称，已经注册的条目——已打补丁的动作名称必须与本地可执行的定义匹配，无论该定义来自内联定义还是可复用的 Action Set（参见 [配置角色动作](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/configuring-actions.md)），否则整个更新在发送前就会被拒绝。
* 熟悉 [配置角色动作](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/configuring-actions.md).

### 发送运行时动作补丁

{% stepper %}
{% step %}

#### 构建补丁

只设置你想更改的字段。 `ConvaiActionConfigPatch` 采用省略与空值区分语义：一个 `null` 字段会保留已确认的值，空列表或空字符串会将其清除，而非空值会替换它。

```csharp
using System.Collections.Generic;
using Convai.Shared.Actions;

var patch = new ConvaiActionConfigPatch
{
    Objects = new List<ConvaiActionObjectDefinition>
    {
        new()
        {
            Name = "Lever",
            Description = "金属墙壁拉杆。",
            GameObjectReference = leverGameObject
        }
    }
};
```

| 字段                       | `null` （省略） | 空列表或字符串  | 非空值                                                  |
| ------------------------ | ----------- | -------- | ---------------------------------------------------- |
| `动作`                     | 保留已确认的动作列表  | 清除请求级动作  | 替换已确认的动作列表                                           |
| `对象`                     | 保留已确认的对象    | 清除已确认的对象 | 替换已确认的对象。同名替换会继承现有的本地 `GameObjectReference` 当新条目未设置时 |
| `角色`                     | 保留已确认的角色    | 清除已确认的角色 | 替换已确认的角色                                             |
| `CurrentAttentionObject` | 保留注意力目标     | 清除注意力目标  | 设置注意力目标。必须与中的名称匹配 `对象` 在替换应用后                        |

替换 `对象` 如果该目标不再存在，会自动清除过期的注意力目标。
{% endstep %}

{% step %}

#### 发送补丁

将补丁传递给 `DynamicContext.Apply` 配合显式的 `updateId` 这样你就可以关联后端确认：

```csharp
using Convai.Runtime;
using Convai.Runtime.DynamicContext;

character.DynamicContext.Apply(new ConvaiDynamicContextUpdate(
    text: null,
    reaction: ConvaiRespondMode.Silent,
    currentAttentionObject: "Lever",
    updateId: "lever-unlock-01",
    actionConfig: patch));
```

{% hint style="warning" %}
发送补丁不会立即更改 `ConvaiCharacter.ActionConfig` 。确认会按更新发送的顺序提交。错误状态、不匹配的确认、断开连接或 30 秒确认超时都会丢弃挂起的变更，而不会重试—— `ActionConfig` 始终反映后端最近确认的快照，而不是你发送的最新补丁。
{% endhint %}
{% endstep %}
{% endstepper %}

### 跟踪更新 ID

提供你自己的 `updateId` 在 `ConvaiDynamicContextUpdate` 而不是依赖 SDK 自动生成的那个。当 `updateId` 被省略时，SDK 会生成一个内部 ID 用于跟踪，但不会返回给调用方，因此你无法将其与后续确认匹配。

一条 `updateId` 一次只能有一个待处理的运行时动作变更。发送第二个带有 `updateId` 且仍在等待确认的请求会在本地被拒绝，并在控制台发出警告；请等待第一个更新完成，或使用不同的 `updateId`.

### 读取后端确认

订阅 `ConvaiManager.ActiveManager.Events.OnDynamicContextUpdateResultReceived` 并按以下内容过滤 `updateId` 你发送的：

```csharp
using Convai.Domain.DomainEvents.Runtime;
using Convai.Runtime.Components;

ConvaiManager.ActiveManager.Events.OnDynamicContextUpdateResultReceived += result =>
{
    if (result.UpdateId != "lever-unlock-01")
        return;

    if (result.Status == "success")
    {
        Debug.Log($"Actions confirmed: objects={result.ObjectsCount}, attention={result.CurrentAttentionObject}");
    }
    else
    {
        Debug.LogWarning($"Action patch failed: {result.Status}");
    }
};
```

`DynamicContextUpdateResultReceived` 除通用动态上下文字段外，还携带该动作更新的强类型元数据：

| 属性                                                | 类型        | 含义                                    |
| ------------------------------------------------- | --------- | ------------------------------------- |
| `UpdateId`                                        | `string`  | 你提供的 ID `ConvaiDynamicContextUpdate`. |
| `状态`                                              | `string`  | `"success"` 在补丁应用时；其他任何值都表示已被拒绝。      |
| `ActionConfigUpdated`                             | `bool?`   | 此确认是否包含动作配置更改。                        |
| `ActionConfigCreated`                             | `bool?`   | 后端是否为该会话创建了新的动作配置。                    |
| `ActionsCount`, `ObjectsCount`, `CharactersCount` | `int?`    | 补丁后已确认配置中的最终计数。                       |
| `CurrentAttentionObject`                          | `string`  | 补丁后的最终注意力对象。                          |
| `CurrentAttentionObjectCleared`                   | `bool?`   | 此更新是否清除了注意力目标。                        |
| `ActionGenerationStrategyChanged`                 | `bool?`   | 后端的动作生成策略是否发生变化。                      |
| `ActionGenerationStrategyStatus`                  | `string`  | 策略更改的状态字符串，包括 `"requires_reconnect"`. |
| `RawExtras`                                       | `JObject` | 尚未以强类型属性公开的字段的原始后端负载。                 |

当 `ActionGenerationStrategyStatus` 是 `"requires_reconnect"`，SDK 会公开该状态，但不会自动重新连接——如果新策略需要，请自行重新连接会话。

若要在代码中发送补丁之前预览其预测结果，请使用中所述 Action Debug 窗口中的运行时补丁组合器 [排查角色动作](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/debugging-and-troubleshooting.md).

### 故障排除

#### 补丁在发送前被拒绝

**症状：** 控制台会发出一条指出该字段名称的警告，例如 `action_config 动作 '...' 没有本地可执行定义` 或 `重复的动作目标名称 '...'`.

**原因：** 该补丁已在本地验证但失败——某个动作名称没有匹配的本地 `ConvaiActionDefinition`，某个目标名称为空或重复，或者当前注意力对象无法与补丁中的对象解析匹配。

**修复：** 更正警告中所命名的字段，并使用新的 `updateId`.

**验证：** 控制台没有显示拒绝警告，并且 `OnDynamicContextUpdateResultReceived` 稍后又针对同一个 `updateId`.

#### 始终没有收到确认

**症状：** `OnDynamicContextUpdateResultReceived` 从未针对你发送的 `updateId` 触发，并且 `ConvaiCharacter.ActionConfig` 也从未反映该补丁。

**原因：** 该更新在 30 秒确认超时、ACK 错误或确认元数据格式错误/不匹配后被丢弃——控制台会记录 `Runtime action mutation discarded update_id=<id> reason=<reasonCode>` 在这些情况下。Convai 响应之前的会话断开也会丢弃该更新，但不会有任何控制台消息。被丢弃的更新不会自动重试。

**修复：** 使用新的重新发送补丁 `updateId` 在确认角色已连接后（`IsInConversation` 是 `true`).

**验证：** `OnDynamicContextUpdateResultReceived` 以 `Status == "success"` 用于新的 `updateId`.

### 下一步

{% content-ref url="/pages/5b02ee57da9de48585f7ea92aa9e94714547d80a" %}
[动作目标解析的工作方式](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/attention-and-reference-grounding.md)
{% endcontent-ref %}

{% content-ref url="/pages/1398e3302b345ef93934a0e6c93b4d8e576ab00e" %}
[排查角色动作问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/debugging-and-troubleshooting.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/character-actions/update-actions-at-runtime.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.
