> 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/scene-metadata/usage-examples.md).

# 场景元数据使用示例

用于医疗培训、工业演练、博物馆导览、运行时对象更新和跟踪属性状态的完整场景元数据设置。

以下示例涵盖了用于训练模拟和交互式体验的真实场景设置。每个示例都是自包含的：先描述 Inspector 配置，然后给出完成行为所需的脚本。请选择与你当前复杂度级别相匹配的示例开始。

### 示例 1：医疗训练模拟——解剖实验室

**场景：** 一个外科训练模拟，其中一名医疗导师 NPC 引导受训者完成解剖实验室。角色必须识别并描述房间中的实体模型和设备——受训者会问诸如“这是什么器官？”或“主动脉在哪里？”之类的问题。

#### 设置

添加 `ConvaiObjectMetadata` 适用于每个解剖模型和设备项：

| 对象名称 | 对象描述                           |
| ---- | ------------------------------ |
| 心脏模型 | 中央检查台上的真人大小解剖心脏模型。显示四个心腔和主要血管。 |
| 肝脏模型 | 展示架左侧安装的成人肝脏模型。肝静脉有颜色编码。       |
| 手术刀  | 放在器械托盘上的标准手术刀。手柄为蓝色。           |
| 听诊器  | 挂在检查台旁边挂钩上的听诊器。                |

添加 `ConvaiSceneMetadataCollector` 到 `ConvaiManager` GameObject。启用 **启动时收集**.

无需脚本。导师角色在会话开始时接收所有描述，并且可以回答基于实际场景的解剖学问题。

{% hint style="success" %}
受训者会问：“有哪些可供学习的模型？”导师回答：“在中央桌上有一个真人大小的心脏模型，显示四个心腔；在你左侧的展示架上是一个带颜色编码肝静脉的成人肝脏模型。”
{% endhint %}

### 示例 2：工业安全演练——基于阶段的元数据

**场景：** 一个包含多个演练阶段的安全培训模块。每个阶段引入不同的危险和设备。AI 导师只应了解与当前阶段相关的道具。

#### 设置

将 **启动时收集** 在……上禁用 `ConvaiSceneMetadataCollector`。使用脚本在每个阶段加载后发送元数据。

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

public class SafetyDrillController : MonoBehaviour
{
    [SerializeField] private ConvaiSceneMetadataCollector _metadataCollector;
    [SerializeField] private ConvaiObjectMetadata[] _phase1Props;
    [SerializeField] private ConvaiObjectMetadata[] _phase2Props;

    private ConvaiObjectMetadata[] _allProps;

    void Awake()
    {
        _allProps = GetComponentsInChildren<ConvaiObjectMetadata>(includeInactive: true);
    }

