> 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` 创建房间并使用 `group-address` 进行寻址，而不是切换活动角色。参见 [构建群聊](/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> 。

### 创建并加入房间

发送一个有序的 `characters` 数组到 `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
  }'
```

每个 `characters` 响应中的条目代表一个角色实例。这个简化响应显示了两个条目；完整响应包含每个请求实例对应的一个条目，以及标准的 `/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
    }
  ]
}
```

使用 `room_url`, `room_name`，并且 `token`加入返回的 LiveKit 房间。另一个人可以通过调用 `/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`。加入现有房间时不要重新发送 `characters` 。

### 映射每个角色实例

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

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

从 `characters[].participant_identity`构建媒体映射。不要通过 `character_id`来匹配 LiveKit 音频轨道，因为克隆的角色实例共享相同的角色 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
    }
  }
}
```

### 切换活动角色

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

```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` 以清除活动目标；在您选择另一个角色之前，对话输入不会路由到任何角色。

### 更新 roster

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