> 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/dynamic-context/dynamic-context-usage-examples.md).

# 动态上下文使用示例

以下示例从单个继电器驱动的触发器逐步推进到脚本化批量更新以及同步的世界对象上下文。每个示例都列出了场景背景、具体的 Inspector 或脚本设置，以及预期的运行时结果。

{% hint style="info" %}
所有示例都假设 `ConvaiManager` 已在场景中，并配置了有效的 API 密钥，且每个 NPC 都有一个 `ConvaiCharacter` 组件，分配了 Character ID 并已连接到 Convai。第五个示例还额外假设至少有一个 `ConvaiCharacter` 在被跟踪值变化时已连接，因为世界对象更新会广播给每个已连接的角色。
{% endhint %}

### 安全演练：站点跟踪

**背景：** 一次消防抑制认证演练。一名训练员 NPC 引导操作员通过各个抑制站。角色必须始终知道操作员当前所在的站点，以便给出站点专属说明和危险警告。

#### 设置（继电器 + 触发脚本）

1. 添加 `ConvaiDynamicContextRelay` 添加到训练员 NPC 的 GameObject（**Convai → Dynamic Context → Convai Dynamic Context Relay**).
2. 在 **Defaults** 部分，设置 **Reaction Mode** 为 `MustRespond` ——角色应当回应每一次站点变更。
3. 启用 **Flush Immediately** ，这样每次站点变更都会立即发送，而不是等待正常的批处理窗口。
4. 向每个站点的触发器体积添加一个小型触发脚本，将每个实例指向同一个继电器：

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

public class StationZoneTrigger : MonoBehaviour
{
    [SerializeField] private ConvaiDynamicContextRelay _relay;
    [SerializeField] private string _stationName;

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
            _relay.SetState("Station", _stationName);
    }
}
```

5. 将 **Station Name** 设置为该区域的标签，例如 `Fire Suppression Bay`，并对每个额外的站点重复此操作。

`ConvaiDynamicContextRelay.SetState` 同时接受状态名和值，因此不能像单参数方法那样直接从 `UnityEvent` 在 Inspector 中绑定。上面的触发脚本会在运行时提供名称和每个区域的值；继电器会解析训练员的 `ConvaiCharacter` 并应用已配置的反应模式。

#### 预期结果

当操作员进入 Fire Suppression Bay 触发区域时， `StationZoneTrigger` 调用 `在继电器上调用` SetState("Station", "Fire Suppression Bay") `MustRespond` ，继电器会以

> "你已经到达 Fire Suppression Bay。鉴于当前极高的危险等级，在接触任何设备之前，请先确认你的 PPE 已穿戴好。"

该 `Station` 状态会保留在本地跟踪器中。如果操作员在任何时候问“我在哪里？”，角色都会用当前的站点值来回答。

### 新员工入职演示：批量状态更新

**背景：** 一次企业入职模拟。一名人力资源代表 NPC 会根据新员工已收集的物品以及已通过的检查点来调整引导。当两个条件同时满足时——一次调用同时发送它们，让角色把二者一起响应。

#### 设置（脚本）

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

public class OnboardingProgressTracker : MonoBehaviour
{
    [SerializeField] private ConvaiCharacter _hrCharacter;

    public void OnAccessCardAndBriefingComplete()
    {
        _hrCharacter.DynamicContext.SetStates(
            new Dictionary<string, string>
            {
                { "AccessCard", "Collected" },
                { "SecurityBriefing", "Completed" }
            },
            ConvaiRespondMode.MustRespond);
    }

    public void CheckIfReadyForFloorAccess()
    {
        bool hasCard = _hrCharacter.DynamicContext.TryGetStateValue("AccessCard", out string cardState)
                       && cardState == "Collected";
        bool hasBriefing = _hrCharacter.DynamicContext.TryGetStateValue("SecurityBriefing", out string briefingState)
                           && briefingState == "Completed";

        if (hasCard && hasBriefing)
            Debug.Log("Employee is ready for floor access.");
    }
}
```

#### 预期结果

