> 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/vision/scripting-api.md).

# Vision 脚本 API

Vision 脚本围绕 `ConvaiVisionPublisher` 用于发布控制， `ConvaiRoomManager` 用于按需查询 Vision 状态和触发，以及用于捕获状态的帧源状态接口。领域事件让你无需轮询即可响应生命周期变化和后端确认 `IsPublishing` 每一帧。

### `ConvaiVisionPublisher`

`ConvaiVisionPublisher` 是一个 `MonoBehaviour` 它管理 WebRTC 视频轨道。通过以下方式获取引用： `GetComponent` 或一个序列化字段。

#### 属性

| 属性             | 类型                    | 描述                                 |
| -------------- | --------------------- | ---------------------------------- |
| `IsPublishing` | `bool`                | `true` 当 WebRTC 视频轨道正在主动发送时。       |
| `FrameSource`  | `IVisionFrameSource`  | 当前正在使用的帧源。 `null` 直到运行时注册完成。       |
| `发布策略`         | `VisionPublishPolicy` | 当前的发布策略。                           |
| `视频轨道名称`       | `string`              | WebRTC 轨道的名称（默认： `"unity-scene"`). |

#### 方法

| 方法                                             | 描述                                          |
| ---------------------------------------------- | ------------------------------------------- |
| `SetPublishPolicy(VisionPublishPolicy policy)` | 更改客户端传输预算。会在下一帧发布时生效。                       |
| `EnablePublishing(bool enabled)`               | 在不更改所选策略的情况下开始或停止发布。仅当策略为 `手动`；对于自动发布策略则忽略。 |

#### 用法

```csharp
using Convai.Modules.Vision;
using Convai.Runtime.Vision.Publishing;
using UnityEngine;

public class VisionController : MonoBehaviour
{
    [SerializeField] private ConvaiVisionPublisher _publisher;

    void Start()
    {
        // 为此场景切换到高响应模式
        _publisher.SetPublishPolicy(VisionPublishPolicy.HighResponsiveness);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.V))
        {
            bool isPublishing = _publisher.IsPublishing;
            Debug.Log($"Track '{_publisher.VideoTrackName}' publishing: {isPublishing}");
        }
    }
}
```

### `IVisionFrameSource`

由所有内置帧源以及任何自定义源实现。

| 成员                     | 种类                    | 描述                                         |
| ---------------------- | --------------------- | ------------------------------------------ |
| `IsCapturing`          | `bool` 属性             | `true` 当源正在主动生成帧时。                         |
| `FrameCount`           | `long` 属性             | 自捕获开始以来生成的帧总数。                             |
| `FrameDimensions`      | `(int 宽度, int 高度)` 属性 | 输出分辨率。返回 `(0, 0)` 在初始化之前。                  |
| `TargetFrameRate`      | `float` 属性            | 配置的每秒帧数。                                   |
| `SourceId`             | `string` 属性           | 用于多源场景的标识字符串。                              |
| `CurrentRenderTexture` | `RenderTexture` 属性    | Y 轴翻转 `RenderTexture` 包含最新帧。 `null` 在未捕获时。 |
| `IsFrameReady`         | `bool` 属性             | `true` 在第一个可用帧可用后。                         |
| `FrameReady`           | `事件 Action`           | 每当有新帧可用时在 Unity 主线程上触发。                    |
| `StartCapture()`       | 方法                    | 开始帧捕获。                                     |
| `StopCapture()`        | 方法                    | 停止帧捕获并释放资源。                                |

### `IVisionFrameSourceStatusProvider`

由内置源实现的可选配套接口。提供更丰富的状态和错误信息。

| 成员               | 种类                         | 描述                                      |
| ---------------- | -------------------------- | --------------------------------------- |
| `状态`             | `VisionSourceState` 属性     | 当前生命周期状态。                               |
| `错误类型`           | `VisionSourceErrorKind` 属性 | 结构化错误类别，当 `State == Failed`.            |
| `状态消息`           | `string` 属性                | 可读的状态详情。                                |
| `HasUsableFrame` | `bool` 属性                  | `true` 当源至少生成了一帧有效帧时。                   |
| `StatusChanged`  | `事件 Action`                | 在以下情况触发：每当 `状态`, `错误类型`，或 `状态消息` 发生变化时。 |

