# Мультиарендные и серверные развертывания

Режим многопользовательского сервера означает запуск Copilot SDK из бэкенд-кода, обслуживающего более одного человека, арендатора, рабочего пространства или интеграционного аккаунта. В этой конфигурации приложение управляет маршрутизацией и авторизацией запросов, а SDK и среда выполнения обеспечивают состояние за сессию, аутентификацию за сессию и явную регистрацию инструментов, чтобы сессия одного пользователя не наследовала инструменты или идентичность другого пользователя.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

**Лучше всего для:** SaaS-продукты, интеграции с партнёрами, внутренние платформы и бэкенд-сервисы, работающие с одновременно работающими пользователями.

## Используйте это руководство, когда

Используйте это руководство при строительстве:

* Многопользовательский SaaS-продукт, в котором встроены агенты на базе Copilot
* Бэкенд для партнёрской интеграции, например, Copilot Studio или выкройка в стиле Fabric
* Любой сервер, который обрабатывает одновременных пользователей, рабочие пространства, арендаторы или запросы
* Общее время выполнения, где несколько SDK-клиентов подключаются к одному процессу Copilot

Это руководство является сестринским вариантом [AUTOTITLE.](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/scaling) Используйте это руководство для топологии, балансировки нагрузки и шаблонов хранения. Используйте это руководство для параметров на уровне SDK и выбора изоляции во время выполнения.

## Ключевые опции SDK

| Опция                           | Используйте его для                                                    | Notes                                                              |
| ------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `mode: "empty"`                 | Отключение инструментов окружающей среды ОС и стандартных настроек CLI | Требуется для многопользовательских или совместных сценариев.      |
| `sessionIdleTimeoutSeconds`     | Очистка занятий холостого хода                                         | Установите тайм-аут на стороне сервера для долгосрочных процессов. |
| `baseDirectory`                 | Изоляция `COPILOT_HOME` каждого экземпляра во время выполнения         | Игнорируется при подключении к существующему runtime.              |
| `sessionFs`                     | Маршрутизация файловой системы сессии с локального диска               | Сопоставьте с провайдерами файловой системы для каждой сессии.     |
| `RuntimeConnection.forUri(url)` | Делюсь одним уже работающим временем выполнения                        | Названия языков различаются; См. примеры ниже.                     |
| За сессию `gitHubToken`         | Определение аутентификации для запрашивающего пользователя             | Предпочитаю этот токен, а не один общий пользовательский токен.    |

### `mode: "empty"`

`mode: "empty"` по умолчанию отключает опциональное Copilot поведение CLI. В режиме многопользовательского сервера это безопасная база, потому что ваше приложение должно чётко определить, какие инструменты, MCP-серверы, навыки и пути рабочего пространства смогут использовать сессия.

Не используйте стандартные `mode: "copilot-cli"` настройки для общих серверов. Этот режим предназначен для агентов кодирования, похожих на CLI, и может раскрывать возможности фоновой файловой системы хоста.

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";

// baseDirectory and sessionIdleTimeoutSeconds apply when the SDK spawns the
// runtime. With RuntimeConnection.forUri(...) configure COPILOT_HOME and the
// idle timeout on the runtime process itself.
const client = new CopilotClient({
    mode: "empty",
    connection: RuntimeConnection.forUri(process.env.COPILOT_RUNTIME_URL!),
});