`OnAccessCardAndBriefingComplete()` 一次性将两个状态加入队列。SDK 会将已排队的更新最多批处理 `ConvaiCharacter.DynamicContextBatchDelaySeconds` （默认 0.5 秒）后，再向 Convai 发送一次规范重建。因为 `MustRespond` 被请求，HR 角色会在批处理刷新后作出回应：

> "你已经拿到了门禁卡并完成了安全简报——你已获准进入楼层。下一步请前往 4B 工作站。"

`TryGetStateValue` 直接从本地跟踪器读取，不需要网络往返。如果该状态已被设置，它会返回当前值；如果从未设置或已被移除，则返回 `false` 。

### 导览游：展品跟踪与访客事件

**背景：** 一次博物馆导览。一名讲解员 NPC 跟踪当前激活的是哪个展品，并按时间顺序记录访客交互，然后利用这些历史记录给出个性化推荐。

#### 设置（两个继电器实例）

`ConvaiDynamicContextRelay` 每个 GameObject 只能包含一个实例，因此具有不同默认反应模式的每个继电器都放在讲解员 NPC 自己的一个子 GameObject 上。

**子 GameObject 1 — "ExhibitRelay"**

* 添加 `ConvaiDynamicContextRelay`.
* **Target → Auto Resolve Character:** 禁用； **Character:** 讲解员的 `ConvaiCharacter` ——继电器位于子 GameObject 上，而不是角色自身的 GameObject 上。
* **Defaults → Reaction Mode:** `Silent` ——展品名称会更新，但不会立即回应；导览叙事负责节奏推进。
* 向每个展品的触发器体积添加一个触发脚本（与第一个示例中的 `StationZoneTrigger` 相同模式），调用 `_relay.SetState("ActiveExhibit", _exhibitName)` 并将每个实例指向此继电器。

**子 GameObject 2 — "EventRelay"**

* 添加 `ConvaiDynamicContextRelay`.
* **Target → Auto Resolve Character:** 禁用； **Character:** 讲解员的 `ConvaiCharacter`.
* **Defaults → Reaction Mode:** `Auto` ——由 Convai 决定某次已记录的交互是否值得立即回应。
* 将 UI 按钮直接连接到 `AddEvent`. `AddEvent` 接收一个字符串参数，因此可以从按钮的 **On Click ()** 以静态字符串参数绑定——无需脚本。将一个按钮绑定到 `EventRelay → AddEvent` ，参数为 `访客询问了斗兽场重建`，再将第二个按钮绑定到 `AddEvent` ，参数为 `访客拍摄了角斗士展品`.

#### 预期结果

随着访客不断参观，讲解员的规范上下文会累积：

```
ActiveExhibit 是 Ancient Rome Collection
访客询问了斗兽场重建
访客拍摄了角斗士展品
```

讲解员会同时引用当前展品和访客的具体交互：

> "既然你拍摄了角斗士展品，你可能会喜欢隔壁房间里关于罗马军械的额外展陈。"

### 应急响应：多状态转换与反应升级

**背景：** 一次工业安全模拟。一名主管 NPC 必须对从例行检查同时切换到应急模式作出响应——三个状态变化和一个已记录事件会一起发生，角色必须在一次回应中全部予以确认。

#### 设置（脚本）

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

public class EmergencyResponseController : MonoBehaviour
{
    [SerializeField] private ConvaiCharacter _supervisorCharacter;