### 监视状态变化

```csharp
using Convai.Runtime.Vision.Sources;
using UnityEngine;

public class FrameSourceMonitor : MonoBehaviour
{
    [SerializeField] private MonoBehaviour _frameSourceComponent;

    private IVisionFrameSourceStatusProvider _statusProvider;

    void Start()
    {
        _statusProvider = _frameSourceComponent as IVisionFrameSourceStatusProvider;
        if (_statusProvider != null)
            _statusProvider.StatusChanged += OnStatusChanged;
    }

    void OnDestroy()
    {
        if (_statusProvider != null)
            _statusProvider.StatusChanged -= OnStatusChanged;
    }

    private void OnStatusChanged()
    {
        Debug.Log($"[Vision] State: {_statusProvider.State}  Error: {_statusProvider.ErrorKind}  {_statusProvider.StatusMessage}");

        if (_statusProvider.State == VisionSourceState.Failed)
            HandleCaptureFailure(_statusProvider.ErrorKind);
    }

    private void HandleCaptureFailure(VisionSourceErrorKind errorKind)
    {
        switch (errorKind)
        {
            case VisionSourceErrorKind.PermissionDenied:
                // 显示提示用户授予摄像头权限的界面
                break;
            case VisionSourceErrorKind.DeviceUnavailable:
                // 提供切换到其他帧源的选项
                break;
        }
    }
}
```

### `VisionSourceState` 参考

| 状态     | 含义                                       |
| ------ | ---------------------------------------- |
| `空闲`   | 尚未开始捕获。                                  |
| `等待权限` | 等待用户授予摄像头权限（Android / iOS）。              |
| `启动中`  | 捕获正在初始化——设备正在打开， `RenderTexture`s 正在被创建。 |
| `就绪`   | 捕获正在运行，且帧正在生成。                           |
| `降级`   | 捕获正在运行，但帧健康检查检测到问题（例如连续的空白帧）。            |
| `已停止`  | 捕获已正常停止。                                 |
| `失败`   | 捕获失败且无法继续。检查 `错误类型` 和 `状态消息`.            |

### `ConvaiRoomManager` vision 方法

`ConvaiRoomManager` 实现了 `IConvaiRoomConnectionService` 并公开了三个运行时方法，这些方法在 SDK 4.4.0 中添加，用于在会话中查询和驱动动态 vision 上下文，而无需重新连接。可通过序列化的 `ConvaiRoomManager` 字段、自定义的 `IConvaiRoomConnectionService` 实现，或 `ConvaiManager.ActiveManager.TryGetRoomConnectionService(out IConvaiRoomConnectionService service)` 当没有场景引用可用时。

{% hint style="warning" %}
**SDK 4.4.0 中的破坏性变更。** `IConvaiRoomConnectionService` 新增了三个成员： `RequestVisionStatus(string updateId = null)`, `TriggerVision(ConvaiVisionTriggerRequest request)`，以及 `UpdateRespondMode(ConvaiRespondModeLane lane, ConvaiRespondMode mode, string updateId = null)`。仅通过 `ConvaiRoomManager` 使用该接口的代码不受影响。任何 `IConvaiRoomConnectionService` 的自定义实现都必须添加这三个方法——在 `false` 当该实现不支持 vision 时，每个方法都应返回该值。
{% endhint %}