const session = await client.createSession({
    sessionId: `user-${user.id}-${crypto.randomUUID()}`,
    model: "gpt-5.4",
    availableTools: ["custom:lookupOrder", "custom:createTicket"],
    gitHubToken: user.githubToken,
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot import CopilotClient, RuntimeConnection
from copilot.session import PermissionHandler

client = CopilotClient(
    mode="empty",
    base_directory=f"/var/lib/my-app/copilot/{runtime_instance_id}",
    session_idle_timeout_seconds=900,
    connection=RuntimeConnection.for_uri(runtime_url),
)
await client.start()

session = await client.create_session(
    session_id=f"user-{user.id}-{request_id}",
    model="gpt-5.4",
    available_tools=["custom:lookupOrder", "custom:createTicket"],
    github_token=user.github_token,
    on_permission_request=PermissionHandler.approve_all,
)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
client := copilot.NewClient(&copilot.ClientOptions{
    Mode:                      copilot.ModeEmpty,
    BaseDirectory:             fmt.Sprintf("/var/lib/my-app/copilot/%s", runtimeInstanceID),
    SessionIdleTimeoutSeconds: 900,
    Connection:                copilot.URIConnection{URL: runtimeURL},
})

session, err := client.CreateSession(ctx, &copilot.SessionConfig{
    SessionID:      fmt.Sprintf("user-%s-%s", user.ID, requestID),
    Model:          "gpt-5.4",
    AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
    GitHubToken:    user.GitHubToken,
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
var client = new CopilotClient(new CopilotClientOptions
{
    Mode = CopilotClientMode.Empty,
    BaseDirectory = $"/var/lib/my-app/copilot/{runtimeInstanceId}",
    SessionIdleTimeoutSeconds = 900,
    Connection = RuntimeConnection.ForUri(runtimeUrl),
});

await using var session = await client.CreateSessionAsync(new SessionConfig
{
    SessionId = $"user-{user.Id}-{requestId}",
    Model = "gpt-5.4",
    AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
    GitHubToken = user.GitHubToken,
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
// setCopilotHome and setSessionIdleTimeoutSeconds are ignored when
// setCliUrl is used; configure those on the runtime process instead.
var client = new CopilotClient(new CopilotClientOptions()
    .setMode(CopilotClientMode.EMPTY)
    .setCliUrl(runtimeUrl)
);

var session = client.createSession(new SessionConfig()
    .setSessionId("user-" + user.id() + "-" + requestId)
    .setModel("gpt-5.4")
    .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
    .setGitHubToken(user.gitHubToken())
).get();
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

```rust
use std::path::PathBuf;
use github_copilot_sdk::{Client, ClientOptions, Transport};
use github_copilot_sdk::mode::ClientMode;
use github_copilot_sdk::types::SessionConfig;

let client = Client::start(
    ClientOptions::new()
        .with_mode(ClientMode::Empty)
        .with_base_directory(PathBuf::from(format!(
            "/var/lib/my-app/copilot/{runtime_instance_id}"
        )))
        .with_session_idle_timeout_seconds(900)
        .with_transport(Transport::External {
            host: runtime_host.to_string(),
            port: runtime_port,
            connection_token: None,
        }),
).await?;

let session = client.create_session(
    SessionConfig::default()
        .with_session_id(format!("user-{}-{request_id}", user.id))
        .with_model("gpt-5.4")
        .with_available_tools(["custom:lookupOrder", "custom:createTicket"])
        .with_github_token(user.github_token),
).await?;
```

</div>

</div>

### `sessionIdleTimeoutSeconds`

Настройте `sessionIdleTimeoutSeconds` серверы так, чтобы неактивные сессии очищались автоматически. Это предотвращает зомби-сессии в долгоработающих процессах и снижает нагрузку на память и файловую систему.

| Language   | Публичная опция                          |
| ---------- | ---------------------------------------- |
| TypeScript | `sessionIdleTimeoutSeconds`              |
| Python     | `session_idle_timeout_seconds`           |
| Go         | `SessionIdleTimeoutSeconds`              |
| .NET       | `SessionIdleTimeoutSeconds`              |
| Java       | `setSessionIdleTimeoutSeconds(...)`      |
| Rust       | `with_session_idle_timeout_seconds(...)` |

Используйте значение, соответствующее продолжительности общения вашего продукта. Для чат-бэкендов обычно 15–30 минут — хороший старт. Для агентов рабочих процессов используйте более длительный тайм-аут и явное удаление после завершения процесса.

### `baseDirectory`

`baseDirectory` устанавливает `COPILOT_HOME` для экземпляра во время выполнения. Используйте его для изоляции состояния runtime, учетных данных и сессионных данных по процессу, поду, работнику или арендатору.

```typescript
const client = new CopilotClient({
    mode: "empty",
    baseDirectory: `/var/lib/my-app/copilot/runtime-${process.env.HOSTNAME}`,
    sessionIdleTimeoutSeconds: 900,
});
```

Состояние сессии во время выполнения хранит под настроенным `COPILOT_HOME`, включая `session-state/{sessionId}`. Если ваше приложение запускает несколько экземпляров во время выполнения, дайте каждому инстансу отдельную директорию, если только вы намеренно не используете общее хранилище.

Когда SDK подключается к уже запущенному runtime с `RuntimeConnection.forUri(url)`, `baseDirectory` он игнорируется клиентом SDK. Настройте `COPILOT_HOME` на процессе выполнения вместо этого.

### `sessionFs`

`sessionFs` регистрирует пользовательский сервер файловой системы сессии, чтобы ввод/вывод файлов с ограниченным графиком можно было маршрутизировать через хранилище приложений вместо локального диска среды выполнения. Используйте его, когда локальный диск эфемерен, когда состояние сессии должно оставаться в объектном хранилище, или когда платформе нужно навязывать пути хранения с учётом арендаторов.

```typescript
const client = new CopilotClient({
    mode: "empty",
    sessionFs: {
        initialCwd: "/workspace",
        sessionStatePath: "/session-state",
        conventions: "posix",
    },
});
```

Для языков, предоставляющих обратный вызов провайдера, настройте `sessionFs` на уровне клиента и предоставляйте обработчик файловой системы для каждой сессии при создании или возобновлении сессии. См. [Возобновление сессии и сохранение](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/session-persistence) для концепций устойчивости и компромиссов при хранении.

Проверенные публичные поверхности SDK:

| Language                                               | Конфигурация на уровне клиента | Провайдер на сессию             |
| ------------------------------------------------------ | ------------------------------ | ------------------------------- |
| TypeScript                                             | `sessionFs`                    |                                 |
| `createSessionFsAdapter` / обратные звонки провайдеров |                                |                                 |
| Python                                                 | `session_fs`                   | `create_session_fs_handler`     |
| Go                                                     | `SessionFS`                    | `CreateSessionFSProvider`       |
| .NET                                                   | `SessionFs`                    | `CreateSessionFsProvider`       |
| Rust                                                   | `with_session_fs(...)`         | `with_session_fs_provider(...)` |

Java в настоящее время не показывает проверенный публичный вариант `sessionFs`, поэтому в этом руководстве не показано выборку Java `sessionFs`.

### `RuntimeConnection.forUri(url)`

Используйте внешнее подключение для выполнения времени, когда несколько SDK-клиентов должны делить одну уже запущенную среду выполнения. Это часто встречается в бэкенд-сервисах, где процесс выполнения управляется отдельно от обработчиков запросов.

| Language   | Внешнее подключение во время выполнения                |
| ---------- | ------------------------------------------------------ |
| TypeScript | `RuntimeConnection.forUri(url)`                        |
| Python     | `RuntimeConnection.for_uri(url)`                       |
| Go         | `copilot.URIConnection{URL: url}`                      |
| .NET       | `RuntimeConnection.ForUri(url)`                        |
| Java       | `setCliUrl(url)`                                       |
| Rust       | `Transport::External { host, port, connection_token }` |

Внешние серверы выполнения управляют собственной аутентификацией и хранением на уровне процесса. Передавайте токены за сессию на `createSession` или `resumeSession` когда нужна аутентификационная лицензия пользователя.

### За сессию `gitHubToken`

Установите `gitHubToken` на каждой сессии так, чтобы GitHub аутентификации для запрашивающего пользователя. Это отличается от токена на уровне клиента, который аутентифицирует процесс выполнения.

```typescript
const session = await client.createSession({
    sessionId: `user-${user.id}-support`,
    model: "gpt-5.4",
    availableTools: ["custom:*"],
    gitHubToken: user.githubToken,
});
```

Используйте токены за сессию для исключения контента, маршрутизации моделей, проверки квот и пользовательского доступа к Copilot. Избегайте совместного использования одного сервисного токена между пользователями, если только ваш продукт намеренно не использует семантику сервис-аккаунт.

## Идентификатор интеграции

Партнёры, создающие брендированные агенты, могут устанавливать идентификатор интеграции для запросов в Центр управления полётом. Время выполнения читает `GITHUB_COPILOT_INTEGRATION_ID` и маркирует его как HTTP-заголовок `Copilot-Integration-Id` на каждом запросе Управления полётами.

```bash
GITHUB_COPILOT_INTEGRATION_ID=my-product-agent copilot --headless --port 4321
```

Идентификатор интеграции по умолчанию — `copilot-developer-cli`. Используйте стабильное значение, например `my-product-agent` для атрибуции и маршрутизации. Идентификатор интеграции в настоящее время настраивается только по переменной среды; это не первоклассный SDK.

Если SDK вызывает время выполнения, передайте переменную среды через опцию клиентской среды. Если вы подключитесь к `RuntimeConnection.forUri(url)`, установите переменную окружения непосредственно на процессе выполнения.

## Гарантии изоляции на уровне сессии

Изоляция на уровне сессии означает, что среда выполнения сохраняет пользовательскую информацию о модели и состояниях в рамках сессии, а не в глобальном общем состоянии.

| Surface                | Изоляционное поведение                                             |
| ---------------------- | ------------------------------------------------------------------ |
| Кэш списка моделей     | За сессию. Поиск модели использует кэш списка моделей сессии.      |
| Состояние сеанса       | Идентификатор сессии под `COPILOT_HOME/session-state/{sessionId}`. |
| GitHub идентичность    | Каждую сессию, когда `gitHubToken` установлена сессия.             |
| Tools                  | Явно в `mode: "empty"`; амбиент в `mode: "copilot-cli"`.           |
| Файловая система хоста | Используется процессом выполнения, если доступны хост-инструменты. |

`mode: "empty"` именно это делает общие шаблоны выполнения жизнеспособными: ни один инструмент ОС не отображается, если ваше приложение не регистрирует или не разрешает их. При `mode: "copilot-cli"`, доступ к файловой системе ОС осуществляется через хост-процесс, поэтому не используйте этот режим для многопользовательского сервера.

Состояние сессии хранится в `COPILOT_HOME/session-state/{sessionId}` , если только вы не направите его через `sessionFs`. Используйте уникальные идентификаторы сессий, которые включают границы вашего арендатора или пользователя, и обеспечивайте контроль доступа перед возобновлением или удалением сессий.

## Сравнение узоров

| Pattern                                     | Используйте, если                                                                                                                                              | Trade-offs                                                                                                                                                                      |
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Шаблон 1: изолированный CLI на пользователя | Вам нужна самая строгая граница изоляции или отдельные учетные данные процесса для каждого пользователя.                                                       | Сильная изоляция; Более высокая стоимость ресурсов. См [. раздел AUTOTITLE](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/scaling).                             |
| Шаблон 2: общий CLI с `mode: "empty"`       | Вам нужно, чтобы одна среда выполнения обслуживала многих пользователей, а ваше приложение управляло инструментами, аутентификацией и идентификаторами сессий. | Эффективно; требуется тщательная регистрация инструментов, токены за сессию и проверка доступа на уровне приложения.                                                            |
| Шаблон 3: гибрид                            | Вы перенаправляете работу с вычислительной нагрузкой в облачные сессии, а лёгкую — в локальные сессии.                                                         | Гибкий; Требуется маршрутизация рабочей нагрузки и обработка политик. См [. раздел AUTOTITLE](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/cloud-sessions). |

### Шаблон 2: общий CLI с `mode: "empty"`

В этом шаблоне все пользователи подключаются через ваш бэкенд к одному пулу runtime. Приложение выполняет аутентификацию пользователя, выбирает идентификатор сессии, передаёт токен GitHub пользователя на сессию и предоставляет явный список разрешений инструментов.

![Диаграмма: блок-схема, показывающая описанный процесс.](/assets/images/help/copilot/copilot-sdk/setup-multi-tenancy-diagram-0.png)

Используйте следующие правила:

* Всегда запускайте клиент или время выполнения в `mode: "empty"`.
* Используйте уникальные идентификаторы сессий и храните метаданные владения в базе данных приложений.
* Проверьте владение перед `resumeSession`, `deleteSession`или любое действие интерфейса, ссылающееся на идентификатор сессии.
* Пропускайте `gitHubToken` каждую сессию, когда запросы должны выполняться от пользователя.
* Регистрируйте только те инструменты, которые нужны сессии, и предпочитайте квалифицированные по источнику списки разрешений, такие как `custom:*` или `mcp:search_docs`.
* Устанавливайте `sessionIdleTimeoutSeconds` и удаляйте завершённые сессии рабочего процесса явно.

## Распространенные ловушки

* Забывая `mode: "empty"`. Режим по умолчанию `copilot-cli` демонстрирует поведение в стиле CLI и может раскрывать файловую систему хоста с помощью окружающих инструментов.
* Не устанавливаю `sessionIdleTimeoutSeconds`. Долгосрочные серверы могут накапливать простою, если не очищать их.
* Обмен одним `gitHubToken` между пользователями вместо передачи токена за сессию.
* Доверие к идентификаторам сессий, предоставленным клиентом, без проверки собственности на вашем бэкенде.
* Настройка `baseDirectory` клиента, который подключается к существующему runtime, и ожидание перемещения хранилища во время выполнения. Настройте процесс выполнения вместо этого.
* Разрешить общие шаблоны инструментов, например `builtin:*` , без проверки, подходит ли каждый из них вашим пользователям.

## См. также

* [Масштабирование и многоарендность](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/scaling): топологии развертывания, шаблоны хранения и сравнение изоляции
* [Настройка серверных сервисов](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/backend-services): запуск времени выполнения в режиме безголового сервера
* [БЁК (принеси свой ключ)](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/auth/byok): использование учетных данных вашего собственного поставщика модели
* [Облачные сессии](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/cloud-sessions): маршрутизация выбранной работы в облачные сессии
* [Возобновление сессии и сохранение](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/session-persistence): управление восстановленным состоянием сессии
* [Возможности](/ru/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features): инструменты, события, крючки и расширенные функции SDK