    public void LoadPhase(int phase)
    {
        // 排除所有道具
        foreach (var prop in _allProps)
            prop.IncludeInMetadata = false;

        // 仅启用当前阶段的道具
        ConvaiObjectMetadata[] activeProps = phase == 1 ? _phase1Props : _phase2Props;
        foreach (var prop in activeProps)
            prop.IncludeInMetadata = true;

        // 发送更新后的负载
        if (_metadataCollector.IsReadyToSendMetadata())
            _metadataCollector.CollectAndSendSceneMetadata();
    }
}
```

每个阶段只将其相关道具发送给 Convai。导师会根据当前演练上下文调整其知识，而不会了解其他阶段的道具。

### 示例 3：交互式博物馆——展品导览

**场景：** 一名虚拟博物馆导览角色会回答游客关于多个展厅中展品的问题。导览员应知道每件展品是什么、在哪里，以及它的重要意义。

#### 设置

添加 `ConvaiObjectMetadata` 附加到每个展品的根 GameObject。编写包含位置提示和关键信息的描述：

| 对象名称     | 对象描述                                           |
| -------- | ---------------------------------------------- |
| 罗塞塔石碑复制品 | 埃及展厅中一块大型石板，位于 2 号展厅中央。包含象形文字、世俗体文字和古希腊文的相同文本。 |
| 罗马军团士兵盔甲 | 位于 3 号展厅左侧墙边模特身上的全套军团士兵战斗盔甲。可追溯到公元 1 世纪。       |
| 维京长船残片   | 保存完好的 9 世纪维京长船船首部分，悬挂在北欧展厅的天花板上。               |

启用 **启动时收集**。当游客问“2 号展厅里有什么？”时，导览员会给出准确且有描述依据的信息。

请从一位知识渊博的导览员会说的话的角度来编写描述。包含房间位置、视觉识别特征和相关背景。AI 会使用 `对象描述` 字段的原文作为其回答的依据。

### 示例 4：运行时上下文更新——结合场景元数据和动态上下文

**场景：** 一个仓库培训场景，其中物品可以移动或移除。当某个危险被清除后，AI 应停止提及它。当有新工具到达时，AI 应立即知晓它。

#### 排除一个已清除的对象

```csharp
public void OnHazardCleared(ConvaiObjectMetadata hazardMetadata)
{
    // 从 AI 上下文中移除，但不销毁 GameObject
    hazardMetadata.IncludeInMetadata = false;

    if (_collector.IsReadyToSendMetadata())
        _collector.CollectAndSendSceneMetadata();
}
```

#### 在运行时添加一个新对象

```csharp
public void OnToolDelivered(GameObject toolObject, string toolName, string toolDescription)
{
    // 在运行时添加元数据组件
    var metadata = toolObject.AddComponent<ConvaiObjectMetadata>();
    metadata.ObjectName = toolName;
    metadata.ObjectDescription = toolDescription;
    // 组件会在 OnEnable 时自动注册

    if (_collector.IsReadyToSendMetadata())
        _collector.CollectAndSendSceneMetadata();
}
```

{% hint style="info" %}
场景元数据和动态上下文是互补的。使用场景元数据告诉 AI 场景中存在什么。使用动态上下文告诉 AI 运行时发生了什么。配对 `CollectAndSendSceneMetadata()` 和 `SetState` 调用 `IConvaiDynamicContext` 使角色同时具备对象感知和事件感知。
{% endhint %}

### 示例 5：仓库装卸区——作为受追踪属性的门状态

**场景：** 仓库安全培训 NPC 必须始终知道装卸区门是打开还是关闭，并且如果门传感器报告卡住，应立即作出反应。每次门移动后重新发送一份 `对象描述` 都需要一个脚本来拦截每次状态变化并重新运行场景元数据收集。受追踪属性可以让角色保持最新，而无需额外步骤。

#### 设置（声明式——基于反射的轮询）

添加 `ConvaiObjectMetadata` 到装卸区门的 GameObject。设置 **对象名称** 到 `LoadingBayDoor` 和 **对象描述** 为门的位置和用途的固定描述。在 **跟踪属性**，添加一个 `ConvaiTrackedContextProperty` 条目：

| 字段    | 值                            |
| ----- | ---------------------------- |
| 属性名称  | `DoorStatus`                 |
| 源组件   | 门的控制器脚本                      |
| 源成员名称 | `Status` ——报告当前状态的公共属性       |
| 初始值   | `关闭` ——仅在反射读取失败时使用           |
| 反应    | `自动` ——让 Convai 决定这种变化是否值得提及 |

```csharp
using UnityEngine;

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

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

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

`ConvaiObjectMetadata` 轮询每个具有一个 **源组件** 在共享的 0.25 秒计时器上进行。 当 `LoadingBayDoorController.Status` 更改时，更新后的值会以状态键 `LoadingBayDoor.DoorStatus` ——无需手动重新发送。

#### 设置（命令式——由代码事件推送）

传感器卡住是一个离散事件，不是每帧读取的值，因此应直接推送，而不是连接反射源。添加第二个 **跟踪属性** 条目，使用 **属性名称** 设置为 `SensorFault`, **初始值** 设置为 `无`，以及 **源组件** 留空。调用 `SetTrackedPropertyValue` 来自传感器自身的事件处理程序：

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

public class DoorSensorMonitor : MonoBehaviour
{
    [SerializeField] private ConvaiObjectMetadata _doorMetadata;

    public void OnSensorJamDetected()
    {
        _doorMetadata.SetTrackedPropertyValue("SensorFault", "Jammed", ConvaiRespondMode.MustRespond);
    }

    public void OnSensorCleared()
    {
        _doorMetadata.SetTrackedPropertyValue("SensorFault", "None", ConvaiRespondMode.Silent);
    }
}
```

`SetTrackedPropertyValue` 构建状态键 `LoadingBayDoor.SensorFault` 并立即将新值分发给每个已连接角色，完全绕过轮询计时器。

#### 预期结果

当受训者问“装卸区门开着吗？”时，培训员会根据当前 `LoadingBayDoor.DoorStatus` 值作答，而不是根据会话开始时写入的描述。如果 `OnSensorJamDetected()` 在门移动时触发， `MustRespond` 位于 `SensorFault` 上的反应

> “停下——装卸区门传感器报告卡住。请勿继续，直到维护人员排除故障。”

如果组件被禁用后又重新启用， `DoorStatus` 会重新读取 `LoadingBayDoorController.Status` 通过其 **源组件** 再次，而 `SensorFault` ——它没有运行时源——则会重置为其 **初始值** 的 `无`. 禁用或销毁 `ConvaiObjectMetadata` 会从每个正在跟踪它们的角色中移除这两个状态键。

### 下一步

{% content-ref url="/pages/f6f3f3d88a3636afea1b0c8774162c2014fba780" %}
[排查场景元数据问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/scene-metadata/troubleshooting-and-diagnostics.md)
{% endcontent-ref %}

{% content-ref url="/pages/eb13f9c057b5d7a65a7d8338048c0f7def05d5cf" %}
[动态上下文](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/dynamic-context.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/scene-metadata/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.