| 方法                                                                                              | 返回     | 描述                                                                                                                      |
| ----------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------- |
| `RequestVisionStatus(string updateId = null)`                                                   | `bool` | 请求后端为当前会话提供动态 vision 缓冲区/状态诊断。后端会以 [`VisionContextStatusReceived`](#visioncontextstatusreceived).                       |
| `TriggerVision(ConvaiVisionTriggerRequest request)`                                             | `bool` | 请求后端为当前会话提供动态 vision 附加/响应行为——要求角色查看缓冲帧，并根据请求做出响应。后端会以 [`VisionContextTriggerReceived`](#visioncontexttriggerreceived). |
| `UpdateRespondMode(ConvaiRespondModeLane lane, ConvaiRespondMode mode, string updateId = null)` | `bool` | 在无需重新连接的情况下，为本次会话剩余部分更改一个输入通道的响应模式。后端会以 [`RespondModeUpdateResultReceived`](#respondmodeupdateresultreceived).          |

每个方法都会返回 `false` 当没有会话传输可用时（例如在房间连接之前）。

```csharp
using Convai.Runtime;
using Convai.Runtime.Adapters.Networking;
using Convai.Runtime.Vision.Context;
using UnityEngine;

public class VisionRuntimeQueries : MonoBehaviour
{
    [SerializeField] private ConvaiRoomManager _roomManager;

    public void QueryVisionStatus()
    {
        // 答案会以 VisionContextStatusReceived 的形式到达。
        _roomManager.RequestVisionStatus();
    }

    public void TriggerVisionLook()
    {
        var request = new ConvaiVisionTriggerRequest
        {
            Text = "桌子上有什么变化？",
            RespondMode = ConvaiRespondMode.MustRespond
        };
        request.SetFrameWindow(-5, -1); // 最近缓冲的五帧

        // 答案会以 VisionContextTriggerReceived 的形式到达。
        _roomManager.TriggerVision(request);
    }

    public void SwitchVisionToAuto()
    {
        // 由 RespondModeUpdateResultReceived 确认。
        _roomManager.UpdateRespondMode(ConvaiRespondModeLane.Vision, ConvaiRespondMode.Auto);
    }
}
```

### `ConvaiVisionTriggerRequest`

`Convai.Runtime.Vision.Context` — 密封类

通过以下方式发送的显式动态 vision 触发参数： `TriggerVision`。触发会请求后端将缓冲的 vision 帧附加到一次轮次中，并根据 `RespondMode`，调用模型。当未设置帧选择时，后端会附加最新的新鲜帧，直到其配置的每轮帧数上限。

```csharp
new ConvaiVisionTriggerRequest(string updateId = null)
```

| 参数         | 类型       | 默认值    | 描述                                                                                   |
| ---------- | -------- | ------ | ------------------------------------------------------------------------------------ |
| `updateId` | `string` | `null` | 幂等键，会在确认消息的 `update_id`。省略时会生成唯一 ID。重复使用相同 ID 会使请求具有幂等性——后端会重放原始确认，而不是再次触发，因此重试始终安全。 |

#### 属性

| 属性                 | 类型                    | 描述                                                                                     |
| ------------------ | --------------------- | -------------------------------------------------------------------------------------- |
| `UpdateId`         | `string`              | 此请求的幂等键，由构造函数设置。                                                                       |
| `文本`               | `string`              | 附随这些帧的可选提示，例如 `"桌子上有什么变化？"`。当为空时，后端会使用其通用的查看帧提示。                                       |
| `RespondMode`      | `ConvaiRespondMode?`  | 此触发如何影响角色的发言。 `null` 使用触发通道在连接时的默认值（`ConvaiVisionRespondModeSettings.Trigger`).        |
| `FrameWindowStart` | `int?`                | 相对帧窗口的起始位置，通过以下方式设置： `SetFrameWindow`.                                                 |
| `FrameWindowEnd`   | `int?`                | 相对帧窗口的结束位置，通过以下方式设置： `SetFrameWindow`.                                                 |
| `FramePtsIds`      | `IReadOnlyList<long>` | 按呈现时间戳（纳秒）进行的可选绝对帧选择，如确认消息中所报告（`attached_frame_pts`）以及 vision 状态响应中所示。当两者都设置时，它优先于帧窗口。 |

#### 方法

| 方法                                             | 描述                                                                                                                          |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `SetFrameWindow(int startIndex, int endIndex)` | 选择缓冲帧的相对窗口，例如 `SetFrameWindow(-5, -1)` 表示最近的五帧。负值从最新的缓冲帧开始向前计数（`-1` = 最新）；非负值是从最早保留帧开始的零基偏移。后端会将越界索引夹到最早保留帧，并在确认中报告实际附加了什么。 |
| `ClearFrameWindow()`                           | 清除先前设置的帧窗口，恢复默认的最新帧选择。                                                                                                      |

触发时的帧选择，按优先级顺序：

1. `FramePtsIds` — 按呈现时间戳进行绝对固定。免受过期窗口限制；若某时间戳对应的帧已离开缓冲区，触发将以 `frame_id_evicted` 结果失败。
2. `SetFrameWindow(startIndex, endIndex)` — 如上所述的相对窗口。
3. 未设置任何内容——后端会附加最新的新鲜帧，直到其配置的每轮帧数上限。

### `ConvaiRespondModeLane`

`Convai.Runtime.Vision.Context` — 枚举

标识哪个输入通道的响应模式 `UpdateRespondMode` 会被更改。用户文本和语音始终响应，且无法更改。

| 值               | 线上模态             | 描述                    |
| --------------- | ---------------- | --------------------- |
| `Vision`        | `vision`         | 新采样的 vision 帧。        |
| `ContextUpdate` | `context_update` | 动态上下文文本更新。            |
| `触发`            | `trigger`        | 不带每请求模式的显式 vision 触发。 |
| `SceneMetadata` | `scene_metadata` | 场景元数据更新。              |

### 领域事件

通过运行时订阅领域事件 `IEventHub` 以响应 Vision 生命周期变化和后端确认，而无需轮询 `IsPublishing` 每一帧。通过以下方式获取事件中心： `ConvaiManager.ActiveManager.TryGetEventHub(out IEventHub hub)`。所有 Vision 事件都是值类型（`只读结构体`）——只需分配一次处理器并持有引用。

```csharp
using Convai.Domain.DomainEvents.Vision;
using Convai.Domain.EventSystem;
using Convai.Runtime.Components;
using UnityEngine;

public class VisionAnalytics : MonoBehaviour
{
    private SubscriptionToken _captureStartedToken;
    private SubscriptionToken _captureStoppedToken;
    private SubscriptionToken _trackPublishedToken;
    private SubscriptionToken _trackUnpublishedToken;
    private SubscriptionToken _visionStatusToken;
    private SubscriptionToken _visionTriggerToken;
    private SubscriptionToken _respondModeToken;

    void Start()
    {
        if (ConvaiManager.ActiveManager == null) return;
        if (!ConvaiManager.ActiveManager.TryGetEventHub(out IEventHub hub)) return;

        _captureStartedToken = hub.Subscribe<VisionCaptureStarted>(OnCaptureStarted, EventDeliveryPolicy.MainThread);
        _captureStoppedToken = hub.Subscribe<VisionCaptureStopped>(OnCaptureStopped, EventDeliveryPolicy.MainThread);
        _trackPublishedToken = hub.Subscribe<VideoTrackPublished>(OnTrackPublished, EventDeliveryPolicy.MainThread);
        _trackUnpublishedToken = hub.Subscribe<VideoTrackUnpublished>(OnTrackUnpublished, EventDeliveryPolicy.MainThread);
        _visionStatusToken = hub.Subscribe<VisionContextStatusReceived>(OnVisionStatus, EventDeliveryPolicy.MainThread);
        _visionTriggerToken = hub.Subscribe<VisionContextTriggerReceived>(OnVisionTrigger, EventDeliveryPolicy.MainThread);
        _respondModeToken = hub.Subscribe<RespondModeUpdateResultReceived>(OnRespondModeUpdate, EventDeliveryPolicy.MainThread);
    }

    void OnDestroy()
    {
        if (ConvaiManager.ActiveManager == null) return;
        if (!ConvaiManager.ActiveManager.TryGetEventHub(out IEventHub hub)) return;

        hub.Unsubscribe(_captureStartedToken);
        hub.Unsubscribe(_captureStoppedToken);
        hub.Unsubscribe(_trackPublishedToken);
        hub.Unsubscribe(_trackUnpublishedToken);
        hub.Unsubscribe(_visionStatusToken);
        hub.Unsubscribe(_visionTriggerToken);
        hub.Unsubscribe(_respondModeToken);
    }

    private void OnCaptureStarted(VisionCaptureStarted e)
        => Debug.Log($"[Vision] 捕获已开始：{e.Width}x{e.Height} @ {e.FramesPerSecond} fps（源：{e.SourceId}）");

    private void OnCaptureStopped(VisionCaptureStopped e)
    {
        Debug.Log($"[Vision] 捕获在 {e.TotalFramesCaptured} 帧后停止。原因：{e.Reason}");
        if (e.IsError)
            Debug.LogError($"[Vision] 错误：{e.ErrorMessage}（代码：{e.ErrorCode}）");
    }

    private void OnTrackPublished(VideoTrackPublished e)
        => Debug.Log($"[Vision] 轨道 '{e.TrackName}' 已发布。SID：{e.TrackSid}");

    private void OnTrackUnpublished(VideoTrackUnpublished e)
        => Debug.Log($"[Vision] 轨道 '{e.TrackName}' 已取消发布。原因：{e.Reason}");

    private void OnVisionStatus(VisionContextStatusReceived e)
        => Debug.Log($"[Vision] 状态：{e.Outcome}（源：{e.ActiveSourceLabel}，最后一帧年龄：{e.LastFrameAgeMs} 毫秒）");

    private void OnVisionTrigger(VisionContextTriggerReceived e)
        => Debug.Log($"[Vision] 触发：{e.Outcome}，附加了 {e.FramesAttached} 帧，响应模式 {e.ActualRespondMode}");

    private void OnRespondModeUpdate(RespondModeUpdateResultReceived e)
        => Debug.Log($"[Vision] '{e.Modality}' 的响应模式现在为 '{e.Mode}'（状态：{e.Status}）");
}
```

### `视觉捕获已开始`

当帧源开始生成帧时触发。

| 属性         | 类型         | 描述                                      |
| ---------- | ---------- | --------------------------------------- |
| `宽度`       | `int`      | 以像素为单位的捕获宽度。                            |
| `高度`       | `int`      | 以像素为单位的捕获高度。                            |
| `每秒帧数`     | `float`    | 配置的帧率。                                  |
| `时间戳`      | `DateTime` | 捕获开始时的 UTC 时间。                          |
| `SourceId` | `string`   | 源标识符（来自 `IVisionFrameSource.SourceId`). |
| `宽高比`      | `float`    | `宽度 / 高度`.                              |
| `总像素数`     | `int`      | `宽度 * 高度`.                              |

### `视觉帧已捕获`

每次捕获到一帧时触发。该事件会在每个已捕获帧上触发——在 60 秒会话中以 15 fps 计算，即 900 个事件。请使用 `EventDeliveryPolicy.Immediate` 并保持处理程序轻量；对于分析用途，请每隔 N 帧采样一次，而不是订阅每个事件。

| 属性         | 类型         | 描述             |
| ---------- | ---------- | -------------- |
| `宽度`       | `int`      | 帧宽度（像素）。       |
| `高度`       | `int`      | 帧高度（像素）。       |
| `帧索引`      | `long`     | 从零开始的捕获帧索引。    |
| `字节大小`     | `long`     | 帧数据大小（字节）。     |
| `时间戳`      | `DateTime` | 帧被捕获时的 UTC 时间。 |
| `SourceId` | `string`   | 源标识符。          |

### `视觉捕获已停止`

当帧源停止生成帧时触发。

| 属性             | 类型         | 描述                                                                    |
| -------------- | ---------- | --------------------------------------------------------------------- |
| `已捕获帧总数`       | `long`     | 会话期间捕获的总帧数。                                                           |
| `时间戳`          | `DateTime` | UTC 停止时间。                                                             |
| `原因`           | `视觉捕获停止原因` | 捕获停止的原因（`用户请求`, `会话结束`, `摄像头丢失`, `错误`, `组件已禁用`).                      |
| `SourceId`     | `string`   | 源标识符。                                                                 |
| `错误消息`         | `string`   | 可读的错误详情。仅在 `Reason == Error`.                                         |
| `错误代码`         | `string`   | 来自以下项的结构化错误代码 `SessionErrorCodes` （Vision\* 常量）。仅在 `Reason == Error`. |
| `IsError`      | `bool`     | `true` 当 `Reason == Error`.                                           |
| `IsNormalStop` | `bool`     | `true` 当 `原因` 是 `用户请求` 或 `会话结束`.                                      |
| `HasErrorCode` | `bool`     | `true` 当 `错误代码` 非空时。                                                  |

