> 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/api-can-kao/core-api-reference/live-apis-beta/multi-character-sessions.md).

# 使用多角色会话

创建一个包含多个角色的 Live API 房间，映射它们的媒体，切换活动角色，并安全地更新成员列表。

创建一个包含多个角色实例的 Live API 房间，并将每个用户轮次路由到一个活动角色。即使两个条目使用相同的角色 ID，角色实例仍然可以独立寻址。

要让多个实例同时回答同一条消息，请创建房间时使用 `group_chat: true` 并通过以下方式寻址它： `群组点名` 而不是切换活动角色。参见 [构建群聊](/api-docs/zh/api-can-kao/core-api-reference/live-apis-beta/build-a-group-chat.md).

{% hint style="info" %}
多角色会话仅对已启用该功能的账户开放。你的账户角色和参与者限制仍然适用。
{% endhint %}

### 前置条件

* 一个可访问 Live API 和多角色会话的 Convai API 密钥
* API 密钥可以访问的一个或多个角色 ID
* 一个稳定、非空的 `end_user_id` 用于每个人类参与者
* 一个可发布音频并接收远程音频轨道和数据消息的 LiveKit 客户端

设置 `LIVE_API_URL` 为 <code class="expression">space.vars.live\_server\_url</code> 。

### 创建并加入房间

发送一个有序的 `角色` 数组到 `POST /connect`。第一个条目会成为初始活动角色。重复一个 `character_id` 会创建该角色的另一个可独立寻址实例。

```bash
curl --request POST "${LIVE_API_URL}/connect" \\
  --header "X-API-Key: ${CONVAI_API_KEY}" \\
  --header "Content-Type: application/json" \\
  --data '{
    "characters": [
      { "character_id": "11111111-1111-4111-8111-111111111111" },
      { "character_id": "22222222-2222-4222-8222-222222222222" },
      { "character_id": "11111111-1111-4111-8111-111111111111" }
    ],
    "connection_type": "audio",
    "end_user_id": "learner-42",
    "shared_session_key": "safety-training-42",
    "max_num_participants": 2
  }'
```

每个 `角色` 响应中的条目代表一个角色实例。这个简化响应显示了两个条目；完整响应包含每个请求实例对应的一个条目，以及标准的 `/connect` 字段：

```json
{
  "room_url": "wss://example.livekit.cloud",
  "room_name": "convai-room-example",
  "token": "LIVEKIT_PARTICIPANT_TOKEN",
  "room_session_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
  "active_membership_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
  "route_epoch": 0,
  "roster_epoch": 0,
  "partial_dispatch": false,
  "characters": [
    {
      "membership_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
      "character_id": "11111111-1111-4111-8111-111111111111",
      "session_id": "CHARACTER_SESSION_TOKEN_1",
      "character_session_id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
      "participant_identity": "CHARACTER_PARTICIPANT_1",
      "is_initial": true,
      "provisioning_status": "dispatch_accepted",
      "failure_code": null
    },
    {
      "membership_id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
      "character_id": "22222222-2222-4222-8222-222222222222",
      "session_id": "CHARACTER_SESSION_TOKEN_2",
      "character_session_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
      "participant_identity": "CHARACTER_PARTICIPANT_2",
      "is_initial": false,
      "provisioning_status": "dispatch_accepted",
      "failure_code": null
    }
  ]
}
```

使用以下方式加入返回的 LiveKit 房间 `room_url`, `room_name`，以及 `token`。另一位人类可以通过调用以下方式加入同一个房间 `/connect` 使用 `mode: "join"`，一个新的 `end_user_id`，以及恰好一个房间定位器：

```json
{
  "mode": "join",
  "room_session_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
  "end_user_id": "learner-43"
}
```

你可以使用 `shared_session_key` 而不是 `room_session_id`。加入现有房间时不要重新发送 `角色` 。

### 映射每个角色实例

将这些标识符用于不同的任务：

| 字段                     | 用于                                      |
| ---------------------- | --------------------------------------- |
| `character_id`         | 标识 Convai 角色定义。它在一个房间内可以重复。             |
| `membership_id`        | 用于定位或移除一个具体的角色实例。                       |
| `participant_identity` | 将该角色实例与其 LiveKit 参与者和媒体轨道匹配。请将该值视为不透明值。 |
| `character_session_id` | 在稍后的会话中继续该角色实例的对话。                      |

从以下内容构建媒体映射： `characters[].participant_identity`。不要按以下方式匹配 LiveKit 音频轨道： `character_id`，因为克隆的角色实例共享相同的角色 ID。

在启用与其交互之前，等待每个可用角色实例都收到一条 `bot-ready` 消息。其 `data.about` 对象标识就绪实例：

```json
{
  "label": "rtvi-ai",
  "type": "bot-ready",
  "data": {
    "about": {
      "room_session_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
      "membership_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
      "character_id": "11111111-1111-4111-8111-111111111111",
      "character_session_id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
      "participant_identity": "CHARACTER_PARTICIPANT_1",
      "is_initial": true,
      "roster_epoch": 0
    }
  }
}
```