    public void TriggerChemicalLeak()
    {
        _supervisorCharacter.DynamicContext.SetStates(
            new Dictionary<string, string>
            {
                { "OperationMode", "Emergency" },
                { "HazardType", "Chemical Leak - Bay 7" },
                { "EvacuationStatus", "In Progress" }
            },
            ConvaiRespondMode.MustRespond);

        _supervisorCharacter.DynamicContext.AddEvent(
            "Bay 7 发生化学泄漏警报——已启动自动通风",
            ConvaiRespondMode.Silent);
    }
}
```

#### 预期结果

两个调用都在同一个去抖窗口内进入队列——即第一次排队变更后的最多 `ConvaiCharacter.DynamicContextBatchDelaySeconds` （默认 0.5 秒）之内。跟踪器将这三个状态和该事件合并为一次规范重建，并在整个批处理中保留请求中最强的反应（`MustRespond` 高于 `Silent`），因此角色只会产生一条回应，涵盖全部四项变化：

> "Bay 7 发生化学泄漏——所有人员立即撤离东翼。Bay 7 通风已启动。未获解除警报前不得重新进入。"

调用 `SetStates` 来处理这三个同时发生的转换，而不是连续调用三次 `SetState` ，可以让这些变化一起保留在角色用于叙述转换的 delta 行中。 `AddEvent` 调用会把警报作为单独的时间顺序行加入，而不会降低该批次已经请求的反应级别。

### 同步的世界对象上下文：共享设备状态

**背景：** 一次带有两个 NPC 的工业安全模拟——一名主管和一名安全讲师。两个角色都必须知道压力阀的开启或关闭状态，而不需要任一角色的脚本直接轮询阀门。

#### 设置（带有跟踪属性的世界对象）

1. 添加 `ConvaiObjectMetadata` 添加到阀门的 GameObject（**Convai → World Object**，或者在 **Add Component**).
2. 将 **中搜索“Convai World Object”** 为 `Object Name` 和 **Object Description** 填写为阀门位置的事实性描述。
3. 在 **Tracked Properties**，添加一个 `ConvaiTrackedContextProperty` 条目：
   * **Property Name:** `Status`
   * **Source Component:** 阀门的控制器脚本
   * **Source Member Name:** 报告当前状态的公共属性或字段名称，例如 `Status`
   * **Initial Value:** `Closed` ——仅在反射读取失败时使用
   * **Reaction:** `Auto` ——让 Convai 自行决定该状态变化是否值得提及

```csharp
using UnityEngine;

public class ValveController : MonoBehaviour
{
    [SerializeField] private bool _isOpen;

    public string Status => _isOpen ? "Open" : "Closed";

    public void SetOpen(bool isOpen) => _isOpen = isOpen;
}
```

SDK 会轮询每个具有 **Source Component** 的跟踪属性，且使用共享计时器。当 `ValveController.Status` 变化时， `ConvaiObjectMetadata` 会使用状态键 `PressureValve.Status`.

{% hint style="info" %}
向每个已连接角色广播更新后的值——不只是一个。若要在没有轮询的 **Source Component**情况下推送一个值，请调用 `SetTrackedPropertyValue("Status", "Open", ConvaiRespondMode.Auto)` 在 `ConvaiObjectMetadata` 组件上从你自己的脚本中调用，而不是配置一个反射源。当你已经明确知道值何时变化，并且想避免每帧进行一次反射读取时，请使用此方法。
{% endhint %}

#### 预期结果

一旦阀门打开，主管和安全讲师都会收到相同的状态更新：

```
PressureValve.Status is Open
```

任何一个 NPC 都可以在不需要专门脚本输入的情况下引用该阀门——例如，主管会说：“压力阀已打开——在确认关闭之前保持原位。” 禁用或移除 `ConvaiObjectMetadata` 组件会移除 `PressureValve.Status` 状态，并使所有正在跟踪它的角色都不再拥有该状态。

### 后续步骤

{% content-ref url="/pages/743bcc7de155496cbbf02a52a5577aee99f28aab" %}
[Relay 组件参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/dynamic-context/relay-component-reference.md)
{% endcontent-ref %}

{% content-ref url="/pages/5c3f9bcc544ac6f441fe54139ac1c670eeb5c958" %}
[动态上下文脚本 API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/dynamic-context/dynamic-context-scripting-api.md)
{% endcontent-ref %}

{% content-ref url="/pages/bb1aef3496a2be08987c770aa7b8072e7d8c5cd6" %}
[同步行为与时序](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/dynamic-context/sync-behavior-and-timing.md)
{% endcontent-ref %}

{% content-ref url="/pages/3e23af730226f449644f6a9c60f206a69124eb0e" %}
[场景元数据](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/scene-metadata.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, and the optional `goal` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/dynamic-context/dynamic-context-usage-examples.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