### `视频轨道已发布`

当 WebRTC 视频轨道成功打开时触发。

{% hint style="warning" %}
`IsVisionTrack` 检查轨道名称 `"vision"`，而不是 `"unity-scene"`。使用默认轨道名称时， `IsVisionTrack` 返回 `false`。请使用 `TrackName` 直接识别轨道，或者将轨道重命名为 `"vision"` ，如果你的集成依赖于 `IsVisionTrack`.
{% endhint %}

| 属性              | 类型         | 描述                                           |
| --------------- | ---------- | -------------------------------------------- |
| `TrackSid`      | `string`   | LiveKit 轨道会话 ID。                             |
| `TrackName`     | `string`   | 由以下项设置的轨道名称： `视频轨道名称` （默认： `"unity-scene"`). |
| `时间戳`           | `DateTime` | UTC 发布时间。                                    |
| `RoomSessionId` | `string`   | 房间会话 ID。                                     |
| `IsVisionTrack` | `bool`     | `true` 当 `TrackName == "vision"` （不区分大小写）。   |

### `视频轨道已取消发布`

当 WebRTC 视频轨道被移除时触发。

| 属性                  | 类型           | 描述                                                                               |
| ------------------- | ------------ | -------------------------------------------------------------------------------- |
| `TrackSid`          | `string`     | LiveKit 轨道会话 ID。                                                                 |
| `TrackName`         | `string`     | 轨道名称。                                                                            |
| `时间戳`               | `DateTime`   | UTC 取消发布时刻。                                                                      |
| `原因`                | `视频轨道取消发布原因` | 轨道为何被取消发布（`用户请求`, `会话结束`, `源丢失`, `错误`, `组件已禁用`).                                 |
| `RoomSessionId`     | `string`     | 房间会话 ID。                                                                         |
| `IsVisionTrack`     | `bool`       | `true` 当 `TrackName == "vision"` （同样需要注意，见 `VideoTrackPublished.IsVisionTrack`). |
| `IsNormalUnpublish` | `bool`       | `true` 当 `原因` 是 `用户请求` 或 `会话结束`.                                                 |