### 切换活动角色

只有活动角色会处理用户的对话输入。发送 `interaction-target` 到 LiveKit 数据通道以切换目标：

```json
{
  "id": "select-assessor-1",
  "type": "interaction-target",
  "data": {
    "room_session_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
    "target_membership_id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
    "expected_route_epoch": 0
  }
}
```

一次成功的 `server-response` 会返回当前目标以及一个新的 `route_epoch`:

```json
{
  "type": "server-response",
  "event_type": "interaction-target",
  "status": "success",
  "extras": {
    "success": true,
    "command_id": "select-assessor-1",
    "room_session_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
    "previous_membership_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
    "active_membership_id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
    "route_epoch": 1,
    "changed": true
  }
}
```

保存返回的 epoch，并在下一次目标更改时将其作为 `expected_route_epoch` 发送。设置 `target_membership_id` 为 `null` 以清除活动目标；在你选择另一个目标之前，对话输入不会路由到任何角色。

### 更新名册

发送 `character-roster-update` 以在不创建新房间的情况下添加或移除角色实例：

```json
{
  "id": "update-roster-1",
  "type": "character-roster-update",
  "data": {
    "room_session_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
    "expected_roster_epoch": 0,
    "add": [
      { "character_id": "33333333-3333-4333-8333-333333333333" }
    ],
    "remove_membership_ids": [
      "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
    ],
    "replacement_target_membership_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
  }
}
```

通过以下方式指定移除项： `membership_id`，而不是 `character_id`。如果移除活动实例，请设置 `replacement_target_membership_id` 为一个仍留在房间中的就绪实例。成员列表不能为空。

成功时， `server-response` 包含 `已添加`, `removed_membership_ids`, `active_membership_id`, `route_epoch`，以及新的 `roster_epoch`。保存这两个返回的 epoch。新实例会发出 `character-status` 消息，随着它们启动并就绪，随后是它们自己的 `bot-ready` 消息。被移除的实例会发出 `character-removed`.

### 验证和排障

在发送对话输入前，请验证：

* 每个预期实例都有一个唯一的 `membership_id` 和 `participant_identity`.
* `partial_dispatch` 是 `false`，或者你的客户端已使用其 `provisioning_status` 和 `failure_code`.
* 每个可用实例都已发出 `bot-ready`.
* 每条远程音频轨道都通过以下方式绑定： `participant_identity`.
* 最新成功的 `route_epoch` 和 `roster_epoch` 用于后续命令。

| 症状                    | 可能原因                        | 修复方法                                                                                          |
| --------------------- | --------------------------- | --------------------------------------------------------------------------------------------- |
| 同一角色的两个副本会解析为同一个客户端对象 | 客户端按以下方式映射： `character_id`. | 按以下方式映射每个实例： `membership_id`，并按以下方式映射媒体： `participant_identity`.                              |
| 目标或名册命令返回一个 epoch 错误  | 另一个已接受的命令先更改了房间状态。          | 再次加入房间以刷新它，然后使用当前 epoch 和新的命令 ID 重试。                                                          |
| 某个角色始终未变为就绪           | 它的配置失败或仍在进行中。               | 检查 `provisioning_status`, `failure_code`，以及 `character-status`；在它变为就绪之前，不要向其路由输入 `bot-ready`. |
| 加入请求被拒绝               | 房间定位器、参与者限制或账户访问无效。         | 发送恰好一个定位器，验证房间处于活动状态，并确认账户限制。                                                                 |

使用唯一的 `id` 用于每个新命令。如果无法确定投递是否成功，请使用相同的 ID 和不变的负载重试同一命令，这样服务器就能安全地识别重复项。

### 下一步

{% content-ref url="/pages/15180836560fd90ff696290b278b06e6bf755122" %}
[构建群聊](/api-docs/zh/api-can-kao/core-api-reference/live-apis-beta/build-a-group-chat.md)
{% endcontent-ref %}

{% content-ref url="/pages/f76eaea2a343c7d72b93487d582ec00dd7ba1c58" %}
[多角色会话](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions.md)
{% endcontent-ref %}

{% content-ref url="/pages/70d752d330612b0fbf1290588e718236d6a18f0e" %}
[连接 API](/api-docs/zh/api-can-kao/core-api-reference/live-apis-beta/connect-api.md)
{% endcontent-ref %}

{% content-ref url="/pages/138cedadc568671d93b18cf90042de5055cbffd5" %}
[客户端到服务器消息](/api-docs/zh/api-can-kao/core-api-reference/live-apis-beta/client-to-server-messages.md)
{% endcontent-ref %}

{% content-ref url="/pages/59c52679f01490a61606cfcd7dd110c8f8fec77f" %}
[服务器到客户端消息](/api-docs/zh/api-can-kao/core-api-reference/live-apis-beta/server-to-client-messages.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/api-can-kao/core-api-reference/live-apis-beta/multi-character-sessions.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.