### `VisionContextStatusReceived`

后端对一个 `vision-status` 查询的确认，该查询通过 `RequestVisionStatus`发送，用于描述会话动态视觉帧缓冲区的状态。

| 属性            | 类型         | 描述                                                                      |
| ------------- | ---------- | ----------------------------------------------------------------------- |
| `状态`          | `string`   | 响应状态： `成功`, `错误`, `处理中`，或 `待处理`.                                        |
| `消息`          | `string`   | 附带响应的可选可读消息。                                                            |
| `UpdateId`    | `string`   | 对请求幂等键的回显。                                                              |
| `结果`          | `string`   | 缓冲区结果： `有可用帧`, `缓冲区为空`, `无活动视频`，或 `未启用 vision`.                         |
| `活动源`         | `string`   | 后端为本次会话选择的视频源的参与者 ID（如果有）。                                              |
| `活动源标签`       | `string`   | 所选视频发布者的源标签（例如 webcam、canvas、screen）。                                   |
| `最新缓冲帧年龄（毫秒）` | `int`      | 最新缓冲帧的年龄（毫秒）； `0` 在未知或没有缓冲帧时。                                           |
| `原始 Extras`   | `JObject`  | 完整的 extras 载荷，包括 `vision_buffer` 诊断对象（保留帧、PTS 窗口、丢弃计数器），适用于没有类型化访问器的字段。 |
| `时间戳`         | `DateTime` | 该事件在客户端创建时的 UTC 时间。                                                     |

### `VisionContextTriggerReceived`

后端对一个 `vision-trigger` 请求，通过 `TriggerVision`发送，报告触发是如何被解析的（响应模式、降级）以及哪些帧被附加到了模型轮次。

| 属性             | 类型                    | 描述                                                                                       |
| -------------- | --------------------- | ---------------------------------------------------------------------------------------- |
| `状态`           | `string`              | 响应状态： `成功`, `错误`, `处理中`，或 `待处理`.                                                         |
| `消息`           | `string`              | 附带响应的可选可读消息。                                                                             |
| `UpdateId`     | `string`              | 对请求幂等键的回显。                                                                               |
| `结果`           | `string`              | 触发结果，例如 `有可用帧`, `缓冲区为空`, `未启用 vision`, `无效的响应模式`, `无效的帧索引`, `frame_id_evicted`，或 `速率受限`. |
| `请求的响应模式`      | `string`              | 请求所要求的响应模式（`silent`/`auto`/`must_respond`).                                              |
| `实际响应模式`       | `string`              | 后端在基于状态的降级后实际应用的响应模式。                                                                    |
| `请求的 LLM 运行策略` | `string`              | 线上请求的 LLM 策略（`true`/`auto`/`false`).                                                     |
| `实际 LLM 运行策略`  | `string`              | 降级后实际应用的 LLM 策略。                                                                         |
| `LlmTriggered` | `bool`                | `true` 当触发导致 LLM 调用时。                                                                    |
| `已降级`          | `bool`                | `true` 当后端降低所请求的响应模式时（例如机器人忙碌、用户正在讲话）。                                                   |
| `降级原因`         | `string`              | 请求为何被降级，例如 `bot_busy` 或 `user_speaking`；否则为空。                                            |
| `附加的帧数`        | `int`                 | 附加到该轮次的图像帧数量。                                                                            |
| `附加结果`         | `string`              | 附加结果： `已附加`, `去重占位符`, `跳过过期项`，或 `无`.                                                     |
| `图像令牌估算`       | `int`                 | 后端估算附加帧所消耗的图像令牌数量（仅用于归因，不计费）。                                                            |
| `附加帧 PTS`      | `IReadOnlyList<long>` | 模型实际看到的帧的展示时间戳（纳秒）。                                                                      |
| `原始 Extras`    | `JObject`             | 完整的 extras 载荷（包括 `vision_buffer` diagnostics）用于没有类型化访问器的字段。                              |
| `时间戳`          | `DateTime`            | 该事件在客户端创建时的 UTC 时间。                                                                      |

### `RespondModeUpdateResultReceived`

后端对一个 `respond-mode-update` 请求，通过 `UpdateRespondMode`，回显该通道和已应用的模式，或在无法更改通道时回显拒绝结果。

| 属性          | 类型         | 描述                                                 |
| ----------- | ---------- | -------------------------------------------------- |
| `状态`        | `string`   | 响应状态： `成功` 在已应用时， `错误` 在被拒绝时。                      |
| `消息`        | `string`   | 可选的可读消息（例如用户输入通道的拒绝原因）。                            |
| `UpdateId`  | `string`   | 当后端返回幂等键时，对请求幂等键的回显。                               |
| `模态`        | `string`   | 更新所针对的通道，作为后端模态字符串（例如 `vision`, `context_update`). |
| `模式`        | `string`   | 该通道当前生效的响应模式（`silent`/`auto`/`must_respond`).      |
| `原始 Extras` | `JObject`  | 完整的 extras 载荷，包括后端完整的 `respond_modes` 通道快照。        |
| `时间戳`       | `DateTime` | 该事件在客户端创建时的 UTC 时间。                                |

### 下一步

{% content-ref url="/pages/cb7758289bc48a93210bce51933fd819fd05e245" %}
[自定义帧源](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/vision/custom-frame-sources.md)
{% endcontent-ref %}

{% content-ref url="/pages/86612bc613c5a299a468b71b3fb8a40e625ee1fe" %}
[排查视觉问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/vision/troubleshooting-and-diagnostics.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/vision/scripting-api.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.
